Skip to content

feature: Add W3C trace context support via adding the traceparent header from $http_traceparent (for OpenTracing + OpenTelemetry)#340

Merged
sriemer merged 2 commits into
ledgetech:masterfrom
sriemer:otel-traceparent
Jun 10, 2026
Merged

feature: Add W3C trace context support via adding the traceparent header from $http_traceparent (for OpenTracing + OpenTelemetry)#340
sriemer merged 2 commits into
ledgetech:masterfrom
sriemer:otel-traceparent

Conversation

@sriemer

@sriemer sriemer commented May 8, 2026

Copy link
Copy Markdown
Contributor

http: Add W3C trace context support to send_request()

NGINX can be used together with an NGINX tracer with W3C trace context
support. That tracer can be based on OpenTracing or OpenTelemetry
(OTel), such as the nginx-otel module.
In the Observability space it is required that all HTTP request
tracers in the line do trace propagation or trace forwarding at least.
This is usually done by sending out an updated traceparent header.
It contains for example a trace ID and a span ID so that the
Observability backend such as Jaeger can correlate all spans to the
same trace.

To be able to trace HTTP requests sent from regular NGINX code and
also the ones sent by LUA HTTP client code with the same NGINX tracer,
the LUA HTTP client code has to be extended to add the traceparent
header from ngx.var.http_traceparent. The value of this
$http_traceparent variable is set by the NGINX tracer. It
updates the span ID inside the traceparent value if the NGINX tracer
is set to propagation mode.
Example with nginx-otel config: otel_trace_context propagate;.

So extend the send_request() function for this, because it already
adds other headers as well and is used when calling request_uri()
as well.

Check if the traceparent header is not set yet but
ngx.var.http_traceparent is set and set it from there.
Also add a code comment describing this as well.

References:


t: Add 3 traceparent header tests

The new traceparent header auto-injection from
ngx.var.http_traceparent has to be tested.

So add a new file t/21-traceparent-header.t containing 3 tests
for that:

  • TEST 1: No traceparent header is set
  • TEST 2: The traceparent header is correctly added when
    ngx.var.http_traceparent is used
  • TEST 3: The traceparent header is not modified from
    ngx.var.http_traceparent if it is already set

Use an NGINX directive set $http_traceparent '00-000...-01'; in
front of the LUA block to emulate nginx-otel behavior.

The case that there is a traceparent header added with
request_uri() and ngx.var.http_traceparent is not set, is already
covered by tests 1 and 3.

@sriemer

sriemer commented May 8, 2026

Copy link
Copy Markdown
Contributor Author

Build fails here due to deprecated Luarocks. See #333.
All code has been tested against OpenResty 1.29.2.2. I've built the test environment from a custom Dockerfile.
See #341.

@sriemer

sriemer commented May 8, 2026

Copy link
Copy Markdown
Contributor Author

The nginx.conf parts I've used to test the real thing together with tcpdumping in a docker-compose based demo:

load_module modules/ngx_otel_module.so;
...
http {
...
    upstream backend {
      server server-app:8080;
    }
    otel_exporter {
        endpoint myobservability-agent:4317;
    }
    otel_trace on;
    otel_service_name myname-openresty-otel;
    server {
        ...
        location /openresty-otel-demo {
            otel_trace_context propagate;
            proxy_pass http://backend;
        }
        location /lua-otel-demo {
            otel_trace_context propagate;
            content_by_lua_block {
                local http = require "resty.http"
                local httpc = http.new()
                local res, err = httpc:request_uri("http://server-app:8080", {
                    method = "GET",
                })
                if not res then
                    ngx.status = ngx.HTTP_BAD_GATEWAY
                    ngx.header["Content-Type"] = "text/plain; charset=utf-8"
                    ngx.say("failed to call upstream: ", err)
                    return
                end
                ngx.status = res.status
                if res.headers["Content-Type"] then
                    ngx.header["Content-Type"] = res.headers["Content-Type"]
                end
                ngx.say(res.body)
            }
        }
    }
}

@sriemer

sriemer commented May 8, 2026

Copy link
Copy Markdown
Contributor Author

@pintsized Please review. TIA

Also let me know if you need help from an experienced FOSS maintainer like me in reviewing open PRs.

@sriemer sriemer changed the title Add OpenTelemetry support via adding the traceparent header from $http_traceparent feature: Add OpenTelemetry support via adding the traceparent header from $http_traceparent May 11, 2026
@sriemer

sriemer commented May 20, 2026

Copy link
Copy Markdown
Contributor Author

@pintsized Any update here? TIA

@sriemer

sriemer commented Jun 2, 2026

Copy link
Copy Markdown
Contributor Author

@pintsized Do you still have any motivation to continue this SW project? Do you need more help? TIA

@sriemer

sriemer commented Jun 3, 2026

Copy link
Copy Markdown
Contributor Author

This even works with OpenTracing based tracers as well which set a traceparent header.
So works with all NGINX tracers setting a traceparent header.

@pintsized

Copy link
Copy Markdown
Member

@pintsized Do you still have any motivation to continue this SW project? Do you need more help? TIA

