github.com/facebookincubator/go-belt@v0.0.0-20230703220935-39cd348f1a38/tool/experimental/tracer/implementation/zipkin/tracer.go (about)

     1  // Copyright 2022 Meta Platforms, Inc. and affiliates.
     2  //
     3  // Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
     4  //
     5  // 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
     6  //
     7  // 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
     8  //
     9  // 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
    10  //
    11  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    12  
    13  package zipkin
    14  
    15  import (
    16  	"context"
    17  	"fmt"
    18  	"log"
    19  	"strings"
    20  	"sync"
    21  
    22  	"github.com/facebookincubator/go-belt"
    23  	"github.com/facebookincubator/go-belt/pkg/field"
    24  	"github.com/facebookincubator/go-belt/tool/experimental/tracer"
    25  	"github.com/openzipkin/zipkin-go"
    26  	logreporter "github.com/openzipkin/zipkin-go/reporter/log"
    27  )
    28  
    29  // TracerImpl is the implementation of tracer.Tracer on top of zipkin.Tracer.
    30  type TracerImpl struct {
    31  	ZipkinTracer      *zipkin.Tracer
    32  	ContextFields     *field.FieldsChain
    33  	compileFieldsOnce sync.Once
    34  	compiledFields    map[string]string
    35  	TraceIDs          belt.TraceIDs
    36  	TagTraceIDs       string
    37  	Hooks             tracer.Hooks
    38  	PreHooks          tracer.Hooks
    39  }
    40  
    41  var _ tracer.Tracer = (*TracerImpl)(nil)
    42  
    43  func (t TracerImpl) clone() *TracerImpl { //nolint:govet
    44  	t.compileFieldsOnce = sync.Once{}
    45  	return &t
    46  }
    47  
    48  // WithContextFields implements tracer.Tracer.
    49  func (t *TracerImpl) WithContextFields(allFields *field.FieldsChain, newFieldsCount int) belt.Tool {
    50  	c := t.clone()
    51  	c.ContextFields = allFields
    52  	return c
    53  }
    54  
    55  // WithTraceIDs implements tracer.Tracer.
    56  func (t *TracerImpl) WithTraceIDs(traceIDs belt.TraceIDs, newTraceIDsCount int) belt.Tool {
    57  	c := t.clone()
    58  	c.TraceIDs = traceIDs
    59  	return c
    60  }
    61  
    62  // Start implements tracer.Tracer.
    63  func (t *TracerImpl) Start(name string, parent tracer.Span, options ...tracer.SpanOption) tracer.Span {
    64  	span, _ := t.newSpanBelt(nil, name, parent, options...)
    65  	return span
    66  }
    67  
    68  // StartWithCtx implements tracer.Tracer.
    69  func (t *TracerImpl) StartWithCtx(ctx context.Context, name string, options ...tracer.SpanOption) (tracer.Span, context.Context) {
    70  	return t.newSpanCtx(ctx, name, nil, options...)
    71  
    72  }
    73  
    74  // StartChildWithCtx implements tracer.Tracer.
    75  func (t *TracerImpl) StartChildWithCtx(ctx context.Context, name string, options ...tracer.SpanOption) (tracer.Span, context.Context) {
    76  	return t.newSpanCtx(ctx, name, tracer.SpanFromCtx(ctx), options...)
    77  }
    78  
    79  // StartWithBelt implements tracer.Tracer.
    80  func (t *TracerImpl) StartWithBelt(belt *belt.Belt, name string, options ...tracer.SpanOption) (tracer.Span, *belt.Belt) {
    81  	return t.newSpanBelt(belt, name, nil, options...)
    82  
    83  }
    84  
    85  // StartChildWithBelt implements tracer.Tracer.
    86  func (t *TracerImpl) StartChildWithBelt(belt *belt.Belt, name string, options ...tracer.SpanOption) (tracer.Span, *belt.Belt) {
    87  	return t.newSpanBelt(belt, name, tracer.SpanFromBelt(belt), options...)
    88  }
    89  
    90  // DefaultTagTraceIDs is the tag name used to store belt.TraceIDs value.
    91  var DefaultTagTraceIDs = `trace_ids`
    92  
    93  func (t *TracerImpl) compileFields() {
    94  	t.compileFieldsOnce.Do(func() {
    95  		t.compiledFields = make(map[string]string, t.ContextFields.Len()+1)
    96  		t.ContextFields.ForEachField(func(f *field.Field) bool {
    97  			t.compiledFields[f.Key] = fmt.Sprint(f.Value)
    98  			return true
    99  		})
   100  		if t.TraceIDs == nil {
   101  			return
   102  		}
   103  		strs := make([]string, 0, len(t.TraceIDs))
   104  		for _, traceID := range t.TraceIDs {
   105  			strs = append(strs, string(traceID))
   106  		}
   107  		t.compiledFields[t.TagTraceIDs] = strings.Join(strs, ",")
   108  	})
   109  }
   110  
   111  // WithPreHooks implements tracer.Tracer.
   112  func (t *TracerImpl) WithPreHooks(hooks ...tracer.Hook) tracer.Tracer {
   113  	c := t.clone()
   114  	if hooks == nil {
   115  		c.PreHooks = nil
   116  	} else {
   117  		c.PreHooks = tracer.Hooks{c.PreHooks, tracer.Hooks(hooks)}
   118  	}
   119  	return c
   120  }
   121  
   122  // WithHooks implements tracer.Tracer.
   123  func (t *TracerImpl) WithHooks(hooks ...tracer.Hook) tracer.Tracer {
   124  	c := t.clone()
   125  	if hooks == nil {
   126  		c.Hooks = nil
   127  	} else {
   128  		c.Hooks = tracer.Hooks{c.Hooks, tracer.Hooks(hooks)}
   129  	}
   130  	return c
   131  }
   132  
   133  // Flush implements tracer.Tracer.
   134  func (t *TracerImpl) Flush() {
   135  	panic("not supported")
   136  }
   137  
   138  // Default returns the default tracer.Tracer on top of zipkin.
   139  var Default = func() tracer.Tracer {
   140  	reporter := logreporter.NewReporter(log.Default())
   141  	defer reporter.Close()
   142  
   143  	tracer, err := zipkin.NewTracer(reporter)
   144  	if err != nil {
   145  		log.Fatalf("unable to create a zipkin tracer: %v", err)
   146  	}
   147  
   148  	return New(tracer)
   149  }
   150  
   151  // New returns a new instance of TracerImpl.
   152  func New(zipkinTracer *zipkin.Tracer, options ...Option) *TracerImpl {
   153  	tracer := &TracerImpl{
   154  		ZipkinTracer: zipkinTracer,
   155  		TagTraceIDs:  DefaultTagTraceIDs,
   156  	}
   157  	for _, opt := range options {
   158  		opt.apply(tracer)
   159  	}
   160  	return tracer
   161  }