@@ -20,7 +20,8 @@ import (
2020 "context"
2121 "fmt"
2222 "io"
23- "net/url"
23+ "os"
24+ "strconv"
2425 "time"
2526
2627 "github.com/containerd/containerd/errdefs"
@@ -35,13 +36,25 @@ import (
3536 "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
3637 "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"
3738 "go.opentelemetry.io/otel/propagation"
38- "go.opentelemetry.io/otel/sdk/resource"
3939 "go.opentelemetry.io/otel/sdk/trace"
40- semconv "go.opentelemetry.io/otel/semconv/v1.21.0"
4140)
4241
4342const exporterPlugin = "otlp"
4443
44+ // OTEL and OTLP standard env vars
45+ // See https://opentelemetry.io/docs/specs/otel/configuration/sdk-environment-variables/
46+ const (
47+ sdkDisabledEnv = "OTEL_SDK_DISABLED"
48+
49+ otlpEndpointEnv = "OTEL_EXPORTER_OTLP_ENDPOINT"
50+ otlpTracesEndpointEnv = "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT"
51+ otlpProtocolEnv = "OTEL_EXPORTER_OTLP_PROTOCOL"
52+ otlpTracesProtocolEnv = "OTEL_EXPORTER_OTLP_TRACES_PROTOCOL"
53+
54+ otelTracesExporterEnv = "OTEL_TRACES_EXPORTER"
55+ otelServiceNameEnv = "OTEL_SERVICE_NAME"
56+ )
57+
4558func init () {
4659 plugin .Register (& plugin.Registration {
4760 ID : exporterPlugin ,
@@ -51,27 +64,38 @@ func init() {
5164 if err := warnOTLPConfig (ic ); err != nil {
5265 return nil , err
5366 }
54- cfg := ic .Config .(* OTLPConfig )
55- if cfg .Endpoint == "" {
56- return nil , fmt .Errorf ("no OpenTelemetry endpoint: %w" , plugin .ErrSkipPlugin )
67+ if err := checkDisabled (); err != nil {
68+ return nil , err
5769 }
58- exp , err := newExporter (ic .Context , cfg )
70+
71+ // If OTEL_TRACES_EXPORTER is set, it must be "otlp"
72+ if v := os .Getenv (otelTracesExporterEnv ); v != "" && v != "otlp" {
73+ return nil , fmt .Errorf ("unsupported traces exporter %q: %w" , v , errdefs .ErrInvalidArgument )
74+ }
75+
76+ exp , err := newExporter (ic .Context )
5977 if err != nil {
6078 return nil , err
6179 }
6280 return trace .NewBatchSpanProcessor (exp ), nil
6381 },
6482 })
6583 plugin .Register (& plugin.Registration {
66- ID : "tracing" ,
67- Type : plugin .InternalPlugin ,
68- Requires : []plugin.Type {plugin .TracingProcessorPlugin },
69- Config : & TraceConfig {ServiceName : "containerd" , TraceSamplingRatio : 1.0 },
84+ ID : "tracing" ,
85+ Type : plugin .InternalPlugin ,
86+ Config : & TraceConfig {},
87+ Requires : []plugin.Type {
88+ plugin .TracingProcessorPlugin ,
89+ },
7090 InitFn : func (ic * plugin.InitContext ) (interface {}, error ) {
71- //get TracingProcessorPlugin which is a dependency
7291 if err := warnTraceConfig (ic ); err != nil {
7392 return nil , err
7493 }
94+ if err := checkDisabled (); err != nil {
95+ return nil , err
96+ }
97+
98+ //get TracingProcessorPlugin which is a dependency
7599 plugins , err := ic .GetByType (plugin .TracingProcessorPlugin )
76100 if err != nil {
77101 return nil , fmt .Errorf ("failed to get tracing processors: %w" , err )
@@ -90,7 +114,7 @@ func init() {
90114 proc := p .(trace.SpanProcessor )
91115 procs = append (procs , proc )
92116 }
93- return newTracer (ic .Context , ic . Config .( * TraceConfig ), procs )
117+ return newTracer (ic .Context , procs )
94118 },
95119 })
96120
@@ -100,108 +124,88 @@ func init() {
100124
101125// OTLPConfig holds the configurations for the built-in otlp span processor
102126type OTLPConfig struct {
103- Endpoint string `toml:"endpoint"`
104- Protocol string `toml:"protocol"`
105- Insecure bool `toml:"insecure"`
127+ Endpoint string `toml:"endpoint,omitempty "`
128+ Protocol string `toml:"protocol,omitempty "`
129+ Insecure bool `toml:"insecure,omitempty "`
106130}
107131
108132// TraceConfig is the common configuration for open telemetry.
109133type TraceConfig struct {
110- ServiceName string `toml:"service_name"`
111- TraceSamplingRatio float64 `toml:"sampling_ratio"`
134+ ServiceName string `toml:"service_name,omitempty "`
135+ TraceSamplingRatio float64 `toml:"sampling_ratio,omitempty "`
112136}
113137
114- type closer struct {
115- close func () error
138+ func checkDisabled () error {
139+ v := os .Getenv (sdkDisabledEnv )
140+ if v != "" {
141+ disable , err := strconv .ParseBool (v )
142+ if err != nil {
143+ return fmt .Errorf ("invalid value for %s: %w: %w" , sdkDisabledEnv , err , errdefs .ErrInvalidArgument )
144+ }
145+ if disable {
146+ return fmt .Errorf ("%w: tracing disabled by env %s=%s" , plugin .ErrSkipPlugin , sdkDisabledEnv , v )
147+ }
148+ }
149+
150+ if os .Getenv (otlpEndpointEnv ) == "" && os .Getenv (otlpTracesEndpointEnv ) == "" {
151+ return fmt .Errorf ("%w: tracing endpoint not configured" , plugin .ErrSkipPlugin )
152+ }
153+ return nil
116154}
117155
118- func (c * closer ) Close () error {
119- return c .close ()
156+ type closerFunc func () error
157+
158+ func (f closerFunc ) Close () error {
159+ return f ()
120160}
121161
122162// newExporter creates an exporter based on the given configuration.
123163//
124164// The default protocol is http/protobuf since it is recommended by
125165// https://github.com/open-telemetry/opentelemetry-specification/blob/v1.8.0/specification/protocol/exporter.md#specify-protocol.
126- func newExporter (ctx context.Context , cfg * OTLPConfig ) (* otlptrace.Exporter , error ) {
166+ func newExporter (ctx context.Context ) (* otlptrace.Exporter , error ) {
127167 const timeout = 5 * time .Second
128168
169+ v := os .Getenv (otlpTracesProtocolEnv )
170+ if v == "" {
171+ v = os .Getenv (otlpProtocolEnv )
172+ }
173+
129174 ctx , cancel := context .WithTimeout (ctx , timeout )
130175 defer cancel ()
131-
132- if cfg .Protocol == "http/protobuf" || cfg .Protocol == "" {
133- u , err := url .Parse (cfg .Endpoint )
134- if err != nil {
135- return nil , fmt .Errorf ("OpenTelemetry endpoint %q %w : %v" , cfg .Endpoint , errdefs .ErrInvalidArgument , err )
136- }
137- opts := []otlptracehttp.Option {
138- otlptracehttp .WithEndpoint (u .Host ),
139- }
140- if u .Scheme == "http" {
141- opts = append (opts , otlptracehttp .WithInsecure ())
142- }
143- return otlptracehttp .New (ctx , opts ... )
144- } else if cfg .Protocol == "grpc" {
145- opts := []otlptracegrpc.Option {
146- otlptracegrpc .WithEndpoint (cfg .Endpoint ),
147- }
148- if cfg .Insecure {
149- opts = append (opts , otlptracegrpc .WithInsecure ())
150- }
151- return otlptracegrpc .New (ctx , opts ... )
176+ switch v {
177+ case "" , "http/protobuf" :
178+ return otlptracehttp .New (ctx )
179+ case "grpc" :
180+ return otlptracegrpc .New (ctx )
181+ default :
182+ // Other protocols such as "http/json" are not supported.
183+ return nil , fmt .Errorf ("OpenTelemetry protocol %q : %w" , v , errdefs .ErrNotImplemented )
152184 }
153- // Other protocols such as "http/json" are not supported.
154- return nil , fmt .Errorf ("OpenTelemetry protocol %q : %w" , cfg .Protocol , errdefs .ErrNotImplemented )
155185}
156186
157187// newTracer configures protocol-agonostic tracing settings such as
158188// its sampling ratio and returns io.Closer.
159189//
160190// Note that this function sets process-wide tracing configuration.
161- func newTracer (ctx context.Context , config * TraceConfig , procs []trace.SpanProcessor ) (io.Closer , error ) {
162-
163- res , err := resource .New (ctx ,
164- resource .WithHost (),
165- resource .WithAttributes (
166- // Service name used to displace traces in backends
167- semconv .ServiceNameKey .String (config .ServiceName ),
168- ),
169- )
170- if err != nil {
171- return nil , fmt .Errorf ("failed to create resource: %w" , err )
191+ func newTracer (ctx context.Context , procs []trace.SpanProcessor ) (io.Closer , error ) {
192+ // Let otel configure the service name from env
193+ if os .Getenv (otelServiceNameEnv ) == "" {
194+ os .Setenv (otelServiceNameEnv , "containerd" )
172195 }
173196
174- sampler := trace .ParentBased (trace .TraceIDRatioBased (config .TraceSamplingRatio ))
175-
176- opts := []trace.TracerProviderOption {
177- trace .WithSampler (sampler ),
178- trace .WithResource (res ),
179- }
197+ otel .SetTextMapPropagator (propagation .NewCompositeTextMapPropagator (propagation.TraceContext {}, propagation.Baggage {}))
180198
199+ opts := make ([]trace.TracerProviderOption , 0 , len (procs ))
181200 for _ , proc := range procs {
182201 opts = append (opts , trace .WithSpanProcessor (proc ))
183202 }
184-
185203 provider := trace .NewTracerProvider (opts ... )
186-
187204 otel .SetTracerProvider (provider )
188205
189- otel .SetTextMapPropagator (propagators ())
190-
191- return & closer {close : func () error {
192- for _ , p := range procs {
193- if err := p .Shutdown (ctx ); err != nil {
194- return err
195- }
196- }
197- return nil
198- }}, nil
199-
200- }
201-
202- // Returns a composite TestMap propagator
203- func propagators () propagation.TextMapPropagator {
204- return propagation .NewCompositeTextMapPropagator (propagation.TraceContext {}, propagation.Baggage {})
206+ return closerFunc (func () error {
207+ return provider .Shutdown (ctx )
208+ }), nil
205209}
206210
207211func warnTraceConfig (ic * plugin.InitContext ) error {
0 commit comments