@@ -18,6 +18,8 @@ import (
1818 "go.opentelemetry.io/otel"
1919 "go.opentelemetry.io/otel/attribute"
2020 "go.opentelemetry.io/otel/metric"
21+ "go.opentelemetry.io/otel/propagation"
22+ "go.opentelemetry.io/otel/trace"
2123)
2224
2325type hubBase struct {
@@ -372,8 +374,31 @@ func (h *hubBase) executeCommandScan(connectionName, table string, queryTimestam
372374 }
373375}
374376
375- func (h * hubBase ) traceContextForScan (table string , columns []string , limit int64 , qualMap map [string ]* proto.Quals , connectionName string ) * telemetry.TraceCtx {
376- ctx , span := telemetry .StartSpan (context .Background (), FdwName , "RemoteHub.Scan (%s)" , table )
377+ func (h * hubBase ) traceContextForScan (table string , columns []string , limit int64 , qualMap map [string ]* proto.Quals , connectionName string , opts types.Options ) * telemetry.TraceCtx {
378+ var baseCtx context.Context = context .Background ()
379+
380+ // Check if we have trace context from session variables
381+ if traceContextStr , exists := opts ["trace_context" ]; exists && traceContextStr != "" {
382+ log .Printf ("[DEBUG] traceContextForScan received trace context: %s" , traceContextStr )
383+ if parentCtx := h .parseTraceContext (traceContextStr ); parentCtx != nil {
384+ baseCtx = parentCtx
385+ log .Printf ("[TRACE] Using parent trace context for scan of table: %s" , table )
386+
387+ // Verify the parent context has the expected trace ID
388+ parentSpanCtx := trace .SpanContextFromContext (parentCtx )
389+ if parentSpanCtx .IsValid () {
390+ log .Printf ("[DEBUG] Parent context TraceID: %s, SpanID: %s" ,
391+ parentSpanCtx .TraceID ().String (), parentSpanCtx .SpanID ().String ())
392+ }
393+ } else {
394+ log .Printf ("[WARN] Failed to parse trace context for table: %s" , table )
395+ }
396+ } else {
397+ log .Printf ("[DEBUG] No trace context found in options for table: %s" , table )
398+ }
399+
400+ // Create span with potentially propagated context
401+ ctx , span := telemetry .StartSpan (baseCtx , FdwName , "RemoteHub.Scan (%s)" , table )
377402 span .SetAttributes (
378403 attribute .StringSlice ("columns" , columns ),
379404 attribute .String ("table" , table ),
@@ -383,9 +408,69 @@ func (h *hubBase) traceContextForScan(table string, columns []string, limit int6
383408 if limit != - 1 {
384409 span .SetAttributes (attribute .Int64 ("limit" , limit ))
385410 }
411+
412+ spanCtx := span .SpanContext ()
413+ if spanCtx .IsValid () {
414+ log .Printf ("[DEBUG] Created span for table %s - TraceID: %s, SpanID: %s" ,
415+ table , spanCtx .TraceID ().String (), spanCtx .SpanID ().String ())
416+ }
417+
386418 return & telemetry.TraceCtx {Ctx : ctx , Span : span }
387419}
388420
421+ // parseTraceContext parses trace context string from session variables
422+ // Format: "traceparent=00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01;tracestate=rojo=00f067aa0ba902b7"
423+ func (h * hubBase ) parseTraceContext (traceContextString string ) context.Context {
424+ log .Printf ("[DEBUG] parseTraceContext called with: %s" , traceContextString )
425+
426+ if traceContextString == "" {
427+ log .Printf ("[DEBUG] Empty trace context string" )
428+ return nil
429+ }
430+
431+ carrier := propagation.MapCarrier {}
432+
433+ // Parse the trace context string format: "traceparent=..;tracestate=.."
434+ parts := strings .Split (traceContextString , ";" )
435+ log .Printf ("[DEBUG] Split trace context into %d parts: %v" , len (parts ), parts )
436+
437+ for _ , part := range parts {
438+ if kv := strings .SplitN (part , "=" , 2 ); len (kv ) == 2 {
439+ key := strings .TrimSpace (kv [0 ])
440+ value := strings .TrimSpace (kv [1 ])
441+ carrier [key ] = value
442+ log .Printf ("[DEBUG] Added to carrier: %s = %s" , key , value )
443+ } else {
444+ log .Printf ("[DEBUG] Skipping invalid part: %s" , part )
445+ }
446+ }
447+
448+ log .Printf ("[DEBUG] Final carrier contents: %v" , carrier )
449+
450+ if len (carrier ) == 0 {
451+ log .Printf ("[WARN] No valid trace context found in: %s" , traceContextString )
452+ return nil
453+ }
454+
455+ // Use OpenTelemetry propagator to extract context
456+ propagator := propagation .NewCompositeTextMapPropagator (
457+ propagation.TraceContext {},
458+ propagation.Baggage {},
459+ )
460+ extractedCtx := propagator .Extract (context .Background (), carrier )
461+
462+ // Verify we actually got a valid span context
463+ spanCtx := trace .SpanContextFromContext (extractedCtx )
464+ if spanCtx .IsValid () {
465+ log .Printf ("[TRACE] Successfully extracted trace context - TraceID: %s, SpanID: %s" ,
466+ spanCtx .TraceID ().String (), spanCtx .SpanID ().String ())
467+ return extractedCtx
468+ }
469+
470+ log .Printf ("[WARN] Extracted trace context is not valid - carrier was: %v" , carrier )
471+ return nil
472+ }
473+
389474// determine whether to include the limit, based on the quals
390475// we ONLY pushdown the limit if all quals have corresponding key columns,
391476// and if the qual operator is supported by the key column
0 commit comments