Skip to content

Commit

Permalink
feat: add built-in metrics (#421)
Browse files Browse the repository at this point in the history
* feat: add built-in metrics

* refactor: rename buckets

* refactor: integrate with otelclient

* refactor: remove sync.once

* style: change simple

* refactor: change default dial fn

* refactor: change to cas

* refactor: rename histogramoption

* refactor: change client option as required
  • Loading branch information
proost authored Dec 14, 2023
1 parent 170c52c commit a035425
Show file tree
Hide file tree
Showing 5 changed files with 423 additions and 37 deletions.
16 changes: 8 additions & 8 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ go 1.20

require (
github.com/oklog/ulid/v2 v2.1.0
go.opentelemetry.io/otel v1.19.0
go.opentelemetry.io/otel/metric v1.19.0
go.opentelemetry.io/otel/sdk v1.19.0
go.opentelemetry.io/otel/sdk/metric v1.19.0
go.opentelemetry.io/otel/trace v1.19.0
go.opentelemetry.io/otel v1.21.0
go.opentelemetry.io/otel/metric v1.21.0
go.opentelemetry.io/otel/sdk v1.21.0
go.opentelemetry.io/otel/sdk/metric v1.21.0
go.opentelemetry.io/otel/trace v1.21.0
)

require (
Expand All @@ -18,15 +18,15 @@ require (
)

require (
github.com/go-logr/logr v1.2.4 // indirect
github.com/go-logr/logr v1.3.0 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
github.com/google/go-cmp v0.5.9 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/google/pprof v0.0.0-20230207041349-798e818bf904 // indirect
github.com/kr/pretty v0.1.0 // indirect
github.com/kr/text v0.2.0 // indirect
golang.org/x/net v0.17.0 // indirect
golang.org/x/sys v0.13.0 // indirect
golang.org/x/sys v0.14.0 // indirect
golang.org/x/text v0.13.0 // indirect
golang.org/x/tools v0.12.0 // indirect
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
Expand Down
16 changes: 16 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,17 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY=
github.com/go-logr/logr v1.3.0/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/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
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/pprof v0.0.0-20230207041349-798e818bf904 h1:4/hN5RUoecvl+RmJRE2YxKWtnnQls6rQjjW5oV7qg2U=
github.com/google/pprof v0.0.0-20230207041349-798e818bf904/go.mod h1:uglQLonpP8qtYCYyzA+8c/9qtqgA3qsXGYqCPKARAFg=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
Expand All @@ -34,21 +38,33 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
go.opentelemetry.io/otel v1.19.0 h1:MuS/TNf4/j4IXsZuJegVzI1cwut7Qc00344rgH7p8bs=
go.opentelemetry.io/otel v1.19.0/go.mod h1:i0QyjOq3UPoTzff0PJB2N66fb4S0+rSbSB15/oyH9fY=
go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc=
go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo=
go.opentelemetry.io/otel/metric v1.19.0 h1:aTzpGtV0ar9wlV4Sna9sdJyII5jTVJEvKETPiOKwvpE=
go.opentelemetry.io/otel/metric v1.19.0/go.mod h1:L5rUsV9kM1IxCj1MmSdS+JQAcVm319EUrDVLrt7jqt8=
go.opentelemetry.io/otel/metric v1.21.0 h1:tlYWfeo+Bocx5kLEloTjbcDwBuELRrIFxwdQ36PlJu4=
go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM=
go.opentelemetry.io/otel/sdk v1.19.0 h1:6USY6zH+L8uMH8L3t1enZPR3WFEmSTADlqldyHtJi3o=
go.opentelemetry.io/otel/sdk v1.19.0/go.mod h1:NedEbbS4w3C6zElbLdPJKOpJQOrGUJ+GfzpjUvI0v1A=
go.opentelemetry.io/otel/sdk v1.21.0 h1:FTt8qirL1EysG6sTQRZ5TokkU8d0ugCj8htOgThZXQ8=
go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E=
go.opentelemetry.io/otel/sdk/metric v1.19.0 h1:EJoTO5qysMsYCa+w4UghwFV/ptQgqSL/8Ni+hx+8i1k=
go.opentelemetry.io/otel/sdk/metric v1.19.0/go.mod h1:XjG0jQyFJrv2PbMvwND7LwCEhsJzCzV5210euduKcKY=
go.opentelemetry.io/otel/sdk/metric v1.21.0 h1:smhI5oD714d6jHE6Tie36fPx4WDFIg+Y6RfAY4ICcR0=
go.opentelemetry.io/otel/sdk/metric v1.21.0/go.mod h1:FJ8RAsoPGv/wYMgBdUJXOm+6pzFY3YdljnXtv1SBE8Q=
go.opentelemetry.io/otel/trace v1.19.0 h1:DFVQmlVbfVeOuBRrwdtaehRrWiL1JoVs9CPIQ1Dzxpg=
go.opentelemetry.io/otel/trace v1.19.0/go.mod h1:mfaSyvGyEJEI0nyV2I4qhNQnbBOUUmYZpYojqMnX2vo=
go.opentelemetry.io/otel/trace v1.21.0 h1:WD9i5gzvoUPuXIXH24ZNBudiarZDKuekPqi/E8fpfLc=
go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ=
go.uber.org/mock v0.3.0 h1:3mUxI1No2/60yUYax92Pt8eNOEecx2D3lcXZh2NEZJo=
go.uber.org/mock v0.3.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q=
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/tools v0.12.0 h1:YW6HUoUmYBpwSgyaGaZq1fHjrBjX1rlpZ54T6mu2kss=
Expand Down
159 changes: 159 additions & 0 deletions rueidisotel/metrics.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
package rueidisotel

import (
"context"
"crypto/tls"
"net"
"sync/atomic"
"time"

"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/metric"

"github.com/redis/rueidis"
)

var (
DefaultHistogramDefaultBuckets = []float64{
.005, .01, .025, .05, .1, .25, .5, 1, 2.5, 5, 10,
}
DefaultDialFn = func(dst string, dialer *net.Dialer, cfg *tls.Config) (conn net.Conn, err error) {
if cfg != nil {
return tls.DialWithDialer(dialer, "tcp", dst, cfg)
}
return dialer.Dial("tcp", dst)
}
)

type HistogramOption struct {
Buckets []float64
}

// WithHistogramOption sets the HistogramOption.
// If not set, DefaultHistogramDefaultBuckets will be used.
func WithHistogramOption(histogramOption HistogramOption) Option {
return func(cli *otelclient) {
cli.histogramOption = histogramOption
}
}

// NewClient creates a new Client.
// The following metrics are recorded:
// - rueidis_dial_attempt: number of dial attempts
// - rueidis_dial_success: number of successful dials
// - rueidis_dial_conns: number of active connections
// - rueidis_dial_latency: dial latency in seconds
func NewClient(clientOption rueidis.ClientOption, opts ...Option) (rueidis.Client, error) {
oclient := newClient(opts...)

if clientOption.DialFn == nil {
clientOption.DialFn = DefaultDialFn
}

attempt, err := oclient.meter.Int64Counter("rueidis_dial_attempt")
if err != nil {
return nil, err
}
oclient.attempt = attempt

success, err := oclient.meter.Int64Counter("rueidis_dial_success")
if err != nil {
return nil, err
}
oclient.success = success

conns, err := oclient.meter.Int64UpDownCounter("rueidis_dial_conns")
if err != nil {
return nil, err
}
oclient.conns = conns

dialLatency, err := oclient.meter.Float64Histogram(
"rueidis_dial_latency",
metric.WithUnit("s"),
metric.WithExplicitBucketBoundaries(oclient.histogramOption.Buckets...),
)
if err != nil {
return nil, err
}
oclient.dialLatency = dialLatency

clientOption.DialFn = trackDialing(
attempt, success, conns, dialLatency, clientOption.DialFn,
)
cli, err := rueidis.NewClient(clientOption)
if err != nil {
return nil, err
}
oclient.client = cli

return oclient, nil
}

func newClient(opts ...Option) *otelclient {
cli := &otelclient{}
for _, opt := range opts {
opt(cli)
}
if cli.histogramOption.Buckets == nil {
cli.histogramOption.Buckets = DefaultHistogramDefaultBuckets
}
if cli.meterProvider == nil {
cli.meterProvider = otel.GetMeterProvider() // Default to global MeterProvider
}
if cli.tracerProvider == nil {
cli.tracerProvider = otel.GetTracerProvider() // Default to global TracerProvider
}

// Now that we have the meterProvider and tracerProvider, get the Meter and Tracer
cli.meter = cli.meterProvider.Meter(name)
cli.tracer = cli.tracerProvider.Tracer(name)
// Now create the counters using the meter
cli.cscMiss, _ = cli.meter.Int64Counter("rueidis_do_cache_miss")
cli.cscHits, _ = cli.meter.Int64Counter("rueidis_do_cache_hits")
return cli
}

func trackDialing(
attempt metric.Int64Counter,
success metric.Int64Counter,
conns metric.Int64UpDownCounter,
dialLatency metric.Float64Histogram,
dialFn func(string, *net.Dialer, *tls.Config) (conn net.Conn, err error),
) func(string, *net.Dialer, *tls.Config) (conn net.Conn, err error) {
return func(network string, dialer *net.Dialer, tlsConfig *tls.Config) (conn net.Conn, err error) {
ctx := context.Background()
attempt.Add(ctx, 1)

start := time.Now()

conn, err = dialFn(network, dialer, tlsConfig)
if err != nil {
return nil, err
}

dialLatency.Record(ctx, time.Since(start).Seconds())
success.Add(ctx, 1)
conns.Add(ctx, 1)

return &connTracker{
Conn: conn,
conns: conns,
once: 0,
}, nil
}
}

type connTracker struct {
net.Conn
conns metric.Int64UpDownCounter
once int32
}

func (t *connTracker) Close() error {
if atomic.CompareAndSwapInt32(&t.once, 0, 1) {
t.conns.Add(context.Background(), -1)
}

return t.Conn.Close()
}
Loading

0 comments on commit a035425

Please sign in to comment.