Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update redisotel to use semconv and add operation #3197

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 11 additions & 10 deletions extra/redisotel/go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
module github.com/redis/go-redis/extra/redisotel/v9

go 1.19
go 1.22

toolchain go1.23.1

replace github.com/redis/go-redis/v9 => ../..

Expand All @@ -9,20 +11,19 @@ replace github.com/redis/go-redis/extra/rediscmd/v9 => ../rediscmd
require (
github.com/redis/go-redis/extra/rediscmd/v9 v9.6.2
github.com/redis/go-redis/v9 v9.6.2
go.opentelemetry.io/otel v1.22.0
go.opentelemetry.io/otel/metric v1.22.0
go.opentelemetry.io/otel/sdk v1.22.0
go.opentelemetry.io/otel/trace v1.22.0
go.opentelemetry.io/otel v1.32.0
go.opentelemetry.io/otel/metric v1.32.0
go.opentelemetry.io/otel/sdk v1.32.0
go.opentelemetry.io/otel/trace v1.32.0
)

require (
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/go-logr/logr v1.4.1 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
golang.org/x/sys v0.16.0 // indirect
github.com/google/uuid v1.6.0 // indirect
golang.org/x/sys v0.27.0 // indirect
)

retract (
v9.5.3 // This version was accidentally released.
)
retract v9.5.3 // This version was accidentally released.
35 changes: 22 additions & 13 deletions extra/redisotel/go.sum
Original file line number Diff line number Diff line change
@@ -1,26 +1,35 @@
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
go.opentelemetry.io/otel v1.22.0 h1:xS7Ku+7yTFvDfDraDIJVpw7XPyuHlB9MCiqqX5mcJ6Y=
go.opentelemetry.io/otel v1.22.0/go.mod h1:eoV4iAi3Ea8LkAEI9+GFT44O6T/D0GWAVFyZVCC6pMI=
go.opentelemetry.io/otel/metric v1.22.0 h1:lypMQnGyJYeuYPhOM/bgjbFM6WE44W1/T45er4d8Hhg=
go.opentelemetry.io/otel/metric v1.22.0/go.mod h1:evJGjVpZv0mQ5QBRJoBF64yMuOf4xCWdXjK8pzFvliY=
go.opentelemetry.io/otel/sdk v1.22.0 h1:6coWHw9xw7EfClIC/+O31R8IY3/+EiRFHevmHafB2Gw=
go.opentelemetry.io/otel/sdk v1.22.0/go.mod h1:iu7luyVGYovrRpe2fmj3CVKouQNdTOkxtLzPvPz1DOc=
go.opentelemetry.io/otel/trace v1.22.0 h1:Hg6pPujv0XG9QaVbGOBVHunyuLcCC3jN7WEhPx83XD0=
go.opentelemetry.io/otel/trace v1.22.0/go.mod h1:RbbHXVqKES9QhzZq/fE5UnOSILqRt40a21sPw2He1xo=
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U=
go.opentelemetry.io/otel v1.32.0/go.mod h1:00DCVSB0RQcnzlwyTfqtxSm+DRr9hpYrHjNGiBHVQIg=
go.opentelemetry.io/otel/metric v1.32.0 h1:xV2umtmNcThh2/a/aCP+h64Xx5wsj8qqnkYZktzNa0M=
go.opentelemetry.io/otel/metric v1.32.0/go.mod h1:jH7CIbbK6SH2V2wE16W05BHCtIDzauciCRLoc/SyMv8=
go.opentelemetry.io/otel/sdk v1.32.0 h1:RNxepc9vK59A8XsgZQouW8ue8Gkb4jpWtJm9ge5lEG4=
go.opentelemetry.io/otel/sdk v1.32.0/go.mod h1:LqgegDBjKMmb2GC6/PrTnteJG39I8/vJCAP9LlJXEjU=
go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQDe03fM=
go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8=
golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
61 changes: 33 additions & 28 deletions extra/redisotel/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/metric"
semconv "go.opentelemetry.io/otel/semconv/v1.27.0"

