github.com/anuvu/tyk@v2.9.0-beta9-dl-apic+incompatible/trace/openzipkin/zipkin.go (about)

     1  package openzipkin
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"strings"
     7  	"time"
     8  
     9  	opentracing "github.com/opentracing/opentracing-go"
    10  	"github.com/opentracing/opentracing-go/log"
    11  	zipkin "github.com/openzipkin/zipkin-go"
    12  	"github.com/openzipkin/zipkin-go/model"
    13  	"github.com/openzipkin/zipkin-go/propagation/b3"
    14  	"github.com/openzipkin/zipkin-go/reporter"
    15  	"github.com/openzipkin/zipkin-go/reporter/http"
    16  )
    17  
    18  var _ opentracing.Tracer = (*zipkinTracer)(nil)
    19  var _ opentracing.SpanContext = (*spanContext)(nil)
    20  var _ opentracing.Span = (*Span)(nil)
    21  
    22  const Name = "zipkin"
    23  
    24  type Span struct {
    25  	span zipkin.Span
    26  	tr   *zipkinTracer
    27  }
    28  
    29  func (s Span) Context() opentracing.SpanContext {
    30  	return spanContext{s.span.Context()}
    31  }
    32  
    33  func (s Span) Finish() {
    34  	s.span.Finish()
    35  }
    36  
    37  func (s Span) FinishWithOptions(opts opentracing.FinishOptions) {
    38  	s.span.Finish()
    39  }
    40  
    41  func (s Span) SetOperationName(operationName string) opentracing.Span {
    42  	s.span.SetName(operationName)
    43  	return s
    44  }
    45  
    46  func (s Span) SetTag(key string, value interface{}) opentracing.Span {
    47  	s.span.Tag(key, fmt.Sprint(value))
    48  	return s
    49  }
    50  
    51  func (s Span) LogFields(fields ...log.Field) {
    52  	now := time.Now()
    53  	lg := &logEncoder{h: func(key string, value interface{}) {
    54  		s.span.Annotate(now, fmt.Sprintf("%s %s", key, value))
    55  	}}
    56  	for _, field := range fields {
    57  		field.Marshal(lg)
    58  	}
    59  }
    60  
    61  type logEncoder struct {
    62  	h func(string, interface{})
    63  }
    64  
    65  func (e *logEncoder) emit(key string, value interface{}) {
    66  	if e.h != nil {
    67  		e.h(key, value)
    68  	}
    69  }
    70  func (e *logEncoder) EmitString(key, value string)             { e.emit(key, value) }
    71  func (e *logEncoder) EmitBool(key string, value bool)          { e.emit(key, value) }
    72  func (e *logEncoder) EmitInt(key string, value int)            { e.emit(key, value) }
    73  func (e *logEncoder) EmitInt32(key string, value int32)        { e.emit(key, value) }
    74  func (e *logEncoder) EmitInt64(key string, value int64)        { e.emit(key, value) }
    75  func (e *logEncoder) EmitUint32(key string, value uint32)      { e.emit(key, value) }
    76  func (e *logEncoder) EmitUint64(key string, value uint64)      { e.emit(key, value) }
    77  func (e *logEncoder) EmitFloat32(key string, value float32)    { e.emit(key, value) }
    78  func (e *logEncoder) EmitFloat64(key string, value float64)    { e.emit(key, value) }
    79  func (e *logEncoder) EmitObject(key string, value interface{}) { e.emit(key, value) }
    80  func (e *logEncoder) EmitLazyLogger(value log.LazyLogger)      {}
    81  
    82  func (s Span) LogKV(alternatingKeyValues ...interface{})                   {}
    83  func (s Span) SetBaggageItem(restrictedKey, value string) opentracing.Span { return s }
    84  func (Span) BaggageItem(restrictedKey string) string                       { return "" }
    85  func (s Span) Tracer() opentracing.Tracer                                  { return s.tr }
    86  func (s Span) LogEvent(event string)                                       {}
    87  func (s Span) LogEventWithPayload(event string, payload interface{})       {}
    88  func (s Span) Log(data opentracing.LogData)                                {}
    89  
    90  type spanContext struct {
    91  	model.SpanContext
    92  }
    93  
    94  func (spanContext) ForeachBaggageItem(handler func(k, v string) bool) {}
    95  
    96  type extractor interface {
    97  	extract(carrier interface{}) (spanContext, error)
    98  }
    99  
   100  var emptyContext spanContext
   101  
   102  func extractHTTPHeader(carrier interface{}) (spanContext, error) {
   103  	c, ok := carrier.(opentracing.HTTPHeadersCarrier)
   104  	if !ok {
   105  		return emptyContext, opentracing.ErrInvalidCarrier
   106  	}
   107  	var (
   108  		traceIDHeader      string
   109  		spanIDHeader       string
   110  		parentSpanIDHeader string
   111  		sampledHeader      string
   112  		flagsHeader        string
   113  		singleHeader       string
   114  	)
   115  	err := c.ForeachKey(func(key, val string) error {
   116  		switch strings.ToLower(key) {
   117  		case b3.TraceID:
   118  			traceIDHeader = val
   119  		case b3.SpanID:
   120  			spanIDHeader = val
   121  		case b3.ParentSpanID:
   122  			parentSpanIDHeader = val
   123  		case b3.Sampled:
   124  			sampledHeader = val
   125  		case b3.Flags:
   126  			flagsHeader = val
   127  		case b3.Context:
   128  			singleHeader = val
   129  		}
   130  		return nil
   131  	})
   132  	if err != nil {
   133  		return emptyContext, err
   134  	}
   135  	if singleHeader != "" {
   136  		ctx, err := b3.ParseSingleHeader(singleHeader)
   137  		if err != nil {
   138  			return emptyContext, err
   139  		}
   140  		return spanContext{*ctx}, nil
   141  	}
   142  	ctx, err := b3.ParseHeaders(
   143  		traceIDHeader, spanIDHeader, parentSpanIDHeader,
   144  		sampledHeader, flagsHeader,
   145  	)
   146  	if err != nil {
   147  		return emptyContext, err
   148  	}
   149  	return spanContext{*ctx}, nil
   150  }
   151  
   152  type extractorFn func(carrier interface{}) (spanContext, error)
   153  
   154  func (fn extractorFn) extract(carrier interface{}) (spanContext, error) {
   155  	return fn(carrier)
   156  }
   157  
   158  type injector interface {
   159  	inject(ctx spanContext, carrier interface{}) error
   160  }
   161  
   162  func injectHTTPHeaders(ctx spanContext, carrier interface{}) error {
   163  	c, ok := carrier.(opentracing.HTTPHeadersCarrier)
   164  	if !ok {
   165  		return opentracing.ErrInvalidCarrier
   166  	}
   167  	if ctx == emptyContext {
   168  		return nil
   169  	}
   170  	c.Set(b3.Context, b3.BuildSingleHeader(ctx.SpanContext))
   171  	return nil
   172  }
   173  
   174  type injectorFn func(ctx spanContext, carrier interface{}) error
   175  
   176  func (fn injectorFn) inject(ctx spanContext, carrier interface{}) error {
   177  	return fn(ctx, carrier)
   178  }
   179  
   180  type zipkinTracer struct {
   181  	zip        *zipkin.Tracer
   182  	extractors map[interface{}]extractor
   183  	injectors  map[interface{}]injector
   184  }
   185  
   186  func NewTracer(zip *zipkin.Tracer) *zipkinTracer {
   187  	return &zipkinTracer{
   188  		zip: zip,
   189  		extractors: map[interface{}]extractor{
   190  			opentracing.HTTPHeaders: extractorFn(extractHTTPHeader),
   191  		},
   192  		injectors: map[interface{}]injector{
   193  			opentracing.HTTPHeaders: injectorFn(injectHTTPHeaders),
   194  		},
   195  	}
   196  }
   197  
   198  func (z *zipkinTracer) StartSpan(operationName string, opts ...opentracing.StartSpanOption) opentracing.Span {
   199  	var o []zipkin.SpanOption
   200  	if len(opts) > 0 {
   201  		var os opentracing.StartSpanOptions
   202  		for _, opt := range opts {
   203  			opt.Apply(&os)
   204  		}
   205  		if len(os.Tags) > 0 {
   206  			t := make(map[string]string)
   207  			for k, v := range os.Tags {
   208  				t[k] = fmt.Sprint(v)
   209  			}
   210  			o = append(o, zipkin.Tags(t))
   211  		}
   212  		for _, ref := range os.References {
   213  			switch ref.Type {
   214  			case opentracing.ChildOfRef:
   215  				sp := ref.ReferencedContext.(spanContext)
   216  				o = append(o, zipkin.Parent(
   217  					sp.SpanContext,
   218  				))
   219  			}
   220  		}
   221  	}
   222  	sp := z.zip.StartSpan(operationName, o...)
   223  	return Span{tr: z, span: sp}
   224  }
   225  
   226  func (z *zipkinTracer) Extract(format interface{}, carrier interface{}) (opentracing.SpanContext, error) {
   227  	if x, ok := z.extractors[format]; ok {
   228  		return x.extract(carrier)
   229  	}
   230  	return nil, opentracing.ErrUnsupportedFormat
   231  }
   232  
   233  func (z *zipkinTracer) Inject(ctx opentracing.SpanContext, format interface{}, carrier interface{}) error {
   234  	c, ok := ctx.(spanContext)
   235  	if !ok {
   236  		return opentracing.ErrInvalidSpanContext
   237  	}
   238  	if x, ok := z.injectors[format]; ok {
   239  		return x.inject(c, carrier)
   240  	}
   241  	return opentracing.ErrUnsupportedFormat
   242  }
   243  
   244  type Tracer struct {
   245  	opentracing.Tracer
   246  	reporter.Reporter
   247  }
   248  
   249  func (Tracer) Name() string {
   250  	return Name
   251  }
   252  
   253  func Init(service string, opts map[string]interface{}) (*Tracer, error) {
   254  	c, err := Load(opts)
   255  	if err != nil {
   256  		return nil, err
   257  	}
   258  	if c.Reporter.URL == "" {
   259  		return nil, errors.New("zipkin: missing url")
   260  	}
   261  	r := http.NewReporter(c.Reporter.URL)
   262  	endpoint, err := zipkin.NewEndpoint(service, "")
   263  	if err != nil {
   264  		return nil, err
   265  	}
   266  	sampler, err := getSampler(c.Sampler)
   267  	if err != nil {
   268  		return nil, err
   269  	}
   270  	tr, err := zipkin.NewTracer(r,
   271  		zipkin.WithLocalEndpoint(endpoint),
   272  		zipkin.WithSampler(sampler),
   273  	)
   274  	if err != nil {
   275  		return nil, err
   276  	}
   277  	return &Tracer{Tracer: NewTracer(tr), Reporter: r}, nil
   278  }
   279  
   280  func getSampler(s Sampler) (zipkin.Sampler, error) {
   281  	if s.Name == "" {
   282  		return zipkin.AlwaysSample, nil
   283  	}
   284  	switch s.Name {
   285  	case "boundary":
   286  		return zipkin.NewBoundarySampler(s.Rate, s.Salt)
   287  	case "count":
   288  		return zipkin.NewCountingSampler(s.Rate)
   289  	case "mod":
   290  		return zipkin.NewModuloSampler(s.Mod), nil
   291  	}
   292  	return nil, fmt.Errorf("zipkin: unknown sampler %s", s.Name)
   293  }