diff --git a/kong-3.6.0-0.rockspec b/kong-3.6.0-0.rockspec index 1453b8b1147..a4b042eed57 100644 --- a/kong-3.6.0-0.rockspec +++ b/kong-3.6.0-0.rockspec @@ -549,6 +549,7 @@ build = { ["kong.tracing.instrumentation"] = "kong/tracing/instrumentation.lua", ["kong.tracing.propagation"] = "kong/tracing/propagation.lua", ["kong.tracing.request_id"] = "kong/tracing/request_id.lua", + ["kong.tracing.tracing_context"] = "kong/tracing/tracing_context.lua", ["kong.timing"] = "kong/timing/init.lua", ["kong.timing.context"] = "kong/timing/context.lua", diff --git a/kong/plugins/opentelemetry/handler.lua b/kong/plugins/opentelemetry/handler.lua index b0a4bfa67d3..db296fe045b 100644 --- a/kong/plugins/opentelemetry/handler.lua +++ b/kong/plugins/opentelemetry/handler.lua @@ -3,6 +3,7 @@ local http = require "resty.http" local clone = require "table.clone" local otlp = require "kong.plugins.opentelemetry.otlp" local propagation = require "kong.tracing.propagation" +local tracing_context = require "kong.tracing.tracing_context" local ngx = ngx @@ -103,8 +104,7 @@ function OpenTelemetryHandler:access(conf) kong.ctx.plugin.should_sample = false end - local injected_parent_span = ngx.ctx.tracing and - ngx.ctx.tracing.injected.balancer_span or root_span + local injected_parent_span = tracing_context.get_unlinked_span("balancer") or root_span local header_type, trace_id, span_id, parent_id, should_sample, _ = propagation_parse(headers, conf.header_type) if should_sample == false then @@ -118,7 +118,8 @@ function OpenTelemetryHandler:access(conf) -- to propagate the correct trace ID we have to set it here -- before passing this span to propagation.set() injected_parent_span.trace_id = trace_id - kong.ctx.plugin.trace_id = trace_id + -- update the Tracing Context with the trace ID extracted from headers + tracing_context.set_raw_trace_id(trace_id) end -- overwrite root span's parent_id @@ -135,7 +136,7 @@ end function OpenTelemetryHandler:header_filter(conf) if conf.http_response_header_for_traceid then - local trace_id = kong.ctx.plugin.trace_id + local trace_id = tracing_context.get_raw_trace_id() if not trace_id then local root_span = ngx.ctx.KONG_SPANS and ngx.ctx.KONG_SPANS[1] trace_id = root_span and root_span.trace_id @@ -156,7 +157,7 @@ function OpenTelemetryHandler:log(conf) end -- overwrite - local trace_id = kong.ctx.plugin.trace_id + local trace_id = tracing_context.get_raw_trace_id() if trace_id then span.trace_id = trace_id end diff --git a/kong/tracing/instrumentation.lua b/kong/tracing/instrumentation.lua index 717b9121445..b9809935171 100644 --- a/kong/tracing/instrumentation.lua +++ b/kong/tracing/instrumentation.lua @@ -6,6 +6,7 @@ local tablex = require "pl.tablex" local base = require "resty.core.base" local cjson = require "cjson" local ngx_re = require "ngx.re" +local tracing_context = require "kong.tracing.tracing_context" local ngx = ngx local var = ngx.var @@ -83,7 +84,7 @@ function _M.balancer(ctx) local last_try_balancer_span do - local balancer_span = ctx.tracing and ctx.tracing.injected.balancer_span + local balancer_span = tracing_context.get_unlinked_span("balancer", ctx) -- pre-created balancer span was not linked yet if balancer_span and not balancer_span.linked then last_try_balancer_span = balancer_span @@ -216,10 +217,6 @@ _M.available_types = available_types -- Record inbound request function _M.request(ctx) - ctx.tracing = { - injected = {}, - } - local client = kong.client local method = get_method() @@ -252,6 +249,9 @@ function _M.request(ctx) }, }) + -- update the tracing context with the request span trace ID + tracing_context.set_raw_trace_id(active_span.trace_id, ctx) + tracer.set_active_span(active_span) end @@ -263,12 +263,14 @@ function _M.precreate_balancer_span(ctx) end local root_span = ctx.KONG_SPANS and ctx.KONG_SPANS[1] - if ctx.tracing then - ctx.tracing.injected.balancer_span = tracer.create_span(nil, { - span_kind = 3, - parent = root_span, - }) - end + local balancer_span = tracer.create_span(nil, { + span_kind = 3, + parent = root_span, + }) + -- The balancer span is created during headers propagation, but is + -- linked later when the balancer data is available, so we add it + -- to the unlinked spans table to keep track of it. + tracing_context.set_unlinked_span("balancer", balancer_span, ctx) end diff --git a/kong/tracing/propagation.lua b/kong/tracing/propagation.lua index dbd7fa70d9a..606fcfa5b87 100644 --- a/kong/tracing/propagation.lua +++ b/kong/tracing/propagation.lua @@ -3,6 +3,7 @@ local openssl_bignum = require "resty.openssl.bn" local table_merge = require "kong.tools.utils".table_merge local split = require "kong.tools.utils".split local strip = require "kong.tools.utils".strip +local tracing_context = require "kong.tracing.tracing_context" local unescape_uri = ngx.unescape_uri local char = string.char local match = string.match @@ -520,52 +521,6 @@ local function find_header_type(headers) end --- Performs a table merge to add trace ID formats to the current request's --- trace ID and returns a table containing all the formats. --- --- Plugins can handle different formats of trace ids depending on their headers --- configuration, multiple plugins executions may result in additional formats --- of the current request's trace id. --- --- The `propagation_trace_id_all_fmt` table is stored in `ngx.ctx` to keep the --- list of formats updated for the current request. --- --- Each item in the resulting `propagation_trace_id_all_fmt` table represents a --- format associated with the trace ID for the current request. --- --- @param trace_id_new_fmt table containing the trace ID formats to be added --- @returns propagation_trace_id_all_fmt table contains all the formats for --- the current request --- --- @example --- --- propagation_trace_id_all_fmt = { datadog = "1234", --- w3c = "abcd" } --- --- trace_id_new_fmt = { ot = "abcd", --- w3c = "abcd" } --- --- propagation_trace_id_all_fmt = { datadog = "1234", --- ot = "abcd", --- w3c = "abcd" } --- -local function add_trace_id_formats(trace_id_new_fmt) - -- TODO: @samugi - move trace ID table in the unified tracing context - local trace_id_all_fmt = ngx.ctx.propagation_trace_id_all_fmt - if not trace_id_all_fmt then - ngx.ctx.propagation_trace_id_all_fmt = trace_id_new_fmt - return trace_id_new_fmt - end - - -- add new formats to trace ID formats table - for format, value in pairs(trace_id_new_fmt) do - trace_id_all_fmt[format] = value - end - - return trace_id_all_fmt -end - - local function parse(headers, conf_header_type) if conf_header_type == "ignore" then return nil @@ -738,7 +693,7 @@ local function set(conf_header_type, found_header_type, proxy_span, conf_default ) end - trace_id_formats = add_trace_id_formats(trace_id_formats) + trace_id_formats = tracing_context.add_trace_id_formats(trace_id_formats) -- add trace IDs to log serializer output kong.log.set_serialize_value("trace_id", trace_id_formats) end diff --git a/kong/tracing/tracing_context.lua b/kong/tracing/tracing_context.lua new file mode 100644 index 00000000000..ebf42ec4bce --- /dev/null +++ b/kong/tracing/tracing_context.lua @@ -0,0 +1,111 @@ +local table_new = require "table.new" + +local ngx = ngx + + +local function init_tracing_context(ctx) + ctx.TRACING_CONTEXT = { + -- trace ID information which includes its raw value (binary) and all the + -- available formats set during headers propagation + trace_id = { + raw = nil, + formatted = table_new(0, 6), + }, + -- Unlinked spans are spans that were created (to generate their ID) + -- but not added to `KONG_SPANS` (because their execution details were not + -- yet available). + unlinked_spans = table_new(0, 1) + } + + return ctx.TRACING_CONTEXT +end + + +local function get_tracing_context(ctx) + ctx = ctx or ngx.ctx + + if not ctx.TRACING_CONTEXT then + return init_tracing_context(ctx) + end + + return ctx.TRACING_CONTEXT +end + + +-- Performs a table merge to add trace ID formats to the current request's +-- trace ID and returns a table containing all the formats. +-- +-- Plugins can handle different formats of trace ids depending on their headers +-- configuration, multiple plugins executions may result in additional formats +-- of the current request's trace id. +-- +-- Each item in the resulting table represents a format associated with the +-- trace ID for the current request. +-- +-- @param trace_id_new_fmt table containing the trace ID formats to be added +-- @param ctx table the current ctx, if available +-- @returns propagation_trace_id_all_fmt table contains all the formats for +-- the current request +-- +-- @example +-- +-- propagation_trace_id_all_fmt = { datadog = "1234", +-- w3c = "abcd" } +-- +-- trace_id_new_fmt = { ot = "abcd", +-- w3c = "abcd" } +-- +-- propagation_trace_id_all_fmt = { datadog = "1234", +-- ot = "abcd", +-- w3c = "abcd" } +-- +local function add_trace_id_formats(trace_id_new_fmt, ctx) + local tracing_context = get_tracing_context(ctx) + local trace_id_all_fmt = tracing_context.trace_id.formatted + + if next(trace_id_all_fmt) == nil then + tracing_context.trace_id.formatted = trace_id_new_fmt + return trace_id_new_fmt + end + + -- add new formats to existing trace ID formats table + for format, value in pairs(trace_id_new_fmt) do + trace_id_all_fmt[format] = value + end + + return trace_id_all_fmt +end + + +local function get_raw_trace_id(ctx) + local tracing_context = get_tracing_context(ctx) + return tracing_context.trace_id.raw +end + + +local function set_raw_trace_id(trace_id, ctx) + local tracing_context = get_tracing_context(ctx) + tracing_context.trace_id.raw = trace_id +end + + +local function get_unlinked_span(name, ctx) + local tracing_context = get_tracing_context(ctx) + return tracing_context.unlinked_spans[name] +end + + +local function set_unlinked_span(name, span, ctx) + local tracing_context = get_tracing_context(ctx) + tracing_context.unlinked_spans[name] = span +end + + + +return { + add_trace_id_formats = add_trace_id_formats, + get_raw_trace_id = get_raw_trace_id, + set_raw_trace_id = set_raw_trace_id, + get_unlinked_span = get_unlinked_span, + set_unlinked_span = set_unlinked_span, +} diff --git a/spec/fixtures/custom_plugins/kong/plugins/trace-propagator/handler.lua b/spec/fixtures/custom_plugins/kong/plugins/trace-propagator/handler.lua index daf8a36c358..909a11f093b 100644 --- a/spec/fixtures/custom_plugins/kong/plugins/trace-propagator/handler.lua +++ b/spec/fixtures/custom_plugins/kong/plugins/trace-propagator/handler.lua @@ -1,4 +1,5 @@ local propagation = require "kong.tracing.propagation" +local tracing_context = require "kong.tracing.tracing_context" local ngx = ngx local kong = kong @@ -18,8 +19,7 @@ function _M:access(conf) if not root_span then root_span = tracer.start_span("root") end - local injected_parent_span = ngx.ctx.tracing and - ngx.ctx.tracing.injected.balancer_span or root_span + local injected_parent_span = tracing_context.get_unlinked_span("balancer") or root_span local header_type, trace_id, span_id, parent_id, should_sample = propagation_parse(headers)