From 94afcde6abbef8621ccc4821c3ecfcbdf85b6743 Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Tue, 13 May 2025 08:32:38 +0200 Subject: [PATCH] refactor: use zap --- channel.go | 2 +- context.go | 3 +- go.go | 134 +++++++++++++++++++++++++++++++---------------------- go.mod | 2 + go.sum | 27 ++++++----- 5 files changed, 99 insertions(+), 69 deletions(-) diff --git a/channel.go b/channel.go index 290e339..46c07a3 100644 --- a/channel.go +++ b/channel.go @@ -74,7 +74,7 @@ func ChannelWithCounterName[T any](name string) ChannelOption[T] { func ChannelWithHistogramName(name string) Option { return func(o *Options) { - o.histogramName = name + o.durationHistogramName = name } } diff --git a/context.go b/context.go index 3dcf4a7..587d4c2 100644 --- a/context.go +++ b/context.go @@ -7,6 +7,7 @@ import ( type contextKey string const ( + NoNameRoutine string = "noname" contextKeyRoutine contextKey = "routine" contextKeyParentRoutine contextKey = "parentRoutine" contextKeySender contextKey = "sender" @@ -24,7 +25,7 @@ func RoutineFromContext(ctx context.Context) string { if value, ok := ctx.Value(contextKeyRoutine).(string); ok { return value } - return "noname" + return NoNameRoutine } func injectSenderIntoContext(ctx context.Context, name string) context.Context { diff --git a/go.go b/go.go index 2d7e620..ff6d100 100644 --- a/go.go +++ b/go.go @@ -4,7 +4,6 @@ import ( "context" "crypto/sha256" "fmt" - "log/slog" "os" "runtime" "time" @@ -15,23 +14,27 @@ import ( "go.opentelemetry.io/otel/metric" semconv "go.opentelemetry.io/otel/semconv/v1.30.0" "go.opentelemetry.io/otel/trace" + "go.uber.org/zap" + "go.uber.org/zap/zapcore" ) type ( Options struct { - l *slog.Logger + l *zap.Logger ctx context.Context //nolint:containedctx // required - level slog.Level + level zapcore.Level name string // telemetry - meter metric.Meter - tracer trace.Tracer - counter metric.Int64UpDownCounter - counterName string - histogram metric.Int64Histogram - histogramName string - histogramEnabled bool - telemetryEnabled bool + meter metric.Meter + tracer trace.Tracer + totalCounter metric.Int64Counter + totalCounterName string + runningCounter metric.Int64UpDownCounter + runningCounterName string + durationHistogram metric.Int64Histogram + durationHistogramName string + durationHistogramEnabled bool + telemetryEnabled bool } 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) { o.l = l } } -func WithLogLevel(level slog.Level) Option { +func WithLogLevel(level zapcore.Level) Option { return func(o *Options) { 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) { - o.counterName = name + o.totalCounterName = name } } -func WithHistogramEnabled(v bool) Option { +func WithRunningCounterName(name string) Option { 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 { return func(o *Options) { - o.histogramName = name + o.durationHistogramName = name } } func Go(fn Func, opts ...Option) <-chan error { o := &Options{ - l: slog.Default(), - level: slog.LevelDebug, - counterName: "gofuncy.routine.count", - histogramName: "gofuncy.routine.duration", - telemetryEnabled: os.Getenv("OTEL_ENABLED") == "true", + l: zap.NewNop(), + level: zapcore.DebugLevel, + totalCounterName: "gofuncy.routine.total.count", + runningCounterName: "gofuncy.routine.running.count", + durationHistogramName: "gofuncy.routine.duration", + telemetryEnabled: os.Getenv("OTEL_ENABLED") == "true", } for _, opt := range opts { @@ -125,74 +135,86 @@ func Go(fn Func, opts ...Option) <-chan error { } } if o.meter != nil { - if value, err := o.meter.Int64UpDownCounter( - o.counterName, - metric.WithDescription("Gofuncy routine counter"), + if value, err := o.meter.Int64Counter( + o.totalCounterName, + metric.WithDescription("Gofuncy total go routine count"), ); err != nil { - o.l.Error("failed to initialize counter", "error", err) + o.l.Error("failed to initialize counter", zap.Error(err)) } 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( - o.histogramName, - metric.WithDescription("Gofuncy routine duration histogram"), + o.durationHistogramName, + metric.WithDescription("Gofuncy go routine duration histogram"), ); err != nil { - o.l.Error("failed to initialize histogram", "error", err) + o.l.Error("failed to initialize histogram", zap.Error(err)) } else { - o.histogram = value + o.durationHistogram = value } } + delay := time.Now() errChan := make(chan error, 1) go func(o *Options, errChan chan<- error) { var err error - defer func() { - o.l.Info("gofuncy --> closing chan") - close(errChan) - o.l.Info("gofuncy --> closing chan") - }() ctx := o.ctx start := time.Now() - l := o.l.With("name", o.name) - if value := RoutineFromContext(ctx); value != "" { - l = l.With("parent", value) + defer close(errChan) + l := o.l.With(zap.String("name", o.name)) + if value := RoutineFromContext(ctx); value != NoNameRoutine { + l = l.With(zap.String("parent", value)) } var span trace.Span if o.tracer != nil { ctx, span = o.tracer.Start(o.ctx, o.name) 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() } - 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() { - if err != nil { - l = l.With("error", err.Error()) - } - l.Log(ctx, o.level, "exiting gofuncy routine", "duration", time.Since(start).Round(time.Millisecond).String()) + l.Log(o.level, "exiting gofuncy routine", + zap.Duration("duration", time.Since(start).Round(time.Millisecond)), + zap.Error(err), + ) }() // create telemetry if enabled - if o.counter != nil { - attrs := metric.WithAttributes(semconv.ProcessRuntimeName(o.name)) - o.counter.Add(ctx, 1, attrs) - defer o.counter.Add(ctx, -1, attrs) + attrs := metric.WithAttributes(semconv.ProcessRuntimeName(o.name)) + if o.runningCounter != nil { + o.runningCounter.Add(ctx, 1, attrs) + defer o.runningCounter.Add(ctx, -1, attrs) } - if o.histogram != nil { - start := time.Now() - defer o.histogram.Record(ctx, time.Since(start).Milliseconds(), metric.WithAttributes( - semconv.ProcessRuntimeName(o.name), + if o.totalCounter != nil { + o.totalCounter.Add(ctx, 1, attrs) + defer o.runningCounter.Add(ctx, -1, attrs, metric.WithAttributes( 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 = injectRoutineIntoContext(ctx, o.name) err = fn(ctx) errChan <- err }(o, errChan) - o.l.Info("gofuncy --> returning") return errChan } diff --git a/go.mod b/go.mod index 74ab2d9..3381ffd 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,7 @@ require ( go.opentelemetry.io/otel v1.35.0 go.opentelemetry.io/otel/metric v1.35.0 go.opentelemetry.io/otel/trace v1.35.0 + go.uber.org/zap v1.27.0 ) require ( @@ -17,5 +18,6 @@ require ( github.com/google/uuid v1.6.0 // indirect github.com/pmezard/go-difflib v1.0.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 ) diff --git a/go.sum b/go.sum index a1eb8b7..912b3e0 100644 --- a/go.sum +++ b/go.sum @@ -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/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/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +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/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/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= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +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/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/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/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/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/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 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/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=