Skip to content

Commit 8bf5ebe

Browse files
Adding functionality to add custom attributes in nginx otel-webserver-module. (#394)
* Nginx attributes feature implementation * corrected branch
1 parent d2e6acb commit 8bf5ebe

File tree

9 files changed

+146
-8
lines changed

9 files changed

+146
-8
lines changed

instrumentation/otel-webserver-module/Dockerfile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ ARG LOG4CXX_VERSION="0.11.0"
2424
ARG GTEST_VERSION="1.10.0"
2525
ARG AUTOMAKE_VERSION="1.16.3"
2626
ARG PCRE_VERSION="8.44"
27-
ARG NGINX_VERSION="1.18.0"
27+
ARG NGINX_VERSION="1.24.0"
2828

2929

3030
# create default non-root user
@@ -273,7 +273,7 @@ RUN cd /otel-webserver-module/build \
273273
&& cd /
274274

275275
RUN cp /otel-webserver-module/conf/nginx/opentelemetry_module.conf /opt/ \
276-
&& sed -i '8i load_module /opt/opentelemetry-webserver-sdk/WebServerModule/Nginx/ngx_http_opentelemetry_module.so;' /etc/nginx/nginx.conf \
276+
&& sed -i '8i load_module /opt/opentelemetry-webserver-sdk/WebServerModule/Nginx/1.24.0/ngx_http_opentelemetry_module.so;' /etc/nginx/nginx.conf \
277277
&& sed -i '33i include /opt/opentelemetry_module.conf;' /etc/nginx/nginx.conf \
278278
&& cd /
279279

instrumentation/otel-webserver-module/codeql-env.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ APRUTIL_VERSION="1.6.1"
3636
LOG4CXX_VERSION="0.11.0"
3737
GTEST_VERSION="1.10.0"
3838
PCRE_VERSION="8.44"
39-
NGINX_VERSION="1.18.0"
39+
NGINX_VERSION="1.24.0"
4040

4141
# Install GRPC
4242
git clone --shallow-submodules --depth 1 --recurse-submodules -b v${GRPC_VERSION} \

instrumentation/otel-webserver-module/include/core/api/Payload.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,11 +87,13 @@ class RequestPayload
8787
std::unordered_map<std::string, std::string>& get_request_headers() {
8888
return request_headers;
8989
}
90+
9091
};
9192

9293
struct ResponsePayload
9394
{
9495
std::unordered_map<std::string, std::string> response_headers;
96+
std::unordered_map<std::string, std::string> otel_attributes;
9597
unsigned int status_code{sdkwrapper::kStatusCodeInit};
9698
};
9799

