diff --git a/instrumentation/nginx/README.md b/instrumentation/nginx/README.md index 9cb37fbcc..54e0a9e30 100644 --- a/instrumentation/nginx/README.md +++ b/instrumentation/nginx/README.md @@ -188,7 +188,7 @@ be started. The default propagator is W3C. The same inheritance rules as [`proxy_set_header`](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_set_header) apply, which means this directive is applied at the current configuration level if and only if there are no `proxy_set_header` directives defined on a lower level. - **required**: `false` -- **syntax**: `opentelemetry_propagate` or `opentelemetry_propagate b3` +- **syntax**: `opentelemetry_propagate` or `opentelemetry_propagate b3` or `opentelemetry_propagate b3multi` - **block**: `http`, `server`, `location` ### `opentelemetry_capture_headers` @@ -249,6 +249,7 @@ The following nginx variables are set by the instrumentation: context](https://www.w3.org/TR/trace-context/#trace-context-http-headers-format), e.g.: `00-0af7651916cd43dd8448eb211c80319c-b9c7c989f97918e1-01` - `opentelemetry_context_b3` - Trace context in the [B3 format](https://github.com/openzipkin/b3-propagation#single-header). Only set when using `opentelemetry_propagate b3`. +- `opentelemetry_sampled` - does current Span records information, "1" or "0" - `opentelemetry_trace_id` - Trace Id of the current span - `opentelemetry_span_id` - Span Id of the current span diff --git a/instrumentation/nginx/src/otel_ngx_module.cpp b/instrumentation/nginx/src/otel_ngx_module.cpp index b94b9725e..292c2c97d 100644 --- a/instrumentation/nginx/src/otel_ngx_module.cpp +++ b/instrumentation/nginx/src/otel_ngx_module.cpp @@ -142,6 +142,9 @@ OtelGetTraceId(ngx_http_request_t* req, ngx_http_variable_value_t* v, uintptr_t static ngx_int_t OtelGetSpanId(ngx_http_request_t* req, ngx_http_variable_value_t* v, uintptr_t data); +static ngx_int_t +OtelGetSampled(ngx_http_request_t* req, ngx_http_variable_value_t* v, uintptr_t data); + static ngx_http_variable_t otel_ngx_variables[] = { { ngx_string("otel_ctx"), @@ -175,6 +178,14 @@ static ngx_http_variable_t otel_ngx_variables[] = { NGX_HTTP_VAR_NOCACHEABLE | NGX_HTTP_VAR_NOHASH, 0, }, + { + ngx_string("opentelemetry_sampled"), + nullptr, + OtelGetSampled, + 0, + NGX_HTTP_VAR_NOCACHEABLE | NGX_HTTP_VAR_NOHASH, + 0, + }, ngx_http_null_variable, }; @@ -223,6 +234,38 @@ nostd::string_view WithoutOtelVarPrefix(ngx_str_t value) { return {(const char*)value.data + prefixLength, value.len - prefixLength}; } +static ngx_int_t +OtelGetSampled(ngx_http_request_t* req, ngx_http_variable_value_t* v, uintptr_t data) { + TraceContext* traceContext = GetTraceContext(req); + + if (traceContext == nullptr || !traceContext->request_span) { + ngx_log_error( + NGX_LOG_ERR, req->connection->log, 0, + "Unable to get trace context when getting span id"); + return NGX_OK; + } + + trace::SpanContext spanContext = traceContext->request_span->GetContext(); + + if (spanContext.IsValid()) { + u_char* isSampled = spanContext.trace_flags().IsSampled() ? (u_char*) "1" : (u_char*) "0"; + + v->len = strlen((const char*)isSampled); + v->valid = 1; + v->no_cacheable = 1; + v->not_found = 0; + v->data = isSampled; + } else { + v->len = 0; + v->valid = 0; + v->no_cacheable = 1; + v->not_found = 1; + v->data = nullptr; + } + + return NGX_OK; +} + static ngx_int_t OtelGetTraceContextVar(ngx_http_request_t* req, ngx_http_variable_value_t* v, uintptr_t data) { if (!IsOtelEnabled(req)) { @@ -764,6 +807,17 @@ std::vector B3PropagationVars() { }; } +std::vector B3MultiPropagationVars() { + return { + {"proxy_set_header", "x-b3-traceid", "$opentelemetry_trace_id"}, + {"proxy_set_header", "x-b3-spanid", "$opentelemetry_span_id"}, + {"proxy_set_header", "x-b3-sampled", "$opentelemetry_sampled"}, + {"fastcgi_param", "HTTP_B3_TRACEID", "$opentelemetry_trace_id"}, + {"fastcgi_param", "HTTP_B3_SPANID", "$opentelemetry_span_id"}, + {"fastcgi_param", "HTTP_B3_SAMPLED", "$opentelemetry_sampled"}, + }; +} + std::vector OtelPropagationVars() { return { {"proxy_set_header", "traceparent", "$opentelemetry_context_traceparent"}, @@ -784,6 +838,8 @@ char* OtelNgxSetPropagation(ngx_conf_t* conf, ngx_command_t*, void* locConf) { if (propagationType == "b3") { locationConf->propagationType = TracePropagationB3; + } else if (propagationType == "b3multi") { + locationConf->propagationType = TracePropagationB3Multi; } else if (propagationType == "w3c") { locationConf->propagationType = TracePropagationW3C; } else { @@ -797,6 +853,8 @@ char* OtelNgxSetPropagation(ngx_conf_t* conf, ngx_command_t*, void* locConf) { std::vector propagationVars; if (locationConf->propagationType == TracePropagationB3) { propagationVars = B3PropagationVars(); + } else if (locationConf->propagationType == TracePropagationB3Multi) { + propagationVars = B3MultiPropagationVars(); } else { propagationVars = OtelPropagationVars(); } diff --git a/instrumentation/nginx/src/propagate.cpp b/instrumentation/nginx/src/propagate.cpp index 4154af935..a51e5c50e 100644 --- a/instrumentation/nginx/src/propagate.cpp +++ b/instrumentation/nginx/src/propagate.cpp @@ -79,6 +79,9 @@ opentelemetry::context::Context ExtractContext(OtelCarrier* carrier) { case TracePropagationW3C: { return OtelW3CPropagator().Extract(textMapCarrier, root); } + case TracePropagationB3Multi: { + return OtelB3MultiPropagator().Extract(textMapCarrier, root); + } case TracePropagationB3: { if (HasHeader(carrier->req, "b3")) { return OtelB3Propagator().Extract(textMapCarrier, root); @@ -104,6 +107,10 @@ void InjectContext(OtelCarrier* carrier, opentelemetry::context::Context context OtelB3Propagator().Inject(textMapCarrier, context); break; } + case TracePropagationB3Multi: { + OtelB3MultiPropagator().Inject(textMapCarrier, context); + break; + } default: break; } diff --git a/instrumentation/nginx/src/trace_context.h b/instrumentation/nginx/src/trace_context.h index de128e024..ef957cd1d 100644 --- a/instrumentation/nginx/src/trace_context.h +++ b/instrumentation/nginx/src/trace_context.h @@ -17,6 +17,7 @@ enum TracePropagationType { TracePropagationUnset, TracePropagationW3C, TracePropagationB3, + TracePropagationB3Multi, }; struct TraceContext {