/
config.go
133 lines (126 loc) 路 4.01 KB
/
config.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
package clue
import (
"context"
"github.com/go-logr/logr"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/metric"
metricnoop "go.opentelemetry.io/otel/metric/noop"
"go.opentelemetry.io/otel/propagation"
sdkmetric "go.opentelemetry.io/otel/sdk/metric"
"go.opentelemetry.io/otel/sdk/resource"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
semconv "go.opentelemetry.io/otel/semconv/v1.24.0"
"go.opentelemetry.io/otel/trace"
tracenoop "go.opentelemetry.io/otel/trace/noop"
"goa.design/clue/log"
)
type (
// Config is used to configure OpenTelemetry.
Config struct {
// MeterProvider is the OpenTelemetry meter provider used by clue
MeterProvider metric.MeterProvider
// TracerProvider is the OpenTelemetry tracer provider used clue
TracerProvider trace.TracerProvider
// Propagators is the OpenTelemetry propagator used by clue
Propagators propagation.TextMapPropagator
// ErrorHandler is the error handler used by OpenTelemetry
ErrorHandler otel.ErrorHandler
}
)
// ConfigureOpenTelemetry sets up code instrumentation using the OpenTelemetry
// API. It leverages the clue logger configured in ctx to log errors.
func ConfigureOpenTelemetry(ctx context.Context, cfg *Config) {
otel.SetMeterProvider(cfg.MeterProvider)
otel.SetTracerProvider(cfg.TracerProvider)
otel.SetTextMapPropagator(cfg.Propagators)
otel.SetLogger(logr.New(log.ToLogrSink(ctx)))
otel.SetErrorHandler(cfg.ErrorHandler)
}
// NewConfig creates a new Config object adequate for use by
// ConfigureOpenTelemetry. The metricExporter and spanExporter are used to
// record telemetry. If either is nil then the corresponding package will not
// record any telemetry. The OpenTelemetry metric provider is configured with a
// periodic reader. The OpenTelemetry tracer provider is configured to use a
// batch span processor and an adaptive sampler that aims at a maximum sampling
// rate of requests per second. The resulting configuration can be modified
// (and providers replaced) by the caller prior to calling
// ConfigureOpenTelemetry.
//
// Example:
//
// metricExporter, err := stdoutmetric.New()
// if err != nil {
// return err
// }
// spanExporter, err := stdouttrace.New()
// if err != nil {
// return err
// }
// cfg := clue.NewConfig("mysvc", "1.0.0", metricExporter, spanExporter)
func NewConfig(
ctx context.Context,
svcName string,
svcVersion string,
metricExporter sdkmetric.Exporter,
spanExporter sdktrace.SpanExporter,
opts ...Option,
) (*Config, error) {
options := defaultOptions(ctx)
for _, o := range opts {
o(options)
}
res, err := resource.Merge(
resource.Default(),
resource.NewWithAttributes(
semconv.SchemaURL,
semconv.ServiceNameKey.String(svcName),
semconv.ServiceVersionKey.String(svcVersion),
))
if err != nil {
return nil, err
}
var meterProvider metric.MeterProvider
if metricExporter == nil {
meterProvider = metricnoop.NewMeterProvider()
} else {
var reader sdkmetric.Reader
if options.readerInterval == 0 {
reader = sdkmetric.NewPeriodicReader(metricExporter)
} else {
reader = sdkmetric.NewPeriodicReader(
metricExporter,
sdkmetric.WithInterval(options.readerInterval),
)
}
meterProvider = sdkmetric.NewMeterProvider(
sdkmetric.WithResource(res),
sdkmetric.WithReader(reader),
)
}
var tracerProvider trace.TracerProvider
if spanExporter == nil {
tracerProvider = tracenoop.NewTracerProvider()
} else {
sampler := sdktrace.ParentBased(
AdaptiveSampler(options.maxSamplingRate, options.sampleSize),
)
tracerProvider = sdktrace.NewTracerProvider(
sdktrace.WithResource(res),
sdktrace.WithSampler(sampler),
sdktrace.WithBatcher(spanExporter),
)
}
return &Config{
MeterProvider: meterProvider,
TracerProvider: tracerProvider,
Propagators: options.propagators,
ErrorHandler: options.errorHandler,
}, nil
}
// NewErrorHandler returns an error handler that logs errors using the clue
// logger configured in ctx.
func NewErrorHandler(ctx context.Context) otel.ErrorHandler {
return otel.ErrorHandlerFunc(func(err error) {
log.Error(ctx, err)
})
}