github.com/m3db/m3@v1.5.0/src/x/opentelemetry/config.go (about) 1 // Copyright (c) 2021 Uber Technologies, Inc. 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a copy 4 // of this software and associated documentation files (the "Software"), to deal 5 // in the Software without restriction, including without limitation the rights 6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 // copies of the Software, and to permit persons to whom the Software is 8 // furnished to do so, subject to the following conditions: 9 // 10 // The above copyright notice and this permission notice shall be included in 11 // all copies or substantial portions of the Software. 12 // 13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 // THE SOFTWARE. 20 21 // Package opentelemetry provides Open Telemetry configuration. 22 package opentelemetry 23 24 import ( 25 "context" 26 "fmt" 27 28 "github.com/uber-go/tally" 29 "go.opentelemetry.io/otel" 30 "go.opentelemetry.io/otel/attribute" 31 "go.opentelemetry.io/otel/exporters/otlp/otlptrace" 32 "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc" 33 "go.opentelemetry.io/otel/propagation" 34 "go.opentelemetry.io/otel/sdk/resource" 35 sdktrace "go.opentelemetry.io/otel/sdk/trace" 36 semconv "go.opentelemetry.io/otel/semconv/v1.4.0" 37 "google.golang.org/grpc" 38 ) 39 40 // Configuration configures an OpenTelemetry trace provider. 41 type Configuration struct { 42 ServiceName string `yaml:"serviceName"` 43 Endpoint string `yaml:"endpoint"` 44 Insecure bool `yaml:"insecure"` 45 Attributes map[string]string `yaml:"attributes"` 46 } 47 48 // TracerProviderOptions is a set of options to use when creating the 49 // trace provider. 50 type TracerProviderOptions struct { 51 // Attributes is a set of programmatic attributes to add at construction. 52 Attributes []attribute.KeyValue 53 } 54 55 // NewTracerProvider returns a new tracer provider. 56 func (c Configuration) NewTracerProvider( 57 ctx context.Context, 58 scope tally.Scope, 59 opts TracerProviderOptions, 60 ) (*sdktrace.TracerProvider, error) { 61 attributes := make([]attribute.KeyValue, 0, 1+len(c.Attributes)+len(opts.Attributes)) 62 attributes = append(attributes, semconv.ServiceNameKey.String(c.ServiceName)) 63 for k, v := range c.Attributes { 64 attributes = append(attributes, attribute.String(k, v)) 65 } 66 attributes = append(attributes, opts.Attributes...) 67 68 res, err := resource.New(ctx, resource.WithAttributes(attributes...)) 69 if err != nil { 70 return nil, fmt.Errorf("failed to create resource: %w", err) 71 } 72 73 driverOpts := []otlptracegrpc.Option{ 74 otlptracegrpc.WithEndpoint(c.Endpoint), 75 otlptracegrpc.WithDialOption(grpc.WithBlock()), 76 } 77 if c.Insecure { 78 driverOpts = append(driverOpts, otlptracegrpc.WithInsecure()) 79 } 80 driver := otlptracegrpc.NewClient(driverOpts...) 81 traceExporter, err := otlptrace.New(ctx, driver) 82 if err != nil { 83 return nil, fmt.Errorf("failed to trace exporter: %w", err) 84 } 85 86 // Register the trace exporter with a TracerProvider, using a batch 87 // span processor to aggregate spans before export. 88 batchSpanProcessor := sdktrace.NewBatchSpanProcessor(traceExporter) 89 tracerMetricsProcessor := newTraceSpanProcessor(scope) 90 tracerProvider := sdktrace.NewTracerProvider( 91 sdktrace.WithSampler(sdktrace.AlwaysSample()), 92 sdktrace.WithResource(res), 93 sdktrace.WithSpanProcessor(batchSpanProcessor), 94 sdktrace.WithSpanProcessor(tracerMetricsProcessor), 95 ) 96 otel.SetTracerProvider(tracerProvider) 97 otel.SetTextMapPropagator(propagation.TraceContext{}) 98 99 return tracerProvider, nil 100 } 101 102 type traceSpanProcessor struct { 103 traceStart tally.Counter 104 traceEnd tally.Counter 105 tracerShutdown tally.Counter 106 tracerForceFlush tally.Counter 107 } 108 109 func newTraceSpanProcessor(scope tally.Scope) sdktrace.SpanProcessor { 110 traceScope := scope.SubScope("trace") 111 tracerScope := scope.SubScope("tracer") 112 return &traceSpanProcessor{ 113 traceStart: traceScope.Counter("start"), 114 traceEnd: traceScope.Counter("end"), 115 tracerShutdown: tracerScope.Counter("shutdown"), 116 tracerForceFlush: tracerScope.Counter("force-flush"), 117 } 118 } 119 120 func (p *traceSpanProcessor) OnStart(parent context.Context, s sdktrace.ReadWriteSpan) { 121 p.traceStart.Inc(1) 122 } 123 124 func (p *traceSpanProcessor) OnEnd(s sdktrace.ReadOnlySpan) { 125 p.traceEnd.Inc(1) 126 } 127 128 func (p *traceSpanProcessor) Shutdown(ctx context.Context) error { 129 p.tracerShutdown.Inc(1) 130 return nil 131 } 132 133 func (p *traceSpanProcessor) ForceFlush(ctx context.Context) error { 134 p.tracerForceFlush.Inc(1) 135 return nil 136 }