diff --git a/apisix/plugins/opentelemetry.lua b/apisix/plugins/opentelemetry.lua index 487c143819ce..b1c9c53b6d5d 100644 --- a/apisix/plugins/opentelemetry.lua +++ b/apisix/plugins/opentelemetry.lua @@ -56,6 +56,24 @@ local lrucache = core.lrucache.new({ local asterisk = string.byte("*", 1) +local function is_valid_trace_id(trace_id) + if not trace_id or #trace_id ~= 32 then + return false + end + + -- must be lowercase hex + if not trace_id:match("^[0-9a-f]+$") then + return false + end + + -- W3C Trace Context: all-zero trace_id is invalid + if trace_id == "00000000000000000000000000000000" then + return false + end + + return true +end + local metadata_schema = { type = "object", properties = { @@ -231,9 +249,17 @@ end local function create_tracer_obj(conf, plugin_info) if plugin_info.trace_id_source == "x-request-id" then + local _original_new_ids = id_generator.new_ids + id_generator.new_ids = function() - local trace_id = core.request.headers()["x-request-id"] or ngx_var.request_id - return trace_id, id_generator.new_span_id() + local trace_id = core.request.headers()["x-request-id"] + or ngx_var.request_id + + if is_valid_trace_id(trace_id) then + return trace_id, id_generator.new_span_id() + end + + return _original_new_ids() end end -- create exporter diff --git a/t/plugin/opentelemetry.t b/t/plugin/opentelemetry.t index daf91e39e8bd..4c78da4229e2 100644 --- a/t/plugin/opentelemetry.t +++ b/t/plugin/opentelemetry.t @@ -434,3 +434,104 @@ HEAD /specific_status tail -n 1 ci/pod/otelcol-contrib/data-otlp.json --- response_body eval qr/.*\/specific_status.*/ + + + +=== TEST 20: recreate route for invalid x-request-id test +--- config + location /t { + content_by_lua_block { + local t = require("lib.test_admin").test + local code, body = t('/apisix/admin/routes/1', + ngx.HTTP_PUT, + [[{ + "plugins": { + "opentelemetry": { + "sampler": { + "name": "always_on" + } + } + }, + "upstream": { + "nodes": { + "127.0.0.1:1980": 1 + }, + "type": "roundrobin" + }, + "uri": "/opentracing" + }]] + ) + + if code >= 300 then + ngx.status = code + end + ngx.say(body) + } + } +--- request +GET /t + + + +=== TEST 21: invalid x-request-id should not crash +--- request +GET /opentracing +--- more_headers +X-Request-Id: 550e8400-e29b-41d4-a716-446655440000 +--- wait: 2 +--- response_body +opentracing +--- no_error_log +[error] + + + +=== TEST 22: invalid x-request-id should still generate a valid trace +--- request +GET /opentracing +--- more_headers +X-Request-Id: 550e8400-e29b-41d4-a716-446655440000 +--- wait: 2 +--- exec +tail -n 1 ci/pod/otelcol-contrib/data-otlp.json +--- response_body eval +qr/"traceId":"(?!0{32})[0-9a-f]{32}"/ + + + +=== TEST 23: all-zero x-request-id should not be used as trace id +--- request +GET /opentracing +--- more_headers +X-Request-Id: 00000000000000000000000000000000 +--- wait: 2 +--- exec +tail -n 1 ci/pod/otelcol-contrib/data-otlp.json +--- response_body eval +qr/"traceId":"(?!0{32})[0-9a-f]{32}"/ + + + +=== TEST 24: uppercase x-request-id should still generate a valid trace id +--- request +GET /opentracing +--- more_headers +X-Request-Id: 550E8400-E29B-41D4-A716-446655440000 +--- wait: 2 +--- exec +tail -n 1 ci/pod/otelcol-contrib/data-otlp.json +--- response_body eval +qr/"traceId":"(?!0{32})[0-9a-f]{32}"/ + + + +=== TEST 25: malformed length x-request-id should still generate a valid trace id +--- request +GET /opentracing +--- more_headers +X-Request-Id: 550e8400e29b41d4a7164466 +--- wait: 2 +--- exec +tail -n 1 ci/pod/otelcol-contrib/data-otlp.json +--- response_body eval +qr/"traceId":"(?!0{32})[0-9a-f]{32}"/