@@ -21,6 +21,8 @@ extern ngx_module_t otel_ngx_module;
2121#include  " nginx_config.h" 
2222#include  " nginx_utils.h" 
2323#include  " propagate.h" 
24+ #include  " post_span_processor.h" 
25+ #include  " post_batch_span_processor.h" 
2426#include  < opentelemetry/context/context.h> 
2527#include  < opentelemetry/nostd/shared_ptr.h> 
2628#include  < opentelemetry/sdk/trace/batch_span_processor.h> 
@@ -38,6 +40,7 @@ extern ngx_module_t otel_ngx_module;
3840#include  < opentelemetry/exporters/otlp/otlp_http_exporter.h> 
3941
4042namespace  trace  =  opentelemetry::trace;
43+ namespace  common  =  opentelemetry::common;
4144namespace  nostd  =  opentelemetry::nostd;
4245namespace  sdktrace  =  opentelemetry::sdk::trace;
4346namespace  otlp  =  opentelemetry::exporter::otlp;
@@ -134,6 +137,8 @@ static ngx_int_t OtelGetContextVar(ngx_http_request_t*, ngx_http_variable_value_
134137  return  NGX_OK;
135138}
136139
140+ 
141+ 
137142static  ngx_int_t 
138143OtelGetTraceContextVar (ngx_http_request_t * req, ngx_http_variable_value_t * v, uintptr_t  data);
139144
@@ -496,21 +501,13 @@ TraceContext* CreateTraceContext(ngx_http_request_t* req, ngx_http_variable_valu
496501  return  context;
497502}
498503
499- ngx_int_t  StartNgxSpan (ngx_http_request_t * req) {
500-   if  (!IsOtelEnabled (req)) {
501-     return  NGX_DECLINED;
502-   }
503- 
504-   //  Internal requests must be called from another location in nginx, that should already have a trace. Without this check, a call would generate an extra (unrelated) span without much information
505-   if  (req->internal ) {
506-     return  NGX_DECLINED;
507-   }
504+ TraceContext* StartNgxTrace (ngx_http_request_t * req) {
508505
509506  ngx_http_variable_value_t * val = ngx_http_get_indexed_variable (req, otel_ngx_variables[0 ].index );
510507
511508  if  (!val) {
512509    ngx_log_error (NGX_LOG_ERR, req->connection ->log , 0 , " Unable to find OpenTelemetry context"  );
513-     return  NGX_DECLINED ;
510+     return  nullptr ;
514511  }
515512
516513  TraceContext* context = CreateTraceContext (req, val);
@@ -524,30 +521,43 @@ ngx_int_t StartNgxSpan(ngx_http_request_t* req) {
524521    incomingContext = ExtractContext (&carrier);
525522  }
526523
527-   trace::StartSpanOptions startOpts;
528-   startOpts.kind  = trace::SpanKind::kServer ;
529-   startOpts.parent  = GetCurrentSpan (incomingContext);
524+   const  auto  operationName = GetOperationName (req);
530525
531-   context->request_span  = GetTracer ()->StartSpan (
532-     GetOperationName (req),
533-     {
534-       {" http.method"  , FromNgxString (req->method_name )},
535-       {" http.flavor"  , NgxHttpFlavor (req)},
536-       {" http.target"  , FromNgxString (req->unparsed_uri )},
537-     },
538-     startOpts);
526+   std::initializer_list<std::pair<nostd::string_view, common::AttributeValue>> commonAttributes = {
527+           {" http.method"  , FromNgxString (req->method_name )},
528+           {" http.flavor"  , NgxHttpFlavor (req)},
529+           {" http.target"  , FromNgxString (req->unparsed_uri )},
530+           //  Add http.route as its according to OpenTelemetry spec
531+           {" http.route"  , FromNgxString (req->unparsed_uri )}
532+   };
533+ 
534+   trace::StartSpanOptions requestStartOpts;
535+   requestStartOpts.parent  = GetCurrentSpan (incomingContext);
536+   requestStartOpts.kind  = trace::SpanKind::kServer ;
537+   context->request_span  = GetTracer ()->StartSpan (operationName,commonAttributes, requestStartOpts);
538+ 
539+   trace::StartSpanOptions innerSpanOpts;
540+   innerSpanOpts.parent  = context->request_span ->GetContext ();
541+   innerSpanOpts.kind  = trace::SpanKind::kInternal ;
542+ 
543+   context->inner_span  = GetTracer ()->StartSpan (operationName,commonAttributes,innerSpanOpts);
539544
540545  nostd::string_view serverName = GetNgxServerName (req);
541546  if  (!serverName.empty ()) {
542547    context->request_span ->SetAttribute (" http.server_name"  , serverName);
548+     context->inner_span ->SetAttribute (" http.server_name"  , serverName);
543549  }
544550
545551  if  (req->headers_in .host ) {
546-     context->request_span ->SetAttribute (" http.host"  , FromNgxString (req->headers_in .host ->value ));
552+     const  auto  host = FromNgxString (req->headers_in .host ->value );
553+     context->request_span ->SetAttribute (" http.host"  , host);
554+     context->inner_span ->SetAttribute (" http.host"  , host);
547555  }
548556
549557  if  (req->headers_in .user_agent ) {
550-     context->request_span ->SetAttribute (" http.user_agent"  , FromNgxString (req->headers_in .user_agent ->value ));
558+     const  auto  userAgent = FromNgxString (req->headers_in .user_agent ->value );
559+     context->request_span ->SetAttribute (" http.user_agent"  , userAgent);
560+     context->inner_span ->SetAttribute (" http.user_agent"  , userAgent);
551561  }
552562
553563  if  (locConf->captureHeaders ) {
@@ -559,10 +569,24 @@ ngx_int_t StartNgxSpan(ngx_http_request_t* req) {
559569                       {excludedHeaders, 2 });
560570  }
561571
562-   auto  outgoingContext = incomingContext.SetValue (trace::kSpanKey , context->request_span );
572+   auto  outgoingContext = incomingContext.SetValue (trace::kSpanKey , context->inner_span );
563573
564574  InjectContext (&carrier, outgoingContext);
565575
576+   return  context;
577+ }
578+ 
579+ ngx_int_t  StartNgxSpan (ngx_http_request_t * req) {
580+   if  (!IsOtelEnabled (req)) {
581+     return  NGX_DECLINED;
582+   }
583+ 
584+   if  (req->internal ) {
585+     return  NGX_DECLINED;
586+   }
587+ 
588+   StartNgxTrace (req);
589+ 
566590  return  NGX_DECLINED;
567591}
568592
@@ -591,10 +615,7 @@ void AddScriptAttributes(
591615  }
592616}
593617
594- ngx_int_t  FinishNgxSpan (ngx_http_request_t * req) {
595-   if  (!IsOtelEnabled (req)) {
596-     return  NGX_DECLINED;
597-   }
618+ void  UpdateSpan (nostd::shared_ptr<opentelemetry::trace::Span> span, ngx_http_request_t * req, bool  captureHeaders = false ) {
598619
599620  TraceContext* context = GetTraceContext (req);
600621
@@ -603,31 +624,22 @@ ngx_int_t FinishNgxSpan(ngx_http_request_t* req) {
603624  }
604625
605626  auto  span = context->request_span ;
606-   const  auto  status_code = req->headers_out .status ;
607-   span->SetAttribute (" http.status_code"  , status_code);
608- 
609-   if  (status_code >= 500 ) {
610-     span->SetStatus (trace::StatusCode::kError );
611-   } else  {
612-     span->SetStatus (trace::StatusCode::kOk );
613-   }
627+   UpdateSpan (span, req, true );
614628
615-   OtelNgxLocationConf* locConf =  GetOtelLocationConf (req); 
629+   if  (context-> inner_span ) { 
616630
617-   if  (locConf->captureHeaders ) {
618-     OtelCaptureHeaders (span, ngx_string (" http.response.header."  ), &req->headers_out .headers ,
619- #if  (NGX_PCRE)
620-                        locConf->sensitiveHeaderNames , locConf->sensitiveHeaderValues ,
621- #endif 
622-                        {});
623-   }
631+     const  bool  hasUpstream = req->upstream  != nullptr ;
632+     if  (hasUpstream) {
633+       context->inner_span ->SetAttribute (" span.kind"  , static_cast <int >(trace::SpanKind::kClient ));
634+     }
624635
625-   AddScriptAttributes (span.get (), GetOtelMainConf (req)->scriptAttributes , req);
626-   AddScriptAttributes (span.get (), locConf->customAttributes , req);
636+     UpdateSpan (context->inner_span , req);
627637
628-   span->UpdateName (GetOperationName (req));
638+     context->inner_span ->End ();
639+   }
629640
630641  span->End ();
642+ 
631643  return  NGX_DECLINED;
632644}
633645
@@ -642,7 +654,7 @@ static ngx_int_t InitModule(ngx_conf_t* conf) {
642654
643655  const  PhaseHandler handlers[] = {
644656    {NGX_HTTP_REWRITE_PHASE, StartNgxSpan},
645-     {NGX_HTTP_LOG_PHASE, FinishNgxSpan}, 
657+     {NGX_HTTP_LOG_PHASE, FinishNgxSpan}
646658  };
647659
648660  for  (const  PhaseHandler& ph : handlers) {
@@ -1292,6 +1304,7 @@ static std::unique_ptr<sdktrace::SpanExporter> CreateExporter(const OtelNgxAgent
12921304
12931305static  std::unique_ptr<sdktrace::SpanProcessor>
12941306CreateProcessor (const  OtelNgxAgentConfig* conf, std::unique_ptr<sdktrace::SpanExporter> exporter) {
1307+ 
12951308  if  (conf->processor .type  == OtelProcessorBatch) {
12961309    sdktrace::BatchSpanProcessorOptions opts;
12971310    opts.max_queue_size  = conf->processor .batch .maxQueueSize ;
@@ -1300,11 +1313,11 @@ CreateProcessor(const OtelNgxAgentConfig* conf, std::unique_ptr<sdktrace::SpanEx
13001313    opts.max_export_batch_size  = conf->processor .batch .maxExportBatchSize ;
13011314
13021315    return  std::unique_ptr<sdktrace::SpanProcessor>(
1303-       new  sdktrace::BatchSpanProcessor (std::move (exporter), opts));
1316+       new  PostBatchSpanProcessor (std::move (exporter), opts));
13041317  }
13051318
13061319  return  std::unique_ptr<sdktrace::SpanProcessor>(
1307-     new  sdktrace::SimpleSpanProcessor (std::move (exporter)));
1320+     new  PostSpanProcessor (std::move (exporter)));
13081321}
13091322
13101323static  std::unique_ptr<sdktrace::Sampler> CreateSampler (const  OtelNgxAgentConfig* conf) {
0 commit comments