Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion instrumentation/nginx/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,9 @@ load_module /path/to/otel_ngx_module.so;

http {
opentelemetry_service_name "nginx-proxy";
opentelemetry_otlp_traces_endpoint "http://collector:4318/v1/traces"
opentelemetry_otlp_traces_endpoint "http://collector:4318/v1/traces";
Copy link

Copilot AI Jul 28, 2025

Choose a reason for hiding this comment

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

This appears to be an unrelated formatting fix (adding missing semicolon) that should be mentioned in the PR description or handled in a separate commit.

Copilot uses AI. Check for mistakes.
opentelemetry_resource_attr "service.version" "1.0.0";
opentelemetry_resource_attr "deployment.environment.name" "production";

server {
listen 80;
Expand Down Expand Up @@ -104,6 +106,14 @@ Service name for the nginx instance (default: `uknown:nginx`).
- **syntax**: `opentelemetry_service_name <name>`
- **block**: `http`

### `opentelemetry_resource_attr`

Adds a custom resource attribute to the trace provider. Resource attributes represent the entity producing telemetry data, e.g. `opentelemetry_resource_attr "service.version" "1.0.0"` or `opentelemetry_resource_attr "deployment.environment.name" "production"`.

- **required**: `false`
- **syntax**: `opentelemetry_resource_attr <key> <value>`
- **block**: `http`

### `opentelemetry_span_processor`

Chooses between simple and batch span processor (default: `batch`).
Expand Down
2 changes: 2 additions & 0 deletions instrumentation/nginx/src/agent_config.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include <string>
#include <unordered_map>

extern "C" {
#include <ngx_core.h>
Expand Down Expand Up @@ -38,4 +39,5 @@ struct OtelNgxAgentConfig

std::string sampler = "parentbased_always_on";
double samplerRatio = 1.0;
std::unordered_map<std::string, std::string> resourceAttributes;
};
37 changes: 36 additions & 1 deletion instrumentation/nginx/src/otel_ngx_module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1051,6 +1051,21 @@ char* OtelNgxSetTracesSamplerRatio(ngx_conf_t* cf, ngx_command_t*, void*) {
return NGX_CONF_OK;
}

char* OtelNgxSetResourceAttr(ngx_conf_t* cf, ngx_command_t*, void*) {
OtelMainConf* otelMainConf = GetOtelMainConf(cf);

Copy link

Copilot AI Jul 28, 2025

Choose a reason for hiding this comment

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

The function should validate that exactly 2 arguments are provided (key and value). Currently, if fewer than 2 arguments are passed, accessing values[2] could cause undefined behavior.

Suggested change
if (cf->args->nelts < 3) {
ngx_log_error(NGX_LOG_ERR, cf->log, 0, "opentelemetry: invalid number of arguments for resource attribute. Expected 2 arguments (key and value).");
return (char*)NGX_CONF_ERROR;
}

Copilot uses AI. Check for mistakes.
ngx_str_t* values = (ngx_str_t*)cf->args->elts;
ngx_str_t* key = &values[1];
ngx_str_t* value = &values[2];

std::string strKey((const char*)key->data, key->len);
std::string strValue((const char*)value->data, value->len);
Comment on lines +1081 to +1082
Copy link

Copilot AI Jul 28, 2025

Choose a reason for hiding this comment

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

The key and value strings are constructed without null-termination validation. If key->data or value->data are not null-terminated within the specified length, this could lead to buffer overruns when used elsewhere.

Suggested change
std::string strKey((const char*)key->data, key->len);
std::string strValue((const char*)value->data, value->len);
std::string strKey;
std::string strValue;
{
std::vector<char> keyBuffer(key->data, key->data + key->len);
keyBuffer.push_back('\0'); // Ensure null-termination
strKey = std::string(keyBuffer.data());
}
{
std::vector<char> valueBuffer(value->data, value->data + value->len);
valueBuffer.push_back('\0'); // Ensure null-termination
strValue = std::string(valueBuffer.data());
}

Copilot uses AI. Check for mistakes.

otelMainConf->agentConfig.resourceAttributes[strKey] = strValue;

return NGX_CONF_OK;
}

static char* OtelNgxSetCustomAttribute(ngx_conf_t* conf, ngx_command_t*, void* userConf) {
OtelNgxLocationConf* locConf = (OtelNgxLocationConf*)userConf;

Expand Down Expand Up @@ -1250,6 +1265,14 @@ static ngx_command_t kOtelNgxCommands[] = {
0,
nullptr,
},
{
ngx_string("opentelemetry_resource_attr"),
NGX_HTTP_MAIN_CONF | NGX_CONF_TAKE2,
OtelNgxSetResourceAttr,
NGX_HTTP_MAIN_CONF_OFFSET,
0,
nullptr,
},
#if (NGX_PCRE)
{
ngx_string("opentelemetry_sensitive_header_names"),
Expand Down Expand Up @@ -1372,10 +1395,22 @@ static ngx_int_t OtelNgxStart(ngx_cycle_t* cycle) {
}

auto processor = CreateProcessor(agentConf, std::move(exporter));

// Build resource attributes
opentelemetry::sdk::resource::ResourceAttributes resourceAttrs;
for (const auto& attr : agentConf->resourceAttributes) {
resourceAttrs[attr.first] = attr.second;
}

// Set service.name if not already provided via resource attributes
if (resourceAttrs.find("service.name") == resourceAttrs.end()) {
resourceAttrs["service.name"] = serviceName;
}

auto provider =
nostd::shared_ptr<opentelemetry::trace::TracerProvider>(new sdktrace::TracerProvider(
std::move(processor),
opentelemetry::sdk::resource::Resource::Create({{"service.name", serviceName}}),
opentelemetry::sdk::resource::Resource::Create(resourceAttrs),
std::move(sampler)));

opentelemetry::trace::Provider::SetTracerProvider(std::move(provider));
Expand Down
2 changes: 2 additions & 0 deletions instrumentation/nginx/test/conf/nginx.conf
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ http {
opentelemetry_service_name "nginx-proxy";
opentelemetry_otlp_traces_endpoint "http://collector:4318/v1/traces";
opentelemetry_span_processor "simple";
opentelemetry_resource_attr "service.version" "1.0.0";
opentelemetry_resource_attr "deployment.environment.name" "test";
opentelemetry_operation_name otel_test;
opentelemetry_ignore_paths ignored.php;
access_log stderr;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,8 @@ defmodule InstrumentationTest do
assert status == 200

assert attrib(resource, "service.name") == "nginx-proxy"
assert attrib(resource, "service.version") == "1.0.0"
assert attrib(resource, "deployment.environment.name") == "test"
end

test "HTTP upstream | span attributes", %{trace_file: trace_file} do
Expand Down