Skip to content

Commit bc9e035

Browse files
committed
add otel experiments
1 parent 3df373a commit bc9e035

File tree

4 files changed

+158
-0
lines changed

4 files changed

+158
-0
lines changed

cmd/device-agent/main.go

+11
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"github.com/nais/device/internal/device-agent/runtimeconfig"
2323
"github.com/nais/device/internal/logger"
2424
"github.com/nais/device/internal/notify"
25+
"github.com/nais/device/internal/otel"
2526
"github.com/nais/device/internal/pb"
2627
"github.com/nais/device/internal/unixsocket"
2728
"github.com/nais/device/internal/version"
@@ -95,6 +96,16 @@ func run(ctx context.Context, log *logrus.Entry, cfg *config.Config, notifier no
9596
return fmt.Errorf("missing prerequisites: %s", err)
9697
}
9798

99+
otelCancel, err := otel.SetupOTelSDK(ctx)
100+
if err != nil {
101+
return fmt.Errorf("setup OTel SDK: %s", err)
102+
}
103+
defer func() {
104+
if err := otelCancel(ctx); err != nil {
105+
log.Errorf("shutdown OTel SDK: %s", err)
106+
}
107+
}()
108+
98109
rc, err := runtimeconfig.New(log.WithField("component", "runtimeconfig"), cfg)
99110
if err != nil {
100111
log.Errorf("instantiate runtime config: %v", err)

go.mod

+9
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ require (
6464
github.com/russross/blackfriday/v2 v2.1.0 // indirect
6565
github.com/stretchr/objx v0.5.0 // indirect
6666
go.opencensus.io v0.24.0 // indirect
67+
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.23.1 // indirect
6768
go.uber.org/atomic v1.11.0 // indirect
6869
go.uber.org/multierr v1.11.0 // indirect
6970
go.uber.org/zap v1.26.0 // indirect
@@ -123,6 +124,7 @@ require (
123124
github.com/butuzov/mirror v1.1.0 // indirect
124125
github.com/catenacyber/perfsprint v0.2.0 // indirect
125126
github.com/ccojocar/zxcvbn-go v1.0.1 // indirect
127+
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
126128
github.com/charithe/durationcheck v0.0.10 // indirect
127129
github.com/chavacava/garif v0.1.0 // indirect
128130
github.com/chigopher/pathlib v0.19.1 // indirect
@@ -172,6 +174,7 @@ require (
172174
github.com/gostaticanalysis/comment v1.4.2 // indirect
173175
github.com/gostaticanalysis/forcetypeassert v0.1.0 // indirect
174176
github.com/gostaticanalysis/nilerr v0.1.1 // indirect
177+
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 // indirect
175178
github.com/hashicorp/go-version v1.6.0 // indirect
176179
github.com/hashicorp/hcl v1.0.0 // indirect
177180
github.com/hexops/gotextdiff v1.0.3 // indirect
@@ -281,9 +284,15 @@ require (
281284
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.48.0 // indirect
282285
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0 // indirect
283286
go.opentelemetry.io/otel v1.23.1 // indirect
287+
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.23.1
288+
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.23.1 // indirect
289+
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.23.1 // indirect
290+
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.23.1 // indirect
284291
go.opentelemetry.io/otel/metric v1.23.1 // indirect
285292
go.opentelemetry.io/otel/sdk v1.23.1 // indirect
293+
go.opentelemetry.io/otel/sdk/metric v1.23.1 // indirect
286294
go.opentelemetry.io/otel/trace v1.23.1 // indirect
295+
go.opentelemetry.io/proto/otlp v1.1.0 // indirect
287296
go.tmz.dev/musttag v0.7.2 // indirect
288297
golang.org/x/exp/typeparams v0.0.0-20231006140011-7918f672742d // indirect
289298
golang.org/x/mod v0.14.0 // indirect

go.sum

+20
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,8 @@ github.com/catenacyber/perfsprint v0.2.0 h1:azOocHLscPjqXVJ7Mf14Zjlkn4uNua0+Hcg1
121121
github.com/catenacyber/perfsprint v0.2.0/go.mod h1:/wclWYompEyjUD2FuIIDVKNkqz7IgBIWXIH3V0Zol50=
122122
github.com/ccojocar/zxcvbn-go v1.0.1 h1:+sxrANSCj6CdadkcMnvde/GWU1vZiiXRbqYSCalV4/4=
123123
github.com/ccojocar/zxcvbn-go v1.0.1/go.mod h1:g1qkXtUSvHP8lhHp5GrSmTz6uWALGRMQdw6Qnz/hi60=
124+
github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
125+
github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
124126
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
125127
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
126128
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
@@ -368,6 +370,8 @@ github.com/gostaticanalysis/nilerr v0.1.1/go.mod h1:wZYb6YI5YAxxq0i1+VJbY0s2YONW
368370
github.com/gostaticanalysis/testutil v0.3.1-0.20210208050101-bfb5c8eec0e4/go.mod h1:D+FIZ+7OahH3ePw/izIEeH5I06eKs1IKI4Xr64/Am3M=
369371
github.com/gostaticanalysis/testutil v0.4.0 h1:nhdCmubdmDF6VEatUNjgUZBJKWRqugoISdUv3PPQgHY=
370372
github.com/gostaticanalysis/testutil v0.4.0/go.mod h1:bLIoPefWXrRi/ssLFWX1dx7Repi5x3CuviD3dgAZaBU=
373+
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 h1:Wqo399gCIufwto+VfwCSvsnfGpF/w5E9CNxSwbpD6No=
374+
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0/go.mod h1:qmOFXW2epJhM0qSnUUYpldc7gVz2KMQwJ/QYCDIa7XU=
371375
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
372376
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
373377
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
@@ -606,6 +610,7 @@ github.com/riza-io/grpc-go v0.2.0/go.mod h1:2bDvR9KkKC3KhtlSHfR3dAXjUMT86kg4UfWF
606610
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
607611
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
608612
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
613+
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
609614
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
610615
github.com/rs/zerolog v1.32.0 h1:keLypqrlIjaFsbmJOBdB/qvyF8KEtCWHwobLp5l/mQ0=
611616
github.com/rs/zerolog v1.32.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
@@ -765,12 +770,26 @@ go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0 h1:sv9kVfa
765770
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0/go.mod h1:SK2UL73Zy1quvRPonmOmRDiWk1KBV3LyIeeIxcEApWw=
766771
go.opentelemetry.io/otel v1.23.1 h1:Za4UzOqJYS+MUczKI320AtqZHZb7EqxO00jAHE0jmQY=
767772
go.opentelemetry.io/otel v1.23.1/go.mod h1:Td0134eafDLcTS4y+zQ26GE8u3dEuRBiBCTUIRHaikA=
773+
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.23.1 h1:ZqRWZJGHXV/1yCcEEVJ6/Uz2JtM79DNS8OZYa3vVY/A=
774+
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.23.1/go.mod h1:D7ynngPWlGJrqyGSDOdscuv7uqttfCE3jcBvffDv9y4=
775+
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.23.1 h1:q/Nj5/2TZRIt6PderQ9oU0M00fzoe8UZuINGw6ETGTw=
776+
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.23.1/go.mod h1:DTE9yAu6r08jU3xa68GiSeI7oRcSEQ2RpKbbQGO+dWM=
777+
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.23.1 h1:o8iWeVFa1BcLtVEV0LzrCxV2/55tB3xLxADr6Kyoey4=
778+
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.23.1/go.mod h1:SEVfdK4IoBnbT2FXNM/k8yC08MrfbhWk3U4ljM8B3HE=
779+
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.23.1 h1:p3A5+f5l9e/kuEBwLOrnpkIDHQFlHmbiVxMURWRK6gQ=
780+
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.23.1/go.mod h1:OClrnXUjBqQbInvjJFjYSnMxBSCXBF8r3b34WqjiIrQ=
781+
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.23.1 h1:cfuy3bXmLJS7M1RZmAL6SuhGtKUp2KEsrm00OlAXkq4=
782+
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.23.1/go.mod h1:22jr92C6KwlwItJmQzfixzQM3oyyuYLCfHiMY+rpsPU=
768783
go.opentelemetry.io/otel/metric v1.23.1 h1:PQJmqJ9u2QaJLBOELl1cxIdPcpbwzbkjfEyelTl2rlo=
769784
go.opentelemetry.io/otel/metric v1.23.1/go.mod h1:mpG2QPlAfnK8yNhNJAxDZruU9Y1/HubbC+KyH8FaCWI=
770785
go.opentelemetry.io/otel/sdk v1.23.1 h1:O7JmZw0h76if63LQdsBMKQDWNb5oEcOThG9IrxscV+E=
771786
go.opentelemetry.io/otel/sdk v1.23.1/go.mod h1:LzdEVR5am1uKOOwfBWFef2DCi1nu3SA8XQxx2IerWFk=
787+
go.opentelemetry.io/otel/sdk/metric v1.23.1 h1:T9/8WsYg+ZqIpMWwdISVVrlGb/N0Jr1OHjR/alpKwzg=
788+
go.opentelemetry.io/otel/sdk/metric v1.23.1/go.mod h1:8WX6WnNtHCgUruJ4TJ+UssQjMtpxkpX0zveQC8JG/E0=
772789
go.opentelemetry.io/otel/trace v1.23.1 h1:4LrmmEd8AU2rFvU1zegmvqW7+kWarxtNOPyeL6HmYY8=
773790
go.opentelemetry.io/otel/trace v1.23.1/go.mod h1:4IpnpJFwr1mo/6HL8XIPJaE9y0+u1KcVmuW7dwFSVrI=
791+
go.opentelemetry.io/proto/otlp v1.1.0 h1:2Di21piLrCqJ3U3eXGCTPHE9R8Nh+0uglSnOyxikMeI=
792+
go.opentelemetry.io/proto/otlp v1.1.0/go.mod h1:GpBHCBWiqvVLDqmHZsoMM3C5ySeKTC7ej/RNTae6MdY=
774793
go.tmz.dev/musttag v0.7.2 h1:1J6S9ipDbalBSODNT5jCep8dhZyMr4ttnjQagmGYR5s=
775794
go.tmz.dev/musttag v0.7.2/go.mod h1:m6q5NiiSKMnQYokefa2xGoyoXnrswCbJ0AWYzf4Zs28=
776795
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
@@ -781,6 +800,7 @@ go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0
781800
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
782801
go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk=
783802
go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo=
803+
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
784804
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
785805
go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak=
786806
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=

internal/otel/otel.go

+118
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
package otel
2+
3+
import (
4+
"context"
5+
"errors"
6+
"runtime"
7+
"time"
8+
9+
"go.opentelemetry.io/otel"
10+
"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp"
11+
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"
12+
"go.opentelemetry.io/otel/propagation"
13+
"go.opentelemetry.io/otel/sdk/metric"
14+
"go.opentelemetry.io/otel/sdk/resource"
15+
"go.opentelemetry.io/otel/sdk/trace"
16+
semconv "go.opentelemetry.io/otel/semconv/v1.17.0"
17+
)
18+
19+
// setupOTelSDK bootstraps the OpenTelemetry pipeline.
20+
// If it does not return an error, make sure to call shutdown for proper cleanup.
21+
func SetupOTelSDK(ctx context.Context) (shutdown func(context.Context) error, err error) {
22+
var shutdownFuncs []func(context.Context) error
23+
24+
// shutdown calls cleanup functions registered via shutdownFuncs.
25+
// The errors from the calls are joined.
26+
// Each registered cleanup will be invoked once.
27+
shutdown = func(ctx context.Context) error {
28+
var err error
29+
for _, fn := range shutdownFuncs {
30+
err = errors.Join(err, fn(ctx))
31+
}
32+
shutdownFuncs = nil
33+
return err
34+
}
35+
36+
// handleErr calls shutdown for cleanup and makes sure that all errors are returned.
37+
handleErr := func(inErr error) {
38+
err = errors.Join(inErr, shutdown(ctx))
39+
}
40+
41+
// Set up propagator.
42+
prop := newPropagator()
43+
otel.SetTextMapPropagator(prop)
44+
45+
// Set up resource.
46+
res := resource.NewWithAttributes(
47+
semconv.SchemaURL,
48+
semconv.ServiceName("device-agent"),
49+
semconv.OSName(runtime.GOOS),
50+
)
51+
52+
// Set up trace provider.
53+
tracerProvider, err := newTraceProvider(ctx, res)
54+
if err != nil {
55+
handleErr(err)
56+
return
57+
}
58+
shutdownFuncs = append(shutdownFuncs, tracerProvider.Shutdown)
59+
otel.SetTracerProvider(tracerProvider)
60+
61+
// Set up meter provider.
62+
meterProvider, err := newMeterProvider(ctx, res)
63+
if err != nil {
64+
handleErr(err)
65+
return
66+
}
67+
shutdownFuncs = append(shutdownFuncs, meterProvider.Shutdown)
68+
otel.SetMeterProvider(meterProvider)
69+
70+
return
71+
}
72+
73+
func newPropagator() propagation.TextMapPropagator {
74+
return propagation.NewCompositeTextMapPropagator(
75+
propagation.TraceContext{},
76+
propagation.Baggage{},
77+
)
78+
}
79+
80+
func newTraceProvider(ctx context.Context, res *resource.Resource) (*trace.TracerProvider, error) {
81+
traceExporter, err := otlptracehttp.New(ctx,
82+
otlptracehttp.WithEndpoint("localhost:12347"),
83+
otlptracehttp.WithURLPath("/collect"),
84+
otlptracehttp.WithInsecure(),
85+
)
86+
if err != nil {
87+
return nil, err
88+
}
89+
90+
traceProvider := trace.NewTracerProvider(
91+
trace.WithBatcher(traceExporter,
92+
// Default is 5s. Set to 1s for demonstrative purposes.
93+
trace.WithBatchTimeout(time.Second)),
94+
trace.WithResource(res),
95+
)
96+
97+
return traceProvider, nil
98+
}
99+
100+
func newMeterProvider(ctx context.Context, res *resource.Resource) (*metric.MeterProvider, error) {
101+
metricExporter, err := otlpmetrichttp.New(ctx,
102+
otlpmetrichttp.WithEndpoint("localhost:12347"),
103+
otlpmetrichttp.WithURLPath("/collect"),
104+
otlpmetrichttp.WithInsecure(),
105+
)
106+
if err != nil {
107+
return nil, err
108+
}
109+
110+
meterProvider := metric.NewMeterProvider(
111+
metric.WithReader(
112+
metric.NewPeriodicReader(metricExporter,
113+
// Default is 1m. Set to 3s for demonstrative purposes.
114+
metric.WithInterval(3*time.Second))),
115+
metric.WithResource(res),
116+
)
117+
return meterProvider, nil
118+
}

0 commit comments

Comments
 (0)