...

Source file src/github.com/grpc-ecosystem/go-grpc-middleware/tracing/opentracing/id_extract.go

Documentation: github.com/grpc-ecosystem/go-grpc-middleware/tracing/opentracing

     1  package grpc_opentracing
     2  
     3  import (
     4  	"strings"
     5  
     6  	grpc_ctxtags "github.com/grpc-ecosystem/go-grpc-middleware/tags"
     7  	opentracing "github.com/opentracing/opentracing-go"
     8  	"google.golang.org/grpc/grpclog"
     9  )
    10  
    11  const (
    12  	TagTraceId           = "trace.traceid"
    13  	TagSpanId            = "trace.spanid"
    14  	TagSampled           = "trace.sampled"
    15  	jaegerNotSampledFlag = "0"
    16  )
    17  
    18  // injectOpentracingIdsToTags writes trace data to ctxtags.
    19  // This is done in an incredibly hacky way, because the public-facing interface of opentracing doesn't give access to
    20  // the TraceId and SpanId of the SpanContext. Only the Tracer's Inject/Extract methods know what these are.
    21  // Most tracers have them encoded as keys with 'traceid' and 'spanid':
    22  // https://github.com/openzipkin/zipkin-go-opentracing/blob/594640b9ef7e5c994e8d9499359d693c032d738c/propagation_ot.go#L29
    23  // https://github.com/opentracing/basictracer-go/blob/1b32af207119a14b1b231d451df3ed04a72efebf/propagation_ot.go#L26
    24  // Jaeger from Uber use one-key schema with next format '{trace-id}:{span-id}:{parent-span-id}:{flags}'
    25  // https://www.jaegertracing.io/docs/client-libraries/#trace-span-identity
    26  // Datadog uses keys ending with 'trace-id' and 'parent-id' (for span) by default:
    27  // https://github.com/DataDog/dd-trace-go/blob/v1/ddtrace/tracer/textmap.go#L77
    28  func injectOpentracingIdsToTags(traceHeaderName string, span opentracing.Span, tags grpc_ctxtags.Tags) {
    29  	if err := span.Tracer().Inject(span.Context(), opentracing.HTTPHeaders,
    30  		&tagsCarrier{Tags: tags, traceHeaderName: traceHeaderName}); err != nil {
    31  		grpclog.Infof("grpc_opentracing: failed extracting trace info into ctx %v", err)
    32  	}
    33  }
    34  
    35  // tagsCarrier is a really hacky way of
    36  type tagsCarrier struct {
    37  	grpc_ctxtags.Tags
    38  	traceHeaderName string
    39  }
    40  
    41  func (t *tagsCarrier) Set(key, val string) {
    42  	key = strings.ToLower(key)
    43  
    44  	if key == t.traceHeaderName {
    45  		parts := strings.Split(val, ":")
    46  		if len(parts) == 4 {
    47  			t.Tags.Set(TagTraceId, parts[0])
    48  			t.Tags.Set(TagSpanId, parts[1])
    49  
    50  			if parts[3] != jaegerNotSampledFlag {
    51  				t.Tags.Set(TagSampled, "true")
    52  			} else {
    53  				t.Tags.Set(TagSampled, "false")
    54  			}
    55  
    56  			return
    57  		}
    58  	}
    59  
    60  	if strings.Contains(key, "traceid") {
    61  		t.Tags.Set(TagTraceId, val) // this will most likely be base-16 (hex) encoded
    62  	}
    63  
    64  	if strings.Contains(key, "spanid") && !strings.Contains(strings.ToLower(key), "parent") {
    65  		t.Tags.Set(TagSpanId, val) // this will most likely be base-16 (hex) encoded
    66  	}
    67  
    68  	if strings.Contains(key, "sampled") {
    69  		switch val {
    70  		case "true", "false":
    71  			t.Tags.Set(TagSampled, val)
    72  		}
    73  	}
    74  
    75  	if strings.HasSuffix(key, "trace-id") {
    76  		t.Tags.Set(TagTraceId, val)
    77  	}
    78  
    79  	if strings.HasSuffix(key, "parent-id") {
    80  		t.Tags.Set(TagSpanId, val)
    81  	}
    82  }
    83  

View as plain text