Skip to content

Commit

Permalink
fix(#18): implement shutdown for tracer and meter (#21)
Browse files Browse the repository at this point in the history
  • Loading branch information
tessig authored Sep 17, 2024
1 parent 76ced0f commit 20dc9d8
Show file tree
Hide file tree
Showing 10 changed files with 271 additions and 26 deletions.
12 changes: 12 additions & 0 deletions .mockery.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
with-expecter: true
disable-version-string: true
inpackage: false
mockname: "{{.InterfaceName}}"
filename: "{{.InterfaceNameSnake}}.go"
outpkg: "mocks"
dir: "{{.InterfaceDirRelative}}/mocks"

packages:
"flamingo.me/opentelemetry":
interfaces:
Shutdowner:
17 changes: 9 additions & 8 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,18 +47,18 @@ Flamingo's `URLPrefixSampler` and config from `flamingo.opencensus.tracing.sampl
Before you can create your own spans, you have to initialize a tracer:

```go
tracer := otel.Tracer("my-app")
var tracer = otel.Tracer("my-app", trace.WithInstrumentationVersion("1.2.3"))
```

Now you can create a span based on a `context.Context`. This will automatically attach all tracing-relevant
information (e.g. trace-ID) to the span.

```go
func doSomething(ctx context.Context) {
ctx, span := tracer.Start(ctx, "my-span")
defer span.End()

// do some work to track with my-span
ctx, span := tracer.Start(ctx, "my-span")
defer span.End()
// do some work to track with my-span
}
```

Expand All @@ -70,14 +70,15 @@ official [OpenTelemetry documentation](https://opentelemetry.io/docs/instrumenta
To collect your own metrics, you have to initialize a meter:

```go
meter := otel.Meter("my-app")
var meter = otel.Meter("my-app", metric.WithInstrumentationVersion("1.2.3"))
```

Now you can create a new metric, e.g. a counter:

```go
counter, _ := meter.Int64Counter("my.count",
metric.WithDescription("count of something"),
counter, _ := meter.Int64Counter("my.count",
metric.WithDescription("count of something"),
metric.WithUnit("{something}")
)

counter.Add(ctx, 1)
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ require (
github.com/redis/go-redis/v9 v9.6.1 // indirect
github.com/spf13/cobra v1.8.1 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/stretchr/objx v0.5.2 // indirect
github.com/zemirco/memorystore v0.0.0-20160308183530-ecd57e5134f6 // indirect
go.opencensus.io v0.24.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.30.0 // indirect
Expand Down
10 changes: 2 additions & 8 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,6 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk=
github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
Expand Down Expand Up @@ -133,6 +131,8 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.2.0/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
Expand All @@ -143,18 +143,12 @@ github.com/zemirco/memorystore v0.0.0-20160308183530-ecd57e5134f6 h1:j+ZgVPhfLkC
github.com/zemirco/memorystore v0.0.0-20160308183530-ecd57e5134f6/go.mod h1:PLhuixMlky6sB4/LEnpp1//u2BcRF2pKUYXLMVyOrIc=
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 h1:x8Z78aZx8cOF0+Kkazoc7lwUNMGy0LrzEMxTm4BbTxg=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0/go.mod h1:62CPTSry9QZtOaSsE3tOzhx6LzDhHnXJ6xHeMNNiM6Q=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 h1:TT4fX+nBOA/+LUkobKGW1ydGcn+G3vRw9+g5HwCphpk=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8=
go.opentelemetry.io/contrib/instrumentation/runtime v0.45.0 h1:2JydY5UiDpqvj2p7sO9bgHuhTy4hgTZ0ymehdq/Ob0Q=
go.opentelemetry.io/contrib/instrumentation/runtime v0.45.0/go.mod h1:ch3a5QxOqVWxas4CzjCFFOOQe+7HgAXC/N1oVxS9DK4=
go.opentelemetry.io/contrib/instrumentation/runtime v0.54.0 h1:KD+8SJvRaW9n0vE0UgkytT207J3CmV1hGf9GYYU73ns=
go.opentelemetry.io/contrib/instrumentation/runtime v0.54.0/go.mod h1:/CsTuLR28IN3Vn13YEc72HljfHiGOMXiCbl4xiCSDhA=
go.opentelemetry.io/otel v1.30.0 h1:F2t8sK4qf1fAmY9ua4ohFS/K+FUuOPemHUIXHtktrts=
go.opentelemetry.io/otel v1.30.0/go.mod h1:tFw4Br9b7fOS+uEao81PJjVMjW/5fvNCbpsDIXqP0pc=
go.opentelemetry.io/otel/bridge/opencensus v0.45.0 h1:kEOlv9Exuv3J8GCf1nLMHfrTPGnZOuIkN8YlRM14TtQ=
go.opentelemetry.io/otel/bridge/opencensus v0.45.0/go.mod h1:tkVMJeFOr43+zzwbxtIWsNcCCDT7rI5/c9rhMfMIENg=
go.opentelemetry.io/otel/bridge/opencensus v1.30.0 h1:F6WsF4aSV6g6IBiK4NZ8gWNHqFjtwxrEsUnrYEGyBSw=
go.opentelemetry.io/otel/bridge/opencensus v1.30.0/go.mod h1:3FOD7DbLQhWLxwnzbYoT1oHucvoQIqLXHez1u2KIxMc=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.30.0 h1:lsInsfvhVIfOI6qHVyysXMNDnjO9Npvl7tlDPJFBVd4=
Expand Down
82 changes: 82 additions & 0 deletions mocks/shutdowner.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions module.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package opentelemetry

//go:generate go run github.com/vektra/mockery/[email protected]

import (
"context"
"fmt"
Expand Down Expand Up @@ -69,6 +71,8 @@ func (m *Module) Inject(
func (m *Module) Configure(injector *dingo.Injector) {
http.DefaultTransport = &correlationIDInjector{next: otelhttp.NewTransport(http.DefaultTransport)}

flamingo.BindEventSubscriber(injector).To(new(Listener))

m.initTraces()
m.initMetrics(injector)
}
Expand Down
28 changes: 28 additions & 0 deletions module_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package opentelemetry_test

import (
"testing"

"flamingo.me/dingo"
"flamingo.me/flamingo/v3/framework/config"
"flamingo.me/flamingo/v3/framework/flamingo"

"flamingo.me/opentelemetry"
)

type (
loggerModule struct{}
)

// Configure DI
func (m *loggerModule) Configure(injector *dingo.Injector) {
injector.Bind(new(flamingo.Logger)).To(new(flamingo.NullLogger))
}

func TestModule_Configure(t *testing.T) {
t.Parallel()

if err := config.TryModules(nil, new(loggerModule), new(opentelemetry.Module)); err != nil {
t.Error(err)
}
}
56 changes: 56 additions & 0 deletions shutdown.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package opentelemetry

import (
"context"

"flamingo.me/flamingo/v3/framework/flamingo"
"go.opentelemetry.io/otel"
)

type (
Shutdowner interface {
Shutdown(ctx context.Context) error
}

Listener struct {
logger flamingo.Logger
}
)

// Inject dependencies
func (l *Listener) Inject(
logger flamingo.Logger,
) *Listener {
l.logger = logger

return l
}

func (l *Listener) Notify(ctx context.Context, event flamingo.Event) {
if _, ok := event.(*flamingo.ShutdownEvent); ok {
tp := otel.GetTracerProvider()
if s, ok := tp.(Shutdowner); ok {
l.shutdown(ctx, s)
}

mp := otel.GetMeterProvider()
if s, ok := mp.(Shutdowner); ok {
l.shutdown(ctx, s)
}
}
}

func (l *Listener) shutdown(ctx context.Context, s Shutdowner) {
l.log().Debugf("Shutdown OpenTelemetry: %T", s)

err := s.Shutdown(ctx)
if err != nil {
l.log().Error("", err)
}
}

func (l *Listener) log() flamingo.Logger {
return l.logger.
WithField(flamingo.LogKeyModule, "opentelemetry").
WithField(flamingo.LogKeyCategory, "Shutdown")
}
77 changes: 77 additions & 0 deletions shutdown_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package opentelemetry_test

import (
"context"
"errors"
"testing"

"flamingo.me/flamingo/v3/framework/flamingo"
"go.opentelemetry.io/otel"
noopMetric "go.opentelemetry.io/otel/metric/noop"
noopTrace "go.opentelemetry.io/otel/trace/noop"

"flamingo.me/opentelemetry"
"flamingo.me/opentelemetry/mocks"
)

type (
tracerProvider struct {
noopTrace.TracerProvider
mocks.Shutdowner
}

meterProvider struct {
noopMetric.MeterProvider
mocks.Shutdowner
}
)

var errShutdown = errors.New("shutdown error")

func TestListener_Notify(t *testing.T) { //nolint:tparallel // no parallel subtests possible because of global state manipulation
t.Parallel()

type args struct {
event flamingo.Event
}

tests := []struct {
name string
args args
traceShutdownError error
meterShutdownError error
}{
{
name: "shutdown meter and tracer successfully",
args: args{
event: new(flamingo.ShutdownEvent),
},
traceShutdownError: nil,
meterShutdownError: nil,
},
{
name: "error on shutdown meter and tracer",
args: args{
event: new(flamingo.ShutdownEvent),
},
traceShutdownError: errShutdown,
meterShutdownError: errShutdown,
},
}

for _, tt := range tests { //nolint:paralleltest // no parallel test possible because of global state manipulation
t.Run(tt.name, func(t *testing.T) {
tp := new(tracerProvider)
tp.Shutdowner.EXPECT().Shutdown(context.Background()).Once().Return(tt.traceShutdownError)
otel.SetTracerProvider(tp)

mp := new(meterProvider)
mp.Shutdowner.EXPECT().Shutdown(context.Background()).Once().Return(tt.meterShutdownError)
otel.SetMeterProvider(mp)

l := new(opentelemetry.Listener).Inject(new(flamingo.NullLogger))

l.Notify(context.Background(), tt.args.event)
})
}
}
10 changes: 0 additions & 10 deletions version.go

This file was deleted.

0 comments on commit 20dc9d8

Please sign in to comment.