Skip to content

Commit 1c339b5

Browse files
author
Vladimir Kuznichenkov
committed
Add support for B3Multi headers propagation
Some services expect [B3 Multi][1] headers as input information. To support that we need to be able to Inject them into upstream requests. Lowercase headers used to be [compatible][2] with Istio Envoy. Tests will be added as a separate commit later on. Solving #36 [1]: https://github.com/openzipkin/b3-propagation#multiple-headers [2]: open-telemetry/opentelemetry-go#765
1 parent 786c3ad commit 1c339b5

File tree

4 files changed

+68
-1
lines changed

4 files changed

+68
-1
lines changed

instrumentation/nginx/README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ be started. The default propagator is W3C.
171171
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.
172172

173173
- **required**: `false`
174-
- **syntax**: `opentelemetry_propagate` or `opentelemetry_propagate b3`
174+
- **syntax**: `opentelemetry_propagate` or `opentelemetry_propagate b3` or `opentelemetry_propagate b3multi`
175175
- **block**: `http`, `server`, `location`
176176

177177
### `opentelemetry_capture_headers`
@@ -232,6 +232,7 @@ The following nginx variables are set by the instrumentation:
232232
context](https://www.w3.org/TR/trace-context/#trace-context-http-headers-format), e.g.: `00-0af7651916cd43dd8448eb211c80319c-b9c7c989f97918e1-01`
233233
- `opentelemetry_context_b3` - Trace context in the [B3
234234
format](https://github.com/openzipkin/b3-propagation#single-header). Only set when using `opentelemetry_propagate b3`.
235+
- `opentelemetry_sampled` - does current Span records information, "1" or "0"
235236
- `opentelemetry_trace_id` - Trace Id of the current span
236237
- `opentelemetry_span_id` - Span Id of the current span
237238

instrumentation/nginx/src/otel_ngx_module.cpp

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,9 @@ OtelGetTraceId(ngx_http_request_t* req, ngx_http_variable_value_t* v, uintptr_t
136136
static ngx_int_t
137137
OtelGetSpanId(ngx_http_request_t* req, ngx_http_variable_value_t* v, uintptr_t data);
138138

139+
static ngx_int_t
140+
OtelGetSampled(ngx_http_request_t* req, ngx_http_variable_value_t* v, uintptr_t data);
141+
139142
static ngx_http_variable_t otel_ngx_variables[] = {
140143
{
141144
ngx_string("otel_ctx"),
@@ -169,6 +172,14 @@ static ngx_http_variable_t otel_ngx_variables[] = {
169172
NGX_HTTP_VAR_NOCACHEABLE | NGX_HTTP_VAR_NOHASH,
170173
0,
171174
},
175+
{
176+
ngx_string("opentelemetry_sampled"),
177+
nullptr,
178+
OtelGetSampled,
179+
0,
180+
NGX_HTTP_VAR_NOCACHEABLE | NGX_HTTP_VAR_NOHASH,
181+
0,
182+
},
172183
ngx_http_null_variable,
173184
};
174185

@@ -217,6 +228,38 @@ nostd::string_view WithoutOtelVarPrefix(ngx_str_t value) {
217228
return {(const char*)value.data + prefixLength, value.len - prefixLength};
218229
}
219230

231+
static ngx_int_t
232+
OtelGetSampled(ngx_http_request_t* req, ngx_http_variable_value_t* v, uintptr_t data) {
233+
TraceContext* traceContext = GetTraceContext(req);
234+
235+
if (traceContext == nullptr || !traceContext->request_span) {
236+
ngx_log_error(
237+
NGX_LOG_ERR, req->connection->log, 0,
238+
"Unable to get trace context when getting span id");
239+
return NGX_OK;
240+
}
241+
242+
trace::SpanContext spanContext = traceContext->request_span->GetContext();
243+
244+
if (spanContext.IsValid()) {
245+
u_char* isSampled = spanContext.trace_flags().IsSampled() ? (u_char*) "1" : (u_char*) "0";
246+
247+
v->len = strlen((const char*)isSampled);
248+
v->valid = 1;
249+
v->no_cacheable = 1;
250+
v->not_found = 0;
251+
v->data = isSampled;
252+
} else {
253+
v->len = 0;
254+
v->valid = 0;
255+
v->no_cacheable = 1;
256+
v->not_found = 1;
257+
v->data = nullptr;
258+
}
259+
260+
return NGX_OK;
261+
}
262+
220263
static ngx_int_t
221264
OtelGetTraceContextVar(ngx_http_request_t* req, ngx_http_variable_value_t* v, uintptr_t data) {
222265
if (!IsOtelEnabled(req)) {
@@ -758,6 +801,17 @@ std::vector<HeaderPropagation> B3PropagationVars() {
758801
};
759802
}
760803

804+
std::vector<HeaderPropagation> B3MultiPropagationVars() {
805+
return {
806+
{"proxy_set_header", "x-b3-traceid", "$opentelemetry_trace_id"},
807+
{"proxy_set_header", "x-b3-spanid", "$opentelemetry_span_id"},
808+
{"proxy_set_header", "x-b3-sampled", "$opentelemetry_sampled"},
809+
{"fastcgi_param", "HTTP_B3_TRACEID", "$opentelemetry_trace_id"},
810+
{"fastcgi_param", "HTTP_B3_SPANID", "$opentelemetry_span_id"},
811+
{"fastcgi_param", "HTTP_B3_SAMPLED", "$opentelemetry_sampled"},
812+
};
813+
}
814+
761815
std::vector<HeaderPropagation> OtelPropagationVars() {
762816
return {
763817
{"proxy_set_header", "traceparent", "$opentelemetry_context_traceparent"},
@@ -778,6 +832,8 @@ char* OtelNgxSetPropagation(ngx_conf_t* conf, ngx_command_t*, void* locConf) {
778832

779833
if (propagationType == "b3") {
780834
locationConf->propagationType = TracePropagationB3;
835+
} else if (propagationType == "b3multi") {
836+
locationConf->propagationType = TracePropagationB3Multi;
781837
} else if (propagationType == "w3c") {
782838
locationConf->propagationType = TracePropagationW3C;
783839
} else {
@@ -791,6 +847,8 @@ char* OtelNgxSetPropagation(ngx_conf_t* conf, ngx_command_t*, void* locConf) {
791847
std::vector<HeaderPropagation> propagationVars;
792848
if (locationConf->propagationType == TracePropagationB3) {
793849
propagationVars = B3PropagationVars();
850+
} else if (locationConf->propagationType == TracePropagationB3Multi) {
851+
propagationVars = B3MultiPropagationVars();
794852
} else {
795853
propagationVars = OtelPropagationVars();
796854
}

instrumentation/nginx/src/propagate.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,9 @@ opentelemetry::context::Context ExtractContext(OtelCarrier* carrier) {
7979
case TracePropagationW3C: {
8080
return OtelW3CPropagator().Extract(textMapCarrier, root);
8181
}
82+
case TracePropagationB3Multi: {
83+
return OtelB3MultiPropagator().Extract(textMapCarrier, root);
84+
}
8285
case TracePropagationB3: {
8386
if (HasHeader(carrier->req, "b3")) {
8487
return OtelB3Propagator().Extract(textMapCarrier, root);
@@ -104,6 +107,10 @@ void InjectContext(OtelCarrier* carrier, opentelemetry::context::Context context
104107
OtelB3Propagator().Inject(textMapCarrier, context);
105108
break;
106109
}
110+
case TracePropagationB3Multi: {
111+
OtelB3MultiPropagator().Inject(textMapCarrier, context);
112+
break;
113+
}
107114
default:
108115
break;
109116
}

instrumentation/nginx/src/trace_context.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ enum TracePropagationType {
1717
TracePropagationUnset,
1818
TracePropagationW3C,
1919
TracePropagationB3,
20+
TracePropagationB3Multi,
2021
};
2122

2223
struct TraceContext {

0 commit comments

Comments
 (0)