"github.com/redis/go-redis/v9"
)
Expand Down Expand Up @@ -36,8 +37,7 @@ func InstrumentMetrics(rdb redis.UniversalClient, opts ...MetricsOption) error {
opt := rdb.Options()
conf.poolName = opt.Addr
}
conf.attrs = append(conf.attrs, attribute.String("pool.name", conf.poolName))

conf.attrs = append(conf.attrs,semconv.DBClientConnectionPoolName(conf.poolName))
if err := reportPoolStats(rdb, conf); err != nil {
return err
}
Expand All @@ -51,7 +51,7 @@ func InstrumentMetrics(rdb redis.UniversalClient, opts ...MetricsOption) error {
opt := rdb.Options()
conf.poolName = opt.Addr
}
conf.attrs = append(conf.attrs, attribute.String("pool.name", conf.poolName))
conf.attrs = append(conf.attrs, semconv.DBClientConnectionPoolName(conf.poolName))

if err := reportPoolStats(rdb, conf); err != nil {
otel.Handle(err)
Expand All @@ -67,7 +67,7 @@ func InstrumentMetrics(rdb redis.UniversalClient, opts ...MetricsOption) error {
opt := rdb.Options()
conf.poolName = opt.Addr
}
conf.attrs = append(conf.attrs, attribute.String("pool.name", conf.poolName))
conf.attrs = append(conf.attrs, semconv.DBClientConnectionPoolName(conf.poolName))

if err := reportPoolStats(rdb, conf); err != nil {
otel.Handle(err)
Expand All @@ -88,40 +88,45 @@ func reportPoolStats(rdb *redis.Client, conf *config) error {
usedAttrs := append(labels, attribute.String("state", "used"))

idleMax, err := conf.meter.Int64ObservableUpDownCounter(
"db.client.connections.idle.max",
metric.WithDescription("The maximum number of idle open connections allowed"),
semconv.DBClientConnectionIdleMaxName,
metric.WithDescription(semconv.DBClientConnectionIdleMaxDescription),
metric.WithUnit(semconv.DBClientConnectionIdleMaxUnit),
)
if err != nil {
return err
}

idleMin, err := conf.meter.Int64ObservableUpDownCounter(
"db.client.connections.idle.min",
metric.WithDescription("The minimum number of idle open connections allowed"),
semconv.DBClientConnectionIdleMinName,
metric.WithDescription(semconv.DBClientConnectionIdleMinDescription),
metric.WithUnit(semconv.DBClientConnectionIdleMinUnit),
)
if err != nil {
return err
}

connsMax, err := conf.meter.Int64ObservableUpDownCounter(
"db.client.connections.max",
metric.WithDescription("The maximum number of open connections allowed"),
semconv.DBClientConnectionMaxName,
metric.WithDescription(semconv.DBClientConnectionMaxDescription),
metric.WithUnit(semconv.DBClientConnectionMaxUnit),
)
if err != nil {
return err
}

usage, err := conf.meter.Int64ObservableUpDownCounter(
"db.client.connections.usage",
metric.WithDescription("The number of connections that are currently in state described by the state attribute"),
semconv.DBClientConnectionCountName,
metric.WithDescription(semconv.DBClientConnectionCountDescription),
metric.WithUnit(semconv.DBClientConnectionCountUnit),
)
if err != nil {
return err
}

timeouts, err := conf.meter.Int64ObservableUpDownCounter(
"db.client.connections.timeouts",
metric.WithDescription("The number of connection timeouts that have occurred trying to obtain a connection from the pool"),
semconv.DBClientConnectionTimeoutsName,
metric.WithDescription(semconv.DBClientConnectionTimeoutsDescription),
metric.WithUnit(semconv.DBClientConnectionTimeoutsUnit),
)
if err != nil {
return err
Expand Down Expand Up @@ -154,18 +159,18 @@ func reportPoolStats(rdb *redis.Client, conf *config) error {

func addMetricsHook(rdb *redis.Client, conf *config) error {
createTime, err := conf.meter.Float64Histogram(
"db.client.connections.create_time",
metric.WithDescription("The time it took to create a new connection."),
metric.WithUnit("ms"),
semconv.DBClientConnectionCreateTimeName,
metric.WithDescription(semconv.DBClientConnectionCreateTimeDescription),
metric.WithUnit(semconv.DBClientConnectionCreateTimeUnit),
)
if err != nil {
return err
}

useTime, err := conf.meter.Float64Histogram(
"db.client.connections.use_time",
metric.WithDescription("The time between borrowing a connection and returning it to the pool."),
metric.WithUnit("ms"),
semconv.DBClientConnectionUseTimeName,
metric.WithDescription(semconv.DBClientConnectionUseTimeDescription),
metric.WithUnit(semconv.DBClientConnectionUseTimeUnit),
)
if err != nil {
return err
Expand Down Expand Up @@ -199,7 +204,7 @@ func (mh *metricsHook) DialHook(hook redis.DialHook) redis.DialHook {
attrs = append(attrs, mh.attrs...)
attrs = append(attrs, statusAttr(err))

mh.createTime.Record(ctx, milliseconds(dur), metric.WithAttributes(attrs...))
mh.createTime.Record(ctx, dur.Seconds(), metric.WithAttributes(attrs...))
return conn, err
}
}
Expand All @@ -216,8 +221,8 @@ func (mh *metricsHook) ProcessHook(hook redis.ProcessHook) redis.ProcessHook {
attrs = append(attrs, mh.attrs...)
attrs = append(attrs, attribute.String("type", "command"))
attrs = append(attrs, statusAttr(err))

mh.useTime.Record(ctx, milliseconds(dur), metric.WithAttributes(attrs...))
attrs = append(attrs, semconv.DBOperationName(cmd.FullName()))
mh.useTime.Record(ctx, dur.Seconds(), metric.WithAttributes(attrs...))

return err
}
Expand All @@ -237,17 +242,17 @@ func (mh *metricsHook) ProcessPipelineHook(
attrs = append(attrs, mh.attrs...)
attrs = append(attrs, attribute.String("type", "pipeline"))
attrs = append(attrs, statusAttr(err))
if len(cmds) > 0 {
attrs = append(attrs, semconv.DBOperationName(cmds[0].FullName()))
attrs = append(attrs, semconv.DBOperationBatchSize(len(cmds)))
}

mh.useTime.Record(ctx, milliseconds(dur), metric.WithAttributes(attrs...))
mh.useTime.Record(ctx, dur.Seconds(), metric.WithAttributes(attrs...))

return err
}
}

func milliseconds(d time.Duration) float64 {
return float64(d) / float64(time.Millisecond)
}

func statusAttr(err error) attribute.KeyValue {
if err != nil {
return attribute.String("status", "error")
Expand Down
7 changes: 3 additions & 4 deletions extra/redisotel/redisotel_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"context"
"testing"

semconv "go.opentelemetry.io/otel/semconv/v1.7.0"
semconv "go.opentelemetry.io/otel/semconv/v1.27.0"

"go.opentelemetry.io/otel"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
Expand All @@ -27,7 +27,7 @@ func TestNewWithTracerProvider(t *testing.T) {
return otel.GetTracerProvider()
})

_ = newTracingHook("redis-hook", WithTracerProvider(tp.TracerProvider("redis-test")))
_ = newTracingHook(WithTracerProvider(tp.TracerProvider("redis-test")))

if !invoked {
t.Fatalf("did not call custom TraceProvider")
Expand All @@ -37,7 +37,6 @@ func TestNewWithTracerProvider(t *testing.T) {
func TestWithDBStatement(t *testing.T) {
provider := sdktrace.NewTracerProvider()
hook := newTracingHook(
"",
WithTracerProvider(provider),
WithDBStatement(false),
)
Expand All @@ -48,7 +47,7 @@ func TestWithDBStatement(t *testing.T) {
processHook := hook.ProcessHook(func(ctx context.Context, cmd redis.Cmder) error {
attrs := trace.SpanFromContext(ctx).(sdktrace.ReadOnlySpan).Attributes()
for _, attr := range attrs {
if attr.Key == semconv.DBStatementKey {
if attr.Key == semconv.DBQueryTextKey {
t.Fatal("Attribute with db statement should not exist")
}
}
Expand Down
32 changes: 9 additions & 23 deletions extra/redisotel/tracing.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (

"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/codes"
semconv "go.opentelemetry.io/otel/semconv/v1.24.0"
semconv "go.opentelemetry.io/otel/semconv/v1.27.0"
"go.opentelemetry.io/otel/trace"

"github.com/redis/go-redis/extra/rediscmd/v9"
Expand All @@ -25,28 +25,25 @@ func InstrumentTracing(rdb redis.UniversalClient, opts ...TracingOption) error {
switch rdb := rdb.(type) {
case *redis.Client:
opt := rdb.Options()
connString := formatDBConnString(opt.Network, opt.Addr)
opts = addServerAttributes(opts, opt.Addr)
rdb.AddHook(newTracingHook(connString, opts...))
rdb.AddHook(newTracingHook(opts...))
return nil
case *redis.ClusterClient:
rdb.AddHook(newTracingHook("", opts...))
rdb.AddHook(newTracingHook(opts...))

rdb.OnNewNode(func(rdb *redis.Client) {
opt := rdb.Options()
opts = addServerAttributes(opts, opt.Addr)
connString := formatDBConnString(opt.Network, opt.Addr)
rdb.AddHook(newTracingHook(connString, opts...))
rdb.AddHook(newTracingHook(opts...))
})
return nil
case *redis.Ring:
rdb.AddHook(newTracingHook("", opts...))
rdb.AddHook(newTracingHook(opts...))

rdb.OnNewNode(func(rdb *redis.Client) {
opt := rdb.Options()
opts = addServerAttributes(opts, opt.Addr)
connString := formatDBConnString(opt.Network, opt.Addr)
rdb.AddHook(newTracingHook(connString, opts...))
rdb.AddHook(newTracingHook(opts...))
})
return nil
default:
Expand All @@ -62,7 +59,7 @@ type tracingHook struct {

var _ redis.Hook = (*tracingHook)(nil)

func newTracingHook(connString string, opts ...TracingOption) *tracingHook {
func newTracingHook(opts ...TracingOption) *tracingHook {
baseOpts := make([]baseOption, len(opts))
for i, opt := range opts {
baseOpts[i] = opt
Expand All @@ -75,10 +72,6 @@ func newTracingHook(connString string, opts ...TracingOption) *tracingHook {
trace.WithInstrumentationVersion("semver:"+redis.Version()),
)
}
if connString != "" {
conf.attrs = append(conf.attrs, semconv.DBConnectionString(connString))
}

return &tracingHook{
conf: conf,

Expand Down Expand Up @@ -116,7 +109,7 @@ func (th *tracingHook) ProcessHook(hook redis.ProcessHook) redis.ProcessHook {

if th.conf.dbStmtEnabled {
cmdString := rediscmd.CmdString(cmd)
attrs = append(attrs, semconv.DBStatement(cmdString))
attrs = append(attrs, semconv.DBQueryText(cmdString))
}

opts := th.spanOpts
Expand Down Expand Up @@ -149,7 +142,7 @@ func (th *tracingHook) ProcessPipelineHook(

summary, cmdsString := rediscmd.CmdsString(cmds)
if th.conf.dbStmtEnabled {
attrs = append(attrs, semconv.DBStatement(cmdsString))
attrs = append(attrs, semconv.DBQueryText(cmdsString))
}

opts := th.spanOpts
Expand All @@ -173,13 +166,6 @@ func recordError(span trace.Span, err error) {
}
}

func formatDBConnString(network, addr string) string {
if network == "tcp" {
network = "redis"
}
return fmt.Sprintf("%s://%s", network, addr)
}

func funcFileLine(pkg string) (string, string, int) {
const depth = 16
var pcs [depth]uintptr
Expand Down
Loading