464 lines
14 KiB
Lua
464 lines
14 KiB
Lua
local propagation_utils = require "kong.observability.tracing.propagation.utils"
|
|
local tablex = require "pl.tablex"
|
|
local shallow_copy = require "kong.tools.table".shallow_copy
|
|
local to_hex = require "resty.string".to_hex
|
|
|
|
local from_hex = propagation_utils.from_hex
|
|
local fmt = string.format
|
|
|
|
|
|
-- W3C Ids
|
|
local trace_id_16_w3c = "0af7651916cd43dd8448eb211c80319c"
|
|
local trace_id_8_w3c_dec = "9532127138774266268" -- 8448eb211c80319c to decimal
|
|
local span_id_8_w3c = "b7ad6b7169203331"
|
|
local span_id_8_w3c_dec = "13235353014750950193" -- b7ad6b7169203331 to decimal
|
|
|
|
-- B3 Ids
|
|
local trace_id_16_b3 = "dc9d1b0ccedf0ecaf4f26ffab84d4f5e"
|
|
local trace_id_8_b3 = "f4f26ffab84d4f5e"
|
|
local span_id_8_b3 = "b7ad6b7169203332"
|
|
local span_id_8_b3p = "f4f26ffab84d4f5f"
|
|
|
|
-- Jaeger Ids
|
|
local trace_id_16_jae = "f744b23fe9aa64f08255043ba51848db"
|
|
local span_id_8_jae = "f4f26ffab84d4f60"
|
|
local span_id_8_jaep = "f4f26ffab84d4f61"
|
|
|
|
local padding_prefix = string.rep("0", 16)
|
|
|
|
-- apply some transformation to a hex id (affects last byte)
|
|
local function transform_hex_id(id)
|
|
local max = string.byte("f")
|
|
local min = string.byte("0")
|
|
|
|
local bytes = { id:byte(1, -1) }
|
|
local last_byte = bytes[#bytes]
|
|
|
|
last_byte = last_byte + 1 < max and last_byte + 1 or min
|
|
bytes[#bytes] = last_byte
|
|
return string.char(unpack(bytes))
|
|
end
|
|
|
|
-- apply some transformation (same as transform_hex_id above) to a binary id
|
|
local function transform_bin_id(bid)
|
|
return from_hex(transform_hex_id(to_hex(bid)))
|
|
end
|
|
|
|
local request_headers_1 = {
|
|
traceparent = fmt("00-%s-%s-01", trace_id_16_w3c, span_id_8_w3c),
|
|
["x-b3-traceid"] = trace_id_16_b3,
|
|
["x-b3-spanid"] = span_id_8_b3,
|
|
["x-b3-sampled"] = "1",
|
|
["x-b3-parentspanid"] = span_id_8_b3p,
|
|
["uber-trace-id"] = fmt("%s:%s:%s:%s", trace_id_16_jae, span_id_8_jae, span_id_8_jaep, "01"),
|
|
}
|
|
|
|
local request_headers_2 = {
|
|
["x-b3-traceid"] = trace_id_8_b3,
|
|
["x-b3-spanid"] = span_id_8_b3,
|
|
["x-b3-sampled"] = "1",
|
|
["x-b3-parentspanid"] = span_id_8_b3p,
|
|
}
|
|
|
|
|
|
local test_data = { {
|
|
description = "extract empty, inject empty (propagation disabled)",
|
|
req_headers = request_headers_1,
|
|
conf = {
|
|
propagation = {
|
|
extract = {},
|
|
inject = {},
|
|
}
|
|
},
|
|
expected = request_headers_1
|
|
}, {
|
|
description = "extract = ignore, inject single heder",
|
|
req_headers = request_headers_1,
|
|
conf = {
|
|
propagation = {
|
|
extract = {},
|
|
inject = { "w3c" },
|
|
}
|
|
},
|
|
cb = function()
|
|
-- no extraction, set some values using the callback
|
|
-- (same as what tracing plugins would do)
|
|
return {
|
|
trace_id = from_hex("0af7651916cd43dd8448eb211c80319d"),
|
|
span_id = from_hex("8448eb211c80319e"),
|
|
should_sample = true,
|
|
}
|
|
end,
|
|
expected = tablex.merge(request_headers_1, {
|
|
traceparent = fmt("00-%s-%s-01", "0af7651916cd43dd8448eb211c80319d", "8448eb211c80319e"),
|
|
}, true)
|
|
}, {
|
|
description = "extract = ignore, inject multiple heders",
|
|
req_headers = request_headers_1,
|
|
conf = {
|
|
propagation = {
|
|
extract = {},
|
|
inject = { "w3c", "b3-single" },
|
|
}
|
|
},
|
|
cb = function()
|
|
-- no extraction, set some values using the callback
|
|
-- (same as what tracing plugins would do)
|
|
return {
|
|
trace_id = from_hex("0af7651916cd43dd8448eb211c80319d"),
|
|
span_id = from_hex("8448eb211c80319e"),
|
|
should_sample = true,
|
|
}
|
|
end,
|
|
expected = tablex.merge(request_headers_1, {
|
|
traceparent = fmt("00-%s-%s-01", "0af7651916cd43dd8448eb211c80319d", "8448eb211c80319e"),
|
|
b3 = fmt("%s-%s-1", "0af7651916cd43dd8448eb211c80319d", "8448eb211c80319e"),
|
|
}, true)
|
|
}, {
|
|
description = "extract = ignore, inject = preserve, no default setting",
|
|
req_headers = request_headers_1,
|
|
conf = {
|
|
propagation = {
|
|
extract = {},
|
|
inject = { "preserve" },
|
|
}
|
|
},
|
|
cb = function()
|
|
-- no extraction, set some values using the callback
|
|
-- (same as what tracing plugins would do)
|
|
return {
|
|
trace_id = from_hex("0af7651916cd43dd8448eb211c80319d"),
|
|
span_id = from_hex("8448eb211c80319e"),
|
|
should_sample = true,
|
|
}
|
|
end,
|
|
expected = tablex.merge(request_headers_1, {
|
|
traceparent = fmt("00-%s-%s-01", "0af7651916cd43dd8448eb211c80319d", "8448eb211c80319e"),
|
|
}, true)
|
|
}, {
|
|
description = "extract = ignore, inject = preserve, uses default format",
|
|
req_headers = request_headers_1,
|
|
conf = {
|
|
propagation = {
|
|
extract = {},
|
|
inject = { "preserve" },
|
|
default_format = "datadog",
|
|
}
|
|
},
|
|
cb = function()
|
|
-- no extraction, set some values using the callback
|
|
-- (same as what tracing plugins would do)
|
|
return {
|
|
trace_id = from_hex("0af7651916cd43dd8448eb211c80319d"),
|
|
span_id = from_hex("8448eb211c80319e"),
|
|
should_sample = true,
|
|
}
|
|
end,
|
|
expected = tablex.merge(request_headers_1, {
|
|
["x-datadog-trace-id"] = "9532127138774266269", -- 8448eb211c80319d to dec
|
|
["x-datadog-parent-id"] = "9532127138774266270", -- 8448eb211c80319e to dec
|
|
["x-datadog-sampling-priority"] = "1"
|
|
}, true)
|
|
}, {
|
|
description = "extract configured with header not found in request, inject = preserve, uses default format",
|
|
req_headers = request_headers_1,
|
|
conf = {
|
|
propagation = {
|
|
extract = { "datadog" },
|
|
inject = { "preserve" },
|
|
default_format = "ot"
|
|
}
|
|
},
|
|
-- apply some updates to the extracted ctx
|
|
cb = function(ctx)
|
|
assert.same(ctx, {})
|
|
|
|
ctx.trace_id = from_hex("0af7651916cd43dd8448eb211c80319d")
|
|
ctx.span_id = from_hex("8448eb211c80319e")
|
|
ctx.should_sample = true
|
|
|
|
return ctx
|
|
end,
|
|
expected = tablex.merge(request_headers_1, {
|
|
["ot-tracer-sampled"] = '1',
|
|
["ot-tracer-spanid"] = '8448eb211c80319e',
|
|
["ot-tracer-traceid"] = '8448eb211c80319d',
|
|
}, true)
|
|
}, {
|
|
description = "extract configured with header found in request, inject = preserve + other formats",
|
|
req_headers = request_headers_1,
|
|
conf = {
|
|
propagation = {
|
|
extract = { "b3", "w3c", "jaeger" },
|
|
inject = { "w3c", "preserve", "b3-single" },
|
|
}
|
|
},
|
|
-- apply some updates to the extracted ctx
|
|
cb = function(ctx)
|
|
ctx.trace_id = transform_bin_id(ctx.trace_id)
|
|
ctx.span_id = transform_bin_id(ctx.span_id)
|
|
ctx.parent_id = transform_bin_id(ctx.parent_id)
|
|
return ctx
|
|
end,
|
|
expected = tablex.merge(request_headers_1, {
|
|
traceparent = fmt("00-%s-%s-01", transform_hex_id(trace_id_16_b3), transform_hex_id(span_id_8_b3)),
|
|
["x-b3-traceid"] = transform_hex_id(trace_id_16_b3),
|
|
["x-b3-spanid"] = transform_hex_id(span_id_8_b3),
|
|
["x-b3-sampled"] = "1",
|
|
["x-b3-parentspanid"] = transform_hex_id(span_id_8_b3p),
|
|
b3 = fmt("%s-%s-1-%s", transform_hex_id(trace_id_16_b3), transform_hex_id(span_id_8_b3),
|
|
transform_hex_id(span_id_8_b3p)),
|
|
}, true)
|
|
}, {
|
|
description = "extract configured with header formats, injection disabled",
|
|
req_headers = request_headers_1,
|
|
conf = {
|
|
propagation = {
|
|
extract = { "gcp", "aws", "ot", "datadog", "b3", "w3c", "jaeger" },
|
|
inject = {},
|
|
}
|
|
},
|
|
cb = function()
|
|
return {
|
|
trace_id = from_hex("abcdef"),
|
|
span_id = from_hex("123fff"),
|
|
should_sample = true,
|
|
}
|
|
end,
|
|
expected = request_headers_1
|
|
}, {
|
|
description = "extract configured with header formats, b3 first",
|
|
req_headers = request_headers_1,
|
|
conf = {
|
|
propagation = {
|
|
extract = { "b3", "w3c", "jaeger" },
|
|
inject = { "w3c" },
|
|
}
|
|
},
|
|
-- apply some updates to the extracted ctx
|
|
cb = function(ctx)
|
|
ctx.trace_id = transform_bin_id(ctx.trace_id)
|
|
ctx.span_id = transform_bin_id(ctx.span_id)
|
|
return ctx
|
|
end,
|
|
expected = tablex.merge(request_headers_1, {
|
|
traceparent = fmt("00-%s-%s-01", transform_hex_id(trace_id_16_b3), transform_hex_id(span_id_8_b3)),
|
|
}, true)
|
|
}, {
|
|
description = "extract configured with header formats, w3c first",
|
|
req_headers = request_headers_1,
|
|
conf = {
|
|
propagation = {
|
|
extract = { "w3c", "b3", "jaeger" },
|
|
inject = { "w3c" },
|
|
}
|
|
},
|
|
-- apply some updates to the extracted ctx
|
|
cb = function(ctx)
|
|
ctx.trace_id = transform_bin_id(ctx.trace_id)
|
|
ctx.span_id = transform_bin_id(ctx.span_id)
|
|
return ctx
|
|
end,
|
|
expected = tablex.merge(request_headers_1, {
|
|
traceparent = fmt("00-%s-%s-01", transform_hex_id(trace_id_16_w3c), transform_hex_id(span_id_8_w3c)),
|
|
}, true)
|
|
}, {
|
|
description = "extract configured with header formats, missing first header",
|
|
req_headers = request_headers_1,
|
|
conf = {
|
|
propagation = {
|
|
extract = { "datadog", "jaeger", "b3" },
|
|
inject = { "w3c" },
|
|
}
|
|
},
|
|
-- apply some updates to the extracted ctx
|
|
cb = function(ctx)
|
|
ctx.trace_id = transform_bin_id(ctx.trace_id)
|
|
ctx.span_id = transform_bin_id(ctx.span_id)
|
|
return ctx
|
|
end,
|
|
expected = tablex.merge(request_headers_1, {
|
|
traceparent = fmt("00-%s-%s-01", transform_hex_id(trace_id_16_jae), transform_hex_id(span_id_8_jae)),
|
|
}, true)
|
|
}, {
|
|
description = "extract configured with header formats, multiple injection",
|
|
req_headers = request_headers_1,
|
|
conf = {
|
|
propagation = {
|
|
extract = { "w3c", "b3", "jaeger" },
|
|
inject = { "datadog", "w3c" },
|
|
}
|
|
},
|
|
-- apply some updates to the extracted ctx
|
|
cb = function(ctx)
|
|
ctx.trace_id = transform_bin_id(ctx.trace_id)
|
|
ctx.span_id = transform_bin_id(ctx.span_id)
|
|
return ctx
|
|
end,
|
|
expected = tablex.merge(request_headers_1, {
|
|
traceparent = fmt("00-%s-%s-01", transform_hex_id(trace_id_16_w3c), transform_hex_id(span_id_8_w3c)),
|
|
["x-datadog-trace-id"] = transform_hex_id(trace_id_8_w3c_dec),
|
|
["x-datadog-parent-id"] = transform_hex_id(span_id_8_w3c_dec),
|
|
["x-datadog-sampling-priority"] = "1"
|
|
}, true)
|
|
}, {
|
|
description = "extract = b3, 64b id, inject = b3 and w3c",
|
|
req_headers = request_headers_2,
|
|
conf = {
|
|
propagation = {
|
|
extract = { "b3", },
|
|
inject = { "w3c", "b3" },
|
|
}
|
|
},
|
|
-- apply some updates to the extracted ctx
|
|
cb = function(ctx)
|
|
ctx.trace_id = transform_bin_id(ctx.trace_id)
|
|
ctx.span_id = transform_bin_id(ctx.span_id)
|
|
ctx.parent_id = transform_bin_id(ctx.parent_id)
|
|
return ctx
|
|
end,
|
|
expected = tablex.merge(request_headers_2, {
|
|
traceparent = fmt("00-%s-%s-01", transform_hex_id(padding_prefix .. trace_id_8_b3), transform_hex_id(span_id_8_b3)),
|
|
["x-b3-traceid"] = transform_hex_id(trace_id_8_b3), -- 64b (same as incoming)
|
|
["x-b3-spanid"] = transform_hex_id(span_id_8_b3),
|
|
["x-b3-sampled"] = "1",
|
|
["x-b3-parentspanid"] = transform_hex_id(span_id_8_b3p),
|
|
}, true)
|
|
}, {
|
|
description = "extract = b3, 128b id, inject = b3 and w3c",
|
|
req_headers = request_headers_1,
|
|
conf = {
|
|
propagation = {
|
|
extract = { "b3", },
|
|
inject = { "w3c", "b3" },
|
|
}
|
|
},
|
|
-- apply some updates to the extracted ctx
|
|
cb = function(ctx)
|
|
ctx.trace_id = transform_bin_id(ctx.trace_id)
|
|
ctx.span_id = transform_bin_id(ctx.span_id)
|
|
ctx.parent_id = transform_bin_id(ctx.parent_id)
|
|
return ctx
|
|
end,
|
|
expected = tablex.merge(request_headers_1, {
|
|
traceparent = fmt("00-%s-%s-01", transform_hex_id(trace_id_16_b3), transform_hex_id(span_id_8_b3)),
|
|
["x-b3-traceid"] = transform_hex_id(trace_id_16_b3), -- 128b (same as incoming)
|
|
["x-b3-spanid"] = transform_hex_id(span_id_8_b3),
|
|
["x-b3-sampled"] = "1",
|
|
["x-b3-parentspanid"] = transform_hex_id(span_id_8_b3p),
|
|
}, true)
|
|
}, {
|
|
description = "extract configured with header formats, inject = preserve (matches jaeger)",
|
|
req_headers = request_headers_1,
|
|
conf = {
|
|
propagation = {
|
|
extract = { "datadog", "jaeger", "b3" },
|
|
inject = { "preserve" },
|
|
}
|
|
},
|
|
-- apply some updates to the extracted ctx
|
|
cb = function(ctx)
|
|
ctx.trace_id = transform_bin_id(ctx.trace_id)
|
|
ctx.span_id = transform_bin_id(ctx.span_id)
|
|
ctx.parent_id = transform_bin_id(ctx.parent_id)
|
|
return ctx
|
|
end,
|
|
expected = tablex.merge(request_headers_1, {
|
|
["uber-trace-id"] = fmt("%s:%s:%s:%s", transform_hex_id(trace_id_16_jae), transform_hex_id(span_id_8_jae),
|
|
transform_hex_id(span_id_8_jaep), "01"),
|
|
}, true)
|
|
}, {
|
|
description = "clear = b3 and w3c",
|
|
req_headers = request_headers_1,
|
|
conf = {
|
|
propagation = {
|
|
extract = { "datadog", "jaeger", "b3", "w3c" },
|
|
inject = { "preserve" },
|
|
clear = {
|
|
"x-b3-traceid",
|
|
"x-b3-spanid",
|
|
"x-b3-sampled",
|
|
"x-b3-parentspanid",
|
|
"traceparent"
|
|
}
|
|
}
|
|
},
|
|
-- apply some updates to the extracted ctx
|
|
cb = function(ctx)
|
|
ctx.trace_id = transform_bin_id(ctx.trace_id)
|
|
ctx.span_id = transform_bin_id(ctx.span_id)
|
|
ctx.parent_id = transform_bin_id(ctx.parent_id)
|
|
return ctx
|
|
end,
|
|
expected = {
|
|
["uber-trace-id"] = fmt("%s:%s:%s:%s", transform_hex_id(trace_id_16_jae), transform_hex_id(span_id_8_jae),
|
|
transform_hex_id(span_id_8_jaep), "01"),
|
|
}
|
|
} }
|
|
|
|
|
|
|
|
describe("Tracing Headers Propagation Module", function()
|
|
local warn, err, set_serialize_value, req_headers
|
|
local old_get_headers = _G.ngx.req.get_headers
|
|
local old_kong = _G.kong
|
|
|
|
_G.ngx.req.get_headers = function()
|
|
return req_headers
|
|
end
|
|
|
|
_G.kong = {
|
|
ctx = {
|
|
plugin = {},
|
|
},
|
|
log = {},
|
|
service = {
|
|
request = {
|
|
set_header = function(name, value)
|
|
req_headers[name] = value
|
|
end,
|
|
clear_header = function(name)
|
|
req_headers[name] = nil
|
|
end,
|
|
}
|
|
}
|
|
}
|
|
local propagation = require "kong.observability.tracing.propagation"
|
|
|
|
lazy_setup(function()
|
|
err = spy.on(kong.log, "err")
|
|
warn = spy.on(kong.log, "warn")
|
|
set_serialize_value = spy.on(kong.log, "set_serialize_value")
|
|
end)
|
|
|
|
lazy_teardown(function()
|
|
_G.kong = old_kong
|
|
_G.ngx.req.get_headers = old_get_headers
|
|
end)
|
|
|
|
describe("propagate() function with", function()
|
|
before_each(function()
|
|
warn:clear()
|
|
err:clear()
|
|
set_serialize_value:clear()
|
|
end)
|
|
|
|
for _, t in ipairs(test_data) do
|
|
it(t.description .. " updates headers correctly", function()
|
|
local conf = t.conf
|
|
local expected = t.expected
|
|
req_headers = shallow_copy(t.req_headers)
|
|
|
|
propagation.propagate(
|
|
propagation.get_plugin_params(conf),
|
|
t.cb or function(c) return c end
|
|
)
|
|
|
|
assert.spy(err).was_not_called()
|
|
assert.spy(warn).was_not_called()
|
|
assert.same(expected, req_headers)
|
|
end)
|
|
end
|
|
end)
|
|
end)
|