@sriemer sorry for the painfully slow response. Yes, the problem is that I really do not have time to maintain this project, or the other related projects in this org. The org itself (ledgetech) was created with the aspiration that perhaps one day other maintainers could look after these modules - would you be interested if I added you to the org?

@sriemer

sriemer commented Jun 5, 2026

Copy link
Copy Markdown
Contributor Author

Would you be interested if I added you to the org?

@pintsized Sure, would definitely avoid that we have to go with a fork that we would have to maintain anyway and have to convince others to move over. Keeping the known upstream definitely helps a lot. I can definitely help the other contributors to get their parts in as well if quality is right. Thanks in advance for adding me.

@sriemer sriemer force-pushed the otel-traceparent branch from 1d1225a to ae57324 Compare June 8, 2026 09:19
@sriemer

sriemer commented Jun 8, 2026

Copy link
Copy Markdown
Contributor Author

Rebased for latest CI checks.

@sriemer sriemer force-pushed the otel-traceparent branch from ae57324 to 9d1b7a3 Compare June 8, 2026 09:46
@sriemer

sriemer commented Jun 8, 2026

Copy link
Copy Markdown
Contributor Author

Force-pushed to change commit description of commit 1 and the code comment to be working with any NGINX tracer supporting the traceparent header. So this also covers the ones based on OpenTracing. Only using nginx-otel as an example NGINX tracer now.
New code comment: -- OpenTelemetry support with NGINX tracer

@sriemer sriemer self-assigned this Jun 8, 2026
@sriemer sriemer force-pushed the otel-traceparent branch from 9d1b7a3 to 2a86257 Compare June 8, 2026 11:04
@sriemer

sriemer commented Jun 8, 2026

Copy link
Copy Markdown
Contributor Author

Rebased for PR #343 changes.

Comment thread lib/resty/http.lua Outdated
sriemer added 2 commits June 9, 2026 09:58
NGINX can be used together with an NGINX tracer with W3C trace context
support. That tracer can be based on OpenTracing or OpenTelemetry
(OTel), such as the `nginx-otel` module.
In the Observability space it is required that all HTTP request
tracers in the line do trace propagation or trace forwarding at least.
This is usually done by sending out an updated `traceparent` header.
It contains for example a trace ID and a span ID so that the
Observability backend such as Jaeger can correlate all spans to the
same trace.

To be able to trace HTTP requests sent from regular NGINX code and
also the ones sent by LUA HTTP client code with the same NGINX tracer,
the LUA HTTP client code has to be extended to add the `traceparent`
header from `ngx.var.http_traceparent`. The value of this
`$http_traceparent` variable is set by the NGINX tracer. It
updates the span ID inside the `traceparent` value if the NGINX tracer
is set to propagation mode.
Example with `nginx-otel` config: `otel_trace_context propagate;`.

So extend the `send_request()` function for this, because it already
adds other headers as well and is used when calling `request_uri()`
as well.

Check if the `traceparent` header is not set yet but
`ngx.var.http_traceparent` is set and set it from there.
Also add a code comment describing this as well.

References:
* https://www.w3.org/TR/trace-context/
* https://github.com/nginxinc/nginx-otel
* https://nginx.org/en/docs/ngx_otel_module.html
* https://nginx.org/en/docs/http/ngx_http_core_module.html#var_http_
The new `traceparent` header auto-injection from
`ngx.var.http_traceparent` has to be tested.

So add a new file `t/21-traceparent-header.t` containing 3 tests
for that:
* TEST 1: No traceparent header is set
* TEST 2: The traceparent header is correctly added when
          ngx.var.http_traceparent is used
* TEST 3: The traceparent header is not modified from
          ngx.var.http_traceparent if it is already set

Use an NGINX directive `set $http_traceparent '00-000...-01';` in
front of the LUA block to emulate `nginx-otel` behavior.

The case that there is a `traceparent` header added with
`request_uri()` and `ngx.var.http_traceparent` is not set, is already
covered by tests 1 and 3.
@sriemer sriemer force-pushed the otel-traceparent branch from 2a86257 to 81d90b7 Compare June 9, 2026 08:10
@sriemer sriemer changed the title feature: Add OpenTelemetry support via adding the traceparent header from $http_traceparent feature: Add W3C trace context support via adding the traceparent header from $http_traceparent (for OpenTracing + OpenTelemetry) Jun 9, 2026
@sriemer sriemer requested a review from aravindjayanthi98 June 9, 2026 08:15
@sriemer

sriemer commented Jun 9, 2026

Copy link
Copy Markdown
Contributor Author

@aravindjayanthi98 Amended that comment, the commit description of the first commit and long and short PR descriptions. Added another reference to https://www.w3.org/TR/trace-context/.
Please rereview. TIA

@aravindjayanthi98 aravindjayanthi98 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@sriemer sriemer merged commit 7837f60 into ledgetech:master Jun 10, 2026
6 checks passed
@sriemer sriemer deleted the otel-traceparent branch June 10, 2026 08:31
@sriemer

sriemer commented Jun 10, 2026

Copy link
Copy Markdown
Contributor Author

Merged with a merge commit to keep a link to the conversation here because it contains important information, such as the NGINX config in #340 (comment).
Thanks. 😃

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants