Skip to content

Commit 4fbc984

Browse files
committed
Changes to configuring otel from env only
These are standard environment variables described by the otel spec in https://opentelemetry.io/docs/specs/otel/configuration/sdk-environment-variables/. The old config options are removed Also since otel will by default try to connect to https://localhost:4318 if no endpoint is set, this will also just disable the otlp plugin when there is no endpoint so we don't have otel continuously trying to connect to the default endpoint, littering the logs with connection failure messages and collecting traces that won't go anywhere. Signed-off-by: Brian Goff <[email protected]>
1 parent 753a525 commit 4fbc984

File tree

4 files changed

+99
-211
lines changed

4 files changed

+99
-211
lines changed

integration/client/testdata/default-1.6.toml

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -168,9 +168,10 @@ version = 2
168168
[plugins."io.containerd.internal.v1.restart"]
169169
interval = "10s"
170170

171-
[plugins."io.containerd.internal.v1.tracing"]
172-
sampling_ratio = 1.0
173-
service_name = "containerd"
171+
# Removed in latest
172+
#[plugins."io.containerd.internal.v1.tracing"]
173+
# sampling_ratio = 1.0
174+
# service_name = "containerd"
174175

175176
[plugins."io.containerd.metadata.v1.bolt"]
176177
content_sharing_policy = "shared"
@@ -225,10 +226,11 @@ version = 2
225226
#[plugins."io.containerd.snapshotter.v1.zfs"]
226227
# root_path = ""
227228

228-
[plugins."io.containerd.tracing.processor.v1.otlp"]
229-
endpoint = ""
230-
insecure = false
231-
protocol = ""
229+
# Removed in latest
230+
#[plugins."io.containerd.tracing.processor.v1.otlp"]
231+
# endpoint = ""
232+
# insecure = false
233+
# protocol = ""
232234

233235
[proxy_plugins]
234236

integration/client/testdata/default-1.7.toml

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -185,9 +185,10 @@ version = 2
185185
[plugins."io.containerd.internal.v1.restart"]
186186
interval = "10s"
187187

188-
[plugins."io.containerd.internal.v1.tracing"]
189-
sampling_ratio = 1.0
190-
service_name = "containerd"
188+
# Removed in latest
189+
#[plugins."io.containerd.internal.v1.tracing"]
190+
# sampling_ratio = 1.0
191+
# service_name = "containerd"
191192

192193
[plugins."io.containerd.metadata.v1.bolt"]
193194
content_sharing_policy = "shared"
@@ -258,10 +259,11 @@ version = 2
258259
#[plugins."io.containerd.snapshotter.v1.zfs"]
259260
# root_path = ""
260261

261-
[plugins."io.containerd.tracing.processor.v1.otlp"]
262-
endpoint = ""
263-
insecure = false
264-
protocol = ""
262+
# Removed in latest
263+
#[plugins."io.containerd.tracing.processor.v1.otlp"]
264+
# endpoint = ""
265+
# insecure = false
266+
# protocol = ""
265267

266268
[plugins."io.containerd.transfer.v1.local"]
267269
config_path = ""

pkg/tracing/plugin/otlp.go

Lines changed: 81 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,10 @@ package plugin
1818

1919
import (
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

4543
const 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+
4759
func 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
96119
type 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.
103126
type 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

203205
func warnTraceConfig(ic *plugin.InitContext) error {

0 commit comments

Comments
 (0)