Skip to content

Commit 9360e37

Browse files
cpuguy83vvoland
authored andcommitted
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]> (cherry picked from commit 4fbc984) Signed-off-by: Paweł Gronowski <[email protected]>
1 parent f235489 commit 9360e37

2 files changed

Lines changed: 85 additions & 199 deletions

File tree

tracing/plugin/otlp.go

Lines changed: 85 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -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

4342
const 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+
4558
func 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
102126
type 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.
109133
type 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

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

tracing/plugin/otlp_test.go

Lines changed: 0 additions & 118 deletions
This file was deleted.

0 commit comments

Comments
 (0)