Skip to content

Commit d588c3c

Browse files
elena-kolevskaofekshenawa
authored andcommitted
First draft. One metric - command duration.
Signed-off-by: Elena Kolevska <[email protected]>
1 parent dc053a4 commit d588c3c

File tree

9 files changed

+808
-5
lines changed

9 files changed

+808
-5
lines changed

example/otel_metrics.go

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
// EXAMPLE: otel_metrics
2+
// HIDE_START
3+
package main
4+
5+
import (
6+
"context"
7+
"log"
8+
"strconv"
9+
"time"
10+
11+
redisotel "github.com/redis/go-redis/extra/redisotel-native/v9"
12+
"github.com/redis/go-redis/v9"
13+
"go.opentelemetry.io/otel"
14+
"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc"
15+
"go.opentelemetry.io/otel/sdk/metric"
16+
)
17+
18+
// ExampleClient_otel_metrics demonstrates how to enable OpenTelemetry metrics
19+
// for Redis operations and export them to an OTLP collector.
20+
func main() {
21+
ctx := context.Background()
22+
23+
// HIDE_END
24+
25+
// STEP_START otel_exporter_setup
26+
// Create OTLP exporter that sends metrics to the collector
27+
// Default endpoint is localhost:4317 (gRPC)
28+
exporter, err := otlpmetricgrpc.New(ctx,
29+
otlpmetricgrpc.WithInsecure(), // Use insecure for local development
30+
// For production, configure TLS and authentication:
31+
// otlpmetricgrpc.WithEndpoint("your-collector:4317"),
32+
// otlpmetricgrpc.WithTLSCredentials(...),
33+
)
34+
if err != nil {
35+
log.Fatalf("Failed to create OTLP exporter: %v", err)
36+
}
37+
// STEP_END
38+
39+
// STEP_START otel_meter_provider
40+
// Create meter provider with periodic reader
41+
// Metrics are exported every 10 seconds
42+
meterProvider := metric.NewMeterProvider(
43+
metric.WithReader(
44+
metric.NewPeriodicReader(exporter,
45+
metric.WithInterval(10*time.Second),
46+
),
47+
),
48+
)
49+
defer func() {
50+
if err := meterProvider.Shutdown(ctx); err != nil {
51+
log.Printf("Error shutting down meter provider: %v", err)
52+
}
53+
}()
54+
55+
// Set the global meter provider
56+
otel.SetMeterProvider(meterProvider)
57+
// STEP_END
58+
59+
// STEP_START redis_client_setup
60+
// Create Redis client
61+
rdb := redis.NewClient(&redis.Options{
62+
Addr: "localhost:6379",
63+
})
64+
defer rdb.Close()
65+
66+
// Initialize OTel instrumentation (uses global meter provider)
67+
if err := redisotel.Init(rdb); err != nil {
68+
log.Fatalf("Failed to initialize OTel: %v", err)
69+
}
70+
defer redisotel.Shutdown()
71+
// STEP_END
72+
73+
// STEP_START redis_operations
74+
// Execute Redis operations - metrics are automatically collected
75+
log.Println("Executing Redis operations...")
76+
for i := range 100 {
77+
if err := rdb.Set(ctx, "key"+strconv.Itoa(i), "value", 0).Err(); err != nil {
78+
log.Printf("Error setting key: %v", err)
79+
}
80+
time.Sleep(time.Millisecond * 100)
81+
}
82+
log.Println("Operations complete. Waiting for metrics to be exported...")
83+
84+
// Wait for metrics to be exported
85+
time.Sleep(15 * time.Second)
86+
// STEP_END
87+
}
88+

