github.com/pf-qiu/concourse/v6@v6.7.3-0.20201207032516-1f455d73275f/tracing/tracer.go (about)

     1  package tracing
     2  
     3  import (
     4  	"context"
     5  
     6  	"go.opentelemetry.io/collector/translator/conventions"
     7  	"go.opentelemetry.io/otel/api/global"
     8  	"go.opentelemetry.io/otel/api/propagation"
     9  	"go.opentelemetry.io/otel/api/trace"
    10  	"go.opentelemetry.io/otel/codes"
    11  	"go.opentelemetry.io/otel/label"
    12  	export "go.opentelemetry.io/otel/sdk/export/trace"
    13  	"go.opentelemetry.io/otel/sdk/resource"
    14  	sdktrace "go.opentelemetry.io/otel/sdk/trace"
    15  )
    16  
    17  //go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 go.opentelemetry.io/otel/api/trace.Tracer
    18  //go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 go.opentelemetry.io/otel/api/trace.Provider
    19  //go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 go.opentelemetry.io/otel/api/trace.Span
    20  
    21  // Configured indicates whether tracing has been configured or not.
    22  //
    23  // This variable is needed in order to shortcircuit span generation when
    24  // tracing hasn't been configured.
    25  //
    26  //
    27  var Configured bool
    28  
    29  type Config struct {
    30  	ServiceName string            `long:"service-name"  description:"service name to attach to traces as metadata" default:"concourse-web"`
    31  	Attributes  map[string]string `long:"attribute"  description:"attributes to attach to traces as metadata"`
    32  	Honeycomb   Honeycomb
    33  	Jaeger      Jaeger
    34  	Stackdriver Stackdriver
    35  	OTLP        OTLP
    36  }
    37  
    38  func (c Config) resource() *resource.Resource {
    39  	attributes := []label.KeyValue{
    40  		label.String(conventions.AttributeTelemetrySDKName, "opentelemetry"),
    41  		label.String(conventions.AttributeTelemetrySDKLanguage, "go"),
    42  		label.String(conventions.AttributeServiceName, c.ServiceName),
    43  	}
    44  
    45  	for key, value := range c.Attributes {
    46  		attributes = append(attributes, label.String(key, value))
    47  	}
    48  
    49  	return resource.New(attributes...)
    50  }
    51  
    52  func (c Config) TraceProvider(exporter func() (export.SpanSyncer, error)) (trace.Provider, error) {
    53  	exp, err := exporter()
    54  	if err != nil {
    55  		return nil, err
    56  	}
    57  
    58  	provider, err := sdktrace.NewProvider(sdktrace.WithConfig(
    59  		sdktrace.Config{
    60  			DefaultSampler: sdktrace.AlwaysSample(),
    61  		}),
    62  		sdktrace.WithSyncer(exp),
    63  		sdktrace.WithResource(c.resource()),
    64  	)
    65  	if err != nil {
    66  		return nil, err
    67  	}
    68  
    69  	return provider, nil
    70  }
    71  
    72  func (c Config) Prepare() error {
    73  	var provider trace.Provider
    74  	var err error
    75  
    76  	switch {
    77  	case c.Honeycomb.IsConfigured():
    78  		provider, err = c.TraceProvider(c.Honeycomb.Exporter)
    79  	case c.Jaeger.IsConfigured():
    80  		provider, err = c.TraceProvider(c.Jaeger.Exporter)
    81  	case c.OTLP.IsConfigured():
    82  		provider, err = c.TraceProvider(c.OTLP.Exporter)
    83  	case c.Stackdriver.IsConfigured():
    84  		provider, err = c.TraceProvider(c.Stackdriver.Exporter)
    85  	}
    86  	if err != nil {
    87  		return err
    88  	}
    89  
    90  	if provider != nil {
    91  		ConfigureTraceProvider(provider)
    92  	}
    93  
    94  	return nil
    95  }
    96  
    97  // StartSpan creates a span, giving back a context that has itself added as the
    98  // parent span.
    99  //
   100  // Calls to this function with a context that has been generated from a previous
   101  // call to this method will make the resulting span a child of the span that
   102  // preceded it.
   103  //
   104  // For instance:
   105  //
   106  // ```
   107  // func fn () {
   108  //
   109  //     rootCtx, rootSpan := StartSpan(context.Background(), "foo", nil)
   110  //     defer rootSpan.End()
   111  //
   112  //     _, childSpan := StartSpan(rootCtx, "bar", nil)
   113  //     defer childSpan.End()
   114  //
   115  // }
   116  // ```
   117  //
   118  // calling `fn()` will lead to the following trace:
   119  //
   120  // ```
   121  // foo   0--------3
   122  //   bar    1----2
   123  // ```
   124  //
   125  // where (0) is the start of the root span, which then gets a child `bar`
   126  // initializing at (1), having its end called (2), and then the last span
   127  // finalization happening for the root span (3) given how `defer` statements
   128  // stack.
   129  //
   130  func StartSpan(
   131  	ctx context.Context,
   132  	component string,
   133  	attrs Attrs,
   134  ) (context.Context, trace.Span) {
   135  	return startSpan(ctx, component, attrs)
   136  }
   137  
   138  func FromContext(ctx context.Context) trace.Span {
   139  	return trace.SpanFromContext(ctx)
   140  }
   141  
   142  func Inject(ctx context.Context, supplier propagation.HTTPSupplier) {
   143  	trace.TraceContext{}.Inject(ctx, supplier)
   144  }
   145  
   146  type WithSpanContext interface {
   147  	SpanContext() propagation.HTTPSupplier
   148  }
   149  
   150  func StartSpanFollowing(
   151  	ctx context.Context,
   152  	following WithSpanContext,
   153  	component string,
   154  	attrs Attrs,
   155  ) (context.Context, trace.Span) {
   156  	if supplier := following.SpanContext(); supplier != nil {
   157  		ctx = trace.TraceContext{}.Extract(ctx, supplier)
   158  	}
   159  
   160  	return startSpan(ctx, component, attrs)
   161  }
   162  
   163  func StartSpanLinkedToFollowing(
   164  	linked context.Context,
   165  	following WithSpanContext,
   166  	component string,
   167  	attrs Attrs,
   168  ) (context.Context, trace.Span) {
   169  	ctx := context.Background()
   170  	if supplier := following.SpanContext(); supplier != nil {
   171  		ctx = trace.TraceContext{}.Extract(ctx, supplier)
   172  	}
   173  	linkedSpanContext := trace.SpanFromContext(linked).SpanContext()
   174  
   175  	return startSpan(
   176  		ctx,
   177  		component,
   178  		attrs,
   179  		trace.LinkedTo(linkedSpanContext),
   180  	)
   181  }
   182  
   183  func startSpan(
   184  	ctx context.Context,
   185  	component string,
   186  	attrs Attrs,
   187  	opts ...trace.StartOption,
   188  ) (context.Context, trace.Span) {
   189  	if !Configured {
   190  		return ctx, trace.NoopSpan{}
   191  	}
   192  
   193  	ctx, span := global.TraceProvider().Tracer("concourse").Start(
   194  		ctx,
   195  		component,
   196  		opts...,
   197  	)
   198  
   199  	if len(attrs) != 0 {
   200  		span.SetAttributes(keyValueSlice(attrs)...)
   201  	}
   202  
   203  	return ctx, span
   204  }
   205  
   206  func End(span trace.Span, err error) {
   207  	if !Configured {
   208  		return
   209  	}
   210  
   211  	if err != nil {
   212  		span.SetStatus(codes.Internal, "")
   213  		span.SetAttributes(
   214  			label.String("error-message", err.Error()),
   215  		)
   216  	}
   217  
   218  	span.End()
   219  }
   220  
   221  // ConfigureTraceProvider configures the sdk to use a given trace provider.
   222  //
   223  // By default, a noop tracer is registered, thus, it's safe to call StartSpan
   224  // and other related methods even before `ConfigureTracer` it called.
   225  //
   226  func ConfigureTraceProvider(tp trace.Provider) {
   227  	global.SetTraceProvider(tp)
   228  	Configured = true
   229  }