Skip to content

Commit

Permalink
refactor(tracing): add tracing context
Browse files Browse the repository at this point in the history
Add a Tracing Context module for managing request-scoped tracing-related
information. This provides an interface with ngx.ctx.TRACING_CONTEXT for
plugins and core to read/update tracing information through.

This commit adds support to read/write:
* Trace ID (raw and all formats)
* Unlinked spans

Follow up will probably include:
* Sampling rate
* Incoming/outgoing tracing headers information
  • Loading branch information
samugi committed Nov 24, 2023
1 parent 67970ea commit 708200b
Show file tree
Hide file tree
Showing 6 changed files with 135 additions and 65 deletions.
1 change: 1 addition & 0 deletions kong-3.6.0-0.rockspec
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
11 changes: 6 additions & 5 deletions kong/plugins/opentelemetry/handler.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand Down
24 changes: 13 additions & 11 deletions kong/tracing/instrumentation.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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

Expand All @@ -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


Expand Down
49 changes: 2 additions & 47 deletions kong/tracing/propagation.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
111 changes: 111 additions & 0 deletions kong/tracing/tracing_context.lua
Original file line number Diff line number Diff line change
@@ -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,
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
local propagation = require "kong.tracing.propagation"
local tracing_context = require "kong.tracing.tracing_context"

local ngx = ngx
local kong = kong
Expand All @@ -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)

Expand Down

0 comments on commit 708200b

Please sign in to comment.