Skip to content

Commit 1785386

Browse files
authored
Add OpenTelemetry autoexport support and clean up metrics handling (#4)
Introduce OpenTelemetry autoexport for tracing and metrics while removing Prometheus-specific code. Simplify initialization and enhance error handling for metric reader initialization. Update version to v0.3.0.
1 parent c5df562 commit 1785386

File tree

5 files changed

+62
-133
lines changed

5 files changed

+62
-133
lines changed

.golangci.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ formatters:
4747
- gofumpt
4848
- golines
4949
- goimports
50+
settings:
51+
golines:
52+
max-len: 120
5053
exclusions:
5154
generated: lax
5255

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
VERSION=v0.2.0
1+
VERSION=v0.3.0
22

33
.PHONY: all
44
all: build

go.mod

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,18 @@ require (
2828
github.com/prometheus/otlptranslator v0.0.2 // indirect
2929
github.com/prometheus/procfs v0.17.0 // indirect
3030
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
31+
go.opentelemetry.io/contrib/exporters/autoexport v0.63.0 // indirect
32+
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.14.0 // indirect
33+
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.14.0 // indirect
34+
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.38.0 // indirect
3135
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 // indirect
36+
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 // indirect
37+
go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.14.0 // indirect
38+
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0 // indirect
39+
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0 // indirect
40+
go.opentelemetry.io/otel/log v0.14.0 // indirect
3241
go.opentelemetry.io/otel/metric v1.38.0 // indirect
42+
go.opentelemetry.io/otel/sdk/log v0.14.0 // indirect
3343
go.opentelemetry.io/otel/trace v1.38.0 // indirect
3444
go.opentelemetry.io/proto/otlp v1.7.1 // indirect
3545
go.yaml.in/yaml/v2 v2.4.2 // indirect

go.sum

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,20 +51,40 @@ go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJyS
5151
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
5252
go.opentelemetry.io/contrib/bridges/prometheus v0.63.0 h1:/Rij/t18Y7rUayNg7Id6rPrEnHgorxYabm2E6wUdPP4=
5353
go.opentelemetry.io/contrib/bridges/prometheus v0.63.0/go.mod h1:AdyDPn6pkbkt2w01n3BubRVk7xAsCRq1Yg1mpfyA/0E=
54+
go.opentelemetry.io/contrib/exporters/autoexport v0.63.0 h1:NLnZybb9KkfMXPwZhd5diBYJoVxiO9Qa06dacEA7ySY=
55+
go.opentelemetry.io/contrib/exporters/autoexport v0.63.0/go.mod h1:OvRg7gm5WRSCtxzGSsrFHbDLToYlStHNZQ+iPNIyD6g=
5456
go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=
5557
go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=
58+
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.14.0 h1:OMqPldHt79PqWKOMYIAQs3CxAi7RLgPxwfFSwr4ZxtM=
59+
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.14.0/go.mod h1:1biG4qiqTxKiUCtoWDPpL3fB3KxVwCiGw81j3nKMuHE=
60+
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.14.0 h1:QQqYw3lkrzwVsoEX0w//EhH/TCnpRdEenKBOOEIMjWc=
61+
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.14.0/go.mod h1:gSVQcr17jk2ig4jqJ2DX30IdWH251JcNAecvrqTxH1s=
5662
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0 h1:vl9obrcoWVKp/lwl8tRE33853I8Xru9HFbw/skNeLs8=
5763
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0/go.mod h1:GAXRxmLJcVM3u22IjTg74zWBrRCKq8BnOqUVLodpcpw=
64+
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.38.0 h1:Oe2z/BCg5q7k4iXC3cqJxKYg0ieRiOqF0cecFYdPTwk=
65+
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.38.0/go.mod h1:ZQM5lAJpOsKnYagGg/zV2krVqTtaVdYdDkhMoX6Oalg=
5866
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 h1:GqRJVj7UmLjCVyVJ3ZFLdPRmhDUp2zFmQe3RHIOsw24=
5967
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0/go.mod h1:ri3aaHSmCTVYu2AWv44YMauwAQc0aqI9gHKIcSbI1pU=
6068
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 h1:lwI4Dc5leUqENgGuQImwLo4WnuXFPetmPpkLi2IrX54=
6169
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0/go.mod h1:Kz/oCE7z5wuyhPxsXDuaPteSWqjSBD5YaSdbxZYGbGk=
70+
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 h1:aTL7F04bJHUlztTsNGJ2l+6he8c+y/b//eR0jjjemT4=
71+
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0/go.mod h1:kldtb7jDTeol0l3ewcmd8SDvx3EmIE7lyvqbasU3QC4=
6272
go.opentelemetry.io/otel/exporters/prometheus v0.60.0 h1:cGtQxGvZbnrWdC2GyjZi0PDKVSLWP/Jocix3QWfXtbo=
6373
go.opentelemetry.io/otel/exporters/prometheus v0.60.0/go.mod h1:hkd1EekxNo69PTV4OWFGZcKQiIqg0RfuWExcPKFvepk=
74+
go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.14.0 h1:B/g+qde6Mkzxbry5ZZag0l7QrQBCtVm7lVjaLgmpje8=
75+
go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.14.0/go.mod h1:mOJK8eMmgW6ocDJn6Bn11CcZ05gi3P8GylBXEkZtbgA=
76+
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0 h1:wm/Q0GAAykXv83wzcKzGGqAnnfLFyFe7RslekZuv+VI=
77+
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0/go.mod h1:ra3Pa40+oKjvYh+ZD3EdxFZZB0xdMfuileHAm4nNN7w=
78+
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0 h1:kJxSDN4SgWWTjG/hPp3O7LCGLcHXFlvS2/FFOrwL+SE=
79+
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0/go.mod h1:mgIOzS7iZeKJdeB8/NYHrJ48fdGc71Llo5bJ1J4DWUE=
80+
go.opentelemetry.io/otel/log v0.14.0 h1:2rzJ+pOAZ8qmZ3DDHg73NEKzSZkhkGIua9gXtxNGgrM=
81+
go.opentelemetry.io/otel/log v0.14.0/go.mod h1:5jRG92fEAgx0SU/vFPxmJvhIuDU9E1SUnEQrMlJpOno=
6482
go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=
6583
go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=
6684
go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=
6785
go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=
86+
go.opentelemetry.io/otel/sdk/log v0.14.0 h1:JU/U3O7N6fsAXj0+CXz21Czg532dW2V4gG1HE/e8Zrg=
87+
go.opentelemetry.io/otel/sdk/log v0.14.0/go.mod h1:imQvII+0ZylXfKU7/wtOND8Hn4OpT3YUoIgqJVksUkM=
6888
go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=
6989
go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=
7090
go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=

pkg/otel/otel.go

Lines changed: 28 additions & 132 deletions
Original file line numberDiff line numberDiff line change
@@ -6,36 +6,27 @@ import (
66
"errors"
77
"fmt"
88
"log"
9-
"net/http"
109
"os"
11-
"time"
10+
"strings"
1211

13-
"github.com/prometheus/client_golang/prometheus"
14-
"github.com/prometheus/client_golang/prometheus/promhttp"
15-
otelprom "go.opentelemetry.io/contrib/bridges/prometheus"
12+
"go.opentelemetry.io/contrib/exporters/autoexport"
1613
"go.opentelemetry.io/otel"
17-
"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc"
18-
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
19-
promexp "go.opentelemetry.io/otel/exporters/prometheus"
2014
"go.opentelemetry.io/otel/propagation"
2115
"go.opentelemetry.io/otel/sdk/metric"
2216
"go.opentelemetry.io/otel/sdk/resource"
2317
"go.opentelemetry.io/otel/sdk/trace"
2418
)
2519

26-
const (
27-
metricsEndpoint = "/metrics"
28-
shutdownTimeout = 5 * time.Second
29-
trueString = "true"
30-
)
31-
3220
// InitGlobalTraceProvider initializes and sets a global trace provider for OpenTelemetry.
3321
func InitGlobalTraceProvider(ctx context.Context) (func(context.Context) (error, error), error) {
34-
var (
35-
traceProvider *trace.TracerProvider
36-
meterProvider *metric.MeterProvider
37-
err error
38-
)
22+
sdkDisabled := getBoolEnv("OTEL_SDK_DISABLED")
23+
if sdkDisabled {
24+
log.Println("OTEL_SDK_DISABLED is set to true, skipping OpenTelemetry initialization")
25+
26+
return func(_ context.Context) (error, error) {
27+
return nil, nil //nolint:nilnil // No-op shutdown function.
28+
}, nil
29+
}
3930

4031
res, err := resource.New(ctx, resource.WithFromEnv(), resource.WithHost())
4132
if errors.Is(err, resource.ErrPartialResource) ||
@@ -45,49 +36,23 @@ func InitGlobalTraceProvider(ctx context.Context) (func(context.Context) (error,
4536
return nil, fmt.Errorf("failed initializing otlp resource: %w", err)
4637
}
4738

48-
if shouldEnableTracing() {
49-
traceProvider, err = initTracerProvider(ctx, res)
50-
if err != nil {
51-
return nil, err
52-
}
39+
traceProvider, err := initTracerProvider(ctx, res)
40+
if err != nil {
41+
return nil, err
5342
}
5443

55-
if shouldEnableMetrics() {
56-
meterProvider, err = initMeterProvider(ctx, res)
57-
if err != nil {
58-
return nil, err
59-
}
44+
meterProvider, err := initMeterProvider(ctx, res)
45+
if err != nil {
46+
return nil, err
6047
}
6148

6249
return func(ctx context.Context) (error, error) {
63-
var traceErr, metricErr error
64-
65-
if traceProvider != nil {
66-
traceErr = traceProvider.Shutdown(ctx)
67-
}
68-
69-
if meterProvider != nil {
70-
metricErr = meterProvider.Shutdown(ctx)
71-
}
72-
73-
return traceErr, metricErr
50+
return traceProvider.Shutdown(ctx), meterProvider.Shutdown(ctx)
7451
}, nil
7552
}
7653

77-
func shouldEnableTracing() bool {
78-
enableTracing := os.Getenv("CF_TELEMETRY_ENABLE")
79-
if enableTracing != trueString {
80-
enableTracing = os.Getenv("CF_TELEMETRY_TRACE_ENABLE")
81-
}
82-
83-
return enableTracing == trueString
84-
}
85-
86-
func initTracerProvider(
87-
ctx context.Context,
88-
res *resource.Resource,
89-
) (*trace.TracerProvider, error) {
90-
exporter, err := otlptracegrpc.New(ctx)
54+
func initTracerProvider(ctx context.Context, res *resource.Resource) (*trace.TracerProvider, error) {
55+
exporter, err := autoexport.NewSpanExporter(ctx)
9156
if err != nil {
9257
return nil, fmt.Errorf("failed initializing global trace provider: %w", err)
9358
}
@@ -108,92 +73,23 @@ func initTracerProvider(
10873
return traceprovider, nil
10974
}
11075

111-
func shouldEnableMetrics() bool {
112-
enableMetrics := os.Getenv("CF_TELEMETRY_ENABLE")
113-
if enableMetrics != trueString {
114-
enableMetrics = os.Getenv("CF_TELEMETRY_METRICS_ENABLE")
115-
}
116-
117-
return enableMetrics == trueString
118-
}
119-
12076
func initMeterProvider(ctx context.Context, res *resource.Resource) (*metric.MeterProvider, error) {
121-
meterProvider, err := newMeterProvider(ctx, res)
77+
reader, err := autoexport.NewMetricReader(ctx)
12278
if err != nil {
123-
return nil, fmt.Errorf("failed initializing global meter provider: %w", err)
79+
return nil, fmt.Errorf("failed initializing autoexport metric reader: %w", err)
12480
}
12581

82+
meterProvider := metric.NewMeterProvider(
83+
metric.WithResource(res),
84+
metric.WithReader(reader),
85+
)
12686
otel.SetMeterProvider(meterProvider)
12787

12888
return meterProvider, nil
12989
}
13090

131-
func newMeterProvider(ctx context.Context, res *resource.Resource) (*metric.MeterProvider, error) {
132-
metricsBindAddress := os.Getenv("METRICS_BIND_ADDRESS")
91+
func getBoolEnv(key string) bool {
92+
val := os.Getenv(key)
13393

134-
var (
135-
reader metric.Reader
136-
err error
137-
)
138-
if metricsBindAddress != "" && metricsBindAddress != "0" {
139-
// using prometheus
140-
reader, err = promexp.New()
141-
if err != nil {
142-
return nil, fmt.Errorf("failed to create Prometheus exporter: %w", err)
143-
}
144-
145-
go serveMetrics(ctx, metricsBindAddress)
146-
} else {
147-
// using otlp grpc
148-
exporter, err := otlpmetricgrpc.New(ctx)
149-
if err != nil {
150-
return nil, fmt.Errorf("failed to create OTLP metric exporter: %w", err)
151-
}
152-
153-
// make sure to read from the prometheus default gatherer
154-
promBridge := otelprom.NewMetricProducer(
155-
otelprom.WithGatherer(prometheus.DefaultGatherer),
156-
)
157-
158-
reader = metric.NewPeriodicReader(
159-
exporter,
160-
metric.WithProducer(promBridge),
161-
)
162-
}
163-
164-
return metric.NewMeterProvider(
165-
metric.WithResource(res),
166-
metric.WithReader(reader),
167-
), nil
168-
}
169-
170-
func serveMetrics(ctx context.Context, metricsBindAddress string) {
171-
log.Printf("serving metrics at localhost%s/metrics", metricsBindAddress)
172-
173-
mux := http.NewServeMux()
174-
mux.Handle(metricsEndpoint, promhttp.Handler())
175-
//nolint:gosec // Ignoring G112: Use of net/http serve function that has no support for setting timeouts.
176-
server := &http.Server{
177-
Addr: metricsBindAddress,
178-
Handler: mux,
179-
}
180-
181-
go func() {
182-
<-ctx.Done()
183-
184-
shutdownCtx, cancel := context.WithTimeout(context.Background(), shutdownTimeout)
185-
defer cancel()
186-
//nolint:contextcheck // We must use context.Background() here because the parent ctx is already canceled.
187-
err := server.Shutdown(shutdownCtx)
188-
if err != nil {
189-
log.Printf("failed to shutdown metrics server: %v", err)
190-
}
191-
}()
192-
193-
err := server.ListenAndServe()
194-
if err != nil && !errors.Is(err, http.ErrServerClosed) {
195-
log.Printf("error serving http: %v", err)
196-
197-
return
198-
}
94+
return strings.EqualFold(val, "true")
19995
}

0 commit comments

Comments
 (0)