refactor: use zap

This commit is contained in:
Kevin Franklin Kim 2025-05-13 08:32:38 +02:00
parent a7193f6c54
commit 94afcde6ab
No known key found for this signature in database
5 changed files with 99 additions and 69 deletions

View File

@ -74,7 +74,7 @@ func ChannelWithCounterName[T any](name string) ChannelOption[T] {
func ChannelWithHistogramName(name string) Option { func ChannelWithHistogramName(name string) Option {
return func(o *Options) { return func(o *Options) {
o.histogramName = name o.durationHistogramName = name
} }
} }

View File

@ -7,6 +7,7 @@ import (
type contextKey string type contextKey string
const ( const (
NoNameRoutine string = "noname"
contextKeyRoutine contextKey = "routine" contextKeyRoutine contextKey = "routine"
contextKeyParentRoutine contextKey = "parentRoutine" contextKeyParentRoutine contextKey = "parentRoutine"
contextKeySender contextKey = "sender" contextKeySender contextKey = "sender"
@ -24,7 +25,7 @@ func RoutineFromContext(ctx context.Context) string {
if value, ok := ctx.Value(contextKeyRoutine).(string); ok { if value, ok := ctx.Value(contextKeyRoutine).(string); ok {
return value return value
} }
return "noname" return NoNameRoutine
} }
func injectSenderIntoContext(ctx context.Context, name string) context.Context { func injectSenderIntoContext(ctx context.Context, name string) context.Context {

134
go.go
View File

@ -4,7 +4,6 @@ import (
"context" "context"
"crypto/sha256" "crypto/sha256"
"fmt" "fmt"
"log/slog"
"os" "os"
"runtime" "runtime"
"time" "time"
@ -15,23 +14,27 @@ import (
"go.opentelemetry.io/otel/metric" "go.opentelemetry.io/otel/metric"
semconv "go.opentelemetry.io/otel/semconv/v1.30.0" semconv "go.opentelemetry.io/otel/semconv/v1.30.0"
"go.opentelemetry.io/otel/trace" "go.opentelemetry.io/otel/trace"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
) )
type ( type (
Options struct { Options struct {
l *slog.Logger l *zap.Logger
ctx context.Context //nolint:containedctx // required ctx context.Context //nolint:containedctx // required
level slog.Level level zapcore.Level
name string name string
// telemetry // telemetry
meter metric.Meter meter metric.Meter
tracer trace.Tracer tracer trace.Tracer
counter metric.Int64UpDownCounter totalCounter metric.Int64Counter
counterName string totalCounterName string
histogram metric.Int64Histogram runningCounter metric.Int64UpDownCounter
histogramName string runningCounterName string
histogramEnabled bool durationHistogram metric.Int64Histogram
telemetryEnabled bool durationHistogramName string
durationHistogramEnabled bool
telemetryEnabled bool
} }
Option func(*Options) Option func(*Options)
) )
@ -48,13 +51,13 @@ func WithContext(ctx context.Context) Option {
} }
} }
func WithLogger(l *slog.Logger) Option { func WithLogger(l *zap.Logger) Option {
return func(o *Options) { return func(o *Options) {
o.l = l o.l = l
} }
} }
func WithLogLevel(level slog.Level) Option { func WithLogLevel(level zapcore.Level) Option {
return func(o *Options) { return func(o *Options) {
o.level = level o.level = level
} }
@ -72,31 +75,38 @@ func WithTracer(v trace.Tracer) Option {
} }
} }
func WithCounterName(name string) Option { func WithTotalCounterName(name string) Option {
return func(o *Options) { return func(o *Options) {
o.counterName = name o.totalCounterName = name
} }
} }
func WithHistogramEnabled(v bool) Option { func WithRunningCounterName(name string) Option {
return func(o *Options) { return func(o *Options) {
o.histogramEnabled = v o.runningCounterName = name
}
}
func WithDurationHistogramEnabled(v bool) Option {
return func(o *Options) {
o.durationHistogramEnabled = v
} }
} }
func WithHistogramName(name string) Option { func WithHistogramName(name string) Option {
return func(o *Options) { return func(o *Options) {
o.histogramName = name o.durationHistogramName = name
} }
} }
func Go(fn Func, opts ...Option) <-chan error { func Go(fn Func, opts ...Option) <-chan error {
o := &Options{ o := &Options{
l: slog.Default(), l: zap.NewNop(),
level: slog.LevelDebug, level: zapcore.DebugLevel,
counterName: "gofuncy.routine.count", totalCounterName: "gofuncy.routine.total.count",
histogramName: "gofuncy.routine.duration", runningCounterName: "gofuncy.routine.running.count",
telemetryEnabled: os.Getenv("OTEL_ENABLED") == "true", durationHistogramName: "gofuncy.routine.duration",
telemetryEnabled: os.Getenv("OTEL_ENABLED") == "true",
} }
for _, opt := range opts { for _, opt := range opts {
@ -125,74 +135,86 @@ func Go(fn Func, opts ...Option) <-chan error {
} }
} }
if o.meter != nil { if o.meter != nil {
if value, err := o.meter.Int64UpDownCounter( if value, err := o.meter.Int64Counter(
o.counterName, o.totalCounterName,
metric.WithDescription("Gofuncy routine counter"), metric.WithDescription("Gofuncy total go routine count"),
); err != nil { ); err != nil {
o.l.Error("failed to initialize counter", "error", err) o.l.Error("failed to initialize counter", zap.Error(err))
} else { } else {
o.counter = value o.totalCounter = value
}
if value, err := o.meter.Int64UpDownCounter(
o.runningCounterName,
metric.WithDescription("Gofuncy running go routine count"),
); err != nil {
o.l.Error("failed to initialize counter", zap.Error(err))
} else {
o.runningCounter = value
} }
} }
if o.meter != nil && o.histogramEnabled { if o.meter != nil && o.durationHistogramEnabled {
if value, err := o.meter.Int64Histogram( if value, err := o.meter.Int64Histogram(
o.histogramName, o.durationHistogramName,
metric.WithDescription("Gofuncy routine duration histogram"), metric.WithDescription("Gofuncy go routine duration histogram"),
); err != nil { ); err != nil {
o.l.Error("failed to initialize histogram", "error", err) o.l.Error("failed to initialize histogram", zap.Error(err))
} else { } else {
o.histogram = value o.durationHistogram = value
} }
} }
delay := time.Now()
errChan := make(chan error, 1) errChan := make(chan error, 1)
go func(o *Options, errChan chan<- error) { go func(o *Options, errChan chan<- error) {
var err error var err error
defer func() {
o.l.Info("gofuncy --> closing chan")
close(errChan)
o.l.Info("gofuncy --> closing chan")
}()
ctx := o.ctx ctx := o.ctx
start := time.Now() start := time.Now()
l := o.l.With("name", o.name) defer close(errChan)
if value := RoutineFromContext(ctx); value != "" { l := o.l.With(zap.String("name", o.name))
l = l.With("parent", value) if value := RoutineFromContext(ctx); value != NoNameRoutine {
l = l.With(zap.String("parent", value))
} }
var span trace.Span var span trace.Span
if o.tracer != nil { if o.tracer != nil {
ctx, span = o.tracer.Start(o.ctx, o.name) ctx, span = o.tracer.Start(o.ctx, o.name)
if span.IsRecording() { if span.IsRecording() {
l = l.With("trace_id", span.SpanContext().TraceID().String()) l = l.With(zap.String("trace_id", span.SpanContext().TraceID().String()))
} }
defer span.End() defer span.End()
} }
l.Log(ctx, o.level, "starting gofuncy routine") l.Log(o.level, "starting gofuncy routine",
zap.Duration("delay", time.Since(delay).Round(time.Millisecond)),
)
defer func() { defer func() {
if err != nil { l.Log(o.level, "exiting gofuncy routine",
l = l.With("error", err.Error()) zap.Duration("duration", time.Since(start).Round(time.Millisecond)),
} zap.Error(err),
l.Log(ctx, o.level, "exiting gofuncy routine", "duration", time.Since(start).Round(time.Millisecond).String()) )
}() }()
// create telemetry if enabled // create telemetry if enabled
if o.counter != nil { attrs := metric.WithAttributes(semconv.ProcessRuntimeName(o.name))
attrs := metric.WithAttributes(semconv.ProcessRuntimeName(o.name)) if o.runningCounter != nil {
o.counter.Add(ctx, 1, attrs) o.runningCounter.Add(ctx, 1, attrs)
defer o.counter.Add(ctx, -1, attrs) defer o.runningCounter.Add(ctx, -1, attrs)
} }
if o.histogram != nil { if o.totalCounter != nil {
start := time.Now() o.totalCounter.Add(ctx, 1, attrs)
defer o.histogram.Record(ctx, time.Since(start).Milliseconds(), metric.WithAttributes( defer o.runningCounter.Add(ctx, -1, attrs, metric.WithAttributes(
semconv.ProcessRuntimeName(o.name),
attribute.Bool("error", err != nil), attribute.Bool("error", err != nil),
)) ))
} }
if o.durationHistogram != nil {
defer func() {
o.durationHistogram.Record(ctx, time.Since(start).Milliseconds(), attrs, metric.WithAttributes(
attribute.Bool("error", err != nil),
))
}()
}
ctx = injectParentRoutineIntoContext(ctx, RoutineFromContext(ctx)) ctx = injectParentRoutineIntoContext(ctx, RoutineFromContext(ctx))
ctx = injectRoutineIntoContext(ctx, o.name) ctx = injectRoutineIntoContext(ctx, o.name)
err = fn(ctx) err = fn(ctx)
errChan <- err errChan <- err
}(o, errChan) }(o, errChan)
o.l.Info("gofuncy --> returning")
return errChan return errChan
} }

2
go.mod
View File

@ -8,6 +8,7 @@ require (
go.opentelemetry.io/otel v1.35.0 go.opentelemetry.io/otel v1.35.0
go.opentelemetry.io/otel/metric v1.35.0 go.opentelemetry.io/otel/metric v1.35.0
go.opentelemetry.io/otel/trace v1.35.0 go.opentelemetry.io/otel/trace v1.35.0
go.uber.org/zap v1.27.0
) )
require ( require (
@ -17,5 +18,6 @@ require (
github.com/google/uuid v1.6.0 // indirect github.com/google/uuid v1.6.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
) )

27
go.sum
View File

@ -7,31 +7,36 @@ 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/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 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= 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.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= 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/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 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/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo=
go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4=
go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ= go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ=
go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y= go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y=
go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q=
go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s=
go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M= go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M=
go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE= go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE=
go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g=
go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI=
go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs= go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs=
go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc= go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=