@@ -18,10 +18,10 @@ package plugin
1818
1919import (
2020 "context"
21- "errors"
2221 "fmt"
2322 "io"
24- "net/url"
23+ "os"
24+ "strconv"
2525 "time"
2626
2727 "github.com/containerd/containerd/v2/pkg/deprecation"
@@ -37,13 +37,25 @@ import (
3737 "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
3838 "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"
3939 "go.opentelemetry.io/otel/propagation"
40- "go.opentelemetry.io/otel/sdk/resource"
4140 "go.opentelemetry.io/otel/sdk/trace"
42- semconv "go.opentelemetry.io/otel/semconv/v1.21.0"
4341)
4442
4543const exporterPlugin = "otlp"
4644
45+ // OTEL and OTLP standard env vars
46+ // See https://opentelemetry.io/docs/specs/otel/configuration/sdk-environment-variables/
47+ const (
48+ sdkDisabledEnv = "OTEL_SDK_DISABLED"
49+
50+ otlpEndpointEnv = "OTEL_EXPORTER_OTLP_ENDPOINT"
51+ otlpTracesEndpointEnv = "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT"
52+ otlpProtocolEnv = "OTEL_EXPORTER_OTLP_PROTOCOL"
53+ otlpTracesProtocolEnv = "OTEL_EXPORTER_OTLP_TRACES_PROTOCOL"
54+
55+ otelTracesExporterEnv = "OTEL_TRACES_EXPORTER"
56+ otelServiceNameEnv = "OTEL_SERVICE_NAME"
57+ )
58+
4759func init () {
4860 registry .Register (& plugin.Registration {
4961 ID : exporterPlugin ,
@@ -53,38 +65,49 @@ func init() {
5365 if err := warnOTLPConfig (ic ); err != nil {
5466 return nil , err
5567 }
56- cfg := ic .Config .(* OTLPConfig )
57- exp , err := newExporter (ic .Context , cfg )
68+ if err := checkDisabled (); err != nil {
69+ return nil , err
70+ }
71+
72+ // If OTEL_TRACES_EXPORTER is set, it must be "otlp"
73+ if v := os .Getenv (otelTracesExporterEnv ); v != "" && v != "otlp" {
74+ return nil , fmt .Errorf ("unsupported traces exporter %q: %w" , v , errdefs .ErrInvalidArgument )
75+ }
76+
77+ exp , err := newExporter (ic .Context )
5878 if err != nil {
5979 return nil , err
6080 }
6181 return trace .NewBatchSpanProcessor (exp ), nil
6282 },
6383 })
6484 registry .Register (& plugin.Registration {
65- ID : "tracing" ,
66- Type : plugins .InternalPlugin ,
85+ ID : "tracing" ,
86+ Type : plugins .InternalPlugin ,
87+ Config : & TraceConfig {},
6788 Requires : []plugin.Type {
6889 plugins .TracingProcessorPlugin ,
6990 },
70- Config : & TraceConfig {
71- ServiceName : "containerd" ,
72- TraceSamplingRatio : 1.0 ,
73- },
7491 InitFn : func (ic * plugin.InitContext ) (interface {}, error ) {
7592 if err := warnTraceConfig (ic ); err != nil {
7693 return nil , err
7794 }
78- // get TracingProcessorPlugin which is a dependency
95+ if err := checkDisabled (); err != nil {
96+ return nil , err
97+ }
98+
99+ //get TracingProcessorPlugin which is a dependency
79100 plugins , err := ic .GetByType (plugins .TracingProcessorPlugin )
80101 if err != nil {
81102 return nil , fmt .Errorf ("failed to get tracing processors: %w" , err )
82103 }
104+
83105 procs := make ([]trace.SpanProcessor , 0 , len (plugins ))
84106 for _ , p := range plugins {
85107 procs = append (procs , p .(trace.SpanProcessor ))
86108 }
87- return newTracer (ic .Context , ic .Config .(* TraceConfig ), procs )
109+
110+ return newTracer (ic .Context , procs )
88111 },
89112 })
90113
@@ -94,110 +117,89 @@ func init() {
94117
95118// OTLPConfig holds the configurations for the built-in otlp span processor
96119type OTLPConfig struct {
97- Endpoint string `toml:"endpoint"`
98- Protocol string `toml:"protocol"`
99- Insecure bool `toml:"insecure"`
120+ Endpoint string `toml:"endpoint,omitempty "`
121+ Protocol string `toml:"protocol,omitempty "`
122+ Insecure bool `toml:"insecure,omitempty "`
100123}
101124
102125// TraceConfig is the common configuration for open telemetry.
103126type TraceConfig struct {
104- ServiceName string `toml:"service_name"`
105- TraceSamplingRatio float64 `toml:"sampling_ratio"`
127+ ServiceName string `toml:"service_name,omitempty "`
128+ TraceSamplingRatio float64 `toml:"sampling_ratio,omitempty "`
106129}
107130
108- type closer struct {
109- close func () error
131+ func checkDisabled () error {
132+ v := os .Getenv (sdkDisabledEnv )
133+ if v != "" {
134+ disable , err := strconv .ParseBool (v )
135+ if err != nil {
136+ return fmt .Errorf ("invalid value for %s: %w: %w" , sdkDisabledEnv , err , errdefs .ErrInvalidArgument )
137+ }
138+ if disable {
139+ return fmt .Errorf ("%w: tracing disabled by env %s=%s" , plugin .ErrSkipPlugin , sdkDisabledEnv , v )
140+ }
141+ }
142+
143+ if os .Getenv (otlpEndpointEnv ) == "" && os .Getenv (otlpTracesEndpointEnv ) == "" {
144+ return fmt .Errorf ("%w: tracing endpoint not configured" , plugin .ErrSkipPlugin )
145+ }
146+ return nil
110147}
111148
112- func (c * closer ) Close () error {
113- return c .close ()
149+ type closerFunc func () error
150+
151+ func (f closerFunc ) Close () error {
152+ return f ()
114153}
115154
116155// newExporter creates an exporter based on the given configuration.
117156//
118157// The default protocol is http/protobuf since it is recommended by
119158// https://github.com/open-telemetry/opentelemetry-specification/blob/v1.8.0/specification/protocol/exporter.md#specify-protocol.
120- func newExporter (ctx context.Context , cfg * OTLPConfig ) (* otlptrace.Exporter , error ) {
159+ func newExporter (ctx context.Context ) (* otlptrace.Exporter , error ) {
121160 const timeout = 5 * time .Second
122161
162+ v := os .Getenv (otlpTracesProtocolEnv )
163+ if v == "" {
164+ v = os .Getenv (otlpProtocolEnv )
165+ }
166+
123167 ctx , cancel := context .WithTimeout (ctx , timeout )
124168 defer cancel ()
125-
126- switch cfg .Protocol {
169+ switch v {
127170 case "" , "http/protobuf" :
128- var opts []otlptracehttp.Option
129- if cfg .Endpoint != "" {
130- u , err := url .Parse (cfg .Endpoint )
131- if err != nil {
132- return nil , fmt .Errorf ("OpenTelemetry endpoint %q %w : %v" , cfg .Endpoint , errdefs .ErrInvalidArgument , err )
133- }
134- opts = append (opts , otlptracehttp .WithEndpoint (u .Host ))
135- if u .Scheme == "http" {
136- opts = append (opts , otlptracehttp .WithInsecure ())
137- }
138- }
139- return otlptracehttp .New (ctx , opts ... )
171+ return otlptracehttp .New (ctx )
140172 case "grpc" :
141- var opts []otlptracegrpc.Option
142- if cfg .Endpoint != "" {
143- opts = append (opts , otlptracegrpc .WithEndpoint (cfg .Endpoint ))
144- }
145- if cfg .Insecure {
146- opts = append (opts , otlptracegrpc .WithInsecure ())
147- }
148- return otlptracegrpc .New (ctx , opts ... )
173+ return otlptracegrpc .New (ctx )
149174 default :
150175 // Other protocols such as "http/json" are not supported.
151- return nil , fmt .Errorf ("OpenTelemetry protocol %q : %w" , cfg . Protocol , errdefs .ErrNotImplemented )
176+ return nil , fmt .Errorf ("OpenTelemetry protocol %q : %w" , v , errdefs .ErrNotImplemented )
152177 }
153178}
154179
155180// newTracer configures protocol-agonostic tracing settings such as
156181// its sampling ratio and returns io.Closer.
157182//
158183// Note that this function sets process-wide tracing configuration.
159- func newTracer (ctx context.Context , config * TraceConfig , procs []trace.SpanProcessor ) (io.Closer , error ) {
160- res , err := resource .New (ctx ,
161- resource .WithHost (),
162- resource .WithAttributes (
163- // Service name used to displace traces in backends
164- semconv .ServiceNameKey .String (config .ServiceName ),
165- ),
166- )
167- if err != nil {
168- return nil , fmt .Errorf ("failed to create resource: %w" , err )
184+ func newTracer (ctx context.Context , procs []trace.SpanProcessor ) (io.Closer , error ) {
185+ // Let otel configure the service name from env
186+ if os .Getenv (otelServiceNameEnv ) == "" {
187+ os .Setenv (otelServiceNameEnv , "containerd" )
169188 }
170189
171- sampler := trace .ParentBased (trace .TraceIDRatioBased (config .TraceSamplingRatio ))
172-
173- opts := []trace.TracerProviderOption {
174- trace .WithSampler (sampler ),
175- trace .WithResource (res ),
176- }
190+ otel .SetTextMapPropagator (propagation .NewCompositeTextMapPropagator (propagation.TraceContext {}, propagation.Baggage {}))
177191
192+ opts := make ([]trace.TracerProviderOption , 0 , len (procs ))
178193 for _ , proc := range procs {
179194 opts = append (opts , trace .WithSpanProcessor (proc ))
180195 }
181-
182196 provider := trace .NewTracerProvider (opts ... )
183-
184197 otel .SetTracerProvider (provider )
185198
186- otel .SetTextMapPropagator (propagators ())
187-
188- return & closer {close : func () error {
189- for _ , p := range procs {
190- if err := p .Shutdown (ctx ); err != nil && ! errors .Is (err , context .Canceled ) {
191- return err
192- }
193- }
194- return nil
195- }}, nil
196- }
199+ return closerFunc (func () error {
200+ return provider .Shutdown (ctx )
201+ }), nil
197202
198- // Returns a composite TestMap propagator
199- func propagators () propagation.TextMapPropagator {
200- return propagation .NewCompositeTextMapPropagator (propagation.TraceContext {}, propagation.Baggage {})
201203}
202204
203205func warnTraceConfig (ic * plugin.InitContext ) error {
0 commit comments