-
Notifications
You must be signed in to change notification settings - Fork 113
/
observability.go
143 lines (129 loc) · 3.91 KB
/
observability.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
134
135
136
137
138
139
140
141
142
143
package observability
import (
"context"
"fmt"
"time"
"github.com/go-logr/zapr"
"go.opentelemetry.io/contrib/instrumentation/runtime"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
"go.opentelemetry.io/otel/exporters/prometheus"
"go.opentelemetry.io/otel/sdk/metric"
"go.opentelemetry.io/otel/sdk/resource"
"go.opentelemetry.io/otel/sdk/trace"
semconv "go.opentelemetry.io/otel/semconv/v1.21.0"
"go.uber.org/zap"
)
// Exporter lists available telemetry exporters
type Exporter string
const (
NoopExporter Exporter = ""
OtelExporter Exporter = "otel"
PrometheusExporter Exporter = "prometheus"
)
// Options for configuring telemetry setup
type Options struct {
MetricsExporter Exporter
TracesExporter Exporter
ServiceName string
ServiceVersion string
}
// ShutdownFunc stops global telemetry
type ShutdownFunc func(context.Context) error
// Start configures traces and metrics globally.
// Use "go.opentelemetry.io/otel.Tracer" to access global tracers.
// Use "go.opentelemetry.io/otel.Meter" to access global meters.
// If using OtelExporter (otel collector), make sure to set the OTEL_EXPORTER_OTLP_ENDPOINT env var.
// For a full list of Otel env vars, see: https://github.com/open-telemetry/opentelemetry-go/tree/main/exporters/otlp/otlptrace.
func Start(ctx context.Context, logger *zap.Logger, opts *Options) (ShutdownFunc, error) {
// Log otel info and errors using Zap
otel.SetLogger(zapr.NewLogger(logger))
otel.SetErrorHandler(otel.ErrorHandlerFunc(func(err error) {
logger.Error("otel error", zap.Error(err))
}))
// Create resource representing the currently running service
res, err := resource.Merge(
resource.Default(),
resource.NewWithAttributes(
semconv.SchemaURL,
semconv.ServiceName(opts.ServiceName),
semconv.ServiceVersion(opts.ServiceVersion),
),
)
if err != nil {
return nil, err
}
// Create global metrics exporter
var meterProvider *metric.MeterProvider
switch opts.MetricsExporter {
case PrometheusExporter:
exp, err := prometheus.New()
if err != nil {
return nil, err
}
meterProvider = metric.NewMeterProvider(metric.WithResource(res), metric.WithReader(exp))
case OtelExporter:
exp, err := otlpmetricgrpc.New(ctx)
if err != nil {
return nil, err
}
r := metric.NewPeriodicReader(exp, metric.WithInterval(15*time.Second))
meterProvider = metric.NewMeterProvider(metric.WithResource(res), metric.WithReader(r))
case NoopExporter:
// Nothing to do
default:
panic(fmt.Errorf("unexpected metrics exporter %q", opts.MetricsExporter))
}
// Set global meter provider
if meterProvider != nil {
otel.SetMeterProvider(meterProvider)
}
// Create global traces exporter
var tracerProvider *trace.TracerProvider
switch opts.TracesExporter {
case OtelExporter:
client := otlptracegrpc.NewClient()
exp, err := otlptrace.New(ctx, client)
if err != nil {
return nil, err
}
bsp := trace.NewBatchSpanProcessor(exp)
tracerProvider = trace.NewTracerProvider(
trace.WithSampler(trace.AlwaysSample()),
trace.WithResource(res),
trace.WithSpanProcessor(bsp),
)
case NoopExporter:
// Nothing to do
default:
panic(fmt.Errorf("unexpected traces exporter %q", opts.TracesExporter))
}
// Set global tracer provider
if tracerProvider != nil {
otel.SetTracerProvider(tracerProvider)
}
// Collect metrics from the Go runtime (polls every 15s by default)
if meterProvider != nil {
err = runtime.Start()
if err != nil {
return nil, err
}
}
// Create callback to shut down globals
shutdown := func(ctx context.Context) error {
var err1, err2 error
if meterProvider != nil {
err1 = meterProvider.Shutdown(ctx)
}
if tracerProvider != nil {
err2 = tracerProvider.Shutdown(ctx)
}
if err1 != nil {
return err1
}
return err2
}
return shutdown, nil
}