Skip to content

Commit

Permalink
Merge pull request #1147 from flipt-io/gm/otel-metrics
Browse files Browse the repository at this point in the history
feat(metrics): move to otel abstractions for metrics recording
  • Loading branch information
GeorgeMac authored Nov 21, 2022
2 parents 41a7827 + 5eaa1e7 commit 3bd1975
Show file tree
Hide file tree
Showing 14 changed files with 207 additions and 309 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## Unreleased

### Changed

- Switched to use otel abstractions for recording metrics [#1147](https://github.com/flipt-io/flipt/pull/1147).

## [v1.15.0](https://github.com/markphelps/flipt/releases/tag/v1.15.0) - 2022-11-17

### Added
Expand Down
4 changes: 3 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,10 @@ require (
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.36.4
go.opentelemetry.io/otel v1.11.1
go.opentelemetry.io/otel/exporters/jaeger v1.11.1
go.opentelemetry.io/otel/exporters/prometheus v0.33.0
go.opentelemetry.io/otel/metric v0.33.0
go.opentelemetry.io/otel/sdk v1.11.1
go.opentelemetry.io/otel/sdk/metric v0.33.0
go.opentelemetry.io/otel/trace v1.11.1
go.uber.org/zap v1.23.0
golang.org/x/exp v0.0.0-20221012211006-4de253d81b95
Expand Down Expand Up @@ -112,7 +115,6 @@ require (
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c // indirect
go.opencensus.io v0.23.0 // indirect
go.opentelemetry.io/otel/metric v0.33.0 // indirect
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.8.0 // indirect
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e // indirect
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1348,6 +1348,8 @@ go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.3.0/go.mod h1:VpP4/RMn
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.3.0/go.mod h1:hO1KLR7jcKaDDKDkvI9dP/FIhpmna5lkqPUQdEjFAM8=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.3.0/go.mod h1:keUU7UfnwWTWpJ+FWnyqmogPa82nuU5VUANFq49hlMY=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.3.0/go.mod h1:QNX1aly8ehqqX1LEa6YniTU7VY9I6R3X/oPxhGdTceE=
go.opentelemetry.io/otel/exporters/prometheus v0.33.0 h1:xXhPj7SLKWU5/Zd4Hxmd+X1C4jdmvc0Xy+kvjFx2z60=
go.opentelemetry.io/otel/exporters/prometheus v0.33.0/go.mod h1:ZSmYfKdYWEdSDBB4njLBIwTf4AU2JNsH3n2quVQDebI=
go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU=
go.opentelemetry.io/otel/metric v0.33.0 h1:xQAyl7uGEYvrLAiV/09iTJlp1pZnQ9Wl793qbVvED1E=
go.opentelemetry.io/otel/metric v0.33.0/go.mod h1:QlTYc+EnYNq/M2mNk1qDDMRLpqCOj2f/r5c7Fd5FYaI=
Expand All @@ -1358,6 +1360,8 @@ go.opentelemetry.io/otel/sdk v1.11.1 h1:F7KmQgoHljhUuJyA+9BiU+EkJfyX5nVVF4wyzWZp
go.opentelemetry.io/otel/sdk v1.11.1/go.mod h1:/l3FE4SupHJ12TduVjUkZtlfFqDCQJlOlithYrdktys=
go.opentelemetry.io/otel/sdk/export/metric v0.20.0/go.mod h1:h7RBNMsDJ5pmI1zExLi+bJK+Dr8NQCh0qGhm1KDnNlE=
go.opentelemetry.io/otel/sdk/metric v0.20.0/go.mod h1:knxiS8Xd4E/N+ZqKmUPf3gTTZ4/0TjTXukfxjzSTpHE=
go.opentelemetry.io/otel/sdk/metric v0.33.0 h1:oTqyWfksgKoJmbrs2q7O7ahkJzt+Ipekihf8vhpa9qo=
go.opentelemetry.io/otel/sdk/metric v0.33.0/go.mod h1:xdypMeA21JBOvjjzDUtD0kzIcHO/SPez+a8HOzJPGp0=
go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw=
go.opentelemetry.io/otel/trace v1.3.0/go.mod h1:c/VDhno8888bvQYmbYLqe41/Ldmr/KKunbvWM4/fEjk=
go.opentelemetry.io/otel/trace v1.11.1 h1:ofxdnzsNrGBYXbP7t7zpUK281+go5rF7dvdIZXF8gdQ=
Expand Down
129 changes: 129 additions & 0 deletions internal/metrics/metrics.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
package metrics

import (
"log"

"go.opentelemetry.io/otel/exporters/prometheus"
"go.opentelemetry.io/otel/metric"
"go.opentelemetry.io/otel/metric/global"
"go.opentelemetry.io/otel/metric/instrument"
"go.opentelemetry.io/otel/metric/instrument/asyncint64"
"go.opentelemetry.io/otel/metric/instrument/syncint64"
sdkmetric "go.opentelemetry.io/otel/sdk/metric"
)

// Meter is the default Flipt-wide otel metric Meter.
var Meter metric.Meter

func init() {
// exporter registers itself on the prom client DefaultRegistrar
exporter, err := prometheus.New()
if err != nil {
log.Fatal(err)
}

provider := sdkmetric.NewMeterProvider(sdkmetric.WithReader(exporter))
global.SetMeterProvider(provider)

Meter = provider.Meter("github.com/flipt-io/flipt")
}

// MustSyncInt64 returns a syncint64 instrument provider based on the global Meter.
// The returns provider panics instead of returning an error when it cannot build
// a required counter, upDownCounter or histogram.
func MustSyncInt64() MustSyncInt64InstrumentProvider {
return mustSyncInt64InstrumentProvider{}
}

// MustSyncInt64InstrumentProvider is a syncint64.InstrumentProvider which panics
// if it cannot successfully build the requestd counter, upDownCounter or histogram.
type MustSyncInt64InstrumentProvider interface {
// Counter creates an instrument for recording increasing values.
Counter(name string, opts ...instrument.Option) syncint64.Counter
// UpDownCounter creates an instrument for recording changes of a value.
UpDownCounter(name string, opts ...instrument.Option) syncint64.UpDownCounter
// Histogram creates an instrument for recording a distribution of values.
Histogram(name string, opts ...instrument.Option) syncint64.Histogram
}

type mustSyncInt64InstrumentProvider struct{}

// Counter creates an instrument for recording increasing values.
func (m mustSyncInt64InstrumentProvider) Counter(name string, opts ...instrument.Option) syncint64.Counter {
counter, err := Meter.SyncInt64().Counter(name, opts...)
if err != nil {
panic(err)
}

return counter
}

// UpDownCounter creates an instrument for recording changes of a value.
func (m mustSyncInt64InstrumentProvider) UpDownCounter(name string, opts ...instrument.Option) syncint64.UpDownCounter {
counter, err := Meter.SyncInt64().UpDownCounter(name, opts...)
if err != nil {
panic(err)
}

return counter
}

// Histogram creates an instrument for recording a distribution of values.
func (m mustSyncInt64InstrumentProvider) Histogram(name string, opts ...instrument.Option) syncint64.Histogram {
hist, err := Meter.SyncInt64().Histogram(name, opts...)
if err != nil {
panic(err)
}

return hist
}

// MustAsyncInt64 returns a syncint64 instrument provider based on the global Meter.
// The returns provider panics instead of returning an error when it cannot build
// a required counter, upDownCounter or histogram.
func MustAsyncInt64() MustAsyncInt64InstrumentProvider {
return mustAsyncInt64InstrumentProvider{}
}

// MustAsyncInt64InstrumentProvider is a syncint64.InstrumentProvider which panics
// if it cannot successfully build the requestd counter, upDownCounter or histogram.
type MustAsyncInt64InstrumentProvider interface {
// Counter creates an instrument for recording increasing values.
Counter(name string, opts ...instrument.Option) asyncint64.Counter
// UpDownCounter creates an instrument for recording changes of a value.
UpDownCounter(name string, opts ...instrument.Option) asyncint64.UpDownCounter
// Histogram creates an instrument for recording a distribution of values.
Gauge(name string, opts ...instrument.Option) asyncint64.Gauge
}

type mustAsyncInt64InstrumentProvider struct{}

// Counter creates an instrument for recording increasing values.
func (m mustAsyncInt64InstrumentProvider) Counter(name string, opts ...instrument.Option) asyncint64.Counter {
counter, err := Meter.AsyncInt64().Counter(name, opts...)
if err != nil {
panic(err)
}

return counter
}

// UpDownCounter creates an instrument for recording changes of a value.
func (m mustAsyncInt64InstrumentProvider) UpDownCounter(name string, opts ...instrument.Option) asyncint64.UpDownCounter {
counter, err := Meter.AsyncInt64().UpDownCounter(name, opts...)
if err != nil {
panic(err)
}

return counter
}

// Gauge creates an instrument for recording a distribution of values.
func (m mustAsyncInt64InstrumentProvider) Gauge(name string, opts ...instrument.Option) asyncint64.Gauge {
gauge, err := Meter.AsyncInt64().Gauge(name, opts...)
if err != nil {
panic(err)
}

return gauge
}
1 change: 0 additions & 1 deletion internal/server/cache/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,4 @@ type Cacher interface {
// Delete removes a value from the cache
Delete(ctx context.Context, key string) error
fmt.Stringer
statsGetter
}
31 changes: 8 additions & 23 deletions internal/server/cache/memory/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,39 +2,32 @@ package memory

import (
"context"
"sync/atomic"

gocache "github.com/patrickmn/go-cache"
"go.flipt.io/flipt/internal/config"
"go.flipt.io/flipt/internal/server/cache"
)

const cacheType = "memory"

// Cache wraps gocache.Cache in order to implement Cacher
type Cache struct {
c *gocache.Cache
missTotal uint64
hitTotal uint64
c *gocache.Cache
}

// NewCache creates a new in memory cache with the provided cache config
func NewCache(cfg config.CacheConfig) *Cache {
var (
gc = gocache.New(cfg.TTL, cfg.Memory.EvictionInterval)
c = &Cache{c: gc}
)

cache.RegisterMetrics(c)
return c
return &Cache{c: gocache.New(cfg.TTL, cfg.Memory.EvictionInterval)}
}

func (c *Cache) Get(_ context.Context, key string) ([]byte, bool, error) {
func (c *Cache) Get(ctx context.Context, key string) ([]byte, bool, error) {
v, ok := c.c.Get(key)
if !ok {
atomic.AddUint64(&c.missTotal, 1)
cache.Observe(ctx, cacheType, cache.Miss)
return nil, false, nil
}

atomic.AddUint64(&c.hitTotal, 1)
cache.Observe(ctx, cacheType, cache.Hit)
return v.([]byte), true, nil
}

Expand All @@ -49,13 +42,5 @@ func (c *Cache) Delete(_ context.Context, key string) error {
}

func (c *Cache) String() string {
return "memory"
}

func (c *Cache) Stats() cache.Stats {
return cache.Stats{
MissTotal: c.missTotal,
HitTotal: c.hitTotal,
ErrorTotal: 0,
}
return cacheType
}
15 changes: 0 additions & 15 deletions internal/server/cache/memory/cache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,25 +37,16 @@ func TestGet(t *testing.T) {
assert.NoError(t, err)
assert.True(t, ok)
assert.Equal(t, []byte("value"), v)
assert.Equal(t, uint64(1), c.Stats().HitTotal)
assert.Equal(t, uint64(0), c.Stats().MissTotal)
assert.Equal(t, uint64(0), c.Stats().ErrorTotal)

v, ok, err = c.Get(ctx, "foo")
assert.NoError(t, err)
assert.False(t, ok)
assert.Nil(t, v)
assert.Equal(t, uint64(1), c.Stats().HitTotal)
assert.Equal(t, uint64(1), c.Stats().MissTotal)
assert.Equal(t, uint64(0), c.Stats().ErrorTotal)

v, ok, err = c.Get(ctx, "key")
assert.NoError(t, err)
assert.True(t, ok)
assert.Equal(t, []byte("value"), v)
assert.Equal(t, uint64(2), c.Stats().HitTotal)
assert.Equal(t, uint64(1), c.Stats().MissTotal)
assert.Equal(t, uint64(0), c.Stats().ErrorTotal)
}

func TestDelete(t *testing.T) {
Expand All @@ -71,9 +62,6 @@ func TestDelete(t *testing.T) {
assert.NoError(t, err)
assert.True(t, ok)
assert.Equal(t, []byte("value"), v)
assert.Equal(t, uint64(1), c.Stats().HitTotal)
assert.Equal(t, uint64(0), c.Stats().MissTotal)
assert.Equal(t, uint64(0), c.Stats().ErrorTotal)

err = c.Delete(ctx, "key")
assert.NoError(t, err)
Expand All @@ -82,7 +70,4 @@ func TestDelete(t *testing.T) {
assert.NoError(t, err)
assert.False(t, ok)
assert.Nil(t, v)
assert.Equal(t, uint64(1), c.Stats().HitTotal)
assert.Equal(t, uint64(1), c.Stats().MissTotal)
assert.Equal(t, uint64(0), c.Stats().ErrorTotal)
}
Loading

0 comments on commit 3bd1975

Please sign in to comment.