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 {
return func(o *Options) {
o.histogramName = name
o.durationHistogramName = name
}
}

View File

@ -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 {

134
go.go
View File

@ -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
}

2
go.mod
View File

@ -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
)

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/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=