package lightstep import ( "encoding/base64" "io" "io/ioutil" "github.com/gogo/protobuf/proto" lightstep "github.com/lightstep/lightstep-tracer-common/golang/gogo/lightsteppb" "github.com/opentracing/opentracing-go" ) // BinaryCarrier is used as the format parameter in inject/extract for lighstep binary propagation. const BinaryCarrier = opentracing.Binary // BinaryPropagator propagates context in binary format var BinaryPropagator binaryPropagator type binaryPropagator struct{} func (binaryPropagator) Inject( spanContext opentracing.SpanContext, opaqueCarrier interface{}, ) error { sc, ok := spanContext.(SpanContext) if !ok { return opentracing.ErrInvalidSpanContext } data, err := proto.Marshal(&lightstep.BinaryCarrier{ BasicCtx: &lightstep.BasicTracerCarrier{ TraceId: sc.TraceID, SpanId: sc.SpanID, Sampled: true, BaggageItems: sc.Baggage, }, }) if err != nil { return err } switch carrier := opaqueCarrier.(type) { case io.Writer: buf := make([]byte, base64.StdEncoding.EncodedLen(len(data))) base64.StdEncoding.Encode(buf, data) _, err = carrier.Write(buf) return err case *string: *carrier = base64.StdEncoding.EncodeToString(data) case *[]byte: *carrier = make([]byte, base64.StdEncoding.EncodedLen(len(data))) base64.StdEncoding.Encode(*carrier, data) default: return opentracing.ErrInvalidCarrier } return nil } func (binaryPropagator) Extract( opaqueCarrier interface{}, ) (opentracing.SpanContext, error) { var data []byte var err error // Decode from string, *string, *[]byte, or []byte switch carrier := opaqueCarrier.(type) { case io.Reader: buf, err := ioutil.ReadAll(carrier) if err != nil { return nil, err } data, err = decodeBase64Bytes(buf) case *string: if carrier != nil { data, err = base64.StdEncoding.DecodeString(*carrier) } case string: data, err = base64.StdEncoding.DecodeString(carrier) case *[]byte: if carrier != nil { data, err = decodeBase64Bytes(*carrier) } case []byte: data, err = decodeBase64Bytes(carrier) default: return nil, opentracing.ErrInvalidCarrier } if err != nil { return nil, err } pb := &lightstep.BinaryCarrier{} if err := proto.Unmarshal(data, pb); err != nil { return nil, err } if pb.BasicCtx == nil { return nil, opentracing.ErrInvalidCarrier } return SpanContext{ TraceID: pb.BasicCtx.TraceId, SpanID: pb.BasicCtx.SpanId, Baggage: pb.BasicCtx.BaggageItems, }, nil } func decodeBase64Bytes(in []byte) ([]byte, error) { data := make([]byte, base64.StdEncoding.DecodedLen(len(in))) n, err := base64.StdEncoding.Decode(data, in) if err != nil { return nil, err } return data[:n], nil }