instrumentation/otel-webserver-module/include/core/api/opentelemetry_ngx_api.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ typedef struct {
4545
const char* http_post_param;
4646
const char* request_method;
4747
const char* client_ip;
48+
4849
http_headers* propagation_headers;
4950
http_headers* request_headers;
5051

@@ -55,6 +56,8 @@ typedef struct {
5556
typedef struct {
5657
http_headers* response_headers;
5758
int response_headers_count;
59+
http_headers* otel_attributes;
60+
int otel_attributes_count;
5861

5962
unsigned int status_code;
6063
}response_payload;

instrumentation/otel-webserver-module/include/core/sdkwrapper/SdkConstants.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ const std::string kAttrNETHostPort = "net.host.port";
3939
const std::string kAttrRequestProtocol = "request_protocol";
4040
const std::string kHTTPFlavor1_0 = "1.0";
4141
const std::string kHTTPFlavor1_1 = "1.1";
42+
const std::string kOtelAttributes = "otel.attribute.";
4243

4344

4445
constexpr int HTTP_ERROR_1XX = 100;

instrumentation/otel-webserver-module/src/core/api/RequestProcessingEngine.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ OTEL_SDK_STATUS_CODE RequestProcessingEngine::startRequest(
8282
std::string(itr->first);
8383
keyValueMap[key] = itr->second;
8484
}
85+
8586
auto span = m_sdkWrapper->CreateSpan(spanName, sdkwrapper::SpanKind::SERVER, keyValueMap, payload->get_http_headers());
8687

8788
LOG4CXX_TRACE(mLogger, "Span started for context: [" << wscontext
@@ -157,6 +158,11 @@ OTEL_SDK_STATUS_CODE RequestProcessingEngine::endRequest(
157158
rootSpan->AddAttribute(key, itr->second);
158159
}
159160

161+
for (auto itr = payload->otel_attributes.begin(); itr != payload->otel_attributes.end(); itr++) {
162+
std::string key = std::string(kOtelAttributes) + std::string(itr->first);
163+
rootSpan->AddAttribute(key, itr->second);
164+
}
165+
160166
rootSpan->AddAttribute(kAttrHTTPStatusCode, payload->status_code);
161167
}
162168

instrumentation/otel-webserver-module/src/core/api/opentelemetry_ngx_api.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,13 +119,17 @@ OTEL_SDK_STATUS_CODE endRequest(OTEL_SDK_HANDLE_REQ req_handle_key, const char*
119119
if (payload != NULL) {
120120
for (int i = 0; i < payload->response_headers_count; i++) {
121121
std::string key(payload->response_headers[i].name);
122-
if (responseHeadersToCapture.find(key)
123-
!= responseHeadersToCapture.end()) {
122+
if (responseHeadersToCapture.find(key) != responseHeadersToCapture.end()) {
124123
responsePayload->response_headers[key]
125124
= payload->response_headers[i].value;
126125
}
127126
}
128127
responsePayload->status_code = payload->status_code;
128+
129+
for(int i=0; i < payload->otel_attributes_count; i++){
130+
std::string key(payload->otel_attributes[i].name);
131+
responsePayload->otel_attributes[key] = payload->otel_attributes[i].value;
132+
}
129133
}
130134

131135
res = wsAgent.endRequest(req_handle_key, errMsg, responsePayload.get());

instrumentation/otel-webserver-module/src/nginx/ngx_http_opentelemetry_module.c

Lines changed: 122 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -383,10 +383,19 @@ static ngx_command_t ngx_http_opentelemetry_commands[] = {
383383
NGX_HTTP_LOC_CONF_OFFSET,
384384
offsetof(ngx_http_opentelemetry_loc_conf_t, nginxTrustIncomingSpans),
385385
NULL},
386-
387-
ngx_null_command /* command termination */
386+
387+
{ ngx_string("NginxAttributes"),
388+
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
389+
ngx_otel_attributes_set,
390+
NGX_HTTP_LOC_CONF_OFFSET,
391+
0,
392+
NULL},
393+
394+
/* command termination */
395+
ngx_null_command
388396
};
389397

398+
390399
/* The module context. */
391400
static ngx_http_module_t ngx_http_opentelemetry_module_ctx = {
392401
NULL, /* preconfiguration */
@@ -454,6 +463,7 @@ static char* ngx_http_opentelemetry_merge_loc_conf(ngx_conf_t *cf, void *parent,
454463
ngx_http_opentelemetry_loc_conf_t *prev = parent;
455464
ngx_http_opentelemetry_loc_conf_t *conf = child;
456465
ngx_otel_set_global_context(prev);
466+
ngx_otel_set_attributes(prev, conf);
457467

458468
ngx_conf_merge_value(conf->nginxModuleEnabled, prev->nginxModuleEnabled, 1);
459469
ngx_conf_merge_value(conf->nginxModuleReportAllInstrumentedModules, prev->nginxModuleReportAllInstrumentedModules, 0);
@@ -673,6 +683,34 @@ static void ngx_http_opentelemetry_exit_worker(ngx_cycle_t *cycle)
673683
ngx_log_error(NGX_LOG_ERR, cycle->log, 0, "mod_opentelemetry: ngx_http_opentelemetry_exit_worker: Exiting Nginx Worker for process with PID: %s**********", worker_conf->pid);
674684
}
675685
}
686+
static char* ngx_otel_attributes_set(ngx_conf_t* cf, ngx_command_t* cmd, void* conf) {
687+
ngx_http_opentelemetry_loc_conf_t * my_conf=(ngx_http_opentelemetry_loc_conf_t *)conf;
688+
689+
ngx_str_t *value = cf->args->elts;
690+
691+
ngx_array_t *arr;
692+
ngx_str_t *elt;
693+
ngx_int_t arg_count = cf->args->nelts;
694+
695+
arr = ngx_array_create(cf->pool, arg_count, sizeof(ngx_str_t));
696+
697+
if (arr == NULL) {
698+
return NGX_CONF_ERROR;
699+
}
700+
701+
// Add elements to the array
702+
for (ngx_int_t i = 1; i < arg_count; i++) {
703+
elt = ngx_array_push(arr);
704+
if (elt == NULL) {
705+
return NGX_CONF_ERROR;
706+
}
707+
ngx_str_set(elt, value[i].data);
708+
elt->len = ngx_strlen(value[i].data);
709+
}
710+
my_conf->nginxAttributes = arr;
711+
return NGX_CONF_OK;
712+
713+
}
676714

677715
static char* ngx_otel_context_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf){
678716
ngx_str_t* value;
@@ -704,6 +742,20 @@ static void ngx_otel_set_global_context(ngx_http_opentelemetry_loc_conf_t * prev
704742
}
705743
}
706744

745+
static void ngx_otel_set_attributes(ngx_http_opentelemetry_loc_conf_t * prev, ngx_http_opentelemetry_loc_conf_t * conf)
746+
{
747+
if (conf->nginxAttributes && (conf->nginxAttributes->nelts) > 0) {
748+
return;
749+
}
750+
if (prev->nginxAttributes && (prev->nginxAttributes->nelts) > 0) {
751+
if((conf->nginxAttributes) == NULL)
752+
{
753+
conf->nginxAttributes = prev->nginxAttributes;
754+
}
755+
}
756+
return;
757+
}
758+
707759
/*
708760
Begin a new interaction
709761
*/
@@ -737,6 +789,7 @@ static OTEL_SDK_STATUS_CODE otel_startInteraction(ngx_http_request_t* r, const c
737789
int ix = 0;
738790
res = startModuleInteraction((void*)ctx->otel_req_handle_key, module_name, "", resolveBackends, propagationHeaders, &ix);
739791

792+
740793
if (OTEL_ISSUCCESS(res))
741794
{
742795
removeUnwantedHeader(r);
@@ -892,6 +945,39 @@ static ngx_uint_t otel_getErrorCode(ngx_http_request_t* r)
892945
else return 0;
893946
}
894947

948+
static void resolve_attributes_variables(ngx_http_request_t* r)
949+
{
950+
ngx_http_opentelemetry_loc_conf_t *conf = ngx_http_get_module_loc_conf(r, ngx_http_opentelemetry_module);
951+
952+
for (ngx_uint_t j = 0; j < conf->nginxAttributes->nelts; j++) {
953+
954+
void *element = conf->nginxAttributes->elts + (j * conf->nginxAttributes->size);
955+
ngx_str_t var_name = (((ngx_str_t *)(conf->nginxAttributes->elts))[j]);
956+
ngx_uint_t key; // The variable's hashed key.
957+
ngx_http_variable_value_t *value; // Pointer to the value object.
958+
959+
if(var_name.data[0] == '$'){
960+
// Get the hashed key.
961+
ngx_str_t new_var_name = var_name;
962+
new_var_name.data++;
963+
new_var_name.len--;
964+
key = ngx_hash_key(new_var_name.data, new_var_name.len);
965+
966+
// Get the variable.
967+
value = ngx_http_get_variable(r, &new_var_name, key);
968+
969+
if (value == NULL || value->not_found) {
970+
// Variable was not found.
971+
} else {
972+
ngx_str_t * ngx_str = (ngx_str_t *)(element);
973+
ngx_str->data = value->data;
974+
ngx_str->len = ngx_strlen(value);
975+
// Variable was found, `value` now contains the value.
976+
}
977+
}
978+
}
979+
}
980+
895981
static ngx_flag_t ngx_initialize_opentelemetry(ngx_http_request_t *r)
896982
{
897983
// check to see if we have already been initialized
@@ -1274,7 +1360,7 @@ static ngx_int_t ngx_http_otel_realip_handler(ngx_http_request_t *r){
12741360

12751361
otel_startInteraction(r, "ngx_http_realip_module");
12761362
ngx_int_t rvalue = h[NGX_HTTP_REALIP_MODULE_INDEX](r);
1277-
otel_stopInteraction(r, "ngx_http_realip_module", OTEL_SDK_NO_HANDLE);
1363+
otel_stopInteraction(r, "ngx_http_realip_module", OTEL_SDK_NO_HANDLE);
12781364

12791365
return rvalue;
12801366
}
@@ -1555,6 +1641,7 @@ static void removeUnwantedHeader(ngx_http_request_t* r)
15551641
}
15561642
}
15571643

1644+
15581645
static void fillRequestPayload(request_payload* req_payload, ngx_http_request_t* r){
15591646
ngx_list_part_t *part;
15601647
ngx_table_elt_t *header;
@@ -1636,6 +1723,7 @@ static void fillRequestPayload(request_payload* req_payload, ngx_http_request_t*
16361723

16371724
ngx_http_opentelemetry_loc_conf_t *conf =
16381725
ngx_http_get_module_loc_conf(r, ngx_http_opentelemetry_module);
1726+
16391727
part = &r->headers_in.headers.part;
16401728
header = (ngx_table_elt_t*)part->elts;
16411729
nelts = part->nelts;
@@ -1669,6 +1757,7 @@ static void fillRequestPayload(request_payload* req_payload, ngx_http_request_t*
16691757
}
16701758
req_payload->propagation_count = propagation_headers_idx;
16711759
req_payload->request_headers_count = request_headers_idx;
1760+
16721761
}
16731762

16741763
static void fillResponsePayload(response_payload* res_payload, ngx_http_request_t* r)
@@ -1689,6 +1778,36 @@ static void fillResponsePayload(response_payload* res_payload, ngx_http_request_
16891778
res_payload->response_headers = ngx_pcalloc(r->pool, nelts * sizeof(http_headers));
16901779
ngx_uint_t headers_count = 0;
16911780

1781+
ngx_http_opentelemetry_loc_conf_t *conf = ngx_http_get_module_loc_conf(r, ngx_http_opentelemetry_module);
1782+
1783+
if (conf->nginxAttributes && (conf->nginxAttributes->nelts) > 0) {
1784+
1785+
res_payload->otel_attributes = ngx_pcalloc(r->pool, ((nelts+1)/3) * sizeof(http_headers));
1786+
int otel_attributes_idx=0;
1787+
1788+
resolve_attributes_variables(r);
1789+
for (ngx_uint_t j = 0, isKey = 1, isValue = 0; j < conf->nginxAttributes->nelts; j++) {
1790+
const char* data = (const char*)(((ngx_str_t *)(conf->nginxAttributes->elts))[j]).data;
1791+
if(strcmp(data, ",") == 0){
1792+
otel_attributes_idx++;
1793+
continue;
1794+
}
1795+
else if(isKey){
1796+
res_payload->otel_attributes[otel_attributes_idx].name = data;
1797+
}
1798+
else{
1799+
res_payload->otel_attributes[otel_attributes_idx].value = data;
1800+
}
1801+
isKey=!isKey;
1802+
isValue=!isValue;
1803+
}
1804+
res_payload->otel_attributes_count = otel_attributes_idx+1;
1805+
}else {
1806+
res_payload->otel_attributes_count = 0;
1807+
}
1808+
1809+
1810+
16921811
for (ngx_uint_t j = 0; j < nelts; j++) {
16931812
h = &header[j];
16941813

instrumentation/otel-webserver-module/src/nginx/ngx_http_opentelemetry_module.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ typedef struct {
104104
ngx_str_t nginxModuleResponseHeaders;
105105
ngx_str_t nginxModuleOtelExporterOtlpHeaders;
106106
ngx_flag_t nginxTrustIncomingSpans;
107+
ngx_array_t *nginxAttributes;
107108

108109
} ngx_http_opentelemetry_loc_conf_t;
109110

@@ -154,7 +155,9 @@ static void otel_payload_decorator(ngx_http_request_t* r, OTEL_SDK_ENV_RECORD* p
154155
static ngx_flag_t otel_requestHasErrors(ngx_http_request_t* r);
155156
static ngx_uint_t otel_getErrorCode(ngx_http_request_t* r);
156157
static char* ngx_otel_context_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
158+
static char* ngx_otel_attributes_set(ngx_conf_t* cf, ngx_command_t*, void* conf);
157159
static void ngx_otel_set_global_context(ngx_http_opentelemetry_loc_conf_t * prev);
160+
static void ngx_otel_set_attributes(ngx_http_opentelemetry_loc_conf_t * prev, ngx_http_opentelemetry_loc_conf_t * conf);
158161
static void removeUnwantedHeader(ngx_http_request_t* r);
159162
/*
160163
Module specific handler

0 commit comments

Comments
 (0)