extra/redisotel-native/config.go

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package redisotel
2+
3+
import (
4+
"go.opentelemetry.io/otel/metric"
5+
)
6+
7+
// config holds the configuration for the instrumentation
8+
type config struct {
9+
meterProvider metric.MeterProvider
10+
histogramBuckets []float64
11+
}
12+
13+
// defaultConfig returns the default configuration
14+
func defaultConfig() config {
15+
return config{
16+
meterProvider: nil, // Will use global otel.GetMeterProvider() if nil
17+
histogramBuckets: defaultHistogramBuckets(),
18+
}
19+
}
20+
21+
// defaultHistogramBuckets returns the default histogram buckets for operation duration
22+
// These buckets are designed to capture typical Redis operation latencies:
23+
// - Sub-millisecond: 0.0001s (0.1ms), 0.0005s (0.5ms)
24+
// - Milliseconds: 0.001s (1ms), 0.005s (5ms), 0.01s (10ms), 0.05s (50ms), 0.1s (100ms)
25+
// - Sub-second: 0.5s (500ms)
26+
// - Seconds: 1s, 5s, 10s
27+
func defaultHistogramBuckets() []float64 {
28+
return []float64{
29+
0.0001, // 0.1ms
30+
0.0005, // 0.5ms
31+
0.001, // 1ms
32+
0.005, // 5ms
33+
0.01, // 10ms
34+
0.05, // 50ms
35+
0.1, // 100ms
36+
0.5, // 500ms
37+
1.0, // 1s
38+
5.0, // 5s
39+
10.0, // 10s
40+
}
41+
}
42+
43+
// Option is a functional option for configuring the instrumentation
44+
type Option interface {
45+
apply(*config)
46+
}
47+
48+
// optionFunc wraps a function to implement the Option interface
49+
type optionFunc func(*config)
50+
51+
func (f optionFunc) apply(c *config) {
52+
f(c)
53+
}
54+
55+
// WithMeterProvider sets the meter provider to use for creating metrics.
56+
// If not provided, the global meter provider from otel.GetMeterProvider() will be used.
57+
func WithMeterProvider(provider metric.MeterProvider) Option {
58+
return optionFunc(func(c *config) {
59+
c.meterProvider = provider
60+
})
61+
}
62+
63+
// WithHistogramBuckets sets custom histogram buckets for operation duration
64+
// Buckets should be in seconds and in ascending order
65+
func WithHistogramBuckets(buckets []float64) Option {
66+
return optionFunc(func(c *config) {
67+
c.histogramBuckets = buckets
68+
})
69+
}

extra/redisotel-native/go.mod

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
module github.com/redis/go-redis/extra/redisotel-native/v9
2+
3+
go 1.23.0
4+
5+
toolchain go1.24.2
6+
7+
replace github.com/redis/go-redis/v9 => ../..
8+
9+
require (
10+
github.com/redis/go-redis/v9 v9.7.0
11+
go.opentelemetry.io/otel v1.38.0
12+
go.opentelemetry.io/otel/metric v1.38.0
13+
go.opentelemetry.io/otel/sdk/metric v1.38.0
14+
)
15+
16+
require (
17+
github.com/cespare/xxhash/v2 v2.3.0 // indirect
18+
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
19+
github.com/go-logr/logr v1.4.3 // indirect
20+
github.com/go-logr/stdr v1.2.2 // indirect
21+
github.com/google/uuid v1.6.0 // indirect
22+
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
23+
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0 // indirect
24+
go.opentelemetry.io/otel/sdk v1.38.0 // indirect
25+
go.opentelemetry.io/otel/trace v1.38.0 // indirect
26+
golang.org/x/sys v0.35.0 // indirect
27+
)

extra/redisotel-native/go.sum

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
2+
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
3+
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
4+
github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
5+
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
6+
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
7+
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
8+
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
9+
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
10+
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
11+
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
12+
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
13+
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
14+
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
15+
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
16+
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
17+
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
18+
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
19+
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
20+
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
21+
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
22+
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
23+
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
24+
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
25+
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
26+
go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=
27+
go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=
28+
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0 h1:wm/Q0GAAykXv83wzcKzGGqAnnfLFyFe7RslekZuv+VI=
29+
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0/go.mod h1:ra3Pa40+oKjvYh+ZD3EdxFZZB0xdMfuileHAm4nNN7w=
30+
go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=
31+
go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=
32+
go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=
33+
go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=
34+
go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=
35+
go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=
36+
go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=
37+
go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
38+
golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
39+
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
40+
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
41+
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

0 commit comments

Comments
 (0)