This is an automated email from the ASF dual-hosted git repository.
shreemaan-abhishek pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix.git
The following commit(s) were added to refs/heads/master by this push:
new 3586b2f80 fix(opentelemetry): preserve booleans, handle multi-value
headers, tighten test (#13315)
3586b2f80 is described below
commit 3586b2f8051ca06ec7686511ed709ca9fa553a66
Author: Shreemaan Abhishek <[email protected]>
AuthorDate: Thu May 7 10:40:14 2026 +0800
fix(opentelemetry): preserve booleans, handle multi-value headers, tighten
test (#13315)
Three follow-ups to #13146 (which started coercing additional_attributes
values to strings before sending them to OTel attr.string):
1. inject_attributes() gated insertion on `if val then`, which silently
drops boolean false (Lua falsy) — regressing any user whose nginx
variable resolves to a boolean false flag. Switch to
`if val ~= nil then` so false survives.
2. ngx.req.get_headers() returns a Lua table for multi-value headers
(e.g. multiple Set-Cookie / X-Forwarded-For entries). tostring()
over a table emits 'table: 0x...' and that's what was landing in
the span attribute. Extract a coerce_attr_value() helper that joins
multi-value entries with ', ' and skips when the source is missing
entirely.
3. TEST 22's response_body regex was qr/.*opentelemetry-lua.*/ which
matches the OTLP exporter marker even when the numeric attributes
are entirely absent from the export — i.e. the test would still
pass with the regression #13146 was supposed to fix. Tighten it to
assert each of request_time / bytes_sent appears as a stringValue.
(upstream_response_time is intentionally not asserted: TEST 21
serves /opentracing directly without proxying, so
$upstream_response_time is nil and the plugin correctly omits the
attribute.)
Signed-off-by: Shreemaan Abhishek <[email protected]>
Signed-off-by: Abhishek Choudhary <[email protected]>
---
apisix/plugins/opentelemetry.lua | 29 ++++++++++++++++++++++++++---
t/plugin/opentelemetry.t | 7 ++++++-
2 files changed, 32 insertions(+), 4 deletions(-)
diff --git a/apisix/plugins/opentelemetry.lua b/apisix/plugins/opentelemetry.lua
index 84bf6202e..2b99948a3 100644
--- a/apisix/plugins/opentelemetry.lua
+++ b/apisix/plugins/opentelemetry.lua
@@ -287,6 +287,22 @@ local function create_tracer_obj(conf, plugin_info)
end
+-- Coerce a header/var value to a string suitable for an OTel string attribute.
+-- ngx.req.get_headers() returns a Lua table for multi-value headers — running
+-- `tostring()` over a table emits "table: 0x..." which is useless in a span,
+-- so join multi-value entries instead. Returns nil when the value cannot be
+-- represented (caller should skip the attribute in that case).
+local function coerce_attr_value(val)
+ if val == nil then
+ return nil
+ end
+ if type(val) == "table" then
+ return table.concat(val, ", ")
+ end
+ return tostring(val)
+end
+
+
local function inject_attributes(attributes, wanted_attributes, source,
with_prefix)
for _, key in ipairs(wanted_attributes) do
local is_key_a_match = #key >= 2 and key:byte(-1) == asterisk and
with_prefix
@@ -295,13 +311,20 @@ local function inject_attributes(attributes,
wanted_attributes, source, with_pre
local prefix = key:sub(0, -2)
for possible_key, value in pairs(source) do
if core.string.has_prefix(possible_key, prefix) then
- core.table.insert(attributes, attr.string(possible_key,
tostring(value)))
+ local coerced = coerce_attr_value(value)
+ if coerced ~= nil then
+ core.table.insert(attributes,
attr.string(possible_key, coerced))
+ end
end
end
else
+ -- ~= nil so boolean `false` survives instead of being silently
dropped.
local val = source[key]
- if val then
- core.table.insert(attributes, attr.string(key, tostring(val)))
+ if val ~= nil then
+ local coerced = coerce_attr_value(val)
+ if coerced ~= nil then
+ core.table.insert(attributes, attr.string(key, coerced))
+ end
end
end
end
diff --git a/t/plugin/opentelemetry.t b/t/plugin/opentelemetry.t
index 0063cda64..a260a62a2 100644
--- a/t/plugin/opentelemetry.t
+++ b/t/plugin/opentelemetry.t
@@ -484,10 +484,15 @@ opentracing
=== TEST 22: check span exported with numeric additional attributes
+# Asserts that numeric nginx variables land as `stringValue` (not intValue,
+# not dropped) once additional_attributes is configured for them.
+# upstream_response_time is intentionally not checked: this test serves
+# /opentracing directly, so $upstream_response_time is nil and the plugin
+# correctly omits the attribute. request_time and bytes_sent are always set.
--- exec
tail -n 1 ci/pod/otelcol-contrib/data-otlp.json
--- response_body eval
-qr/.*opentelemetry-lua.*/
+qr/.*opentelemetry-lua.*"key":"request_time","value":\{"stringValue":"[^"]+"\}.*"key":"bytes_sent","value":\{"stringValue":"[^"]+"\}.*/s