Add variables.
This commit is contained in:
parent
20f365b3c1
commit
3ad853ea59
2 changed files with 177 additions and 15 deletions
67
README.md
67
README.md
|
|
@ -51,7 +51,7 @@ Dumping all the requests could be useful even in non-distributed environment.
|
||||||
http {
|
http {
|
||||||
server {
|
server {
|
||||||
location / {
|
location / {
|
||||||
otel_trace on;
|
otel_trace $otel_parent_sampled;
|
||||||
otel_trace_context propagate;
|
otel_trace_context propagate;
|
||||||
|
|
||||||
proxy_pass http://backend;
|
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
|
## How to Use
|
||||||
|
|
||||||
### Directives
|
### 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.
|
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
|
## License
|
||||||
|
|
||||||
[Apache License, Version 2.0](https://github.com/nginxinc/nginx-otel/blob/main/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()};
|
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)
|
OtelCtx* getOtelCtx(ngx_http_request_t* r)
|
||||||
{
|
{
|
||||||
return (OtelCtx*)ngx_http_get_module_ctx(r, gHttpModule);
|
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);
|
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)
|
ngx_int_t onRequestStart(ngx_http_request_t* r)
|
||||||
{
|
{
|
||||||
// don't let internal redirects to override sampling decision
|
// 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;
|
bool sampled = false;
|
||||||
|
|
||||||
auto lcf = (LocationConf*)ngx_http_get_module_loc_conf(r, gHttpModule);
|
auto lcf = getLocationConf(r);
|
||||||
if (lcf->trace != NULL) {
|
if (lcf->trace != NULL) {
|
||||||
ngx_str_t trace;
|
ngx_str_t trace;
|
||||||
if (ngx_http_complex_value(r, lcf->trace, &trace) != NGX_OK) {
|
if (ngx_http_complex_value(r, lcf->trace, &trace) != NGX_OK) {
|
||||||
return NGX_ERROR;
|
return NGX_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
sampled = toStrView(trace) == "on";
|
sampled = toStrView(trace) == "on" || toStrView(trace) == "1";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!lcf->traceContext && !sampled) {
|
if (!lcf->traceContext && !sampled) {
|
||||||
return NGX_DECLINED;
|
return NGX_DECLINED;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ctx = getOtelCtx(r);
|
auto ctx = ensureOtelCtx(r);
|
||||||
if (ctx) {
|
|
||||||
return NGX_DECLINED;
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx = createOtelCtx(r);
|
|
||||||
if (!ctx) {
|
if (!ctx) {
|
||||||
return NGX_ERROR;
|
return NGX_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lcf->traceContext & Propagation::Extract) {
|
ctx->current.sampled = sampled;
|
||||||
ctx->parent = extract(r);
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx->current = TraceContext::generate(sampled, ctx->parent);
|
|
||||||
|
|
||||||
ngx_int_t rc = NGX_OK;
|
ngx_int_t rc = NGX_OK;
|
||||||
|
|
||||||
|
|
@ -571,6 +589,85 @@ char* initMainConf(ngx_conf_t* cf, void* conf)
|
||||||
return NGX_CONF_OK;
|
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)
|
void* createLocationConf(ngx_conf_t* cf)
|
||||||
{
|
{
|
||||||
auto conf = (LocationConf*)ngx_pcalloc(cf->pool, sizeof(LocationConf));
|
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 = {
|
ngx_http_module_t gHttpModuleCtx = {
|
||||||
NULL, /* preconfiguration */
|
addVariables, /* preconfiguration */
|
||||||
initModule, /* postconfiguration */
|
initModule, /* postconfiguration */
|
||||||
|
|
||||||
createMainConf, /* create main configuration */
|
createMainConf, /* create main configuration */
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue