diff --git a/CHANGELOG.md b/CHANGELOG.md index c1ad0d075e5f..291b01140a30 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -190,6 +190,8 @@ [#10160](https://github.com/Kong/kong/pull/10160) - For `http.flavor`. It should be a string value, not a double. [#10160](https://github.com/Kong/kong/pull/10160) +- **OpenTelemetry**: Fix a bug that when getting the trace of other formats, the trace ID reported and propagated could be of incorrect length. + [#10332](https://github.com/Kong/kong/pull/10332) - **OAuth2**: `refresh_token_ttl` is now limited between `0` and `100000000` by schema validator. Previously numbers that are too large causes requests to fail. [#10068](https://github.com/Kong/kong/pull/10068) diff --git a/kong/plugins/opentelemetry/handler.lua b/kong/plugins/opentelemetry/handler.lua index 5856c1cea340..b41ce20cdb3c 100644 --- a/kong/plugins/opentelemetry/handler.lua +++ b/kong/plugins/opentelemetry/handler.lua @@ -19,7 +19,8 @@ local propagation_parse = propagation.parse local propagation_set = propagation.set local null = ngx.null local encode_traces = otlp.encode_traces -local transform_span = otlp.transform_span +local translate_span_trace_id = otlp.translate_span +local encode_span = otlp.transform_span local _log_prefix = "[otel] " @@ -108,7 +109,7 @@ local function process_span(span, queue) span.trace_id = trace_id end - local pb_span = transform_span(span) + local pb_span = encode_span(span) queue:add(pb_span) end @@ -132,6 +133,7 @@ function OpenTelemetryHandler:access() end -- overwrite trace id + -- as we are in a chain of existing trace if trace_id then root_span.trace_id = trace_id kong.ctx.plugin.trace_id = trace_id @@ -145,7 +147,7 @@ function OpenTelemetryHandler:access() root_span.parent_id = parent_id end - propagation_set("preserve", header_type, root_span, "w3c") + propagation_set("preserve", header_type, translate_span_trace_id(root_span), "w3c") end function OpenTelemetryHandler:log(conf) diff --git a/kong/plugins/opentelemetry/otlp.lua b/kong/plugins/opentelemetry/otlp.lua index d84c5c7d97fb..2b209e7f7639 100644 --- a/kong/plugins/opentelemetry/otlp.lua +++ b/kong/plugins/opentelemetry/otlp.lua @@ -10,8 +10,13 @@ local insert = table.insert local tablepool_fetch = tablepool.fetch local tablepool_release = tablepool.release local deep_copy = utils.deep_copy +local shallow_copy = utils.shallow_copy local table_merge = utils.table_merge +local getmetatable = getmetatable +local setmetatable = setmetatable +local TRACE_ID_LEN = 16 +local NULL = "\0" local POOL_OTLP = "KONG_OTLP" local EMPTY_TAB = {} @@ -72,9 +77,43 @@ local function transform_events(events) return pb_events end +-- translate the span to otlp format +-- currently it only adjust the trace id to 16 bytes +-- we don't do it in place because the span is shared +-- and we need to preserve the original information as much as possible +local function translate_span_trace_id(span) + local trace_id = span.trace_id + local len = #trace_id + local new_id = trace_id + + if len == TRACE_ID_LEN then + return span + end + + -- make sure the trace id is of 16 bytes + if len > TRACE_ID_LEN then + new_id = trace_id:sub(-TRACE_ID_LEN) + + elseif len < TRACE_ID_LEN then + new_id = NULL:rep(TRACE_ID_LEN - len) .. trace_id + end + + local translated = shallow_copy(span) + setmetatable(translated, getmetatable(span)) + + translated.trace_id = new_id + span = translated + + return span +end + +-- this function is to prepare span to be encoded and sent via grpc +-- TODO: renaming this to encode_span local function transform_span(span) assert(type(span) == "table") + span = translate_span_trace_id(span) + local pb_span = { trace_id = span.trace_id, span_id = span.span_id, @@ -161,6 +200,7 @@ do end return { + translate_span = translate_span_trace_id, transform_span = transform_span, encode_traces = encode_traces, } diff --git a/spec/03-plugins/37-opentelemetry/03-propagation_spec.lua b/spec/03-plugins/37-opentelemetry/03-propagation_spec.lua index 8ce89d2a1f09..d116cfb78dc3 100644 --- a/spec/03-plugins/37-opentelemetry/03-propagation_spec.lua +++ b/spec/03-plugins/37-opentelemetry/03-propagation_spec.lua @@ -160,5 +160,27 @@ describe("propagation tests #" .. strategy, function() assert.equals(trace_id, json.headers["ot-tracer-traceid"]) end) + + it("propagates dd headers", function() + local trace_id = gen_trace_id() + local trace_id_truncated = trace_id:sub(1, 16) + local span_id = gen_span_id() + local r = proxy_client:get("/", { + headers = { + ["ot-tracer-traceid"] = trace_id_truncated, + ["ot-tracer-spanid"] = span_id, + ["ot-tracer-sampled"] = "1", + host = "http-route", + }, + }) + local body = assert.response(r).has.status(200) + local json = cjson.decode(body) + + assert.equals(#trace_id, #json.headers["ot-tracer-traceid"], + "trace ID was not padded correctly") + + local expected = string.rep("0", 16) .. trace_id_truncated + assert.equals(expected, json.headers["ot-tracer-traceid"]) + end) end) end