Skip to content
Snippets Groups Projects
Commit 3ad853ea authored by Pavel Pautov's avatar Pavel Pautov Committed by dplotnikov-f5
Browse files

Add variables.

parent 20f365b3
No related branches found
No related tags found
No related merge requests found
......@@ -51,7 +51,7 @@ Dumping all the requests could be useful even in non-distributed environment.
http {
server {
location / {
otel_trace on;
otel_trace $otel_parent_sampled;
otel_trace_context propagate;
proxy_pass http://backend;
......@@ -60,6 +60,33 @@ http {
}
```
### Ratio-based Tracing
```nginx
http {
# trace 10% of requests
split_clients $otel_trace_id $ratio_sampler {
10% on;
* off;
}
# or we can trace 10% of user sessions
split_clients $cookie_sessionid $session_sampler {
10% on;
* off;
}
server {
location / {
otel_trace $ratio_sampler;
otel_trace_context inject;
proxy_pass http://backend;
}
}
}
```
## How to Use
### Directives
......@@ -111,6 +138,44 @@ Maximum number of spans to be sent in one batch per worker. Detault is 512.
Maximum number of pending batches per worker, over the limit spans are dropped. Default is 4.
### Variables
`$otel_trace_id` - trace id.
`$otel_span_id` - current span id.
`$otel_parent_id` - parent span id.
`$otel_parent_sampled` - `sampled` flag of parent span, `1`/`0`.
### Default span [attributes](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/semantic_conventions/http.md)
`http.method`
`http.target`
`http.route`
`http.scheme`
`http.flavor`
`http.user_agent`
`http.request_content_length`
`http.response_content_length`
`http.status_code`
`net.host.name`
`net.host.port`
`net.sock.peer.addr`
`net.sock.peer.port`
## License
[Apache License, Version 2.0](https://github.com/nginxinc/nginx-otel/blob/main/LICENSE)
......
......@@ -118,6 +118,11 @@ ngx_str_t toNgxStr(StrView str)
return ngx_str_t{str.size(), (u_char*)str.data()};
}
LocationConf* getLocationConf(ngx_http_request_t* r)
{
return (LocationConf*)ngx_http_get_module_loc_conf(r, gHttpModule);
}
OtelCtx* getOtelCtx(ngx_http_request_t* r)
{
return (OtelCtx*)ngx_http_get_module_ctx(r, gHttpModule);
......@@ -235,6 +240,28 @@ ngx_int_t inject(ngx_http_request_t* r, const TraceContext& tc)
return setHeader(r, "tracestate", tc.state);
}
OtelCtx* ensureOtelCtx(ngx_http_request_t* r)
{
auto ctx = getOtelCtx(r);
if (ctx) {
return ctx;
}
ctx = createOtelCtx(r);
if (!ctx) {
return NULL;
}
auto lcf = getLocationConf(r);
if (lcf->traceContext & Propagation::Extract) {
ctx->parent = extract(r);
}
ctx->current = TraceContext::generate(false, ctx->parent);
return ctx;
}
ngx_int_t onRequestStart(ngx_http_request_t* r)
{
// don't let internal redirects to override sampling decision
......@@ -244,35 +271,26 @@ ngx_int_t onRequestStart(ngx_http_request_t* r)
bool sampled = false;
auto lcf = (LocationConf*)ngx_http_get_module_loc_conf(r, gHttpModule);
auto lcf = getLocationConf(r);
if (lcf->trace != NULL) {
ngx_str_t trace;
if (ngx_http_complex_value(r, lcf->trace, &trace) != NGX_OK) {
return NGX_ERROR;
}
sampled = toStrView(trace) == "on";
sampled = toStrView(trace) == "on" || toStrView(trace) == "1";
}
if (!lcf->traceContext && !sampled) {
return NGX_DECLINED;
}
auto ctx = getOtelCtx(r);
if (ctx) {
return NGX_DECLINED;
}
ctx = createOtelCtx(r);
auto ctx = ensureOtelCtx(r);
if (!ctx) {
return NGX_ERROR;
}
if (lcf->traceContext & Propagation::Extract) {
ctx->parent = extract(r);
}
ctx->current = TraceContext::generate(sampled, ctx->parent);
ctx->current.sampled = sampled;
ngx_int_t rc = NGX_OK;
......@@ -571,6 +589,85 @@ char* initMainConf(ngx_conf_t* cf, void* conf)
return NGX_CONF_OK;
}
template <class Id>
ngx_int_t hexIdVar(ngx_http_request_t* r, ngx_http_variable_value_t* v,
uintptr_t data)
{
auto ctx = ensureOtelCtx(r);
if (!ctx) {
return NGX_ERROR;
}
auto id = (Id*)((char*)ctx + data);
if (id->IsValid()) {
auto size = id->Id().size() * 2;
auto buf = (char*)ngx_pnalloc(r->pool, size);
if (buf == NULL) {
return NGX_ERROR;
}
id->ToLowerBase16({buf, size});
v->len = size;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
v->data = (u_char*)buf;
} else {
v->not_found = 1;
}
return NGX_OK;
}
ngx_int_t parentSampledVar(ngx_http_request_t* r, ngx_http_variable_value_t* v,
uintptr_t data)
{
auto ctx = ensureOtelCtx(r);
if (!ctx) {
return NGX_ERROR;
}
v->len = 1;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
v->data = (u_char*)(ctx->parent.sampled ? "1" : "0");
return NGX_OK;
}
ngx_int_t addVariables(ngx_conf_t* cf)
{
using namespace opentelemetry::trace;
ngx_http_variable_t vars[] = {
{ ngx_string("otel_trace_id"), NULL, hexIdVar<TraceId>,
offsetof(OtelCtx, current.traceId) },
{ ngx_string("otel_span_id"), NULL, hexIdVar<SpanId>,
offsetof(OtelCtx, current.spanId) },
{ ngx_string("otel_parent_id"), NULL, hexIdVar<SpanId>,
offsetof(OtelCtx, parent.spanId) },
{ ngx_string("otel_parent_sampled"), NULL, parentSampledVar }
};
for (auto& v : vars) {
auto var = ngx_http_add_variable(cf, &v.name, 0);
if (var == NULL) {
return NGX_ERROR;
}
var->get_handler = v.get_handler;
var->data = v.data;
}
return NGX_OK;
}
void* createLocationConf(ngx_conf_t* cf)
{
auto conf = (LocationConf*)ngx_pcalloc(cf->pool, sizeof(LocationConf));
......@@ -596,7 +693,7 @@ char* mergeLocationConf(ngx_conf_t* cf, void* parent, void* child)
}
ngx_http_module_t gHttpModuleCtx = {
NULL, /* preconfiguration */
addVariables, /* preconfiguration */
initModule, /* postconfiguration */
createMainConf, /* create main configuration */
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment