1package lightstepoc 2 3import ( 4 "context" 5 "errors" 6 7 "github.com/lightstep/lightstep-tracer-go" 8 "github.com/lightstep/lightstep-tracer-go/lightstepoc/internal/conversions" 9 "github.com/opentracing/opentracing-go" 10 "github.com/opentracing/opentracing-go/ext" 11 "github.com/opentracing/opentracing-go/log" 12 "go.opencensus.io/trace" 13) 14 15var ( 16 // ErrFailedToCreateExporter indicates that the underlying tracer could not be created, 17 // but the root reason is not known. 18 ErrFailedToCreateExporter = errors.New("lightstepoc: failed to create exporter") 19) 20 21// Exporter may be registered with OpenCensus so that span data can be exported to LightStep 22type Exporter struct { 23 tracer lightstep.Tracer 24} 25 26// NewExporter creates a new Exporter. 27// It returns an error if the underlying tracer could not be created, e.g., due to invalid options 28func NewExporter(opts ...Option) (*Exporter, error) { 29 c := defaultConfig() 30 31 for _, opt := range opts { 32 opt(c) 33 } 34 35 tracer := lightstep.NewTracer(c.tracerOptions) 36 if tracer == nil { 37 if err := c.tracerOptions.Validate(); err != nil { 38 return nil, err 39 } 40 41 return nil, ErrFailedToCreateExporter 42 } 43 44 return &Exporter{ 45 tracer: tracer, 46 }, nil 47} 48 49// ExportSpan queues the span to be sent LightStep. 50// Spans are typically batched for performance reasons. Call `Exporter#Flush` to send all queued spans. 51func (e *Exporter) ExportSpan(sd *trace.SpanData) { 52 opts := []opentracing.StartSpanOption{ 53 opentracing.StartTime(sd.StartTime), 54 lightstep.SetTraceID(conversions.ConvertTraceID(sd.SpanContext.TraceID)), 55 lightstep.SetSpanID(conversions.ConvertSpanID(sd.SpanContext.SpanID)), 56 lightstep.SetParentSpanID(conversions.ConvertSpanID(sd.ParentSpanID)), 57 } 58 59 for _, link := range sd.Links { 60 if link.Type == trace.LinkTypeChild { 61 spanContext := conversions.ConvertLinkToSpanContext(link) 62 opts = append(opts, opentracing.ChildOf(spanContext)) 63 } 64 } 65 66 switch sd.SpanKind { 67 case trace.SpanKindServer: 68 opts = append(opts, ext.SpanKindRPCServer) 69 case trace.SpanKindClient: 70 opts = append(opts, ext.SpanKindRPCClient) 71 } 72 73 span := e.tracer.StartSpan(sd.Name, opts...) 74 75 for _, entry := range sd.SpanContext.Tracestate.Entries() { 76 span.SetBaggageItem(entry.Key, entry.Value) 77 } 78 79 ext.HTTPStatusCode.Set(span, uint16(sd.Status.Code)) 80 81 for k, v := range sd.Attributes { 82 span.SetTag(k, v) 83 } 84 85 var logRecords []opentracing.LogRecord 86 for _, annotation := range sd.Annotations { 87 logRecords = append(logRecords, opentracing.LogRecord{ 88 Timestamp: annotation.Time, 89 Fields: []log.Field{log.Object(annotation.Message, annotation.Attributes)}, 90 }) 91 } 92 93 span.FinishWithOptions(opentracing.FinishOptions{ 94 FinishTime: sd.EndTime, 95 LogRecords: logRecords, 96 }) 97} 98 99// Flush sends all buffered spans to LightStep 100func (e *Exporter) Flush(ctx context.Context) { 101 e.tracer.Flush(ctx) 102} 103 104// Close flushes all buffered spans and then kills open connections to LightStep, releasing resources 105func (e *Exporter) Close(ctx context.Context) { 106 e.tracer.Close(ctx) 107} 108