From 91dff05755d960ca8fc5e0475c7ecb92ae5cb975 Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Fri, 31 Jul 2026 12:14:09 +0200 Subject: [PATCH 01/23] feat: bump foomo/go --- examples/go.mod | 2 +- examples/go.sum | 4 ++-- go.mod | 3 ++- go.sum | 4 ++-- integration/gotsrpc/go.mod | 2 +- integration/gotsrpc/go.sum | 4 ++-- integration/nats/go.mod | 2 +- integration/nats/go.sum | 4 ++-- integration/temporal/go.mod | 2 +- integration/temporal/go.sum | 4 ++-- internal/runtimeutil/caller.go | 2 +- net/stream/go.mod | 2 +- net/stream/go.sum | 4 ++-- telemetry/main_test.go | 11 +++++++++++ 14 files changed, 31 insertions(+), 19 deletions(-) create mode 100644 telemetry/main_test.go diff --git a/examples/go.mod b/examples/go.mod index e8b7e51..f0aae29 100644 --- a/examples/go.mod +++ b/examples/go.mod @@ -45,7 +45,7 @@ require ( github.com/fatih/color v1.19.0 // indirect github.com/fbiville/markdown-table-formatter v0.3.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect - github.com/foomo/go v0.14.1 // indirect + github.com/foomo/go v0.15.0 // indirect github.com/foomo/goflux v0.4.4 // indirect github.com/foomo/gofuncy v0.2.0 // indirect github.com/foomo/gostandards v0.3.0 // indirect diff --git a/examples/go.sum b/examples/go.sum index 97a048b..4964378 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -102,8 +102,8 @@ github.com/fbiville/markdown-table-formatter v0.3.0 h1:PIm1UNgJrFs8q1htGTw+wnnNY github.com/fbiville/markdown-table-formatter v0.3.0/go.mod h1:q89TDtSEVDdTaufgSbfHpNVdPU/bmfvqNkrC5HagmLY= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/foomo/go v0.14.1 h1:33ePCyAClSj2pqcEI9isyiEe1qoMd6c+Mn0ClLntSoM= -github.com/foomo/go v0.14.1/go.mod h1:jeSB/atkoqSoJ3+ak0+b/Xtj7IMyDj1odzJroudT7Dw= +github.com/foomo/go v0.15.0 h1:i6bcReoSLPpRVUVsd7anB6BCVBNimaOjiDeI+9I9rq0= +github.com/foomo/go v0.15.0/go.mod h1:jeSB/atkoqSoJ3+ak0+b/Xtj7IMyDj1odzJroudT7Dw= github.com/foomo/goflux v0.4.4 h1:T7QhIPdZze3bNEeNjdEAzBV08/ikEgmTmK3maWucAo4= github.com/foomo/goflux v0.4.4/go.mod h1:c2qy02JR9Y5qlVl49nDSEipCQENbGhDZzjT8p72G7Xs= github.com/foomo/gofuncy v0.2.0 h1:fanMIpHocWfoP+u8sevF+Qb/gEh38QeiS6FjeXB+Sx0= diff --git a/go.mod b/go.mod index dec8a17..c99929a 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.26.0 require ( github.com/avast/retry-go/v4 v4.7.0 github.com/fbiville/markdown-table-formatter v0.3.0 - github.com/foomo/go v0.14.1 + github.com/foomo/go v0.15.0 github.com/foomo/goflux v0.4.4 github.com/foomo/gofuncy v0.2.0 github.com/foomo/gostandards v0.3.0 @@ -48,6 +48,7 @@ require ( go.opentelemetry.io/otel/sdk/log v0.20.0 go.opentelemetry.io/otel/sdk/metric v1.44.0 go.opentelemetry.io/otel/trace v1.44.0 + go.uber.org/goleak v1.3.0 go.uber.org/zap v1.28.0 golang.org/x/crypto v0.54.0 golang.org/x/sync v0.22.0 diff --git a/go.sum b/go.sum index b927d3e..176fed8 100644 --- a/go.sum +++ b/go.sum @@ -78,8 +78,8 @@ github.com/fbiville/markdown-table-formatter v0.3.0 h1:PIm1UNgJrFs8q1htGTw+wnnNY github.com/fbiville/markdown-table-formatter v0.3.0/go.mod h1:q89TDtSEVDdTaufgSbfHpNVdPU/bmfvqNkrC5HagmLY= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/foomo/go v0.14.1 h1:33ePCyAClSj2pqcEI9isyiEe1qoMd6c+Mn0ClLntSoM= -github.com/foomo/go v0.14.1/go.mod h1:jeSB/atkoqSoJ3+ak0+b/Xtj7IMyDj1odzJroudT7Dw= +github.com/foomo/go v0.15.0 h1:i6bcReoSLPpRVUVsd7anB6BCVBNimaOjiDeI+9I9rq0= +github.com/foomo/go v0.15.0/go.mod h1:jeSB/atkoqSoJ3+ak0+b/Xtj7IMyDj1odzJroudT7Dw= github.com/foomo/goflux v0.4.4 h1:T7QhIPdZze3bNEeNjdEAzBV08/ikEgmTmK3maWucAo4= github.com/foomo/goflux v0.4.4/go.mod h1:c2qy02JR9Y5qlVl49nDSEipCQENbGhDZzjT8p72G7Xs= github.com/foomo/gofuncy v0.2.0 h1:fanMIpHocWfoP+u8sevF+Qb/gEh38QeiS6FjeXB+Sx0= diff --git a/integration/gotsrpc/go.mod b/integration/gotsrpc/go.mod index 7ded885..e290580 100644 --- a/integration/gotsrpc/go.mod +++ b/integration/gotsrpc/go.mod @@ -20,7 +20,7 @@ require ( github.com/ebitengine/purego v0.10.1 // indirect github.com/fbiville/markdown-table-formatter v0.3.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect - github.com/foomo/go v0.14.1 // indirect + github.com/foomo/go v0.15.0 // indirect github.com/foomo/gostandards v0.3.0 // indirect github.com/foomo/opentelemetry-go v0.4.0 // indirect github.com/go-logr/logr v1.4.4 // indirect diff --git a/integration/gotsrpc/go.sum b/integration/gotsrpc/go.sum index f3b5f32..10c4e47 100644 --- a/integration/gotsrpc/go.sum +++ b/integration/gotsrpc/go.sum @@ -19,8 +19,8 @@ github.com/fbiville/markdown-table-formatter v0.3.0 h1:PIm1UNgJrFs8q1htGTw+wnnNY github.com/fbiville/markdown-table-formatter v0.3.0/go.mod h1:q89TDtSEVDdTaufgSbfHpNVdPU/bmfvqNkrC5HagmLY= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/foomo/go v0.14.1 h1:33ePCyAClSj2pqcEI9isyiEe1qoMd6c+Mn0ClLntSoM= -github.com/foomo/go v0.14.1/go.mod h1:jeSB/atkoqSoJ3+ak0+b/Xtj7IMyDj1odzJroudT7Dw= +github.com/foomo/go v0.15.0 h1:i6bcReoSLPpRVUVsd7anB6BCVBNimaOjiDeI+9I9rq0= +github.com/foomo/go v0.15.0/go.mod h1:jeSB/atkoqSoJ3+ak0+b/Xtj7IMyDj1odzJroudT7Dw= github.com/foomo/gostandards v0.3.0 h1:Ev88Tdu0+52UH/d0l2KcAWx542A13o42d++LSTG0DC4= github.com/foomo/gostandards v0.3.0/go.mod h1:8hJ56tpyFAVwavs5FuUF3po7Bq7hOTkQ1+DzFi4GCWg= github.com/foomo/gotsrpc/v2 v2.16.1 h1:ih/YRUJpO3DOpw6cWXOVS4b6nOmfXxF+zudptxYFLxs= diff --git a/integration/nats/go.mod b/integration/nats/go.mod index d21d57c..03e1b86 100644 --- a/integration/nats/go.mod +++ b/integration/nats/go.mod @@ -5,7 +5,7 @@ go 1.26.0 replace github.com/foomo/keel => ../../ require ( - github.com/foomo/go v0.14.1 + github.com/foomo/go v0.15.0 github.com/foomo/gofuncy v0.2.0 github.com/foomo/keel v0.27.1 github.com/foomo/opentelemetry-go v0.4.0 diff --git a/integration/nats/go.sum b/integration/nats/go.sum index 1ff4478..a06d11a 100644 --- a/integration/nats/go.sum +++ b/integration/nats/go.sum @@ -76,8 +76,8 @@ github.com/fbiville/markdown-table-formatter v0.3.0 h1:PIm1UNgJrFs8q1htGTw+wnnNY github.com/fbiville/markdown-table-formatter v0.3.0/go.mod h1:q89TDtSEVDdTaufgSbfHpNVdPU/bmfvqNkrC5HagmLY= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/foomo/go v0.14.1 h1:33ePCyAClSj2pqcEI9isyiEe1qoMd6c+Mn0ClLntSoM= -github.com/foomo/go v0.14.1/go.mod h1:jeSB/atkoqSoJ3+ak0+b/Xtj7IMyDj1odzJroudT7Dw= +github.com/foomo/go v0.15.0 h1:i6bcReoSLPpRVUVsd7anB6BCVBNimaOjiDeI+9I9rq0= +github.com/foomo/go v0.15.0/go.mod h1:jeSB/atkoqSoJ3+ak0+b/Xtj7IMyDj1odzJroudT7Dw= github.com/foomo/goflux v0.4.4 h1:T7QhIPdZze3bNEeNjdEAzBV08/ikEgmTmK3maWucAo4= github.com/foomo/goflux v0.4.4/go.mod h1:c2qy02JR9Y5qlVl49nDSEipCQENbGhDZzjT8p72G7Xs= github.com/foomo/gofuncy v0.2.0 h1:fanMIpHocWfoP+u8sevF+Qb/gEh38QeiS6FjeXB+Sx0= diff --git a/integration/temporal/go.mod b/integration/temporal/go.mod index 1a2af8b..67809e2 100644 --- a/integration/temporal/go.mod +++ b/integration/temporal/go.mod @@ -5,7 +5,7 @@ go 1.26.0 replace github.com/foomo/keel => ../../ require ( - github.com/foomo/go v0.14.1 + github.com/foomo/go v0.15.0 github.com/foomo/keel v0.27.1 github.com/pkg/errors v0.9.1 go.opentelemetry.io/otel v1.44.0 diff --git a/integration/temporal/go.sum b/integration/temporal/go.sum index 03e9342..e55b19a 100644 --- a/integration/temporal/go.sum +++ b/integration/temporal/go.sum @@ -12,8 +12,8 @@ github.com/facebookgo/clock v0.0.0-20150410010913-600d898af40a h1:yDWHCSQ40h88yi github.com/facebookgo/clock v0.0.0-20150410010913-600d898af40a/go.mod h1:7Ga40egUymuWXxAe151lTNnCv97MddSOVsjpPPkityA= github.com/fbiville/markdown-table-formatter v0.3.0 h1:PIm1UNgJrFs8q1htGTw+wnnNYvwXQMMMIKNZop2SSho= github.com/fbiville/markdown-table-formatter v0.3.0/go.mod h1:q89TDtSEVDdTaufgSbfHpNVdPU/bmfvqNkrC5HagmLY= -github.com/foomo/go v0.14.1 h1:33ePCyAClSj2pqcEI9isyiEe1qoMd6c+Mn0ClLntSoM= -github.com/foomo/go v0.14.1/go.mod h1:jeSB/atkoqSoJ3+ak0+b/Xtj7IMyDj1odzJroudT7Dw= +github.com/foomo/go v0.15.0 h1:i6bcReoSLPpRVUVsd7anB6BCVBNimaOjiDeI+9I9rq0= +github.com/foomo/go v0.15.0/go.mod h1:jeSB/atkoqSoJ3+ak0+b/Xtj7IMyDj1odzJroudT7Dw= github.com/foomo/opentelemetry-go v0.4.0 h1:UQneCUSokIYJXzFUKQSI8rlelbUuf6atgSZMhvD+Nzo= github.com/foomo/opentelemetry-go v0.4.0/go.mod h1:R3Se/rc5FRAs4ThE6JQ9Oq3cOLo2MOsUzZLJxZquwxA= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= diff --git a/internal/runtimeutil/caller.go b/internal/runtimeutil/caller.go index b654cc1..57e7c43 100644 --- a/internal/runtimeutil/caller.go +++ b/internal/runtimeutil/caller.go @@ -34,7 +34,7 @@ func StackTrace(num, skip int) string { for { frame, more := frames.Next() - fmt.Fprintf(&ret, "%s\n %s:%d\n", frame.Function, frame.File, frame.Line) + _, _ = fmt.Fprintf(&ret, "%s\n %s:%d\n", frame.Function, frame.File, frame.Line) if !more || len(ret.String()) == num { break diff --git a/net/stream/go.mod b/net/stream/go.mod index 475abda..3007dc9 100644 --- a/net/stream/go.mod +++ b/net/stream/go.mod @@ -5,7 +5,7 @@ go 1.26.0 replace github.com/foomo/keel => ../../ require ( - github.com/foomo/go v0.14.1 + github.com/foomo/go v0.15.0 github.com/foomo/keel v0.27.1 github.com/nats-io/nats.go v1.52.0 github.com/pkg/errors v0.9.1 diff --git a/net/stream/go.sum b/net/stream/go.sum index ac7469e..ad1ddd5 100644 --- a/net/stream/go.sum +++ b/net/stream/go.sum @@ -36,8 +36,8 @@ github.com/fbiville/markdown-table-formatter v0.3.0 h1:PIm1UNgJrFs8q1htGTw+wnnNY github.com/fbiville/markdown-table-formatter v0.3.0/go.mod h1:q89TDtSEVDdTaufgSbfHpNVdPU/bmfvqNkrC5HagmLY= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/foomo/go v0.14.1 h1:33ePCyAClSj2pqcEI9isyiEe1qoMd6c+Mn0ClLntSoM= -github.com/foomo/go v0.14.1/go.mod h1:jeSB/atkoqSoJ3+ak0+b/Xtj7IMyDj1odzJroudT7Dw= +github.com/foomo/go v0.15.0 h1:i6bcReoSLPpRVUVsd7anB6BCVBNimaOjiDeI+9I9rq0= +github.com/foomo/go v0.15.0/go.mod h1:jeSB/atkoqSoJ3+ak0+b/Xtj7IMyDj1odzJroudT7Dw= github.com/foomo/opentelemetry-go v0.4.0 h1:UQneCUSokIYJXzFUKQSI8rlelbUuf6atgSZMhvD+Nzo= github.com/foomo/opentelemetry-go v0.4.0/go.mod h1:R3Se/rc5FRAs4ThE6JQ9Oq3cOLo2MOsUzZLJxZquwxA= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= diff --git a/telemetry/main_test.go b/telemetry/main_test.go new file mode 100644 index 0000000..753fe19 --- /dev/null +++ b/telemetry/main_test.go @@ -0,0 +1,11 @@ +package telemetry_test + +import ( + "testing" + + "go.uber.org/goleak" +) + +func TestMain(m *testing.M) { + goleak.VerifyTestMain(m) +} From 2a44c10380eaa315487ff4b2c5b5eaeaeda9bd39 Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Fri, 31 Jul 2026 12:23:37 +0200 Subject: [PATCH 02/23] fix: typos --- joboption.go | 2 +- option.go | 2 +- telemetry/autoconfig.go | 2 +- telemetry/loggerprovider.go | 9 +++++++-- telemetry/meterprovider.go | 4 ++-- telemetry/profiler.go | 7 +++---- telemetry/resource.go | 6 +++--- telemetry/traceprovider.go | 2 +- 8 files changed, 19 insertions(+), 15 deletions(-) diff --git a/joboption.go b/joboption.go index 85e0c14..d968a95 100644 --- a/joboption.go +++ b/joboption.go @@ -221,7 +221,7 @@ func JobWithOTLPGRCPLogger(enabled bool) JobOption { if config.GetBool(inst.Config(), "otel.enabled", enabled)() { var err error - inst.loggerProvider, err = telemetry.NewOTLPGRCPLoggerProvider(inst.ctx) + inst.loggerProvider, err = telemetry.NewOTLPGRPCLoggerProvider(inst.ctx) log.Must(inst.l, err, "failed to create otlp grpc logger provider") } } diff --git a/option.go b/option.go index c38807b..0d3b622 100644 --- a/option.go +++ b/option.go @@ -172,7 +172,7 @@ func WithOTLPGRCPLogger(enabled bool) Option { if config.GetBool(inst.Config(), "otel.enabled", enabled)() { var err error - inst.loggerProvider, err = telemetry.NewOTLPGRCPLoggerProvider(inst.ctx) + inst.loggerProvider, err = telemetry.NewOTLPGRPCLoggerProvider(inst.ctx) log.Must(inst.l, err, "failed to create otlp grpc logger provider") } } diff --git a/telemetry/autoconfig.go b/telemetry/autoconfig.go index 3f0fc5e..273f0db 100644 --- a/telemetry/autoconfig.go +++ b/telemetry/autoconfig.go @@ -94,7 +94,7 @@ func NewLoggerProviderFromEnv(ctx context.Context) (log.LoggerProvider, error) { case exporterOTLP: switch protocol := otlpProtocol("logs"); protocol { case protocolGRPC: - return NewOTLPGRCPLoggerProvider(ctx) + return NewOTLPGRPCLoggerProvider(ctx) case protocolHTTP: return NewOTLPHTTPLoggerProvider(ctx) default: diff --git a/telemetry/loggerprovider.go b/telemetry/loggerprovider.go index fe76d8b..0d26913 100644 --- a/telemetry/loggerprovider.go +++ b/telemetry/loggerprovider.go @@ -75,8 +75,8 @@ func NewOTLPHTTPLoggerProvider(ctx context.Context) (log.LoggerProvider, error) return newLoggerProvider(ctx, sdklog.NewBatchProcessor(exp)) } -// NewOTLPGRCPLoggerProvider creates a new OTLP gRPC-based logger provider using the provided context. -func NewOTLPGRCPLoggerProvider(ctx context.Context) (log.LoggerProvider, error) { +// NewOTLPGRPCLoggerProvider creates a new OTLP gRPC-based logger provider using the provided context. +func NewOTLPGRPCLoggerProvider(ctx context.Context) (log.LoggerProvider, error) { exp, err := otlploggrpc.New(ctx) if err != nil { return nil, err @@ -85,6 +85,11 @@ func NewOTLPGRCPLoggerProvider(ctx context.Context) (log.LoggerProvider, error) return newLoggerProvider(ctx, sdklog.NewBatchProcessor(exp)) } +// Deprecated: use NewOTLPGRPCLoggerProvider (this was a misspelling). +func NewOTLPGRCPLoggerProvider(ctx context.Context) (log.LoggerProvider, error) { + return NewOTLPGRPCLoggerProvider(ctx) +} + func newLoggerProvider(ctx context.Context, p sdklog.Processor) (log.LoggerProvider, error) { resource, err := NewResource(ctx) if err != nil { diff --git a/telemetry/meterprovider.go b/telemetry/meterprovider.go index d8268c0..f2c5925 100644 --- a/telemetry/meterprovider.go +++ b/telemetry/meterprovider.go @@ -23,7 +23,7 @@ func MeterProvider() metric.MeterProvider { return otel.GetMeterProvider() } -// NewNoopMeterProvider returns a no-op metric.MeterProvider and sets it as the global MeterProvider. +// NewNoopMeterProvider returns a no-op metric.MeterProvider. func NewNoopMeterProvider() metric.MeterProvider { return noop.NewMeterProvider() } @@ -36,7 +36,7 @@ func NewStdOutMeterProvider(ctx context.Context, opts ...stdoutmetric.Option) (m opts = append(opts, stdoutmetric.WithEncoder(enc)) } - if !env.GetBool("OTEL_EXPORTER_STDOUT_TIMESTAMP", true) { + if !env.GetBool("OTEL_EXPORTER_STDOUT_TIMESTAMPS", true) { opts = append(opts, stdoutmetric.WithoutTimestamps()) } diff --git a/telemetry/profiler.go b/telemetry/profiler.go index cdf055a..67162af 100644 --- a/telemetry/profiler.go +++ b/telemetry/profiler.go @@ -74,7 +74,7 @@ func NewProfiler(ctx context.Context) (*pyroscope.Profiler, error) { key = "service_git_ref" case semconv.VCSRepositoryURLFullKey: key = "service_repository" - case "vcs_repository_path": + case "vcs.repository.path": key = "service_root_path" default: key = strings.ReplaceAll(string(attr.Key), ".", "_") @@ -85,9 +85,8 @@ func NewProfiler(ctx context.Context) (*pyroscope.Profiler, error) { p, err := pyroscope.Start(pyroscope.Config{ ApplicationName: name, - // Logger: internalpyroscope.NewLogger(), - ProfileTypes: profileTypes, - Tags: tags, + ProfileTypes: profileTypes, + Tags: tags, }) if err != nil { return nil, err diff --git a/telemetry/resource.go b/telemetry/resource.go index 2d34a4f..a364257 100644 --- a/telemetry/resource.go +++ b/telemetry/resource.go @@ -9,15 +9,15 @@ import ( semconv "go.opentelemetry.io/otel/semconv/v1.41.0" ) -// ResourceEnvMap maps environment variables to semantic attributes. +// envAttributes maps environment variables to semantic attributes. var envAttributes = map[attribute.Key][]string{ semconv.VCSRepositoryNameKey: {"REPO_NAME", "REPOSITORY_NAME", "GIT_REPOSITORY_NAME", "GITHUB_REPOSITORY", "GITHUB_REPOSITORY_NAME", "GIT_OTEL_VCS_REPOSITORY_NAME"}, semconv.VCSRepositoryURLFullKey: {"REPO_URL", "REPOSITORY_URL", "GIT_REPOSITORY_URL", "OTEL_VCS_REPOSITORY_URL_FULL"}, semconv.VCSRefBaseNameKey: {"OTEL_VCS_BASE_NAME"}, - semconv.VCSRefBaseRevisionKey: {"OTEL_VCS_BASE_REVSION"}, + semconv.VCSRefBaseRevisionKey: {"OTEL_VCS_BASE_REVISION"}, semconv.VCSRefBaseTypeKey: {"OTEL_VCS_BASE_TYPE"}, semconv.VCSRefHeadNameKey: {"GIT_BRANCH", "OTEL_VCS_HEAD_NAME"}, - semconv.VCSRefHeadRevisionKey: {"GIT_COMMIT", "GIT_COMMIT_HASH", "OTEL_VCS_HEAD_REVSION"}, + semconv.VCSRefHeadRevisionKey: {"GIT_COMMIT", "GIT_COMMIT_HASH", "OTEL_VCS_HEAD_REVISION"}, semconv.VCSRefHeadTypeKey: {"GIT_TYPE", "OTEL_VCS_HEAD_TYPE"}, "vcs.repository.path": {"REPO_PATH", "REPOSITORY_PATH", "GIT_REPOSITORY_PATH", "OTEL_VCS_ROOT_PATH"}, } diff --git a/telemetry/traceprovider.go b/telemetry/traceprovider.go index 3c42dd2..0e8e001 100644 --- a/telemetry/traceprovider.go +++ b/telemetry/traceprovider.go @@ -19,7 +19,7 @@ func TracerProvider() trace.TracerProvider { return otel.GetTracerProvider() } -// NewNoopTraceProvider creates and returns a no-op tracer provider, setting it as the global otel tracer provider. +// NewNoopTraceProvider creates and returns a no-op tracer provider. func NewNoopTraceProvider() trace.TracerProvider { return noop.NewTracerProvider() } From 222211ea94ade4905d330ef318e4283a92aa3ccf Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Fri, 31 Jul 2026 12:38:37 +0200 Subject: [PATCH 03/23] feat: add scope version --- telemetry/config.go | 23 +++++++++++++++++++++++ telemetry/meter.go | 4 +++- telemetry/tracer.go | 4 +++- 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/telemetry/config.go b/telemetry/config.go index 49ec5f4..0778d3e 100644 --- a/telemetry/config.go +++ b/telemetry/config.go @@ -1,6 +1,29 @@ package telemetry +import ( + "runtime/debug" + "sync" +) + var ( Name = "github.com/foomo/keel" DefaultServiceName = "undefined" ) + +// Version returns the keel module version for use as the OTel instrumentation +// scope version. Resolved once from build info; empty string if unavailable. +var Version = sync.OnceValue(func() string { + bi, ok := debug.ReadBuildInfo() + if !ok { + return "" + } + if bi.Main.Path == Name { + return bi.Main.Version + } + for _, d := range bi.Deps { + if d.Path == Name { + return d.Version + } + } + return "" +}) diff --git a/telemetry/meter.go b/telemetry/meter.go index 3888f89..07b2bd5 100644 --- a/telemetry/meter.go +++ b/telemetry/meter.go @@ -5,6 +5,8 @@ import ( ) // Meter returns a metric.Meter instance with the provided options, using the default MeterProvider and the defined Name. +// The instrumentation scope version defaults to the keel module version; pass a +// metric.WithInstrumentationVersion option to override it. func Meter(opts ...metric.MeterOption) metric.Meter { - return MeterProvider().Meter(Name, opts...) + return MeterProvider().Meter(Name, append([]metric.MeterOption{metric.WithInstrumentationVersion(Version())}, opts...)...) } diff --git a/telemetry/tracer.go b/telemetry/tracer.go index b01ec50..10abc60 100644 --- a/telemetry/tracer.go +++ b/telemetry/tracer.go @@ -5,6 +5,8 @@ import ( ) // Tracer returns a trace.Tracer instance configured with optional TracerOptions. +// The instrumentation scope version defaults to the keel module version; pass a +// trace.WithInstrumentationVersion option to override it. func Tracer(opts ...trace.TracerOption) trace.Tracer { - return TracerProvider().Tracer(Name, opts...) + return TracerProvider().Tracer(Name, append([]trace.TracerOption{trace.WithInstrumentationVersion(Version())}, opts...)...) } From 2eb2b90aba41df60d5b861e705cbb9ed9fcb3078 Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Fri, 31 Jul 2026 14:02:41 +0200 Subject: [PATCH 04/23] feat: add scope version --- telemetry/config.go | 3 + telemetry/context.go | 4 +- telemetry/metric.go | 196 ++++++--------------------------------- telemetry/metric_test.go | 27 ++++++ 4 files changed, 62 insertions(+), 168 deletions(-) create mode 100644 telemetry/metric_test.go diff --git a/telemetry/config.go b/telemetry/config.go index 0778d3e..98e931d 100644 --- a/telemetry/config.go +++ b/telemetry/config.go @@ -17,13 +17,16 @@ var Version = sync.OnceValue(func() string { if !ok { return "" } + if bi.Main.Path == Name { return bi.Main.Version } + for _, d := range bi.Deps { if d.Path == Name { return d.Version } } + return "" }) diff --git a/telemetry/context.go b/telemetry/context.go index 1731bb7..58f63db 100644 --- a/telemetry/context.go +++ b/telemetry/context.go @@ -203,9 +203,9 @@ func (c Context) startSpan(prefix string, skip int, opts ...trace.SpanStartOptio )) } - ctx, span := Tracer().Start(c.Context, name, opts...) //nolint:spancheck + ctx, span := Tracer().Start(c.Context, name, opts...) - return Ctx(ctx), span //nolint:spancheck + return Ctx(ctx), span } func (c Context) log(ctx context.Context, lvl zapcore.Level, msg string, skip int, kv ...attribute.KeyValue) { diff --git a/telemetry/metric.go b/telemetry/metric.go index a20ef64..21e197d 100644 --- a/telemetry/metric.go +++ b/telemetry/metric.go @@ -1,36 +1,14 @@ package telemetry import ( - "context" - - foomosemconv "github.com/foomo/opentelemetry-go/semconv" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/metric" "go.opentelemetry.io/otel/metric/noop" - semconv "go.opentelemetry.io/otel/semconv/v1.41.0" ) -// NewIntHistogram creates and returns a Int64Histogram metric instrument with the specified name and optional settings. -func NewIntHistogram(name string, opts ...any) metric.Int64Histogram { - var ( - meterOptions []metric.MeterOption - metricOptions []metric.Int64HistogramOption - ) - - for _, v := range opts { - switch t := v.(type) { - case metric.MeterOption: - meterOptions = append(meterOptions, t) - case metric.HistogramOption: - metricOptions = append(metricOptions, t) - case metric.Int64HistogramOption: - metricOptions = append(metricOptions, t) - default: - Ctx(context.TODO()).LogWarn("invalid Histogram option", foomosemconv.ReflectType(v)) - } - } - - m, err := Meter(meterOptions...).Int64Histogram(name, metricOptions...) +// NewIntHistogram creates and returns a Int64Histogram metric instrument with the specified name and options. +func NewIntHistogram(name string, opts ...metric.Int64HistogramOption) metric.Int64Histogram { + m, err := Meter().Int64Histogram(name, opts...) if err != nil { otel.Handle(err) return noop.Int64Histogram{} @@ -39,27 +17,9 @@ func NewIntHistogram(name string, opts ...any) metric.Int64Histogram { return m } -// NewFloatHistogram creates and returns a Float64Histogram metric instrument with the specified name and optional settings. -func NewFloatHistogram(name string, opts ...any) metric.Float64Histogram { - var ( - meterOptions []metric.MeterOption - metricOptions []metric.Float64HistogramOption - ) - - for _, v := range opts { - switch t := v.(type) { - case metric.MeterOption: - meterOptions = append(meterOptions, t) - case metric.HistogramOption: - metricOptions = append(metricOptions, t) - case metric.Float64HistogramOption: - metricOptions = append(metricOptions, t) - default: - Ctx(context.TODO()).LogWarn("invalid Histogram option", foomosemconv.ReflectType(v)) - } - } - - m, err := Meter(meterOptions...).Float64Histogram(name, metricOptions...) +// NewFloatHistogram creates and returns a Float64Histogram metric instrument with the specified name and options. +func NewFloatHistogram(name string, opts ...metric.Float64HistogramOption) metric.Float64Histogram { + m, err := Meter().Float64Histogram(name, opts...) if err != nil { otel.Handle(err) return noop.Float64Histogram{} @@ -68,162 +28,66 @@ func NewFloatHistogram(name string, opts ...any) metric.Float64Histogram { return m } -// NewIntGauge creates and returns a Int64Gauge metric instrument with the specified name and optional settings. -func NewIntGauge(name string, opts ...any) metric.Int64Gauge { - var ( - meterOptions []metric.MeterOption - metricOptions []metric.Int64GaugeOption - ) - - for _, v := range opts { - switch t := v.(type) { - case metric.MeterOption: - meterOptions = append(meterOptions, t) - case metric.Int64GaugeOption: - metricOptions = append(metricOptions, t) - default: - Ctx(context.TODO()).LogWarn("invalid Gauge option", foomosemconv.ReflectType(v)) - } - } - - m, err := Meter(meterOptions...).Int64Gauge(name, metricOptions...) +// NewIntGauge creates and returns a Int64Gauge metric instrument with the specified name and options. +func NewIntGauge(name string, opts ...metric.Int64GaugeOption) metric.Int64Gauge { + m, err := Meter().Int64Gauge(name, opts...) if err != nil { - Ctx(context.TODO()).LogWarn("failed to create Gauge", semconv.ErrorType(err), semconv.ExceptionMessage(err.Error())) + otel.Handle(err) return noop.Int64Gauge{} } return m } -// NewFloatGauge creates and returns a Float64Gauge metric with the specified name and optional configurations. -func NewFloatGauge(name string, opts ...any) metric.Float64Gauge { - var ( - meterOptions []metric.MeterOption - metricOptions []metric.Float64GaugeOption - ) - - for _, v := range opts { - switch t := v.(type) { - case metric.MeterOption: - meterOptions = append(meterOptions, t) - case metric.Float64GaugeOption: - metricOptions = append(metricOptions, t) - default: - Ctx(context.TODO()).LogWarn("invalid Gauge option", foomosemconv.ReflectType(v)) - } - } - - m, err := Meter(meterOptions...).Float64Gauge(name, metricOptions...) +// NewFloatGauge creates and returns a Float64Gauge metric instrument with the specified name and options. +func NewFloatGauge(name string, opts ...metric.Float64GaugeOption) metric.Float64Gauge { + m, err := Meter().Float64Gauge(name, opts...) if err != nil { - Ctx(context.TODO()).LogWarn("failed to create Gauge", semconv.ErrorType(err), semconv.ExceptionMessage(err.Error())) + otel.Handle(err) return noop.Float64Gauge{} } return m } -// NewIntCounter creates and returns a Int64Counter metric instrument with the specified name and optional settings. -func NewIntCounter(name string, opts ...any) metric.Int64Counter { - var ( - meterOptions []metric.MeterOption - metricOptions []metric.Int64CounterOption - ) - - for _, v := range opts { - switch t := v.(type) { - case metric.MeterOption: - meterOptions = append(meterOptions, t) - case metric.Int64CounterOption: - metricOptions = append(metricOptions, t) - default: - Ctx(context.TODO()).LogWarn("invalid Counter option", foomosemconv.ReflectType(v)) - } - } - - m, err := Meter(meterOptions...).Int64Counter(name, metricOptions...) +// NewIntCounter creates and returns a Int64Counter metric instrument with the specified name and options. +func NewIntCounter(name string, opts ...metric.Int64CounterOption) metric.Int64Counter { + m, err := Meter().Int64Counter(name, opts...) if err != nil { - Ctx(context.TODO()).LogWarn("failed to create Counter", semconv.ErrorType(err), semconv.ExceptionMessage(err.Error())) + otel.Handle(err) return noop.Int64Counter{} } return m } -// NewFloatCounter creates and returns a Float64Counter metric instrument with the specified name and optional settings. -func NewFloatCounter(name string, opts ...any) metric.Float64Counter { - var ( - meterOptions []metric.MeterOption - metricOptions []metric.Float64CounterOption - ) - - for _, v := range opts { - switch t := v.(type) { - case metric.MeterOption: - meterOptions = append(meterOptions, t) - case metric.Float64CounterOption: - metricOptions = append(metricOptions, t) - default: - Ctx(context.TODO()).LogWarn("invalid Counter option", foomosemconv.ReflectType(v)) - } - } - - m, err := Meter(meterOptions...).Float64Counter(name, metricOptions...) +// NewFloatCounter creates and returns a Float64Counter metric instrument with the specified name and options. +func NewFloatCounter(name string, opts ...metric.Float64CounterOption) metric.Float64Counter { + m, err := Meter().Float64Counter(name, opts...) if err != nil { - Ctx(context.TODO()).LogWarn("failed to create Counter", semconv.ErrorType(err), semconv.ExceptionMessage(err.Error())) + otel.Handle(err) return noop.Float64Counter{} } return m } -// NewIntUpDownCounter creates and returns a Int64UpDownCounter metric instrument with the specified name and optional settings. -func NewIntUpDownCounter(name string, opts ...any) metric.Int64UpDownCounter { - var ( - meterOptions []metric.MeterOption - metricOptions []metric.Int64UpDownCounterOption - ) - - for _, v := range opts { - switch t := v.(type) { - case metric.MeterOption: - meterOptions = append(meterOptions, t) - case metric.Int64UpDownCounterOption: - metricOptions = append(metricOptions, t) - default: - Ctx(context.TODO()).LogWarn("invalid UpDownCounter option", foomosemconv.ReflectType(v)) - } - } - - m, err := Meter(meterOptions...).Int64UpDownCounter(name, metricOptions...) +// NewIntUpDownCounter creates and returns a Int64UpDownCounter metric instrument with the specified name and options. +func NewIntUpDownCounter(name string, opts ...metric.Int64UpDownCounterOption) metric.Int64UpDownCounter { + m, err := Meter().Int64UpDownCounter(name, opts...) if err != nil { - Ctx(context.TODO()).LogWarn("failed to create UpDownCounter", semconv.ErrorType(err), semconv.ExceptionMessage(err.Error())) + otel.Handle(err) return noop.Int64UpDownCounter{} } return m } -// NewFloatUpDownCounter creates and returns a Float64UpDownCounter metric instrument with the specified name and optional settings. -func NewFloatUpDownCounter(name string, opts ...any) metric.Float64UpDownCounter { - var ( - meterOptions []metric.MeterOption - metricOptions []metric.Float64UpDownCounterOption - ) - - for _, v := range opts { - switch t := v.(type) { - case metric.MeterOption: - meterOptions = append(meterOptions, t) - case metric.Float64UpDownCounterOption: - metricOptions = append(metricOptions, t) - default: - Ctx(context.TODO()).LogWarn("invalid UpDownCounter option", foomosemconv.ReflectType(v)) - } - } - - m, err := Meter(meterOptions...).Float64UpDownCounter(name, metricOptions...) +// NewFloatUpDownCounter creates and returns a Float64UpDownCounter metric instrument with the specified name and options. +func NewFloatUpDownCounter(name string, opts ...metric.Float64UpDownCounterOption) metric.Float64UpDownCounter { + m, err := Meter().Float64UpDownCounter(name, opts...) if err != nil { - Ctx(context.TODO()).LogWarn("failed to create UpDownCounter", semconv.ErrorType(err), semconv.ExceptionMessage(err.Error())) + otel.Handle(err) return noop.Float64UpDownCounter{} } diff --git a/telemetry/metric_test.go b/telemetry/metric_test.go new file mode 100644 index 0000000..9aa1da4 --- /dev/null +++ b/telemetry/metric_test.go @@ -0,0 +1,27 @@ +package telemetry_test + +import ( + "testing" + + "github.com/foomo/keel/telemetry" + "github.com/stretchr/testify/assert" + "go.opentelemetry.io/otel/metric" +) + +// TestNewMetricInstruments verifies the typed constructors build non-nil +// instruments and accept the shared/typed options that compile for each kind. +func TestNewMetricInstruments(t *testing.T) { + t.Parallel() + + // Shared InstrumentOption (WithDescription/WithUnit) applies to every kind; + // WithExplicitBucketBoundaries is histogram-only. Wrong-kind options would + // fail to compile — that is the point of the typed signatures. + assert.NotNil(t, telemetry.NewIntHistogram("h.int", metric.WithUnit("ms"), metric.WithExplicitBucketBoundaries(1, 2, 5))) + assert.NotNil(t, telemetry.NewFloatHistogram("h.float", metric.WithExplicitBucketBoundaries(0.1, 0.5))) + assert.NotNil(t, telemetry.NewIntGauge("g.int", metric.WithDescription("d"))) + assert.NotNil(t, telemetry.NewFloatGauge("g.float")) + assert.NotNil(t, telemetry.NewIntCounter("c.int", metric.WithUnit("{req}"))) + assert.NotNil(t, telemetry.NewFloatCounter("c.float")) + assert.NotNil(t, telemetry.NewIntUpDownCounter("ud.int")) + assert.NotNil(t, telemetry.NewFloatUpDownCounter("ud.float")) +} From 6ddf1d2607d0d60d417f943a1837e90f0a895bf5 Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Fri, 31 Jul 2026 15:31:32 +0200 Subject: [PATCH 05/23] feat: update telemetry package name --- telemetry/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/telemetry/config.go b/telemetry/config.go index 98e931d..73f52d2 100644 --- a/telemetry/config.go +++ b/telemetry/config.go @@ -6,7 +6,7 @@ import ( ) var ( - Name = "github.com/foomo/keel" + Name = "github.com/foomo/keel/telemetry" DefaultServiceName = "undefined" ) From 17ef4ea02549be2fc20d9408cf59c32c598797c7 Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Fri, 31 Jul 2026 15:31:59 +0200 Subject: [PATCH 06/23] feat: add debug.enabled attribute key --- semconv/debug.go | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 semconv/debug.go diff --git a/semconv/debug.go b/semconv/debug.go new file mode 100644 index 0000000..da2e9e8 --- /dev/null +++ b/semconv/debug.go @@ -0,0 +1,15 @@ +package semconv + +import ( + "go.opentelemetry.io/otel/attribute" +) + +const ( + // DebugEnabledKey is the key for debug.enabled. + DebugEnabledKey = attribute.Key("debug.enabled") +) + +// DebugEnabled returns a new attribute.KeyValue for keel.service.type. +func DebugEnabled(v bool) attribute.KeyValue { + return DebugEnabledKey.Bool(v) +} From 213e0a5f57a1bce24d07dcadecb7c784b1506f6a Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Fri, 31 Jul 2026 16:20:49 +0200 Subject: [PATCH 07/23] feat: use foomo.go CallFrame for code attributes --- go.mod | 2 +- go.sum | 4 ++-- telemetry/code.go | 16 ++-------------- telemetry/logger.go | 11 ++++++++++- 4 files changed, 15 insertions(+), 18 deletions(-) diff --git a/go.mod b/go.mod index dec8a17..dc1e1cb 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.26.0 require ( github.com/avast/retry-go/v4 v4.7.0 github.com/fbiville/markdown-table-formatter v0.3.0 - github.com/foomo/go v0.14.1 + github.com/foomo/go v0.15.0 github.com/foomo/goflux v0.4.4 github.com/foomo/gofuncy v0.2.0 github.com/foomo/gostandards v0.3.0 diff --git a/go.sum b/go.sum index b927d3e..176fed8 100644 --- a/go.sum +++ b/go.sum @@ -78,8 +78,8 @@ github.com/fbiville/markdown-table-formatter v0.3.0 h1:PIm1UNgJrFs8q1htGTw+wnnNY github.com/fbiville/markdown-table-formatter v0.3.0/go.mod h1:q89TDtSEVDdTaufgSbfHpNVdPU/bmfvqNkrC5HagmLY= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/foomo/go v0.14.1 h1:33ePCyAClSj2pqcEI9isyiEe1qoMd6c+Mn0ClLntSoM= -github.com/foomo/go v0.14.1/go.mod h1:jeSB/atkoqSoJ3+ak0+b/Xtj7IMyDj1odzJroudT7Dw= +github.com/foomo/go v0.15.0 h1:i6bcReoSLPpRVUVsd7anB6BCVBNimaOjiDeI+9I9rq0= +github.com/foomo/go v0.15.0/go.mod h1:jeSB/atkoqSoJ3+ak0+b/Xtj7IMyDj1odzJroudT7Dw= github.com/foomo/goflux v0.4.4 h1:T7QhIPdZze3bNEeNjdEAzBV08/ikEgmTmK3maWucAo4= github.com/foomo/goflux v0.4.4/go.mod h1:c2qy02JR9Y5qlVl49nDSEipCQENbGhDZzjT8p72G7Xs= github.com/foomo/gofuncy v0.2.0 h1:fanMIpHocWfoP+u8sevF+Qb/gEh38QeiS6FjeXB+Sx0= diff --git a/telemetry/code.go b/telemetry/code.go index 1df1db4..f036608 100644 --- a/telemetry/code.go +++ b/telemetry/code.go @@ -1,23 +1,11 @@ package telemetry import ( - runtimex "github.com/foomo/go/runtime" + goruntime "github.com/foomo/go/runtime" "go.opentelemetry.io/otel/attribute" semconv "go.opentelemetry.io/otel/semconv/v1.41.0" ) -func CodeCaller(skip int) []attribute.KeyValue { - if shortName, _, file, line, ok := runtimex.Caller(skip + 1); ok { - return []attribute.KeyValue{ - semconv.CodeFunctionName(shortName), - semconv.CodeFilePath(file), - semconv.CodeLineNumber(line), - } - } - - return nil -} - func CodeStacktrace(num, skip int) attribute.KeyValue { - return semconv.CodeStacktrace(runtimex.StackTrace(num, skip+1)) + return semconv.CodeStacktrace(goruntime.StackTrace(num, skip+1)) } diff --git a/telemetry/logger.go b/telemetry/logger.go index a92c802..308a071 100644 --- a/telemetry/logger.go +++ b/telemetry/logger.go @@ -2,10 +2,13 @@ package telemetry import ( "context" + "path" + goruntime "github.com/foomo/go/runtime" "github.com/foomo/keel/log" foomosemconv "github.com/foomo/opentelemetry-go/semconv" "go.opentelemetry.io/otel/attribute" + semconv "go.opentelemetry.io/otel/semconv/v1.41.0" "go.opentelemetry.io/otel/trace" "go.uber.org/zap" "go.uber.org/zap/zapcore" @@ -42,7 +45,13 @@ func Log(ctx context.Context, lvl zapcore.Level, msg string, skip int, kv ...att ) } - attrs = append(attrs, CodeCaller(skip+1)...) + if fr := goruntime.CallFrame(skip + 1); !fr.Zero() { + attrs = append(attrs, + semconv.CodeFunctionName(fr.Short()), + semconv.CodeFilePath(path.Join(path.Base(path.Dir(fr.File)), path.Base(fr.File))), + semconv.CodeLineNumber(fr.Line), + ) + } zap.L().WithOptions(zap.WithCaller(false)).Log(lvl, msg, log.Attributes(attrs...)...) } From 3f7113927464a3866c7e12fcbcebfff0d26c0721 Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Fri, 31 Jul 2026 16:35:33 +0200 Subject: [PATCH 08/23] feat: replace runtimex with goruntime --- internal/runtimeutil/caller.go | 45 ---------------------------- internal/runtimeutil/caller_test.go | 46 ----------------------------- telemetry/code.go | 12 ++++---- 3 files changed, 6 insertions(+), 97 deletions(-) delete mode 100644 internal/runtimeutil/caller.go delete mode 100644 internal/runtimeutil/caller_test.go diff --git a/internal/runtimeutil/caller.go b/internal/runtimeutil/caller.go deleted file mode 100644 index 57e7c43..0000000 --- a/internal/runtimeutil/caller.go +++ /dev/null @@ -1,45 +0,0 @@ -package runtimeutil - -import ( - "fmt" - "runtime" - "strings" -) - -func Caller(skip int) (shortName, fullName, file string, line int, ok bool) { //nolint:nonamedreturns - pc, file, line, ok := runtime.Caller(skip + 1) - if !ok { - return "unknown", "Unknown", "unknown", 0, false - } - - fullName = runtime.FuncForPC(pc).Name() - - // Split fullName by last slash to separate package path and the rest - lastSlash := strings.LastIndex(fullName, "/") - if lastSlash != -1 { - return fullName[lastSlash+1:], fullName, file, line, true - } - - return fullName, fullName, file, line, true -} - -func StackTrace(num, skip int) string { - pcs := make([]uintptr, num) - n := runtime.Callers(skip+1, pcs) - pcs = pcs[:n] - - var ret strings.Builder - - frames := runtime.CallersFrames(pcs) - for { - frame, more := frames.Next() - - _, _ = fmt.Fprintf(&ret, "%s\n %s:%d\n", frame.Function, frame.File, frame.Line) - - if !more || len(ret.String()) == num { - break - } - } - - return strings.Trim(ret.String(), "\n") -} diff --git a/internal/runtimeutil/caller_test.go b/internal/runtimeutil/caller_test.go deleted file mode 100644 index 8c2f8fc..0000000 --- a/internal/runtimeutil/caller_test.go +++ /dev/null @@ -1,46 +0,0 @@ -package runtimeutil_test - -import ( - "fmt" - "strings" - "testing" - - "github.com/foomo/keel/internal/runtimeutil" - "github.com/stretchr/testify/assert" -) - -type caller struct{} - -func (c *caller) caller() (string, string, string, int, bool) { - return runtimeutil.Caller(0) -} - -func TestCaller(t *testing.T) { - t.Parallel() - - shortName, fullName, file, line, _ := runtimeutil.Caller(0) - - assert.Equal(t, "runtimeutil_test.TestCaller", shortName) - assert.Equal(t, "github.com/foomo/keel/internal/runtimeutil_test.TestCaller", fullName) - assert.True(t, strings.HasSuffix(file, "/internal/runtimeutil/caller_test.go")) - assert.Equal(t, 21, line) - - c := new(caller) - shortName, fullName, file, line, _ = c.caller() - - assert.Equal(t, "runtimeutil_test.(*caller).caller", shortName) - assert.Equal(t, "github.com/foomo/keel/internal/runtimeutil_test.(*caller).caller", fullName) - assert.True(t, strings.HasSuffix(file, "/internal/runtimeutil/caller_test.go")) - assert.Equal(t, 15, line) -} - -func TestStackTrace(t *testing.T) { - t.Parallel() - - stack := runtimeutil.StackTrace(2, 1) - parts := strings.Split(stack, "\n") - - fmt.Println(parts) - assert.Len(t, parts, 4) - assert.Equal(t, "github.com/foomo/keel/internal/runtimeutil_test.TestStackTrace", parts[0]) -} diff --git a/telemetry/code.go b/telemetry/code.go index 1df1db4..e1e34d2 100644 --- a/telemetry/code.go +++ b/telemetry/code.go @@ -1,17 +1,17 @@ package telemetry import ( - runtimex "github.com/foomo/go/runtime" + goruntime "github.com/foomo/go/runtime" "go.opentelemetry.io/otel/attribute" semconv "go.opentelemetry.io/otel/semconv/v1.41.0" ) func CodeCaller(skip int) []attribute.KeyValue { - if shortName, _, file, line, ok := runtimex.Caller(skip + 1); ok { + if fr := goruntime.CallFrame(skip + 1); !fr.Zero() { return []attribute.KeyValue{ - semconv.CodeFunctionName(shortName), - semconv.CodeFilePath(file), - semconv.CodeLineNumber(line), + semconv.CodeFunctionName(fr.Name()), + semconv.CodeFilePath(fr.File), + semconv.CodeLineNumber(fr.Line), } } @@ -19,5 +19,5 @@ func CodeCaller(skip int) []attribute.KeyValue { } func CodeStacktrace(num, skip int) attribute.KeyValue { - return semconv.CodeStacktrace(runtimex.StackTrace(num, skip+1)) + return semconv.CodeStacktrace(goruntime.StackTrace(num, skip+1)) } From 7ab4bfaeb3727e063da263f117448d072b304e7e Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Fri, 31 Jul 2026 16:36:03 +0200 Subject: [PATCH 09/23] feat: make ctx private and expose helper --- telemetry/context.go | 159 ++++++++++++++++++++++++++++++------------- 1 file changed, 110 insertions(+), 49 deletions(-) diff --git a/telemetry/context.go b/telemetry/context.go index 58f63db..f47b7ce 100644 --- a/telemetry/context.go +++ b/telemetry/context.go @@ -2,9 +2,12 @@ package telemetry import ( "context" + "path" "runtime/pprof" + "time" - "github.com/foomo/keel/internal/runtimeutil" + goruntime "github.com/foomo/go/runtime" + keelsemconv "github.com/foomo/keel/semconv" foomosemconv "github.com/foomo/opentelemetry-go/semconv" "github.com/grafana/pyroscope-go" "github.com/pkg/errors" @@ -16,9 +19,10 @@ import ( ) type Context struct { - context.Context + ctx context.Context } +// Ctx returns a new Context from the given context.Context. func Ctx(ctx context.Context) Context { return Context{ctx} } @@ -27,33 +31,103 @@ func Ctx(ctx context.Context) Context { // ~ Public methods // ------------------------------------------------------------------------------------------------ -// LogDebug logs a message at debug level. +// LogDebug logs a message at `debug` level. func (c Context) LogDebug(msg string, kv ...attribute.KeyValue) { - c.log(c.Context, zapcore.DebugLevel, msg, 1, kv...) + c.log(c.ctx, zapcore.DebugLevel, msg, 1, kv...) } -// LogInfo logs a message at info level. +// LogInfo logs a message at `info` level. func (c Context) LogInfo(msg string, kv ...attribute.KeyValue) { - c.log(c.Context, zapcore.InfoLevel, msg, 1, kv...) + c.log(c.ctx, zapcore.InfoLevel, msg, 1, kv...) } -// LogWarn logs a message at warn level. +// LogWarn logs a message at `warn` level. func (c Context) LogWarn(msg string, kv ...attribute.KeyValue) { - c.log(c.Context, zapcore.WarnLevel, msg, 1, kv...) + c.log(c.ctx, zapcore.WarnLevel, msg, 1, kv...) } -// LogError logs a message at error level. +// LogError logs a message at `error` level. func (c Context) LogError(msg string, kv ...attribute.KeyValue) { - c.log(c.Context, zapcore.ErrorLevel, msg, 1, kv...) + c.log(c.ctx, zapcore.ErrorLevel, msg, 1, kv...) +} + +// Context returns the underlying context.Context. +func (c Context) Context() context.Context { + return c.ctx +} + +// ContextWithCancel returns a copy of the context with a new Done channel. +// The returned context's Done channel is closed when the returned cancel function +// is called or when the parent context's Done channel is closed, whichever happens first. +func (c Context) ContextWithCancel() (context.Context, context.CancelFunc) { + return context.WithCancel(c.ctx) +} + +// ContextWithCancelCause returns a copy of the context with a new Done channel and +// a CancelCauseFunc instead of a CancelFunc. Calling cancel with a non-nil error +// (the "cause") records that error in the context; it can then be retrieved using Cause(ctx). +func (c Context) ContextWithCancelCause() (context.Context, context.CancelCauseFunc) { + return context.WithCancelCause(c.ctx) +} + +// ContextWith returns a copy of the context with a deadline. +// The returned context's Done channel is closed when the deadline expires, when the +// returned cancel function is called, or when the parent context's Done channel is +// closed, whichever happens first. +func (c Context) ContextWith(deadline time.Time) (context.Context, context.CancelFunc) { + return context.WithDeadline(c.ctx, deadline) +} + +// ContextWithTimeout returns a copy of the context with a timeout. +// It is equivalent to ContextWith(time.Now().Add(timeout)). +func (c Context) ContextWithTimeout(timeout time.Duration) (context.Context, context.CancelFunc) { + return context.WithTimeout(c.ctx, timeout) +} + +// ContextWithValue returns a copy of the context with the key-value pair associated. +func (c Context) ContextWithValue(key, val any) context.Context { + return context.WithValue(c.ctx, key, val) +} + +// ContextWithoutCancel returns a copy of the context that is not canceled when +// parent is canceled. The returned context returns no Deadline or Err, and its +// Done channel is nil. +func (c Context) ContextWithoutCancel() context.Context { + return context.WithoutCancel(c.ctx) +} + +// Value returns the value associated with this context for key, or nil +// if no value is associated with key. +func (c Context) Value(key any) any { + return c.ctx.Value(key) +} + +// Deadline returns the time when work done on behalf of this context should be +// canceled. Deadline returns ok==false when no deadline is set. +func (c Context) Deadline() (deadline time.Time, ok bool) { + return c.ctx.Deadline() +} + +// Done returns a channel that's closed when work done on behalf of this context +// should be canceled. Done may return nil if this context can never be canceled. +func (c Context) Done() <-chan struct{} { + return c.ctx.Done() +} + +// Err returns a non-nil error value after Done is closed. Err returns Canceled +// if the context was canceled or DeadlineExceeded if the context's deadline passed. +func (c Context) Err() error { + return c.ctx.Err() } // Span returns the span from the context. func (c Context) Span() trace.Span { - return trace.SpanFromContext(c.Context) + return trace.SpanFromContext(c.ctx) } +// SetSpanDebug sets the span debug attribute. func (c Context) SetSpanDebug() { - c.Span().SetAttributes(attribute.Bool("debug.enabled", true)) + c.Span().SetAttributes(keelsemconv.DebugEnabled(true)) } // EndSpan ends the span. @@ -61,7 +135,7 @@ func (c Context) EndSpan(err error, opts ...trace.SpanEndOption) { sp := c.Span() if sp.IsRecording() { if err != nil { - sp.RecordError(err, trace.WithAttributes(semconv.CodeStacktrace(runtimeutil.StackTrace(3, 1)))) + sp.RecordError(err, trace.WithAttributes(CodeStacktrace(3, 0))) sp.SetStatus(codes.Error, errors.Cause(err).Error()) } else { c.SetSpanStatusOK() @@ -90,34 +164,22 @@ func (c Context) DeferEndSpan(err *error, opts ...trace.SpanEndOption) { // SetSpanStatusOK sets the status of the span to ok. func (c Context) SetSpanStatusOK() { - sp := c.Span() - if sp.IsRecording() { - sp.SetStatus(codes.Ok, "") - } + c.Span().SetStatus(codes.Ok, "") } // SetSpanStatusError sets the status of the span to error. func (c Context) SetSpanStatusError(description string) { - sp := c.Span() - if sp.IsRecording() { - sp.SetStatus(codes.Error, description) - } + c.Span().SetStatus(codes.Error, description) } // SetSpanName sets the name of the span. func (c Context) SetSpanName(name string) { - sp := c.Span() - if sp.IsRecording() { - sp.SetName(name) - } + c.Span().SetName(name) } // SetSpanAttributes sets the attributes of the span. func (c Context) SetSpanAttributes(kv ...attribute.KeyValue) { - sp := c.Span() - if sp.IsRecording() { - sp.SetAttributes(kv...) - } + c.Span().SetAttributes(kv...) } // RecordError records an error on the span and logs it. @@ -144,27 +206,24 @@ func (c Context) RecordSpanError(err error, kv ...attribute.KeyValue) { // AddSpanEvent adds an event to the span. func (c Context) AddSpanEvent(name string, kv ...attribute.KeyValue) { - sp := c.Span() - if sp.IsRecording() { - sp.AddEvent(name, trace.WithAttributes(kv...)) - } + c.Span().AddEvent(name, trace.WithAttributes(kv...)) } // StartSpan starts a span. func (c Context) StartSpan(opts ...trace.SpanStartOption) Context { - ctx, _ := c.startSpan("FUNC", 1, opts...) + ctx, _ := c.startSpan("", 1, opts...) return ctx } // StartSpanWithNewRoot sets the name of the span. func (c Context) StartSpanWithNewRoot(opts ...trace.SpanStartOption) Context { - ctx, _ := c.startSpan("FUNC", 1, append(opts, trace.WithNewRoot(), trace.WithLinks(trace.LinkFromContext(c.Context)))...) + ctx, _ := c.startSpan("", 1, append(opts, trace.WithNewRoot(), trace.WithLinks(trace.LinkFromContext(c.ctx)))...) return ctx } // StartSpanWithProfile starts a span and profiles the handler. func (c Context) StartSpanWithProfile(name string, handler func(ctx Context), kv ...attribute.KeyValue) { - ctx, span := c.startSpan("FUNC", 1, trace.WithAttributes(kv...)) + ctx, span := c.startSpan("", 1, trace.WithAttributes(kv...)) defer span.End() ctx.StartProfile(name, handler, kv...) @@ -174,14 +233,14 @@ func (c Context) StartSpanWithProfile(name string, handler func(ctx Context), kv func (c Context) StartProfile(name string, handler func(ctx Context), kv ...attribute.KeyValue) { attr := foomosemconv.ProfileName(name) c.Span().SetAttributes(attr) - pyroscope.TagWrapper(c.Context, PyroscopeLabels(append(kv, attr)...), func(ctx context.Context) { + pyroscope.TagWrapper(c.ctx, PyroscopeLabels(append(kv, attr)...), func(ctx context.Context) { handler(Ctx(ctx)) }) } // SetProfileAttributes sets the labels for the profile. func (c Context) SetProfileAttributes(kv ...attribute.KeyValue) Context { - ctx := pprof.WithLabels(c.Context, PyroscopeLabels(kv...)) + ctx := pprof.WithLabels(c.ctx, PyroscopeLabels(kv...)) pprof.SetGoroutineLabels(ctx) return Ctx(ctx) @@ -191,19 +250,21 @@ func (c Context) SetProfileAttributes(kv ...attribute.KeyValue) Context { // ~ Private methods // ------------------------------------------------------------------------------------------------ -func (c Context) startSpan(prefix string, skip int, opts ...trace.SpanStartOption) (Context, trace.Span) { - name := prefix - - if shortName, _, file, line, ok := runtimeutil.Caller(skip + 1); ok { - name += " " + shortName - opts = append(opts, trace.WithAttributes( - semconv.CodeFunctionName(shortName), - semconv.CodeLineNumber(line), - semconv.CodeFilePath(file), - )) +func (c Context) startSpan(name string, skip int, opts ...trace.SpanStartOption) (Context, trace.Span) { + if name == "" { + if fr := goruntime.CallFrame(skip + 1); !fr.Zero() { + name = path.Base(fr.Pkg) + "." + fr.Short() + opts = append(opts, trace.WithAttributes( + semconv.CodeFunctionName(fr.Name()), + semconv.CodeLineNumber(fr.Line), + semconv.CodeFilePath(fr.File), + )) + } else { + name = "runtime.go" + } } - ctx, span := Tracer().Start(c.Context, name, opts...) + ctx, span := Tracer().Start(c.ctx, name, opts...) return Ctx(ctx), span } From a8eab7e4ee9b7a561c7f6d2c1325a729e95cdb99 Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Fri, 31 Jul 2026 18:56:53 +0200 Subject: [PATCH 10/23] feat: mark deprecated functions and variables --- metrics/metrics_http.go | 4 ++++ metrics/readme.go | 1 + 2 files changed, 5 insertions(+) diff --git a/metrics/metrics_http.go b/metrics/metrics_http.go index 8d3e2b7..85e0f74 100644 --- a/metrics/metrics_http.go +++ b/metrics/metrics_http.go @@ -4,18 +4,22 @@ import ( "github.com/prometheus/client_golang/prometheus" ) +// Deprecated: use otelhttp func NewHTTPRequestSizeSummaryVec(namespace string) *prometheus.SummaryVec { return NewRequestSizeSummaryVec(namespace, "http", []string{"method", "code"}) } +// Deprecated: use otelhttp func NewHTTPResponseSizeSummaryVec(namespace string) *prometheus.SummaryVec { return NewResponseSizeSummaryVec(namespace, "http", []string{"method", "code"}) } +// Deprecated: use otelhttp func NewHTTPRequestsCounterVec(namespace string) *prometheus.CounterVec { return NewRequestsCounterVec(namespace, "http", []string{"method", "code"}) } +// Deprecated: use otelhttp func NewHTTPRequestDurationHistogram(namespace string) prometheus.Histogram { return NewRequestDurationHistogram(namespace, "http") } diff --git a/metrics/readme.go b/metrics/readme.go index 683973e..3252740 100644 --- a/metrics/readme.go +++ b/metrics/readme.go @@ -5,6 +5,7 @@ import ( "github.com/prometheus/client_golang/prometheus" ) +// Deprecated: will be removed in upcoming releases func Readme() string { md := markdown.Markdown{} From 7f3a4a64e1138217394a5fd36dacc6ae685f636f Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Fri, 31 Jul 2026 18:57:01 +0200 Subject: [PATCH 11/23] fix: typos --- service/goroutine.go | 2 +- service/goroutine_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/service/goroutine.go b/service/goroutine.go index 8e6976b..63e6c45 100644 --- a/service/goroutine.go +++ b/service/goroutine.go @@ -56,7 +56,7 @@ func NewGoRoutine(l *zap.Logger, name string, handler GoRoutineFn, opts ...GoRou // ~ Options // ------------------------------------------------------------------------------------------------ -func GoRoutineWithPralllel(v int) GoRoutineOption { +func GoRoutineWithParallel(v int) GoRoutineOption { return func(o *GoRoutine) { o.parallel = v } diff --git a/service/goroutine_test.go b/service/goroutine_test.go index 02b732b..2684101 100644 --- a/service/goroutine_test.go +++ b/service/goroutine_test.go @@ -27,7 +27,7 @@ func ExampleNewGoRoutine() { for { // handle graceful shutdowns if err := ctx.Err(); errors.Is(context.Cause(ctx), service.ErrServiceShutdown) { - l.Info("context has been canceled du to graceful shutdow") + l.Info("context has been canceled du to graceful shutdown") return nil } else if err != nil { return errors.Wrap(err, "unexpected context error") From 7feeab164b725c95810a69bd6b1802882c7f8b04 Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Fri, 31 Jul 2026 18:57:30 +0200 Subject: [PATCH 12/23] feat: add deprecation notics --- service/httpreadme.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/service/httpreadme.go b/service/httpreadme.go index c12eee0..4444c75 100644 --- a/service/httpreadme.go +++ b/service/httpreadme.go @@ -14,6 +14,7 @@ var ( DefaultHTTPReadmePath = "/readme" ) +// Deprecated: will be removed in upcoming releases func NewHTTPReadme(l *zap.Logger, name, addr, path string, readmers func() []interfaces.Readmer) *HTTP { handler := http.NewServeMux() handler.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) { @@ -36,6 +37,7 @@ func NewHTTPReadme(l *zap.Logger, name, addr, path string, readmers func() []int return NewHTTP(l, name, addr, handler) } +// Deprecated: will be removed in upcoming releases func NewDefaultHTTPReadme(l *zap.Logger, readmers func() []interfaces.Readmer) *HTTP { return NewHTTPReadme( l, From 2c54a281b68620a7d81394cc155322f9bd847098 Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Fri, 31 Jul 2026 18:57:47 +0200 Subject: [PATCH 13/23] feat: extend helper methods and make err optional --- utils/net/http/errors.go | 209 +++++++++++++++++++++++++++++++++++---- 1 file changed, 188 insertions(+), 21 deletions(-) diff --git a/utils/net/http/errors.go b/utils/net/http/errors.go index 3ef969f..be7942d 100644 --- a/utils/net/http/errors.go +++ b/utils/net/http/errors.go @@ -1,11 +1,12 @@ package httputils import ( + "errors" "net/http" httplog "github.com/foomo/keel/net/http/log" "github.com/foomo/keel/telemetry" - "github.com/pkg/errors" + "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" semconv "go.opentelemetry.io/otel/semconv/v1.41.0" "go.uber.org/zap" @@ -13,53 +14,219 @@ import ( ) // InternalServerError http response -func InternalServerError(l *zap.Logger, w http.ResponseWriter, r *http.Request, err error) { - ServerError(l, w, r, http.StatusInternalServerError, err) +func InternalServerError(l *zap.Logger, w http.ResponseWriter, r *http.Request, errs ...error) { + ServerError(l, w, r, http.StatusInternalServerError, errs...) } // InternalServiceUnavailable http response -func InternalServiceUnavailable(l *zap.Logger, w http.ResponseWriter, r *http.Request, err error) { - ServerError(l, w, r, http.StatusServiceUnavailable, err) +func InternalServiceUnavailable(l *zap.Logger, w http.ResponseWriter, r *http.Request, errs ...error) { + ServerError(l, w, r, http.StatusServiceUnavailable, errs...) } // InternalServiceTooEarly http response -func InternalServiceTooEarly(l *zap.Logger, w http.ResponseWriter, r *http.Request, err error) { - ServerError(l, w, r, http.StatusTooEarly, err) +func InternalServiceTooEarly(l *zap.Logger, w http.ResponseWriter, r *http.Request, errs ...error) { + ServerError(l, w, r, http.StatusTooEarly, errs...) } // UnauthorizedServerError http response -func UnauthorizedServerError(l *zap.Logger, w http.ResponseWriter, r *http.Request, err error) { - ServerError(l, w, r, http.StatusUnauthorized, err) +func UnauthorizedServerError(l *zap.Logger, w http.ResponseWriter, r *http.Request, errs ...error) { + ServerError(l, w, r, http.StatusUnauthorized, errs...) } // BadRequestServerError http response -func BadRequestServerError(l *zap.Logger, w http.ResponseWriter, r *http.Request, err error) { - ServerError(l, w, r, http.StatusBadRequest, err) +func BadRequestServerError(l *zap.Logger, w http.ResponseWriter, r *http.Request, errs ...error) { + ServerError(l, w, r, http.StatusBadRequest, errs...) } // MethodNotAllowedServerError http response -func MethodNotAllowedServerError(l *zap.Logger, w http.ResponseWriter, r *http.Request, err error) { - ServerError(l, w, r, http.StatusMethodNotAllowed, err) +func MethodNotAllowedServerError(l *zap.Logger, w http.ResponseWriter, r *http.Request, errs ...error) { + ServerError(l, w, r, http.StatusMethodNotAllowed, errs...) } // RequestEntityTooLargeServerError http response -func RequestEntityTooLargeServerError(l *zap.Logger, w http.ResponseWriter, r *http.Request, err error) { - ServerError(l, w, r, http.StatusRequestEntityTooLarge, err) +func RequestEntityTooLargeServerError(l *zap.Logger, w http.ResponseWriter, r *http.Request, errs ...error) { + ServerError(l, w, r, http.StatusRequestEntityTooLarge, errs...) } // NotFoundServerError http response -func NotFoundServerError(l *zap.Logger, w http.ResponseWriter, r *http.Request, err error) { - ServerError(l, w, r, http.StatusNotFound, err) +func NotFoundServerError(l *zap.Logger, w http.ResponseWriter, r *http.Request, errs ...error) { + ServerError(l, w, r, http.StatusNotFound, errs...) +} + +// PaymentRequiredServerError http response +func PaymentRequiredServerError(l *zap.Logger, w http.ResponseWriter, r *http.Request, errs ...error) { + ServerError(l, w, r, http.StatusPaymentRequired, errs...) +} + +// ForbiddenServerError http response +func ForbiddenServerError(l *zap.Logger, w http.ResponseWriter, r *http.Request, errs ...error) { + ServerError(l, w, r, http.StatusForbidden, errs...) +} + +// NotAcceptableServerError http response +func NotAcceptableServerError(l *zap.Logger, w http.ResponseWriter, r *http.Request, errs ...error) { + ServerError(l, w, r, http.StatusNotAcceptable, errs...) +} + +// ProxyAuthRequiredServerError http response +func ProxyAuthRequiredServerError(l *zap.Logger, w http.ResponseWriter, r *http.Request, errs ...error) { + ServerError(l, w, r, http.StatusProxyAuthRequired, errs...) +} + +// RequestTimeoutServerError http response +func RequestTimeoutServerError(l *zap.Logger, w http.ResponseWriter, r *http.Request, errs ...error) { + ServerError(l, w, r, http.StatusRequestTimeout, errs...) +} + +// ConflictServerError http response +func ConflictServerError(l *zap.Logger, w http.ResponseWriter, r *http.Request, errs ...error) { + ServerError(l, w, r, http.StatusConflict, errs...) +} + +// GoneServerError http response +func GoneServerError(l *zap.Logger, w http.ResponseWriter, r *http.Request, errs ...error) { + ServerError(l, w, r, http.StatusGone, errs...) +} + +// LengthRequiredServerError http response +func LengthRequiredServerError(l *zap.Logger, w http.ResponseWriter, r *http.Request, errs ...error) { + ServerError(l, w, r, http.StatusLengthRequired, errs...) +} + +// PreconditionFailedServerError http response +func PreconditionFailedServerError(l *zap.Logger, w http.ResponseWriter, r *http.Request, errs ...error) { + ServerError(l, w, r, http.StatusPreconditionFailed, errs...) +} + +// RequestURITooLongServerError http response +func RequestURITooLongServerError(l *zap.Logger, w http.ResponseWriter, r *http.Request, errs ...error) { + ServerError(l, w, r, http.StatusRequestURITooLong, errs...) +} + +// UnsupportedMediaTypeServerError http response +func UnsupportedMediaTypeServerError(l *zap.Logger, w http.ResponseWriter, r *http.Request, errs ...error) { + ServerError(l, w, r, http.StatusUnsupportedMediaType, errs...) +} + +// RequestedRangeNotSatisfiableServerError http response +func RequestedRangeNotSatisfiableServerError(l *zap.Logger, w http.ResponseWriter, r *http.Request, errs ...error) { + ServerError(l, w, r, http.StatusRequestedRangeNotSatisfiable, errs...) +} + +// ExpectationFailedServerError http response +func ExpectationFailedServerError(l *zap.Logger, w http.ResponseWriter, r *http.Request, errs ...error) { + ServerError(l, w, r, http.StatusExpectationFailed, errs...) +} + +// TeapotServerError http response +func TeapotServerError(l *zap.Logger, w http.ResponseWriter, r *http.Request, errs ...error) { + ServerError(l, w, r, http.StatusTeapot, errs...) +} + +// MisdirectedRequestServerError http response +func MisdirectedRequestServerError(l *zap.Logger, w http.ResponseWriter, r *http.Request, errs ...error) { + ServerError(l, w, r, http.StatusMisdirectedRequest, errs...) +} + +// UnprocessableEntityServerError http response +func UnprocessableEntityServerError(l *zap.Logger, w http.ResponseWriter, r *http.Request, errs ...error) { + ServerError(l, w, r, http.StatusUnprocessableEntity, errs...) +} + +// LockedServerError http response +func LockedServerError(l *zap.Logger, w http.ResponseWriter, r *http.Request, errs ...error) { + ServerError(l, w, r, http.StatusLocked, errs...) +} + +// FailedDependencyServerError http response +func FailedDependencyServerError(l *zap.Logger, w http.ResponseWriter, r *http.Request, errs ...error) { + ServerError(l, w, r, http.StatusFailedDependency, errs...) +} + +// UpgradeRequiredServerError http response +func UpgradeRequiredServerError(l *zap.Logger, w http.ResponseWriter, r *http.Request, errs ...error) { + ServerError(l, w, r, http.StatusUpgradeRequired, errs...) +} + +// PreconditionRequiredServerError http response +func PreconditionRequiredServerError(l *zap.Logger, w http.ResponseWriter, r *http.Request, errs ...error) { + ServerError(l, w, r, http.StatusPreconditionRequired, errs...) +} + +// TooManyRequestsServerError http response +func TooManyRequestsServerError(l *zap.Logger, w http.ResponseWriter, r *http.Request, errs ...error) { + ServerError(l, w, r, http.StatusTooManyRequests, errs...) +} + +// RequestHeaderFieldsTooLargeServerError http response +func RequestHeaderFieldsTooLargeServerError(l *zap.Logger, w http.ResponseWriter, r *http.Request, errs ...error) { + ServerError(l, w, r, http.StatusRequestHeaderFieldsTooLarge, errs...) +} + +// UnavailableForLegalReasonsServerError http response +func UnavailableForLegalReasonsServerError(l *zap.Logger, w http.ResponseWriter, r *http.Request, errs ...error) { + ServerError(l, w, r, http.StatusUnavailableForLegalReasons, errs...) +} + +// NotImplementedServerError http response +func NotImplementedServerError(l *zap.Logger, w http.ResponseWriter, r *http.Request, errs ...error) { + ServerError(l, w, r, http.StatusNotImplemented, errs...) +} + +// BadGatewayServerError http response +func BadGatewayServerError(l *zap.Logger, w http.ResponseWriter, r *http.Request, errs ...error) { + ServerError(l, w, r, http.StatusBadGateway, errs...) +} + +// GatewayTimeoutServerError http response +func GatewayTimeoutServerError(l *zap.Logger, w http.ResponseWriter, r *http.Request, errs ...error) { + ServerError(l, w, r, http.StatusGatewayTimeout, errs...) +} + +// HTTPVersionNotSupportedServerError http response +func HTTPVersionNotSupportedServerError(l *zap.Logger, w http.ResponseWriter, r *http.Request, errs ...error) { + ServerError(l, w, r, http.StatusHTTPVersionNotSupported, errs...) +} + +// VariantAlsoNegotiatesServerError http response +func VariantAlsoNegotiatesServerError(l *zap.Logger, w http.ResponseWriter, r *http.Request, errs ...error) { + ServerError(l, w, r, http.StatusVariantAlsoNegotiates, errs...) +} + +// InsufficientStorageServerError http response +func InsufficientStorageServerError(l *zap.Logger, w http.ResponseWriter, r *http.Request, errs ...error) { + ServerError(l, w, r, http.StatusInsufficientStorage, errs...) +} + +// LoopDetectedServerError http response +func LoopDetectedServerError(l *zap.Logger, w http.ResponseWriter, r *http.Request, errs ...error) { + ServerError(l, w, r, http.StatusLoopDetected, errs...) +} + +// NotExtendedServerError http response +func NotExtendedServerError(l *zap.Logger, w http.ResponseWriter, r *http.Request, errs ...error) { + ServerError(l, w, r, http.StatusNotExtended, errs...) +} + +// NetworkAuthenticationRequiredServerError http response +func NetworkAuthenticationRequiredServerError(l *zap.Logger, w http.ResponseWriter, r *http.Request, errs ...error) { + ServerError(l, w, r, http.StatusNetworkAuthenticationRequired, errs...) } // ServerError http response -func ServerError(l *zap.Logger, w http.ResponseWriter, r *http.Request, code int, err error) { - if err != nil { +func ServerError(l *zap.Logger, w http.ResponseWriter, r *http.Request, code int, errs ...error) { + if err := errors.Join(errs...); err != nil { + errType := semconv.ErrorType(err) telemetry.Ctx(r.Context()).RecordError(err) + + if labeler, ok := otelhttp.LabelerFromContext(r.Context()); ok { + labeler.Add(errType) + } + // add log entry if labeler, ok := httplog.LabelerFromRequest(r); ok { - labeler.Add(log.FErrorType(err), log.FError(errors.Wrap(err, "http server error"))) - } else { + labeler.Add(log.Attribute(errType), log.FError(err)) + } else if l != nil { l = log.WithError(l, err) l = log.WithHTTPRequest(l, r) l.Error("http server error", log.Attribute(semconv.HTTPResponseStatusCode(code))) From 3e764a29359ec4ba41bc622d3ff9b046b00e1e5a Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Fri, 31 Jul 2026 19:04:08 +0200 Subject: [PATCH 14/23] fix: lint issues --- config/readme.go | 1 + env/readme.go | 1 + option.go | 4 +++- server.go | 5 +++++ service/httpreadme_test.go | 2 +- telemetry/context.go | 6 +++--- 6 files changed, 14 insertions(+), 5 deletions(-) diff --git a/config/readme.go b/config/readme.go index bb557f5..92e37dd 100644 --- a/config/readme.go +++ b/config/readme.go @@ -6,6 +6,7 @@ import ( "github.com/foomo/keel/markdown" ) +// Deprecated: will be removed in future releases func Readme() string { var ( configRows [][]string diff --git a/env/readme.go b/env/readme.go index 11f6793..28889ce 100644 --- a/env/readme.go +++ b/env/readme.go @@ -6,6 +6,7 @@ import ( "github.com/foomo/keel/markdown" ) +// Deprecated: will be removed in future releases func Readme() string { var rows [][]string diff --git a/option.go b/option.go index 0d3b622..ce6c7d8 100644 --- a/option.go +++ b/option.go @@ -364,6 +364,8 @@ func WithHTTPHealthzService(enabled bool) Option { } // WithHTTPReadmeService option with default value +// +// Deprecated: will be removed in future releases func WithHTTPReadmeService(enabled bool) Option { return func(inst *Server) { if config.GetBool(inst.Config(), "service.readme.enabled", enabled)() { @@ -374,7 +376,7 @@ func WithHTTPReadmeService(enabled bool) Option { } } -// WithInitService option with default value +// WithInitService option with a default value func WithInitService(service Service) Option { return func(inst *Server) { if service == nil || slices.Contains(inst.initServices, service) { diff --git a/server.go b/server.go index 6e15837..9b3920c 100644 --- a/server.go +++ b/server.go @@ -149,6 +149,7 @@ func NewServer(opts ...Option) *Server { // add probe inst.AddAlwaysHealthzers(inst) + //nolint:staticcheck //SA1019 inst.AddReadmers( interfaces.ReadmeFunc(env.Readme), interfaces.ReadmeFunc(config.Readme), @@ -251,11 +252,15 @@ func (s *Server) AddClosers(closers ...any) { } // AddReadmer adds a readmer to be added to the exposed readme +// +// Deprecated: will be removed in future releases func (s *Server) AddReadmer(readmer interfaces.Readmer) { s.addReadmers(readmer) } // AddReadmers adds readmers to be added to the exposed readme +// +// Deprecated: will be removed in future releases func (s *Server) AddReadmers(readmers ...interfaces.Readmer) { for _, readmer := range readmers { s.AddReadmer(readmer) diff --git a/service/httpreadme_test.go b/service/httpreadme_test.go index e29286f..a6058cf 100644 --- a/service/httpreadme_test.go +++ b/service/httpreadme_test.go @@ -27,7 +27,7 @@ func _ExampleNewHTTPReadme() { svr := keel.NewServer( keel.WithLogger(zap.NewNop()), keel.WithTelemetry(), - keel.WithHTTPReadmeService(true), + keel.WithHTTPReadmeService(true), //nolint:staticcheck keel.WithGracefulPeriod(3*time.Second), ) diff --git a/telemetry/context.go b/telemetry/context.go index f47b7ce..e53856d 100644 --- a/telemetry/context.go +++ b/telemetry/context.go @@ -104,7 +104,7 @@ func (c Context) Value(key any) any { // Deadline returns the time when work done on behalf of this context should be // canceled. Deadline returns ok==false when no deadline is set. -func (c Context) Deadline() (deadline time.Time, ok bool) { +func (c Context) Deadline() (deadline time.Time, ok bool) { //nolint:nonamedreturns return c.ctx.Deadline() } @@ -264,9 +264,9 @@ func (c Context) startSpan(name string, skip int, opts ...trace.SpanStartOption) } } - ctx, span := Tracer().Start(c.ctx, name, opts...) + ctx, span := Tracer().Start(c.ctx, name, opts...) //nolint:spancheck - return Ctx(ctx), span + return Ctx(ctx), span //nolint:spancheck } func (c Context) log(ctx context.Context, lvl zapcore.Level, msg string, skip int, kv ...attribute.KeyValue) { From 9996753972e144909e8725ddd5f450b0e7708f9b Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Sat, 1 Aug 2026 22:01:43 +0200 Subject: [PATCH 15/23] test: fix typo --- service/goroutine_test.go | 2 +- telemetry/main_test.go | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/service/goroutine_test.go b/service/goroutine_test.go index 2684101..72ef453 100644 --- a/service/goroutine_test.go +++ b/service/goroutine_test.go @@ -50,7 +50,7 @@ func ExampleNewGoRoutine() { // {"level":"info","msg":"keel closer closed","graceful_period":"3s"} // {"level":"info","msg":"keel closer closed: closers"} // {"level":"info","msg":"stopping keel service","keel_service_type":"goroutine","keel_service_name":"demo"} - // {"level":"info","msg":"context has been canceled du to graceful shutdow","keel_service_type":"goroutine","keel_service_name":"demo","keel_service_inst":0} + // {"level":"info","msg":"context has been canceled du to graceful shutdown","keel_service_type":"goroutine","keel_service_name":"demo","keel_service_inst":0} // {"level":"debug","msg":"keel closer closed","name":"*service.GoRoutine"} // {"level":"debug","msg":"keel closer closed","name":"noop.TracerProvider"} // {"level":"debug","msg":"keel closer closed","name":"noop.MeterProvider"} diff --git a/telemetry/main_test.go b/telemetry/main_test.go index 753fe19..10464c4 100644 --- a/telemetry/main_test.go +++ b/telemetry/main_test.go @@ -7,5 +7,8 @@ import ( ) func TestMain(m *testing.M) { - goleak.VerifyTestMain(m) + goleak.VerifyTestMain(m, + goleak.IgnoreTopFunction("go.opentelemetry.io/otel/sdk/metric.(*PeriodicReader).run"), + goleak.IgnoreTopFunction("go.opentelemetry.io/otel/sdk/trace.(*batchSpanProcessor).processQueue"), + ) } From 72aafca2464775ff7c95ca57784e7e124b3fc772 Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Sat, 1 Aug 2026 22:39:35 +0200 Subject: [PATCH 16/23] feat: add trace api --- .../gotsrpc/net/middleware/telemetry.go | 23 +++-- telemetry/context.go | 79 +++++++---------- telemetry/span.go | 84 ++++++++++++++++++- 3 files changed, 121 insertions(+), 65 deletions(-) diff --git a/integration/gotsrpc/net/middleware/telemetry.go b/integration/gotsrpc/net/middleware/telemetry.go index 26b46aa..514edc7 100644 --- a/integration/gotsrpc/net/middleware/telemetry.go +++ b/integration/gotsrpc/net/middleware/telemetry.go @@ -17,6 +17,7 @@ import ( "github.com/foomo/keel/telemetry" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/codes" "go.opentelemetry.io/otel/metric" semconv "go.opentelemetry.io/otel/semconv/v1.41.0" "go.uber.org/zap" @@ -128,21 +129,19 @@ func TelemetryWithOptions(opts TelemetryOptions) keelhttp.Middleware { return func(l *zap.Logger, name string, next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { *r = *gotsrpc.RequestWithStatsContext(r) + sp := telemetry.SpanFromContext(r.Context()) - ctx := telemetry.Ctx(r.Context()) - ctx.AddSpanEvent("GOTSRPC Telemetry") - - r = r.WithContext(ctx) + sp.AddEvent("GOTSRPC Telemetry") next.ServeHTTP(w, r) if stats, ok := gotsrpc.GetStatsForRequest(r); ok { if !opts.PayloadAttributeDisabled { - ctx.SetSpanAttributes(keelsemconv.GoTSRPCPayload(sanitizePayload(r))) + sp.SetAttributes(keelsemconv.GoTSRPCPayload(sanitizePayload(r))) } // override span name - ctx.SetSpanName(fmt.Sprintf("%s/%s", stats.Service, stats.Func)) + sp.SetName(fmt.Sprintf("%s/%s", stats.Service, stats.Func)) // define default attributes attrs := []attribute.KeyValue{ @@ -153,25 +152,25 @@ func TelemetryWithOptions(opts TelemetryOptions) keelhttp.Middleware { } // add trace attributes - ctx.SetSpanAttributes(append(attrs, + sp.SetAttributes(append(attrs, keelsemconv.GoTSRPCMarshalling(stats.Marshalling.Milliseconds()), keelsemconv.GoTSRPCUnmarshalling(stats.Unmarshalling.Milliseconds()), )...) if stats.ErrorCode != 0 { - ctx.SetSpanStatusError(stats.ErrorMessage) - ctx.SetSpanAttributes(keelsemconv.GoTSRPCErrorCode(stats.ErrorCode)) + sp.SetStatus(codes.Error, stats.ErrorMessage) + sp.SetAttributes(keelsemconv.GoTSRPCErrorCode(stats.ErrorCode)) } if stats.ErrorType != "" { - ctx.SetSpanAttributes(keelsemconv.GoTSRPCErrorType(stats.ErrorType)) + sp.SetAttributes(keelsemconv.GoTSRPCErrorType(stats.ErrorType)) } if stats.ErrorMessage != "" { - ctx.SetSpanAttributes(keelsemconv.GoTSRPCErrorMessage(stats.ErrorMessage)) + sp.SetAttributes(keelsemconv.GoTSRPCErrorMessage(stats.ErrorMessage)) } - m.Record(ctx, + m.Record(r.Context(), stats.Execution.Seconds(), stats.Package, stats.Service, diff --git a/telemetry/context.go b/telemetry/context.go index e53856d..1eb97ba 100644 --- a/telemetry/context.go +++ b/telemetry/context.go @@ -7,7 +7,6 @@ import ( "time" goruntime "github.com/foomo/go/runtime" - keelsemconv "github.com/foomo/keel/semconv" foomosemconv "github.com/foomo/opentelemetry-go/semconv" "github.com/grafana/pyroscope-go" "github.com/pkg/errors" @@ -28,71 +27,75 @@ func Ctx(ctx context.Context) Context { } // ------------------------------------------------------------------------------------------------ -// ~ Public methods +// ~ Log methods // ------------------------------------------------------------------------------------------------ // LogDebug logs a message at `debug` level. func (c Context) LogDebug(msg string, kv ...attribute.KeyValue) { - c.log(c.ctx, zapcore.DebugLevel, msg, 1, kv...) + Log(c.ctx, zapcore.DebugLevel, msg, 1, kv...) } // LogInfo logs a message at `info` level. func (c Context) LogInfo(msg string, kv ...attribute.KeyValue) { - c.log(c.ctx, zapcore.InfoLevel, msg, 1, kv...) + Log(c.ctx, zapcore.InfoLevel, msg, 1, kv...) } // LogWarn logs a message at `warn` level. func (c Context) LogWarn(msg string, kv ...attribute.KeyValue) { - c.log(c.ctx, zapcore.WarnLevel, msg, 1, kv...) + Log(c.ctx, zapcore.WarnLevel, msg, 1, kv...) } // LogError logs a message at `error` level. func (c Context) LogError(msg string, kv ...attribute.KeyValue) { - c.log(c.ctx, zapcore.ErrorLevel, msg, 1, kv...) + Log(c.ctx, zapcore.ErrorLevel, msg, 1, kv...) } +// ------------------------------------------------------------------------------------------------ +// ~ Context methods +// ------------------------------------------------------------------------------------------------ + // Context returns the underlying context.Context. func (c Context) Context() context.Context { return c.ctx } -// ContextWithCancel returns a copy of the context with a new Done channel. +// WithCancel returns a copy of the context with a new Done channel. // The returned context's Done channel is closed when the returned cancel function // is called or when the parent context's Done channel is closed, whichever happens first. -func (c Context) ContextWithCancel() (context.Context, context.CancelFunc) { +func (c Context) WithCancel() (context.Context, context.CancelFunc) { return context.WithCancel(c.ctx) } -// ContextWithCancelCause returns a copy of the context with a new Done channel and +// WithCancelCause returns a copy of the context with a new Done channel and // a CancelCauseFunc instead of a CancelFunc. Calling cancel with a non-nil error // (the "cause") records that error in the context; it can then be retrieved using Cause(ctx). -func (c Context) ContextWithCancelCause() (context.Context, context.CancelCauseFunc) { +func (c Context) WithCancelCause() (context.Context, context.CancelCauseFunc) { return context.WithCancelCause(c.ctx) } -// ContextWith returns a copy of the context with a deadline. +// WithDeadline returns a copy of the context with a deadline. // The returned context's Done channel is closed when the deadline expires, when the // returned cancel function is called, or when the parent context's Done channel is // closed, whichever happens first. -func (c Context) ContextWith(deadline time.Time) (context.Context, context.CancelFunc) { +func (c Context) WithDeadline(deadline time.Time) (context.Context, context.CancelFunc) { return context.WithDeadline(c.ctx, deadline) } -// ContextWithTimeout returns a copy of the context with a timeout. +// WithTimeout returns a copy of the context with a timeout. // It is equivalent to ContextWith(time.Now().Add(timeout)). -func (c Context) ContextWithTimeout(timeout time.Duration) (context.Context, context.CancelFunc) { +func (c Context) WithTimeout(timeout time.Duration) (context.Context, context.CancelFunc) { return context.WithTimeout(c.ctx, timeout) } -// ContextWithValue returns a copy of the context with the key-value pair associated. -func (c Context) ContextWithValue(key, val any) context.Context { +// WithValue returns a copy of the context with the key-value pair associated. +func (c Context) WithValue(key, val any) context.Context { return context.WithValue(c.ctx, key, val) } -// ContextWithoutCancel returns a copy of the context that is not canceled when +// WithoutCancel returns a copy of the context that is not canceled when // parent is canceled. The returned context returns no Deadline or Err, and its // Done channel is nil. -func (c Context) ContextWithoutCancel() context.Context { +func (c Context) WithoutCancel() context.Context { return context.WithoutCancel(c.ctx) } @@ -120,46 +123,28 @@ func (c Context) Err() error { return c.ctx.Err() } +// ------------------------------------------------------------------------------------------------ +// ~ Trace methods +// ------------------------------------------------------------------------------------------------ + // Span returns the span from the context. func (c Context) Span() trace.Span { - return trace.SpanFromContext(c.ctx) + return SpanFromContext(c.ctx) } // SetSpanDebug sets the span debug attribute. func (c Context) SetSpanDebug() { - c.Span().SetAttributes(keelsemconv.DebugEnabled(true)) + SetSpanDebug(c.ctx) } // EndSpan ends the span. func (c Context) EndSpan(err error, opts ...trace.SpanEndOption) { - sp := c.Span() - if sp.IsRecording() { - if err != nil { - sp.RecordError(err, trace.WithAttributes(CodeStacktrace(3, 0))) - sp.SetStatus(codes.Error, errors.Cause(err).Error()) - } else { - c.SetSpanStatusOK() - } - - sp.End(opts...) - } + EndSpan(c.ctx, err, opts...) } -// DeferEndSpan is a helper so you can do `defer ctx.DeferEndSpan(&err)` instead of `defer func(){ ctx.EndSpan(err) }()` +// DeferEndSpan is a helper, so you can do `defer ctx.DeferEndSpan(&err)` instead of `defer func(){ ctx.EndSpan(err) }()` func (c Context) DeferEndSpan(err *error, opts ...trace.SpanEndOption) { - e := *err - - sp := c.Span() - if sp.IsRecording() { - if e != nil { - sp.RecordError(e, trace.WithAttributes(CodeStacktrace(5, 2))) - sp.SetStatus(codes.Error, errors.Cause(e).Error()) - } else { - c.SetSpanStatusOK() - } - - sp.End(opts...) - } + DeferEndSpan(c.ctx, err, opts...) } // SetSpanStatusOK sets the status of the span to ok. @@ -268,7 +253,3 @@ func (c Context) startSpan(name string, skip int, opts ...trace.SpanStartOption) return Ctx(ctx), span //nolint:spancheck } - -func (c Context) log(ctx context.Context, lvl zapcore.Level, msg string, skip int, kv ...attribute.KeyValue) { - Log(ctx, lvl, msg, skip+1, kv...) -} diff --git a/telemetry/span.go b/telemetry/span.go index 59494d0..6e635bb 100644 --- a/telemetry/span.go +++ b/telemetry/span.go @@ -3,23 +3,99 @@ package telemetry import ( "context" + keelsemconv "github.com/foomo/keel/semconv" + "github.com/pkg/errors" + "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/codes" "go.opentelemetry.io/otel/trace" ) -// Deprecated: use Ctx instead. +// Deprecated: use StartSpan instead. func Start(ctx context.Context, spanName string, opts ...trace.SpanStartOption) (context.Context, trace.Span) { + return StartSpan(ctx, spanName, opts...) +} + +// StartSpan starts a new span with the given name and options. +func StartSpan(ctx context.Context, spanName string, opts ...trace.SpanStartOption) (context.Context, trace.Span) { return Tracer().Start(ctx, spanName, opts...) //nolint:spancheck } -// Deprecated: use Ctx instead. +func SpanFromContext(ctx context.Context) trace.Span { + return trace.SpanFromContext(ctx) +} + +// AddSpanEvent adds an event to the span. +func AddSpanEvent(ctx context.Context, name string, opts ...trace.EventOption) { + SpanFromContext(ctx).AddEvent(name, opts...) +} + +// SetSpanAttributes sets attributes on the span. +func SetSpanAttributes(ctx context.Context, attrs ...attribute.KeyValue) { + SpanFromContext(ctx).SetAttributes(attrs...) +} + +// SetSpanName sets the name of the span. +func SetSpanName(ctx context.Context, name string) { + SpanFromContext(ctx).SetName(name) +} + +// IsSpanRecording returns true if the span is recording. +func IsSpanRecording(ctx context.Context) bool { + return SpanFromContext(ctx).IsRecording() +} + +// SetSpanDebug sets the span debug attribute. +func SetSpanDebug(ctx context.Context) { + SpanFromContext(ctx).SetAttributes(keelsemconv.DebugEnabled(true)) +} + +// SetSpanStatusOK sets the status of the span to ok. +func SetSpanStatusOK(ctx context.Context) { + SpanFromContext(ctx).SetStatus(codes.Ok, "") +} + +// SetSpanStatusError sets the status of the span to error. +func SetSpanStatusError(ctx context.Context, description string) { + SpanFromContext(ctx).SetStatus(codes.Error, description) +} + +// Deprecated: use EndSpan instead. func End(sp trace.Span, err error) { if err != nil { - sp.RecordError(err) - sp.SetStatus(codes.Error, err.Error()) + sp.RecordError(err, trace.WithAttributes(CodeStacktrace(3, 0))) + sp.SetStatus(codes.Error, errors.Cause(err).Error()) } else { sp.SetStatus(codes.Ok, "") } sp.End() } + +// EndSpan ends the span. +func EndSpan(ctx context.Context, err error, opts ...trace.SpanEndOption) { + sp := SpanFromContext(ctx) + if err != nil { + sp.RecordError(err, trace.WithAttributes(CodeStacktrace(3, 0))) + sp.SetStatus(codes.Error, errors.Cause(err).Error()) + } else { + sp.SetStatus(codes.Ok, "") + } + + sp.End(opts...) +} + +// DeferEndSpan is a helper, so you can do `defer ctx.DeferEndSpan(&err)` instead of `defer func(){ ctx.EndSpan(err) }()` +func DeferEndSpan(ctx context.Context, err *error, opts ...trace.SpanEndOption) { + e := *err + + sp := SpanFromContext(ctx) + + if e != nil { + sp.RecordError(e, trace.WithAttributes(CodeStacktrace(5, 2))) + sp.SetStatus(codes.Error, errors.Cause(e).Error()) + } else { + sp.SetStatus(codes.Ok, "") + } + + sp.End(opts...) +} From 7da2cdfe39bae15a46f10fe00d497a0e1a2bcf7a Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Sun, 2 Aug 2026 16:38:13 +0200 Subject: [PATCH 17/23] refactor: move startSpan --- telemetry/context.go | 32 +++----------------------------- telemetry/span.go | 26 +++++++++++++++++++++++--- 2 files changed, 26 insertions(+), 32 deletions(-) diff --git a/telemetry/context.go b/telemetry/context.go index 1eb97ba..8952b73 100644 --- a/telemetry/context.go +++ b/telemetry/context.go @@ -2,17 +2,14 @@ package telemetry import ( "context" - "path" "runtime/pprof" "time" - goruntime "github.com/foomo/go/runtime" foomosemconv "github.com/foomo/opentelemetry-go/semconv" "github.com/grafana/pyroscope-go" "github.com/pkg/errors" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/codes" - semconv "go.opentelemetry.io/otel/semconv/v1.41.0" "go.opentelemetry.io/otel/trace" "go.uber.org/zap/zapcore" ) @@ -196,19 +193,19 @@ func (c Context) AddSpanEvent(name string, kv ...attribute.KeyValue) { // StartSpan starts a span. func (c Context) StartSpan(opts ...trace.SpanStartOption) Context { - ctx, _ := c.startSpan("", 1, opts...) + ctx, _ := startSpan(c.ctx, 1, opts...) return ctx } // StartSpanWithNewRoot sets the name of the span. func (c Context) StartSpanWithNewRoot(opts ...trace.SpanStartOption) Context { - ctx, _ := c.startSpan("", 1, append(opts, trace.WithNewRoot(), trace.WithLinks(trace.LinkFromContext(c.ctx)))...) + ctx, _ := startSpan(c.ctx, 1, append(opts, trace.WithNewRoot(), trace.WithLinks(trace.LinkFromContext(c.ctx)))...) return ctx } // StartSpanWithProfile starts a span and profiles the handler. func (c Context) StartSpanWithProfile(name string, handler func(ctx Context), kv ...attribute.KeyValue) { - ctx, span := c.startSpan("", 1, trace.WithAttributes(kv...)) + ctx, span := startSpan(c.ctx, 1, trace.WithAttributes(kv...)) defer span.End() ctx.StartProfile(name, handler, kv...) @@ -230,26 +227,3 @@ func (c Context) SetProfileAttributes(kv ...attribute.KeyValue) Context { return Ctx(ctx) } - -// ------------------------------------------------------------------------------------------------ -// ~ Private methods -// ------------------------------------------------------------------------------------------------ - -func (c Context) startSpan(name string, skip int, opts ...trace.SpanStartOption) (Context, trace.Span) { - if name == "" { - if fr := goruntime.CallFrame(skip + 1); !fr.Zero() { - name = path.Base(fr.Pkg) + "." + fr.Short() - opts = append(opts, trace.WithAttributes( - semconv.CodeFunctionName(fr.Name()), - semconv.CodeLineNumber(fr.Line), - semconv.CodeFilePath(fr.File), - )) - } else { - name = "runtime.go" - } - } - - ctx, span := Tracer().Start(c.ctx, name, opts...) //nolint:spancheck - - return Ctx(ctx), span //nolint:spancheck -} diff --git a/telemetry/span.go b/telemetry/span.go index 6e635bb..9a48e93 100644 --- a/telemetry/span.go +++ b/telemetry/span.go @@ -2,22 +2,25 @@ package telemetry import ( "context" + "path" + goruntime "github.com/foomo/go/runtime" keelsemconv "github.com/foomo/keel/semconv" "github.com/pkg/errors" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/codes" + semconv "go.opentelemetry.io/otel/semconv/v1.41.0" "go.opentelemetry.io/otel/trace" ) // Deprecated: use StartSpan instead. func Start(ctx context.Context, spanName string, opts ...trace.SpanStartOption) (context.Context, trace.Span) { - return StartSpan(ctx, spanName, opts...) + return startSpan(ctx, 1, opts...) } // StartSpan starts a new span with the given name and options. -func StartSpan(ctx context.Context, spanName string, opts ...trace.SpanStartOption) (context.Context, trace.Span) { - return Tracer().Start(ctx, spanName, opts...) //nolint:spancheck +func StartSpan(ctx context.Context, opts ...trace.SpanStartOption) (context.Context, trace.Span) { + return startSpan(ctx, 1, opts...) } func SpanFromContext(ctx context.Context) trace.Span { @@ -99,3 +102,20 @@ func DeferEndSpan(ctx context.Context, err *error, opts ...trace.SpanEndOption) sp.End(opts...) } + +func startSpan(ctx context.Context, skip int, opts ...trace.SpanStartOption) (Context, trace.Span) { + name := "runtime.go" + + if fr := goruntime.CallFrame(skip + 1); !fr.Zero() { + name = path.Base(fr.Pkg) + opts = append(opts, trace.WithAttributes( + semconv.CodeFunctionName(fr.Name()), + semconv.CodeLineNumber(fr.Line), + semconv.CodeFilePath(fr.File), + )) + } + + ctx, span := Tracer().Start(ctx, name, opts...) //nolint:spancheck + + return Ctx(ctx), span //nolint:spancheck +} From e86fea731e8e8c9e804a45feea2a1a393c9f9f3e Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Tue, 4 Aug 2026 13:45:28 +0200 Subject: [PATCH 18/23] feat: mark deprecations --- integration/gotsrpc/net/middleware/telemetry.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/integration/gotsrpc/net/middleware/telemetry.go b/integration/gotsrpc/net/middleware/telemetry.go index 514edc7..e95bc08 100644 --- a/integration/gotsrpc/net/middleware/telemetry.go +++ b/integration/gotsrpc/net/middleware/telemetry.go @@ -80,6 +80,8 @@ func TelemetryWithPayloadAttributeDisabled(v bool) TelemetryOption { } // Telemetry middleware +// +// Deprecated: use gotsrpc v3 as includes otel func Telemetry(opts ...TelemetryOption) keelhttp.Middleware { options := DefaultTelemetryOptions() @@ -93,6 +95,8 @@ func Telemetry(opts ...TelemetryOption) keelhttp.Middleware { } // TelemetryWithOptions middleware +// +// Deprecated: use gotsrpc v3 as includes otel func TelemetryWithOptions(opts TelemetryOptions) keelhttp.Middleware { m, err := gotsrpcconv.NewExecutionDuration( opts.meter, From bcbcc1a39970c1ba38f6113a4bb824fbc228c692 Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Tue, 4 Aug 2026 14:06:09 +0200 Subject: [PATCH 19/23] feat: add StartDebugTrace --- telemetry/span.go | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/telemetry/span.go b/telemetry/span.go index 9a48e93..a1fe8f4 100644 --- a/telemetry/span.go +++ b/telemetry/span.go @@ -23,6 +23,11 @@ func StartSpan(ctx context.Context, opts ...trace.SpanStartOption) (context.Cont return startSpan(ctx, 1, opts...) } +// StartDebugSpan starts a new span with the given name and options and adds the debug attr. +func StartDebugSpan(ctx context.Context, opts ...trace.SpanStartOption) (context.Context, trace.Span) { + return startSpan(ctx, 1, append(opts, trace.WithAttributes(keelsemconv.DebugEnabled(true)))...) +} + func SpanFromContext(ctx context.Context) trace.Span { return trace.SpanFromContext(ctx) } @@ -80,8 +85,6 @@ func EndSpan(ctx context.Context, err error, opts ...trace.SpanEndOption) { if err != nil { sp.RecordError(err, trace.WithAttributes(CodeStacktrace(3, 0))) sp.SetStatus(codes.Error, errors.Cause(err).Error()) - } else { - sp.SetStatus(codes.Ok, "") } sp.End(opts...) @@ -89,18 +92,7 @@ func EndSpan(ctx context.Context, err error, opts ...trace.SpanEndOption) { // DeferEndSpan is a helper, so you can do `defer ctx.DeferEndSpan(&err)` instead of `defer func(){ ctx.EndSpan(err) }()` func DeferEndSpan(ctx context.Context, err *error, opts ...trace.SpanEndOption) { - e := *err - - sp := SpanFromContext(ctx) - - if e != nil { - sp.RecordError(e, trace.WithAttributes(CodeStacktrace(5, 2))) - sp.SetStatus(codes.Error, errors.Cause(e).Error()) - } else { - sp.SetStatus(codes.Ok, "") - } - - sp.End(opts...) + EndSpan(ctx, *err) } func startSpan(ctx context.Context, skip int, opts ...trace.SpanStartOption) (Context, trace.Span) { From 98445ce132d17c5561789b262d184bc3a153a2fb Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Tue, 4 Aug 2026 16:40:53 +0200 Subject: [PATCH 20/23] feat: add gotsrpc services and distributed rw lock --- Makefile | 8 +- examples/go.mod | 24 +++-- examples/go.sum | 58 ++++++----- go.mod | 28 +++--- go.sum | 56 ++++------- integration/gotsrpc/go.mod | 2 +- integration/gotsrpc/go.sum | 4 +- integration/gotsrpc/gorpcclient.go | 6 ++ integration/gotsrpc/gorpcclientservice.go | 33 ++++++ integration/gotsrpc/gorpcproxy.go | 6 ++ integration/gotsrpc/gorpcproxyservice.go | 35 +++++++ integration/nats/go.mod | 9 +- integration/nats/go.sum | 29 +++--- integration/temporal/go.mod | 2 +- integration/temporal/go.sum | 4 +- net/stream/go.mod | 2 +- net/stream/go.sum | 4 +- persistence/distributedrwlock.go | 16 +++ persistence/mongo/distributedrwlock.go | 100 +++++++++++++++++++ persistence/mongo/distributedrwlockconfig.go | 83 +++++++++++++++ persistence/mongo/go.mod | 1 + persistence/mongo/go.sum | 80 +++++++++++++++ 22 files changed, 468 insertions(+), 122 deletions(-) create mode 100644 integration/gotsrpc/gorpcclient.go create mode 100644 integration/gotsrpc/gorpcclientservice.go create mode 100644 integration/gotsrpc/gorpcproxy.go create mode 100644 integration/gotsrpc/gorpcproxyservice.go create mode 100644 persistence/distributedrwlock.go create mode 100644 persistence/mongo/distributedrwlock.go create mode 100644 persistence/mongo/distributedrwlockconfig.go diff --git a/Makefile b/Makefile index e7321c1..78c214c 100644 --- a/Makefile +++ b/Makefile @@ -155,7 +155,7 @@ actionlint: @actionlint .PHONY: help -# https://patorjk.com/software/taag/#p=display&f=Tmplr&t=keel&x=none&v=4&h=4&w=80&we=false +# https://patorjk.com/software/taag/#p=display&f=Future+Smooth&t=keel&x=none&v=4&h=4&w=80&we=false ## Show help text help: g=\033[0;32m help: b=\033[0;34m @@ -163,9 +163,9 @@ help: w=\033[0;90m help: e=\033[0m help: @echo "$(g)" - @echo "┓ ┓" - @echo "┃┏┏┓┏┓┃" - @echo "┛┗┗ ┗ ┗" + @echo "╷╭ ╭─╴╭─╴╷" + @echo "├┴╮├╴ ├╴ │" + @echo "╵ ╵╰─╴╰─╴╰─╴" @echo "with ❤ foomo by bestbytes" @echo "$(e)" @echo "$(b)Usage:$(e)\n make [task]" diff --git a/examples/go.mod b/examples/go.mod index f0aae29..f42cfb5 100644 --- a/examples/go.mod +++ b/examples/go.mod @@ -45,10 +45,11 @@ require ( github.com/fatih/color v1.19.0 // indirect github.com/fbiville/markdown-table-formatter v0.3.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect - github.com/foomo/go v0.15.0 // indirect - github.com/foomo/goflux v0.4.4 // indirect - github.com/foomo/gofuncy v0.2.0 // indirect + github.com/foomo/go v0.16.0 // indirect + github.com/foomo/goflux v0.6.0 // indirect + github.com/foomo/gofuncy v0.4.0 // indirect github.com/foomo/gostandards v0.3.0 // indirect + github.com/foomo/mongo-lock v0.2.0 // indirect github.com/foomo/opentelemetry-go v0.4.0 // indirect github.com/fsnotify/fsnotify v1.10.1 // indirect github.com/go-logr/logr v1.4.4 // indirect @@ -59,13 +60,13 @@ require ( github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/google/s2a-go v0.1.9 // indirect - github.com/googleapis/enterprise-certificate-proxy v0.3.15 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.3.16 // indirect github.com/googleapis/gax-go/v2 v2.22.0 // indirect github.com/grafana/otel-profiling-go v0.6.0 // indirect github.com/grafana/pyroscope-go v1.4.1 // indirect github.com/grafana/pyroscope-go/godeltaprof v0.1.11 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0 // indirect - github.com/hashicorp/consul/api v1.34.2 // indirect + github.com/hashicorp/consul/api v1.34.3 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-hclog v1.6.3 // indirect @@ -79,7 +80,7 @@ require ( github.com/klauspost/compress v1.19.1 // indirect github.com/lib/pq v1.12.3 // indirect github.com/lufia/plan9stats v0.0.0-20260330125221-c963978e514e // indirect - github.com/mattn/go-colorable v0.1.14 // indirect + github.com/mattn/go-colorable v0.1.15 // indirect github.com/mattn/go-isatty v0.0.22 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect @@ -120,7 +121,7 @@ require ( go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/contrib/bridges/otelzap v0.19.0 // indirect go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/v2/mongo/otelmongo v0.0.0-20260623174712-bbae83b5df0c // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.68.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.69.0 // indirect go.opentelemetry.io/contrib/instrumentation/host v0.69.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0 // indirect go.opentelemetry.io/contrib/instrumentation/runtime v0.69.0 // indirect @@ -143,18 +144,19 @@ require ( go.uber.org/multierr v1.11.0 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect golang.org/x/crypto v0.54.0 // indirect - golang.org/x/exp v0.0.0-20260508232706-74f9aab9d74a // indirect + golang.org/x/exp v0.0.0-20260529124908-c761662dc8c9 // indirect + golang.org/x/mod v0.38.0 // indirect golang.org/x/net v0.57.0 // indirect golang.org/x/oauth2 v0.36.0 // indirect golang.org/x/sync v0.22.0 // indirect golang.org/x/sys v0.47.0 // indirect golang.org/x/text v0.40.0 // indirect golang.org/x/time v0.15.0 // indirect - google.golang.org/api v0.278.0 // indirect - google.golang.org/genproto v0.0.0-20260511170946-3700d4141b60 // indirect + google.golang.org/api v0.282.0 // indirect + google.golang.org/genproto v0.0.0-20260526163538-3dc84a4a5aaa // indirect google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa // indirect - google.golang.org/grpc v1.81.1 // indirect + google.golang.org/grpc v1.82.1 // indirect google.golang.org/protobuf v1.36.11 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/examples/go.sum b/examples/go.sum index 4964378..881082f 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -1,5 +1,5 @@ -charm.land/lipgloss/v2 v2.0.2 h1:xFolbF8JdpNkM2cEPTfXEcW1p6NRzOWTSamRfYEw8cs= -charm.land/lipgloss/v2 v2.0.2/go.mod h1:KjPle2Qd3YmvP1KL5OMHiHysGcNwq6u83MUjYkFvEkM= +charm.land/lipgloss/v2 v2.0.3 h1:yM2zJ4Cf5Y51b7RHIwioil4ApI/aypFXXVHSwlM6RzU= +charm.land/lipgloss/v2 v2.0.3/go.mod h1:7myLU9iG/3xluAWzpY/fSxYYHCgoKTie7laxk6ATwXA= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.123.0 h1:2NAUJwPR47q+E35uaJeYoNhuNEM9kM8SjgRgdeOJUSE= cloud.google.com/go v0.123.0/go.mod h1:xBoMV08QcqUGuPW65Qfm1o9Y4zKZBpGS+7bImXLTAZU= @@ -46,8 +46,8 @@ github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UF github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/charmbracelet/colorprofile v0.4.3 h1:QPa1IWkYI+AOB+fE+mg/5/4HRMZcaXex9t5KX76i20Q= github.com/charmbracelet/colorprofile v0.4.3/go.mod h1:/zT4BhpD5aGFpqQQqw7a+VtHCzu+zrQtt1zhMt9mR4Q= -github.com/charmbracelet/ultraviolet v0.0.0-20260330092749-0f94982c930b h1:ASDO9RT6SNKTQN87jO2bRfxHFJq8cgeYdFzivY2gCeM= -github.com/charmbracelet/ultraviolet v0.0.0-20260330092749-0f94982c930b/go.mod h1:Vo8TffMf0q7Uho/n8e6XpBZvOWtd3g39yX+9P5rRutA= +github.com/charmbracelet/ultraviolet v0.0.0-20260416161146-9c68a866306c h1:a+Q3cOt8vEb6ETG/st32Qjm8R5fdI9wSKb3tqPISnoY= +github.com/charmbracelet/ultraviolet v0.0.0-20260416161146-9c68a866306c/go.mod h1:bAAz7dh/FTYfC+oiHavL4mX1tOIBZ0ZwYjSi3qE6ivM= github.com/charmbracelet/x/ansi v0.11.7 h1:kzv1kJvjg2S3r9KHo8hDdHFQLEqn4RBCb39dAYC84jI= github.com/charmbracelet/x/ansi v0.11.7/go.mod h1:9qGpnAVYz+8ACONkZBUWPtL7lulP9No6p1epAihUZwQ= github.com/charmbracelet/x/term v0.2.2 h1:xVRT/S2ZcKdhhOuSP4t5cLi5o+JxklsoEObBSgfgZRk= @@ -102,14 +102,16 @@ github.com/fbiville/markdown-table-formatter v0.3.0 h1:PIm1UNgJrFs8q1htGTw+wnnNY github.com/fbiville/markdown-table-formatter v0.3.0/go.mod h1:q89TDtSEVDdTaufgSbfHpNVdPU/bmfvqNkrC5HagmLY= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/foomo/go v0.15.0 h1:i6bcReoSLPpRVUVsd7anB6BCVBNimaOjiDeI+9I9rq0= -github.com/foomo/go v0.15.0/go.mod h1:jeSB/atkoqSoJ3+ak0+b/Xtj7IMyDj1odzJroudT7Dw= -github.com/foomo/goflux v0.4.4 h1:T7QhIPdZze3bNEeNjdEAzBV08/ikEgmTmK3maWucAo4= -github.com/foomo/goflux v0.4.4/go.mod h1:c2qy02JR9Y5qlVl49nDSEipCQENbGhDZzjT8p72G7Xs= -github.com/foomo/gofuncy v0.2.0 h1:fanMIpHocWfoP+u8sevF+Qb/gEh38QeiS6FjeXB+Sx0= -github.com/foomo/gofuncy v0.2.0/go.mod h1:WnqsC/Ku/19tk0LYHVG8z9tsT9duKqpxHMiJioznv1M= +github.com/foomo/go v0.16.0 h1:Hw2rl0ieMB+s9NK8+MuIHzD22h48whyoKV+CA+lFG1k= +github.com/foomo/go v0.16.0/go.mod h1:jeSB/atkoqSoJ3+ak0+b/Xtj7IMyDj1odzJroudT7Dw= +github.com/foomo/goflux v0.6.0 h1:O9PYXGevBi2rymxZ+AWm2Kollced45vb4mwz1xWQX1M= +github.com/foomo/goflux v0.6.0/go.mod h1:xJZGTK4gZnmiZ5NqcKfTAHtXt9uBB27fRdrH0Voy+jI= +github.com/foomo/gofuncy v0.4.0 h1:wxfFOQSp+eZYy9YFXY7A8PPu0n51t4Xhvd6tOm0OSSs= +github.com/foomo/gofuncy v0.4.0/go.mod h1:ulEUpkz38K6trv71GM7fHjaUqa/NbWOZUE5MAbfe/Kk= github.com/foomo/gostandards v0.3.0 h1:Ev88Tdu0+52UH/d0l2KcAWx542A13o42d++LSTG0DC4= github.com/foomo/gostandards v0.3.0/go.mod h1:8hJ56tpyFAVwavs5FuUF3po7Bq7hOTkQ1+DzFi4GCWg= +github.com/foomo/mongo-lock v0.2.0 h1:xURP2FijZ/feACB5YL1UKUXk23M+x5L+yltEK+sJm0g= +github.com/foomo/mongo-lock v0.2.0/go.mod h1:5LMCz8IeaTMCWcgh+aPoDeIjY1qpu8MXbx+FNrGAUFA= github.com/foomo/opentelemetry-go v0.4.0 h1:UQneCUSokIYJXzFUKQSI8rlelbUuf6atgSZMhvD+Nzo= github.com/foomo/opentelemetry-go v0.4.0/go.mod h1:R3Se/rc5FRAs4ThE6JQ9Oq3cOLo2MOsUzZLJxZquwxA= github.com/foomo/opentelemetry-go/exporters/glossy/glossymetric v0.4.0 h1:o2EScdH3ZgIU2sTHbOnCRXsMr6wTHjAYx63rriQRmtU= @@ -137,6 +139,8 @@ github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiU github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U= +github.com/go-test/deep v1.1.1/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro= github.com/go-viper/mapstructure/v2 v2.5.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= @@ -170,8 +174,7 @@ github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0= github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM= 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/googleapis/enterprise-certificate-proxy v0.3.15 h1:xolVQTEXusUcAA5UgtyRLjelpFFHWlPQ4XfWGc7MBas= -github.com/googleapis/enterprise-certificate-proxy v0.3.15/go.mod h1:vqVt9yG9480NtzREnTlmGSBmFrA+bzb0yl0TxoBQXOg= +github.com/googleapis/enterprise-certificate-proxy v0.3.16 h1:F/VPrx0YPBdksZJQdCAp0WUsqnNmZpUZszzfYt0M5Dw= github.com/googleapis/gax-go/v2 v2.22.0 h1:PjIWBpgGIVKGoCXuiCoP64altEJCj3/Ei+kSU5vlZD4= github.com/googleapis/gax-go/v2 v2.22.0/go.mod h1:irWBbALSr0Sk3qlqb9SyJ1h68WjgeFuiOzI4Rqw5+aY= github.com/grafana/otel-profiling-go v0.6.0 h1:W7lOZaJj4IJISXMcM1UBk3fJF3tzF2OD6MJBJaQp1H8= @@ -182,8 +185,7 @@ github.com/grafana/pyroscope-go/godeltaprof v0.1.11 h1:el5LYpXissAiCKZ5/6yjlr6mh github.com/grafana/pyroscope-go/godeltaprof v0.1.11/go.mod h1:jl1V8M4cWsXciROCPIDDG7CtjSjT/ECbp6eLVuMxYRI= github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0 h1:5VipnvEpbqr2gA2VbM+nYVbkIF28c5ZQfqCBQ5g2xfk= github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0/go.mod h1:Hyl3n6Twe1hvtd9XUXDec4pTvgMSEixRuQKPTMH2bNs= -github.com/hashicorp/consul/api v1.34.2 h1:B5jqSSKwWyY8U8WiGS5vmPEPkkF0bAvrECykdZkDR80= -github.com/hashicorp/consul/api v1.34.2/go.mod h1:+gAdHQa2zvgYX3ZfcgITtnYCSj6AgS/cgotvCKaE+b8= +github.com/hashicorp/consul/api v1.34.3 h1:OiZaQnwkS6uvutie3CF6NFXj8uScNezDlsU9MEqKT0s= github.com/hashicorp/consul/sdk v0.18.1 h1:RDTeBvAeOveI2xI86sV+8WkaN7OkP4zz+cG3fOobDCM= github.com/hashicorp/consul/sdk v0.18.1/go.mod h1:XdP2tEJmAvlK4jgoKTTtohGkRJlS4mU44mv9/sjU21s= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -258,8 +260,7 @@ github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8S github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= -github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= -github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= +github.com/mattn/go-colorable v0.1.15 h1:+u9SLTRGnXv73cEsnsmoZBom+dMU88B2M0aDcWy0/jY= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.22 h1:j8l17JJ9i6VGPUFUYoTUKPSgKe/83EYU2zBC7YNKMw4= @@ -403,6 +404,8 @@ github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8 github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/testcontainers/testcontainers-go v0.43.0 h1:oEQx5MW2DGd9z3AeEQfB2lPM0eLs7ztyaGRu75bFo5A= github.com/testcontainers/testcontainers-go v0.43.0/go.mod h1:+VxkT2NQnKOZPKi6praMuMKYHYyOGXr0XSBSlSMCzFo= +github.com/testcontainers/testcontainers-go/modules/mongodb v0.43.0 h1:RJlAAz8dv61icyHvFmrr1xZHJEWZdvBfVBAU6wnmGPM= +github.com/testcontainers/testcontainers-go/modules/mongodb v0.43.0/go.mod h1:1zaDEZyV1SK+mpz83tmB2KthF6DHaS4Y+lRvy3d2XiE= github.com/testcontainers/testcontainers-go/modules/nats v0.43.0 h1:n1KcDXc18F687ODlTra411qWs+U+SH8VdnMM4kwpGo0= github.com/testcontainers/testcontainers-go/modules/nats v0.43.0/go.mod h1:nIBpPkiorwXM5LDOQKTD9Osxr/cWv1W4FcAx43kM7jY= github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= @@ -445,8 +448,7 @@ go.opentelemetry.io/contrib/bridges/otelzap v0.19.0 h1:48Eq3xxFx2KlL/tF7lnl42kKJ go.opentelemetry.io/contrib/bridges/otelzap v0.19.0/go.mod h1:cQbV77F0u6HmtZPiQD9oxp2esaOEb4uLqIta6OFIKOk= go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/v2/mongo/otelmongo v0.0.0-20260623174712-bbae83b5df0c h1:etHDCLakSn0jdNgLzYZ0zGKiwaNMof0R/uA+hVqIXQo= go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/v2/mongo/otelmongo v0.0.0-20260623174712-bbae83b5df0c/go.mod h1:VgtIsrVXKo8KmG2sFvQazHcQ98P2FHQ+ZePXtpTPjqs= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.68.0 h1:0Qx7VGBacMm9ZENQ7TnNObTYI4ShC+lHI16seduaxZo= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.68.0/go.mod h1:Sje3i3MjSPKTSPvVWCaL8ugBzJwik3u4smCjUeuupqg= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.69.0 h1:2yEATaop1/a1I4psnSLgWVPLWwCzkqWakgJy7xTDVy0= go.opentelemetry.io/contrib/instrumentation/host v0.69.0 h1:N/wKAdIOKd9U4bwiwY3j95e2ZR48onTMR/NI/SZQ/a4= go.opentelemetry.io/contrib/instrumentation/host v0.69.0/go.mod h1:rE1Bxmu3mwcmyTJV4EQdJ/C6zCUnuT9jCiinhRXLAXc= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0 h1:8tvICD4vSTOOsNrsI4Ljf6C+6UKvpTEH5XY3JMoyPoo= @@ -516,13 +518,11 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.54.0 h1:YLIA59K4fiNzHzjnZt2tUJQjQtUWfWbeHBqKtk3eScw= golang.org/x/crypto v0.54.0/go.mod h1:KWL8ny2AZdGR2cWmzeHrp2azQPGogOv+HeQaVEXC2dk= -golang.org/x/exp v0.0.0-20260508232706-74f9aab9d74a h1:+3jdDGGB8NGb1Zktc737jlt3/A5f6UlwSzmvqUuufxw= -golang.org/x/exp v0.0.0-20260508232706-74f9aab9d74a/go.mod h1:d2fgXJLVs4dYDHUk5lwMIfzRzSrWCfGZb0ZqeLa/Vcw= +golang.org/x/exp v0.0.0-20260529124908-c761662dc8c9 h1:4d4PbuBNwaxMXkXI8yiIYjydtMU+04RHeuSxJdgKftM= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.37.0 h1:vF1DjpVEshcIqoEaauuHebaLk1O1forxjxBaVn884JQ= -golang.org/x/mod v0.37.0/go.mod h1:m8S8VeM9r4dzDwjrKO0a1sZP3YjeMamRRlD+fmR2Q/0= +golang.org/x/mod v0.38.0 h1:MECBjubtXD7yj4HrhIUcywNaGeNVUdfVnxmPajOk4yk= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -591,25 +591,21 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.47.0 h1:7Kn5x/d1svx/PzryTsqeoZN4TZwqeH5pGWjefhLi/1Q= -golang.org/x/tools v0.47.0/go.mod h1:dFHnyTvFWY212G+h7ZY4Vsp/K3U4/7W9TyVaAul8uCA= +golang.org/x/tools v0.48.0 h1:3+hClM1aLL5mjMKm5ovokw9epgRXPuu2tILgismM6RE= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= -google.golang.org/api v0.278.0 h1:W7jiRvRi53VYFfZ/HoZjQBtJk7gOFbHD8ot1RzVZU6E= -google.golang.org/api v0.278.0/go.mod h1:B9TqLBwJqVjp1mtt7WeoQwWRwvu/400y5lETOql+giQ= +google.golang.org/api v0.282.0 h1:WmJiSVqUnKqJCpJOx7YADbXaC+9DDsnGSfllFSj7R2I= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/genproto v0.0.0-20260511170946-3700d4141b60 h1:rhBdfmsOlOZIvz3Y5/BdUzPg2CkO8L7QQPKj96B8554= -google.golang.org/genproto v0.0.0-20260511170946-3700d4141b60/go.mod h1:8xo2Pj1b20ZOCpzlU3B9qieMwVIAXx1QVZWLMlPL6sM= +google.golang.org/genproto v0.0.0-20260526163538-3dc84a4a5aaa h1:mfj8IS4EA4VAR9a6QDVxTQkLY64iBybb5QI1B4pXrpE= google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa h1:Kjn0N0tCrDgiAFW+lGO4JZ3ck44CehvJQMAwj9QF0G8= google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:q4lMZS6kskjT5HvCPrnnypcDPVJqT/f4nfxmkE7gryY= google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa h1:mZHHdPZl0dbGHCflZgAq/Q468DWVFcU2whhB2KAo8fk= google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= -google.golang.org/grpc v1.81.1 h1:VnnIIZ88UzOOKLukQi+ImGz8O1Wdp8nAGGnvOfEIWQQ= -google.golang.org/grpc v1.81.1/go.mod h1:xGH9GfzOyMTGIOXBJmXt+BX/V0kcdQbdcuwQ/zNw42I= +google.golang.org/grpc v1.82.1 h1:NnAxzGRA0677vCa4BUkOAnO5+FfQqVl9iUXeD0IqcGE= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -631,3 +627,5 @@ gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q= +gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA= diff --git a/go.mod b/go.mod index c99929a..bd240ae 100644 --- a/go.mod +++ b/go.mod @@ -5,9 +5,9 @@ go 1.26.0 require ( github.com/avast/retry-go/v4 v4.7.0 github.com/fbiville/markdown-table-formatter v0.3.0 - github.com/foomo/go v0.15.0 - github.com/foomo/goflux v0.4.4 - github.com/foomo/gofuncy v0.2.0 + github.com/foomo/go v0.16.0 + github.com/foomo/goflux v0.6.0 + github.com/foomo/gofuncy v0.4.0 github.com/foomo/gostandards v0.3.0 github.com/foomo/opentelemetry-go v0.4.0 github.com/go-logr/logr v1.4.4 @@ -68,7 +68,6 @@ require ( github.com/buger/jsonparser v1.1.2 // indirect github.com/cenkalti/backoff/v5 v5.0.3 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect - github.com/charmbracelet/x/ansi v0.11.7 // indirect github.com/coreos/go-semver v0.3.1 // indirect github.com/coreos/go-systemd/v22 v22.7.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect @@ -84,11 +83,11 @@ require ( github.com/google/btree v1.1.3 // indirect github.com/google/go-cmp v0.7.0 // indirect github.com/google/s2a-go v0.1.9 // indirect - github.com/googleapis/enterprise-certificate-proxy v0.3.15 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.3.16 // indirect github.com/googleapis/gax-go/v2 v2.22.0 // indirect github.com/grafana/pyroscope-go/godeltaprof v0.1.11 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0 // indirect - github.com/hashicorp/consul/api v1.34.2 // indirect + github.com/hashicorp/consul/api v1.34.3 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-hclog v1.6.3 // indirect @@ -100,14 +99,14 @@ require ( github.com/hashicorp/serf v0.10.2 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/lufia/plan9stats v0.0.0-20260330125221-c963978e514e // indirect - github.com/mattn/go-colorable v0.1.14 // indirect + github.com/mattn/go-colorable v0.1.15 // indirect github.com/mattn/go-isatty v0.0.22 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/nats-io/nats.go v1.52.0 // indirect - github.com/nats-io/nkeys v0.4.15 // indirect + github.com/nats-io/nkeys v0.4.16 // indirect github.com/nats-io/nuid v1.0.1 // indirect github.com/pb33f/ordered-map/v2 v2.3.1 // indirect github.com/pelletier/go-toml/v2 v2.3.1 // indirect @@ -120,7 +119,7 @@ require ( github.com/prometheus/procfs v0.21.1 // indirect github.com/sagikazarmark/crypt v0.31.0 // indirect github.com/sagikazarmark/locafero v0.12.0 // indirect - github.com/shirou/gopsutil/v4 v4.26.4 // indirect + github.com/shirou/gopsutil/v4 v4.26.5 // indirect github.com/spf13/afero v1.15.0 // indirect github.com/spf13/cast v1.10.0 // indirect github.com/spf13/pflag v1.0.10 // indirect @@ -133,22 +132,23 @@ require ( go.etcd.io/etcd/client/v2 v2.305.30 // indirect go.etcd.io/etcd/client/v3 v3.6.11 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.68.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.69.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.44.0 // indirect go.opentelemetry.io/proto/otlp v1.10.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect go.yaml.in/yaml/v4 v4.0.0-rc.2 // indirect - golang.org/x/exp v0.0.0-20260508232706-74f9aab9d74a // indirect + golang.org/x/exp v0.0.0-20260529124908-c761662dc8c9 // indirect golang.org/x/net v0.57.0 // indirect golang.org/x/oauth2 v0.36.0 // indirect golang.org/x/sys v0.47.0 // indirect golang.org/x/text v0.40.0 // indirect golang.org/x/time v0.15.0 // indirect - google.golang.org/api v0.278.0 // indirect - google.golang.org/genproto v0.0.0-20260511170946-3700d4141b60 // indirect + golang.org/x/tools v0.48.0 // indirect + google.golang.org/api v0.282.0 // indirect + google.golang.org/genproto v0.0.0-20260526163538-3dc84a4a5aaa // indirect google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa // indirect - google.golang.org/grpc v1.81.1 // indirect + google.golang.org/grpc v1.82.1 // indirect google.golang.org/protobuf v1.36.11 // indirect ) diff --git a/go.sum b/go.sum index 176fed8..8864c76 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,5 @@ -charm.land/lipgloss/v2 v2.0.2 h1:xFolbF8JdpNkM2cEPTfXEcW1p6NRzOWTSamRfYEw8cs= -charm.land/lipgloss/v2 v2.0.2/go.mod h1:KjPle2Qd3YmvP1KL5OMHiHysGcNwq6u83MUjYkFvEkM= +charm.land/lipgloss/v2 v2.0.3 h1:yM2zJ4Cf5Y51b7RHIwioil4ApI/aypFXXVHSwlM6RzU= +charm.land/lipgloss/v2 v2.0.3/go.mod h1:7myLU9iG/3xluAWzpY/fSxYYHCgoKTie7laxk6ATwXA= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.123.0 h1:2NAUJwPR47q+E35uaJeYoNhuNEM9kM8SjgRgdeOJUSE= cloud.google.com/go v0.123.0/go.mod h1:xBoMV08QcqUGuPW65Qfm1o9Y4zKZBpGS+7bImXLTAZU= @@ -38,8 +38,8 @@ github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UF github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/charmbracelet/colorprofile v0.4.3 h1:QPa1IWkYI+AOB+fE+mg/5/4HRMZcaXex9t5KX76i20Q= github.com/charmbracelet/colorprofile v0.4.3/go.mod h1:/zT4BhpD5aGFpqQQqw7a+VtHCzu+zrQtt1zhMt9mR4Q= -github.com/charmbracelet/ultraviolet v0.0.0-20260330092749-0f94982c930b h1:ASDO9RT6SNKTQN87jO2bRfxHFJq8cgeYdFzivY2gCeM= -github.com/charmbracelet/ultraviolet v0.0.0-20260330092749-0f94982c930b/go.mod h1:Vo8TffMf0q7Uho/n8e6XpBZvOWtd3g39yX+9P5rRutA= +github.com/charmbracelet/ultraviolet v0.0.0-20260416161146-9c68a866306c h1:a+Q3cOt8vEb6ETG/st32Qjm8R5fdI9wSKb3tqPISnoY= +github.com/charmbracelet/ultraviolet v0.0.0-20260416161146-9c68a866306c/go.mod h1:bAAz7dh/FTYfC+oiHavL4mX1tOIBZ0ZwYjSi3qE6ivM= github.com/charmbracelet/x/ansi v0.11.7 h1:kzv1kJvjg2S3r9KHo8hDdHFQLEqn4RBCb39dAYC84jI= github.com/charmbracelet/x/ansi v0.11.7/go.mod h1:9qGpnAVYz+8ACONkZBUWPtL7lulP9No6p1epAihUZwQ= github.com/charmbracelet/x/term v0.2.2 h1:xVRT/S2ZcKdhhOuSP4t5cLi5o+JxklsoEObBSgfgZRk= @@ -78,12 +78,12 @@ github.com/fbiville/markdown-table-formatter v0.3.0 h1:PIm1UNgJrFs8q1htGTw+wnnNY github.com/fbiville/markdown-table-formatter v0.3.0/go.mod h1:q89TDtSEVDdTaufgSbfHpNVdPU/bmfvqNkrC5HagmLY= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/foomo/go v0.15.0 h1:i6bcReoSLPpRVUVsd7anB6BCVBNimaOjiDeI+9I9rq0= -github.com/foomo/go v0.15.0/go.mod h1:jeSB/atkoqSoJ3+ak0+b/Xtj7IMyDj1odzJroudT7Dw= -github.com/foomo/goflux v0.4.4 h1:T7QhIPdZze3bNEeNjdEAzBV08/ikEgmTmK3maWucAo4= -github.com/foomo/goflux v0.4.4/go.mod h1:c2qy02JR9Y5qlVl49nDSEipCQENbGhDZzjT8p72G7Xs= -github.com/foomo/gofuncy v0.2.0 h1:fanMIpHocWfoP+u8sevF+Qb/gEh38QeiS6FjeXB+Sx0= -github.com/foomo/gofuncy v0.2.0/go.mod h1:WnqsC/Ku/19tk0LYHVG8z9tsT9duKqpxHMiJioznv1M= +github.com/foomo/go v0.16.0 h1:Hw2rl0ieMB+s9NK8+MuIHzD22h48whyoKV+CA+lFG1k= +github.com/foomo/go v0.16.0/go.mod h1:jeSB/atkoqSoJ3+ak0+b/Xtj7IMyDj1odzJroudT7Dw= +github.com/foomo/goflux v0.6.0 h1:O9PYXGevBi2rymxZ+AWm2Kollced45vb4mwz1xWQX1M= +github.com/foomo/goflux v0.6.0/go.mod h1:xJZGTK4gZnmiZ5NqcKfTAHtXt9uBB27fRdrH0Voy+jI= +github.com/foomo/gofuncy v0.4.0 h1:wxfFOQSp+eZYy9YFXY7A8PPu0n51t4Xhvd6tOm0OSSs= +github.com/foomo/gofuncy v0.4.0/go.mod h1:ulEUpkz38K6trv71GM7fHjaUqa/NbWOZUE5MAbfe/Kk= github.com/foomo/gostandards v0.3.0 h1:Ev88Tdu0+52UH/d0l2KcAWx542A13o42d++LSTG0DC4= github.com/foomo/gostandards v0.3.0/go.mod h1:8hJ56tpyFAVwavs5FuUF3po7Bq7hOTkQ1+DzFi4GCWg= github.com/foomo/opentelemetry-go v0.4.0 h1:UQneCUSokIYJXzFUKQSI8rlelbUuf6atgSZMhvD+Nzo= @@ -144,8 +144,7 @@ github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0= github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM= 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/googleapis/enterprise-certificate-proxy v0.3.15 h1:xolVQTEXusUcAA5UgtyRLjelpFFHWlPQ4XfWGc7MBas= -github.com/googleapis/enterprise-certificate-proxy v0.3.15/go.mod h1:vqVt9yG9480NtzREnTlmGSBmFrA+bzb0yl0TxoBQXOg= +github.com/googleapis/enterprise-certificate-proxy v0.3.16 h1:F/VPrx0YPBdksZJQdCAp0WUsqnNmZpUZszzfYt0M5Dw= github.com/googleapis/gax-go/v2 v2.22.0 h1:PjIWBpgGIVKGoCXuiCoP64altEJCj3/Ei+kSU5vlZD4= github.com/googleapis/gax-go/v2 v2.22.0/go.mod h1:irWBbALSr0Sk3qlqb9SyJ1h68WjgeFuiOzI4Rqw5+aY= github.com/grafana/otel-profiling-go v0.6.0 h1:W7lOZaJj4IJISXMcM1UBk3fJF3tzF2OD6MJBJaQp1H8= @@ -156,8 +155,7 @@ github.com/grafana/pyroscope-go/godeltaprof v0.1.11 h1:el5LYpXissAiCKZ5/6yjlr6mh github.com/grafana/pyroscope-go/godeltaprof v0.1.11/go.mod h1:jl1V8M4cWsXciROCPIDDG7CtjSjT/ECbp6eLVuMxYRI= github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0 h1:5VipnvEpbqr2gA2VbM+nYVbkIF28c5ZQfqCBQ5g2xfk= github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0/go.mod h1:Hyl3n6Twe1hvtd9XUXDec4pTvgMSEixRuQKPTMH2bNs= -github.com/hashicorp/consul/api v1.34.2 h1:B5jqSSKwWyY8U8WiGS5vmPEPkkF0bAvrECykdZkDR80= -github.com/hashicorp/consul/api v1.34.2/go.mod h1:+gAdHQa2zvgYX3ZfcgITtnYCSj6AgS/cgotvCKaE+b8= +github.com/hashicorp/consul/api v1.34.3 h1:OiZaQnwkS6uvutie3CF6NFXj8uScNezDlsU9MEqKT0s= github.com/hashicorp/consul/sdk v0.18.1 h1:RDTeBvAeOveI2xI86sV+8WkaN7OkP4zz+cG3fOobDCM= github.com/hashicorp/consul/sdk v0.18.1/go.mod h1:XdP2tEJmAvlK4jgoKTTtohGkRJlS4mU44mv9/sjU21s= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -228,8 +226,7 @@ github.com/lufia/plan9stats v0.0.0-20260330125221-c963978e514e h1:Q6MvJtQK/iRcRt github.com/lufia/plan9stats v0.0.0-20260330125221-c963978e514e/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= -github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= -github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= +github.com/mattn/go-colorable v0.1.15 h1:+u9SLTRGnXv73cEsnsmoZBom+dMU88B2M0aDcWy0/jY= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.22 h1:j8l17JJ9i6VGPUFUYoTUKPSgKe/83EYU2zBC7YNKMw4= @@ -258,8 +255,7 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/nats-io/nats.go v1.52.0 h1:n3avV4VBsCgsdwh71TppsTwtv+QdPs7ntSKM8qJLGsc= github.com/nats-io/nats.go v1.52.0/go.mod h1:26HypzazeOkyO3/mqd1zZd53STJN0EjCYF9Uy2ZOBno= -github.com/nats-io/nkeys v0.4.15 h1:JACV5jRVO9V856KOapQ7x+EY8Jo3qw1vJt/9Jpwzkk4= -github.com/nats-io/nkeys v0.4.15/go.mod h1:CpMchTXC9fxA5zrMo4KpySxNjiDVvr8ANOSZdiNfUrs= +github.com/nats-io/nkeys v0.4.16 h1:rd5oAuLOb8mnAycB0xleuEBNS1pVVnN0fv/FF34Eypg= github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= @@ -318,8 +314,7 @@ github.com/sagikazarmark/locafero v0.12.0 h1:/NQhBAkUb4+fH1jivKHWusDYFjMOOKU88ee github.com/sagikazarmark/locafero v0.12.0/go.mod h1:sZh36u/YSZ918v0Io+U9ogLYQJ9tLLBmM4eneO6WwsI= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= -github.com/shirou/gopsutil/v4 v4.26.4 h1:B4SXVbcwTyrocPHEmWBC4uCYr4Xcu3MK1TXqbprAOWY= -github.com/shirou/gopsutil/v4 v4.26.4/go.mod h1:LZ6ewCSkBqUpvSOf+LsTGnRinC6iaNUNMGBtDkJBaLQ= +github.com/shirou/gopsutil/v4 v4.26.5 h1:RPcBXkpz7kOj9PqGFQOlBPZHsyaPvPVQc098y9RmCNM= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= @@ -374,8 +369,7 @@ go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/contrib/bridges/otelzap v0.19.0 h1:48Eq3xxFx2KlL/tF7lnl42kKJBDlhNTLRzv0h154JnM= go.opentelemetry.io/contrib/bridges/otelzap v0.19.0/go.mod h1:cQbV77F0u6HmtZPiQD9oxp2esaOEb4uLqIta6OFIKOk= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.68.0 h1:0Qx7VGBacMm9ZENQ7TnNObTYI4ShC+lHI16seduaxZo= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.68.0/go.mod h1:Sje3i3MjSPKTSPvVWCaL8ugBzJwik3u4smCjUeuupqg= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.69.0 h1:2yEATaop1/a1I4psnSLgWVPLWwCzkqWakgJy7xTDVy0= go.opentelemetry.io/contrib/instrumentation/host v0.69.0 h1:N/wKAdIOKd9U4bwiwY3j95e2ZR48onTMR/NI/SZQ/a4= go.opentelemetry.io/contrib/instrumentation/host v0.69.0/go.mod h1:rE1Bxmu3mwcmyTJV4EQdJ/C6zCUnuT9jCiinhRXLAXc= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0 h1:8tvICD4vSTOOsNrsI4Ljf6C+6UKvpTEH5XY3JMoyPoo= @@ -444,12 +438,10 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.54.0 h1:YLIA59K4fiNzHzjnZt2tUJQjQtUWfWbeHBqKtk3eScw= golang.org/x/crypto v0.54.0/go.mod h1:KWL8ny2AZdGR2cWmzeHrp2azQPGogOv+HeQaVEXC2dk= -golang.org/x/exp v0.0.0-20260508232706-74f9aab9d74a h1:+3jdDGGB8NGb1Zktc737jlt3/A5f6UlwSzmvqUuufxw= -golang.org/x/exp v0.0.0-20260508232706-74f9aab9d74a/go.mod h1:d2fgXJLVs4dYDHUk5lwMIfzRzSrWCfGZb0ZqeLa/Vcw= +golang.org/x/exp v0.0.0-20260529124908-c761662dc8c9 h1:4d4PbuBNwaxMXkXI8yiIYjydtMU+04RHeuSxJdgKftM= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.37.0 h1:vF1DjpVEshcIqoEaauuHebaLk1O1forxjxBaVn884JQ= -golang.org/x/mod v0.37.0/go.mod h1:m8S8VeM9r4dzDwjrKO0a1sZP3YjeMamRRlD+fmR2Q/0= +golang.org/x/mod v0.38.0 h1:MECBjubtXD7yj4HrhIUcywNaGeNVUdfVnxmPajOk4yk= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -506,25 +498,21 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.47.0 h1:7Kn5x/d1svx/PzryTsqeoZN4TZwqeH5pGWjefhLi/1Q= -golang.org/x/tools v0.47.0/go.mod h1:dFHnyTvFWY212G+h7ZY4Vsp/K3U4/7W9TyVaAul8uCA= +golang.org/x/tools v0.48.0 h1:3+hClM1aLL5mjMKm5ovokw9epgRXPuu2tILgismM6RE= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= -google.golang.org/api v0.278.0 h1:W7jiRvRi53VYFfZ/HoZjQBtJk7gOFbHD8ot1RzVZU6E= -google.golang.org/api v0.278.0/go.mod h1:B9TqLBwJqVjp1mtt7WeoQwWRwvu/400y5lETOql+giQ= +google.golang.org/api v0.282.0 h1:WmJiSVqUnKqJCpJOx7YADbXaC+9DDsnGSfllFSj7R2I= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/genproto v0.0.0-20260511170946-3700d4141b60 h1:rhBdfmsOlOZIvz3Y5/BdUzPg2CkO8L7QQPKj96B8554= -google.golang.org/genproto v0.0.0-20260511170946-3700d4141b60/go.mod h1:8xo2Pj1b20ZOCpzlU3B9qieMwVIAXx1QVZWLMlPL6sM= +google.golang.org/genproto v0.0.0-20260526163538-3dc84a4a5aaa h1:mfj8IS4EA4VAR9a6QDVxTQkLY64iBybb5QI1B4pXrpE= google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa h1:Kjn0N0tCrDgiAFW+lGO4JZ3ck44CehvJQMAwj9QF0G8= google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:q4lMZS6kskjT5HvCPrnnypcDPVJqT/f4nfxmkE7gryY= google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa h1:mZHHdPZl0dbGHCflZgAq/Q468DWVFcU2whhB2KAo8fk= google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= -google.golang.org/grpc v1.81.1 h1:VnnIIZ88UzOOKLukQi+ImGz8O1Wdp8nAGGnvOfEIWQQ= -google.golang.org/grpc v1.81.1/go.mod h1:xGH9GfzOyMTGIOXBJmXt+BX/V0kcdQbdcuwQ/zNw42I= +google.golang.org/grpc v1.82.1 h1:NnAxzGRA0677vCa4BUkOAnO5+FfQqVl9iUXeD0IqcGE= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= diff --git a/integration/gotsrpc/go.mod b/integration/gotsrpc/go.mod index e290580..ce9d85e 100644 --- a/integration/gotsrpc/go.mod +++ b/integration/gotsrpc/go.mod @@ -20,7 +20,7 @@ require ( github.com/ebitengine/purego v0.10.1 // indirect github.com/fbiville/markdown-table-formatter v0.3.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect - github.com/foomo/go v0.15.0 // indirect + github.com/foomo/go v0.16.0 // indirect github.com/foomo/gostandards v0.3.0 // indirect github.com/foomo/opentelemetry-go v0.4.0 // indirect github.com/go-logr/logr v1.4.4 // indirect diff --git a/integration/gotsrpc/go.sum b/integration/gotsrpc/go.sum index 10c4e47..7423ca7 100644 --- a/integration/gotsrpc/go.sum +++ b/integration/gotsrpc/go.sum @@ -19,8 +19,8 @@ github.com/fbiville/markdown-table-formatter v0.3.0 h1:PIm1UNgJrFs8q1htGTw+wnnNY github.com/fbiville/markdown-table-formatter v0.3.0/go.mod h1:q89TDtSEVDdTaufgSbfHpNVdPU/bmfvqNkrC5HagmLY= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/foomo/go v0.15.0 h1:i6bcReoSLPpRVUVsd7anB6BCVBNimaOjiDeI+9I9rq0= -github.com/foomo/go v0.15.0/go.mod h1:jeSB/atkoqSoJ3+ak0+b/Xtj7IMyDj1odzJroudT7Dw= +github.com/foomo/go v0.16.0 h1:Hw2rl0ieMB+s9NK8+MuIHzD22h48whyoKV+CA+lFG1k= +github.com/foomo/go v0.16.0/go.mod h1:jeSB/atkoqSoJ3+ak0+b/Xtj7IMyDj1odzJroudT7Dw= github.com/foomo/gostandards v0.3.0 h1:Ev88Tdu0+52UH/d0l2KcAWx542A13o42d++LSTG0DC4= github.com/foomo/gostandards v0.3.0/go.mod h1:8hJ56tpyFAVwavs5FuUF3po7Bq7hOTkQ1+DzFi4GCWg= github.com/foomo/gotsrpc/v2 v2.16.1 h1:ih/YRUJpO3DOpw6cWXOVS4b6nOmfXxF+zudptxYFLxs= diff --git a/integration/gotsrpc/gorpcclient.go b/integration/gotsrpc/gorpcclient.go new file mode 100644 index 0000000..831f971 --- /dev/null +++ b/integration/gotsrpc/gorpcclient.go @@ -0,0 +1,6 @@ +package gotsrpc + +type GoRPCClient interface { + Start() + Stop() +} diff --git a/integration/gotsrpc/gorpcclientservice.go b/integration/gotsrpc/gorpcclientservice.go new file mode 100644 index 0000000..11abcd8 --- /dev/null +++ b/integration/gotsrpc/gorpcclientservice.go @@ -0,0 +1,33 @@ +package gotsrpc + +import ( + "context" +) + +type GoRPCClientService struct { + client GoRPCClient + cancel context.CancelFunc +} + +func NewGoRPCClientService(client GoRPCClient) *GoRPCClientService { + return &GoRPCClientService{ + client: client, + } +} + +func (s *GoRPCClientService) Start(ctx context.Context) error { + ctx, cancel := context.WithCancel(ctx) + s.cancel = cancel + s.client.Start() + <-ctx.Done() + s.client.Stop() + return ctx.Err() +} + +func (s *GoRPCClientService) Close(ctx context.Context) error { + if s.cancel != nil { + s.cancel() + s.cancel = nil + } + return nil +} diff --git a/integration/gotsrpc/gorpcproxy.go b/integration/gotsrpc/gorpcproxy.go new file mode 100644 index 0000000..157ecd7 --- /dev/null +++ b/integration/gotsrpc/gorpcproxy.go @@ -0,0 +1,6 @@ +package gotsrpc + +type GoRPCProxy interface { + Start() error + Stop() +} diff --git a/integration/gotsrpc/gorpcproxyservice.go b/integration/gotsrpc/gorpcproxyservice.go new file mode 100644 index 0000000..71c7ff2 --- /dev/null +++ b/integration/gotsrpc/gorpcproxyservice.go @@ -0,0 +1,35 @@ +package gotsrpc + +import ( + "context" +) + +type GoRPCProxyService struct { + proxy GoRPCProxy + cancel context.CancelFunc +} + +func NewGoRPCProxyService(proxy GoRPCProxy) *GoRPCProxyService { + return &GoRPCProxyService{ + proxy: proxy, + } +} + +func (s *GoRPCProxyService) Start(ctx context.Context) error { + ctx, cancel := context.WithCancel(ctx) + s.cancel = cancel + if err := s.proxy.Start(); err != nil { + return err + } + <-ctx.Done() + s.proxy.Stop() + return ctx.Err() +} + +func (s *GoRPCProxyService) Close(ctx context.Context) error { + if s.cancel != nil { + s.cancel() + s.cancel = nil + } + return nil +} diff --git a/integration/nats/go.mod b/integration/nats/go.mod index 03e1b86..c04dc95 100644 --- a/integration/nats/go.mod +++ b/integration/nats/go.mod @@ -5,8 +5,8 @@ go 1.26.0 replace github.com/foomo/keel => ../../ require ( - github.com/foomo/go v0.15.0 - github.com/foomo/gofuncy v0.2.0 + github.com/foomo/go v0.16.0 + github.com/foomo/gofuncy v0.4.0 github.com/foomo/keel v0.27.1 github.com/foomo/opentelemetry-go v0.4.0 github.com/nats-io/nats-server/v2 v2.14.3 @@ -36,7 +36,7 @@ require ( github.com/fatih/color v1.19.0 // indirect github.com/fbiville/markdown-table-formatter v0.3.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect - github.com/foomo/goflux v0.4.4 // indirect + github.com/foomo/goflux v0.6.0 // indirect github.com/foomo/gostandards v0.3.0 // indirect github.com/fsnotify/fsnotify v1.10.1 // indirect github.com/go-logr/logr v1.4.4 // indirect @@ -134,6 +134,7 @@ require ( go.yaml.in/yaml/v3 v3.0.4 // indirect golang.org/x/crypto v0.54.0 // indirect golang.org/x/exp v0.0.0-20260529124908-c761662dc8c9 // indirect + golang.org/x/mod v0.38.0 // indirect golang.org/x/net v0.57.0 // indirect golang.org/x/oauth2 v0.36.0 // indirect golang.org/x/sync v0.22.0 // indirect @@ -144,7 +145,7 @@ require ( google.golang.org/genproto v0.0.0-20260526163538-3dc84a4a5aaa // indirect google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa // indirect - google.golang.org/grpc v1.81.1 // indirect + google.golang.org/grpc v1.82.1 // indirect google.golang.org/protobuf v1.36.11 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/integration/nats/go.sum b/integration/nats/go.sum index a06d11a..6c96248 100644 --- a/integration/nats/go.sum +++ b/integration/nats/go.sum @@ -1,5 +1,5 @@ -charm.land/lipgloss/v2 v2.0.2 h1:xFolbF8JdpNkM2cEPTfXEcW1p6NRzOWTSamRfYEw8cs= -charm.land/lipgloss/v2 v2.0.2/go.mod h1:KjPle2Qd3YmvP1KL5OMHiHysGcNwq6u83MUjYkFvEkM= +charm.land/lipgloss/v2 v2.0.3 h1:yM2zJ4Cf5Y51b7RHIwioil4ApI/aypFXXVHSwlM6RzU= +charm.land/lipgloss/v2 v2.0.3/go.mod h1:7myLU9iG/3xluAWzpY/fSxYYHCgoKTie7laxk6ATwXA= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.123.0 h1:2NAUJwPR47q+E35uaJeYoNhuNEM9kM8SjgRgdeOJUSE= cloud.google.com/go v0.123.0/go.mod h1:xBoMV08QcqUGuPW65Qfm1o9Y4zKZBpGS+7bImXLTAZU= @@ -36,8 +36,8 @@ github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UF github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/charmbracelet/colorprofile v0.4.3 h1:QPa1IWkYI+AOB+fE+mg/5/4HRMZcaXex9t5KX76i20Q= github.com/charmbracelet/colorprofile v0.4.3/go.mod h1:/zT4BhpD5aGFpqQQqw7a+VtHCzu+zrQtt1zhMt9mR4Q= -github.com/charmbracelet/ultraviolet v0.0.0-20260330092749-0f94982c930b h1:ASDO9RT6SNKTQN87jO2bRfxHFJq8cgeYdFzivY2gCeM= -github.com/charmbracelet/ultraviolet v0.0.0-20260330092749-0f94982c930b/go.mod h1:Vo8TffMf0q7Uho/n8e6XpBZvOWtd3g39yX+9P5rRutA= +github.com/charmbracelet/ultraviolet v0.0.0-20260416161146-9c68a866306c h1:a+Q3cOt8vEb6ETG/st32Qjm8R5fdI9wSKb3tqPISnoY= +github.com/charmbracelet/ultraviolet v0.0.0-20260416161146-9c68a866306c/go.mod h1:bAAz7dh/FTYfC+oiHavL4mX1tOIBZ0ZwYjSi3qE6ivM= github.com/charmbracelet/x/ansi v0.11.7 h1:kzv1kJvjg2S3r9KHo8hDdHFQLEqn4RBCb39dAYC84jI= github.com/charmbracelet/x/ansi v0.11.7/go.mod h1:9qGpnAVYz+8ACONkZBUWPtL7lulP9No6p1epAihUZwQ= github.com/charmbracelet/x/term v0.2.2 h1:xVRT/S2ZcKdhhOuSP4t5cLi5o+JxklsoEObBSgfgZRk= @@ -76,12 +76,12 @@ github.com/fbiville/markdown-table-formatter v0.3.0 h1:PIm1UNgJrFs8q1htGTw+wnnNY github.com/fbiville/markdown-table-formatter v0.3.0/go.mod h1:q89TDtSEVDdTaufgSbfHpNVdPU/bmfvqNkrC5HagmLY= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/foomo/go v0.15.0 h1:i6bcReoSLPpRVUVsd7anB6BCVBNimaOjiDeI+9I9rq0= -github.com/foomo/go v0.15.0/go.mod h1:jeSB/atkoqSoJ3+ak0+b/Xtj7IMyDj1odzJroudT7Dw= -github.com/foomo/goflux v0.4.4 h1:T7QhIPdZze3bNEeNjdEAzBV08/ikEgmTmK3maWucAo4= -github.com/foomo/goflux v0.4.4/go.mod h1:c2qy02JR9Y5qlVl49nDSEipCQENbGhDZzjT8p72G7Xs= -github.com/foomo/gofuncy v0.2.0 h1:fanMIpHocWfoP+u8sevF+Qb/gEh38QeiS6FjeXB+Sx0= -github.com/foomo/gofuncy v0.2.0/go.mod h1:WnqsC/Ku/19tk0LYHVG8z9tsT9duKqpxHMiJioznv1M= +github.com/foomo/go v0.16.0 h1:Hw2rl0ieMB+s9NK8+MuIHzD22h48whyoKV+CA+lFG1k= +github.com/foomo/go v0.16.0/go.mod h1:jeSB/atkoqSoJ3+ak0+b/Xtj7IMyDj1odzJroudT7Dw= +github.com/foomo/goflux v0.6.0 h1:O9PYXGevBi2rymxZ+AWm2Kollced45vb4mwz1xWQX1M= +github.com/foomo/goflux v0.6.0/go.mod h1:xJZGTK4gZnmiZ5NqcKfTAHtXt9uBB27fRdrH0Voy+jI= +github.com/foomo/gofuncy v0.4.0 h1:wxfFOQSp+eZYy9YFXY7A8PPu0n51t4Xhvd6tOm0OSSs= +github.com/foomo/gofuncy v0.4.0/go.mod h1:ulEUpkz38K6trv71GM7fHjaUqa/NbWOZUE5MAbfe/Kk= github.com/foomo/gostandards v0.3.0 h1:Ev88Tdu0+52UH/d0l2KcAWx542A13o42d++LSTG0DC4= github.com/foomo/gostandards v0.3.0/go.mod h1:8hJ56tpyFAVwavs5FuUF3po7Bq7hOTkQ1+DzFi4GCWg= github.com/foomo/opentelemetry-go v0.4.0 h1:UQneCUSokIYJXzFUKQSI8rlelbUuf6atgSZMhvD+Nzo= @@ -446,8 +446,7 @@ golang.org/x/exp v0.0.0-20260529124908-c761662dc8c9 h1:4d4PbuBNwaxMXkXI8yiIYjydt golang.org/x/exp v0.0.0-20260529124908-c761662dc8c9/go.mod h1:d2fgXJLVs4dYDHUk5lwMIfzRzSrWCfGZb0ZqeLa/Vcw= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.37.0 h1:vF1DjpVEshcIqoEaauuHebaLk1O1forxjxBaVn884JQ= -golang.org/x/mod v0.37.0/go.mod h1:m8S8VeM9r4dzDwjrKO0a1sZP3YjeMamRRlD+fmR2Q/0= +golang.org/x/mod v0.38.0 h1:MECBjubtXD7yj4HrhIUcywNaGeNVUdfVnxmPajOk4yk= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -505,8 +504,7 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.47.0 h1:7Kn5x/d1svx/PzryTsqeoZN4TZwqeH5pGWjefhLi/1Q= -golang.org/x/tools v0.47.0/go.mod h1:dFHnyTvFWY212G+h7ZY4Vsp/K3U4/7W9TyVaAul8uCA= +golang.org/x/tools v0.48.0 h1:3+hClM1aLL5mjMKm5ovokw9epgRXPuu2tILgismM6RE= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -522,8 +520,7 @@ google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa h1: google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:q4lMZS6kskjT5HvCPrnnypcDPVJqT/f4nfxmkE7gryY= google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa h1:mZHHdPZl0dbGHCflZgAq/Q468DWVFcU2whhB2KAo8fk= google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= -google.golang.org/grpc v1.81.1 h1:VnnIIZ88UzOOKLukQi+ImGz8O1Wdp8nAGGnvOfEIWQQ= -google.golang.org/grpc v1.81.1/go.mod h1:xGH9GfzOyMTGIOXBJmXt+BX/V0kcdQbdcuwQ/zNw42I= +google.golang.org/grpc v1.82.1 h1:NnAxzGRA0677vCa4BUkOAnO5+FfQqVl9iUXeD0IqcGE= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= diff --git a/integration/temporal/go.mod b/integration/temporal/go.mod index 67809e2..99bf406 100644 --- a/integration/temporal/go.mod +++ b/integration/temporal/go.mod @@ -5,7 +5,7 @@ go 1.26.0 replace github.com/foomo/keel => ../../ require ( - github.com/foomo/go v0.15.0 + github.com/foomo/go v0.16.0 github.com/foomo/keel v0.27.1 github.com/pkg/errors v0.9.1 go.opentelemetry.io/otel v1.44.0 diff --git a/integration/temporal/go.sum b/integration/temporal/go.sum index e55b19a..b837c89 100644 --- a/integration/temporal/go.sum +++ b/integration/temporal/go.sum @@ -12,8 +12,8 @@ github.com/facebookgo/clock v0.0.0-20150410010913-600d898af40a h1:yDWHCSQ40h88yi github.com/facebookgo/clock v0.0.0-20150410010913-600d898af40a/go.mod h1:7Ga40egUymuWXxAe151lTNnCv97MddSOVsjpPPkityA= github.com/fbiville/markdown-table-formatter v0.3.0 h1:PIm1UNgJrFs8q1htGTw+wnnNYvwXQMMMIKNZop2SSho= github.com/fbiville/markdown-table-formatter v0.3.0/go.mod h1:q89TDtSEVDdTaufgSbfHpNVdPU/bmfvqNkrC5HagmLY= -github.com/foomo/go v0.15.0 h1:i6bcReoSLPpRVUVsd7anB6BCVBNimaOjiDeI+9I9rq0= -github.com/foomo/go v0.15.0/go.mod h1:jeSB/atkoqSoJ3+ak0+b/Xtj7IMyDj1odzJroudT7Dw= +github.com/foomo/go v0.16.0 h1:Hw2rl0ieMB+s9NK8+MuIHzD22h48whyoKV+CA+lFG1k= +github.com/foomo/go v0.16.0/go.mod h1:jeSB/atkoqSoJ3+ak0+b/Xtj7IMyDj1odzJroudT7Dw= github.com/foomo/opentelemetry-go v0.4.0 h1:UQneCUSokIYJXzFUKQSI8rlelbUuf6atgSZMhvD+Nzo= github.com/foomo/opentelemetry-go v0.4.0/go.mod h1:R3Se/rc5FRAs4ThE6JQ9Oq3cOLo2MOsUzZLJxZquwxA= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= diff --git a/net/stream/go.mod b/net/stream/go.mod index 3007dc9..ba7e611 100644 --- a/net/stream/go.mod +++ b/net/stream/go.mod @@ -5,7 +5,7 @@ go 1.26.0 replace github.com/foomo/keel => ../../ require ( - github.com/foomo/go v0.15.0 + github.com/foomo/go v0.16.0 github.com/foomo/keel v0.27.1 github.com/nats-io/nats.go v1.52.0 github.com/pkg/errors v0.9.1 diff --git a/net/stream/go.sum b/net/stream/go.sum index ad1ddd5..001c4e2 100644 --- a/net/stream/go.sum +++ b/net/stream/go.sum @@ -36,8 +36,8 @@ github.com/fbiville/markdown-table-formatter v0.3.0 h1:PIm1UNgJrFs8q1htGTw+wnnNY github.com/fbiville/markdown-table-formatter v0.3.0/go.mod h1:q89TDtSEVDdTaufgSbfHpNVdPU/bmfvqNkrC5HagmLY= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/foomo/go v0.15.0 h1:i6bcReoSLPpRVUVsd7anB6BCVBNimaOjiDeI+9I9rq0= -github.com/foomo/go v0.15.0/go.mod h1:jeSB/atkoqSoJ3+ak0+b/Xtj7IMyDj1odzJroudT7Dw= +github.com/foomo/go v0.16.0 h1:Hw2rl0ieMB+s9NK8+MuIHzD22h48whyoKV+CA+lFG1k= +github.com/foomo/go v0.16.0/go.mod h1:jeSB/atkoqSoJ3+ak0+b/Xtj7IMyDj1odzJroudT7Dw= github.com/foomo/opentelemetry-go v0.4.0 h1:UQneCUSokIYJXzFUKQSI8rlelbUuf6atgSZMhvD+Nzo= github.com/foomo/opentelemetry-go v0.4.0/go.mod h1:R3Se/rc5FRAs4ThE6JQ9Oq3cOLo2MOsUzZLJxZquwxA= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= diff --git a/persistence/distributedrwlock.go b/persistence/distributedrwlock.go new file mode 100644 index 0000000..c75c7d9 --- /dev/null +++ b/persistence/distributedrwlock.go @@ -0,0 +1,16 @@ +package keelpersistence + +import ( + "context" +) + +// DistributedRWLock coordinates uploads (shared) against the sync +// (exclusive) on one cluster-wide resource. Implemented by +// DistributedRWLockMongo; faked in tests. Acquire* return (false, nil) +// when blocked by the other side +// (no error). +type DistributedRWLock interface { + AcquireShared(ctx context.Context, lockID string) (bool, error) + AcquireExclusive(ctx context.Context, lockID string) (bool, error) + Release(ctx context.Context, lockID string) error +} diff --git a/persistence/mongo/distributedrwlock.go b/persistence/mongo/distributedrwlock.go new file mode 100644 index 0000000..c78790c --- /dev/null +++ b/persistence/mongo/distributedrwlock.go @@ -0,0 +1,100 @@ +package keelmongo + +import ( + "context" + "errors" + "fmt" + "time" + + mongolock "github.com/foomo/mongo-lock" +) + +// DistributedRWLock acquires shared and exclusive locks on one configured resource. +type DistributedRWLock struct { + client *mongolock.Client + resourceName string + sharedTTL uint + exclusiveTTL uint + drainWait time.Duration + drainTimeout time.Duration +} + +// NewDistributedRWLock builds the lock on the configured collection of persistor and ensures its +// indexes exist. +func NewDistributedRWLock(persistor *Persistor, cfg DistributedRWLockConfig) (*DistributedRWLock, error) { + cfg, err := cfg.normalized() + if err != nil { + return nil, err + } + + col, err := persistor.Collection(cfg.CollectionName) + if err != nil { + return nil, fmt.Errorf("distributedreadwritelock: collection: %w", err) + } + + return &DistributedRWLock{ + client: mongolock.NewClient(col.Col()), + resourceName: cfg.ResourceName, + sharedTTL: uint(cfg.SharedTTL.Seconds()), + exclusiveTTL: uint(cfg.ExclusiveTTL.Seconds()), + drainWait: cfg.DrainWait, + drainTimeout: cfg.DrainTimeout, + }, nil +} + +func (l *DistributedRWLock) CreateIndexes(ctx context.Context) error { + return l.client.CreateIndexes(ctx) +} + +// AcquireShared takes a shared lock. It returns (false, nil) when the exclusive +// lock is held — the caller should reject the request — and (true, nil) on +// success. Multiple shared holders are allowed concurrently. +func (l *DistributedRWLock) AcquireShared(ctx context.Context, lockID string) (bool, error) { + err := l.client.SLock(ctx, l.resourceName, lockID, mongolock.LockDetails{TTL: l.sharedTTL}, -1) + + switch { + case err == nil: + return true, nil + case errors.Is(err, mongolock.ErrAlreadyLocked): + return false, nil + default: + return false, fmt.Errorf("distributedreadwritelock: shared: %w", err) + } +} + +// AcquireExclusive takes the exclusive lock. It retries for up to DrainTimeout to +// let in-flight shared locks drain, then returns (false, nil) if still blocked so +// the caller skips this round. +func (l *DistributedRWLock) AcquireExclusive(ctx context.Context, lockID string) (bool, error) { + deadline := time.Now().Add(l.drainTimeout) + + for { + err := l.client.XLock(ctx, l.resourceName, lockID, mongolock.LockDetails{TTL: l.exclusiveTTL}) + if err == nil { + return true, nil + } + + if !errors.Is(err, mongolock.ErrAlreadyLocked) { + return false, fmt.Errorf("distributedreadwritelock: exclusive: %w", err) + } + + if time.Now().After(deadline) { + return false, nil + } + + select { + case <-ctx.Done(): + return false, ctx.Err() + case <-time.After(l.drainWait): + } + } +} + +// Release releases the lock held under lockID (shared or exclusive). +func (l *DistributedRWLock) Release(ctx context.Context, lockID string) error { + if _, err := l.client.Unlock(ctx, lockID); err != nil { + return fmt.Errorf("distributedreadwritelock: unlock: %w", err) + } + + return nil +} diff --git a/persistence/mongo/distributedrwlockconfig.go b/persistence/mongo/distributedrwlockconfig.go new file mode 100644 index 0000000..d799053 --- /dev/null +++ b/persistence/mongo/distributedrwlockconfig.go @@ -0,0 +1,83 @@ +// Package distributedreadwritelock is a small shared/exclusive distributed lock over +// MongoDB (github.com/foomo/mongo-lock) used to coordinate concurrent work +// against a single exclusive operation on one cluster-wide resource. Concurrent +// workers take a shared lock; the exclusive operation takes an exclusive lock. +// While the exclusive lock is held, shared locks cannot be acquired (and are +// rejected); while any shared lock is held, the exclusive lock cannot be +// acquired (and waits/retries until in-flight shared holders drain). +// +// It is configured per use case via DistributedRWLockConfig (collection, resource name, TTLs and +// drain bounds), so the same coordination primitive can back different +// resources. +package keelmongo + +import ( + "errors" + "time" +) + +const ( + // defaultDistributedRWLockExclusiveTTL auto-releases an exclusive lock if the holder crashes + // mid-run. It must exceed the holder's run timeout. + defaultDistributedRWLockExclusiveTTL = 15 * time.Minute + // defaultDistributedRWLockSharedTTL auto-releases a shared lock if the holder dies mid-flight. + // Generous, since a shared holder's work can take a while. + defaultDistributedRWLockSharedTTL = 10 * time.Minute + // defaultDistributedRWLockDrainWait/defaultDrainTimeout bound how long AcquireExclusive retries + // to let in-flight shared locks drain before giving up for this round. + defaultDistributedRWLockDrainWait = 1 * time.Second + // defaultDistributedRWLockDrainTimeout bounds the maximum time AcquireExclusive retries for shared locks to drain. + defaultDistributedRWLockDrainTimeout = 60 * time.Second +) + +// DistributedRWLockConfig configures a coordinated shared/exclusive lock. CollectionName and +// ResourceName are required; the durations and TTLs fall back to defaults when +// left at their zero value. +type DistributedRWLockConfig struct { + // CollectionName is the dedicated Mongo collection holding the lock documents. + CollectionName string + // ResourceName is the single resource shared and exclusive holders contend on. + ResourceName string + // ExclusiveTTL auto-releases the exclusive lock if its holder crashes; it must + // exceed the holder's run timeout. Defaults to 15m. + ExclusiveTTL time.Duration + // SharedTTL auto-releases a shared lock if its holder dies mid-flight. + // Defaults to 10m. + SharedTTL time.Duration + // DrainWait is the retry interval while AcquireExclusive waits for in-flight + // shared holders to drain. Defaults to 1s. + DrainWait time.Duration + // DrainTimeout bounds how long AcquireExclusive retries before giving up for + // this round. Defaults to 60s. + DrainTimeout time.Duration +} + +// normalized validates required identifiers and fills unset durations/TTLs with +// their defaults, returning the completed config. +func (c DistributedRWLockConfig) normalized() (DistributedRWLockConfig, error) { + if c.CollectionName == "" { + return DistributedRWLockConfig{}, errors.New("distributedreadwritelock: CollectionName is required") + } + + if c.ResourceName == "" { + return DistributedRWLockConfig{}, errors.New("distributedreadwritelock: ResourceName is required") + } + + if c.ExclusiveTTL <= 0 { + c.ExclusiveTTL = defaultDistributedRWLockExclusiveTTL + } + + if c.SharedTTL <= 0 { + c.SharedTTL = defaultDistributedRWLockSharedTTL + } + + if c.DrainWait <= 0 { + c.DrainWait = defaultDistributedRWLockDrainWait + } + + if c.DrainTimeout <= 0 { + c.DrainTimeout = defaultDistributedRWLockDrainTimeout + } + + return c, nil +} diff --git a/persistence/mongo/go.mod b/persistence/mongo/go.mod index 36bbd2f..a14ce75 100644 --- a/persistence/mongo/go.mod +++ b/persistence/mongo/go.mod @@ -6,6 +6,7 @@ replace github.com/foomo/keel => ../../ require ( github.com/foomo/keel v0.27.1 + github.com/foomo/mongo-lock v0.2.0 github.com/go-logr/zapr v1.3.0 github.com/pkg/errors v0.9.1 go.mongodb.org/mongo-driver/v2 v2.8.0 diff --git a/persistence/mongo/go.sum b/persistence/mongo/go.sum index 99146c7..c6b9a65 100644 --- a/persistence/mongo/go.sum +++ b/persistence/mongo/go.sum @@ -1,9 +1,39 @@ +dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8= +dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA= +github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg= +github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= +github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= +github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= +github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI= +github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M= +github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE= +github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk= +github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= +github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= +github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A= +github.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7npe7dG/wG+uFPw= +github.com/cpuguy83/dockercfg v0.3.2 h1:DlJTyZGBDlXqUZ2Dk2Q3xHs/FtnooJJVaad2S9GKorA= +github.com/cpuguy83/dockercfg v0.3.2/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= +github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= +github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94= +github.com/docker/go-connections v0.6.0/go.mod h1:AahvXYshr6JgfUJGdDCs2b5EZG/vmaMAntpSFH5BFKE= +github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/ebitengine/purego v0.10.1 h1:dewVBCBT2GaMu1SrNTYxQhgQBethzfhiwvZiLGP/qyY= +github.com/ebitengine/purego v0.10.1/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= github.com/fbiville/markdown-table-formatter v0.3.0 h1:PIm1UNgJrFs8q1htGTw+wnnNYvwXQMMMIKNZop2SSho= github.com/fbiville/markdown-table-formatter v0.3.0/go.mod h1:q89TDtSEVDdTaufgSbfHpNVdPU/bmfvqNkrC5HagmLY= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/foomo/mongo-lock v0.2.0 h1:xURP2FijZ/feACB5YL1UKUXk23M+x5L+yltEK+sJm0g= +github.com/foomo/mongo-lock v0.2.0/go.mod h1:5LMCz8IeaTMCWcgh+aPoDeIjY1qpu8MXbx+FNrGAUFA= github.com/foomo/opentelemetry-go v0.4.0 h1:UQneCUSokIYJXzFUKQSI8rlelbUuf6atgSZMhvD+Nzo= github.com/foomo/opentelemetry-go v0.4.0/go.mod h1:R3Se/rc5FRAs4ThE6JQ9Oq3cOLo2MOsUzZLJxZquwxA= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= @@ -13,18 +43,62 @@ 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/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg= +github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= +github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= +github.com/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U= +github.com/go-test/deep v1.1.1/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= 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/klauspost/compress v1.19.1 h1:VsB4HPswih7mmZ8WleSFQ75c/Ui1M4trX5oAsJnhSlk= github.com/klauspost/compress v1.19.1/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ= +github.com/lufia/plan9stats v0.0.0-20260330125221-c963978e514e h1:Q6MvJtQK/iRcRtzAscm/zF23XxJlbECiGPyRicsX+Ak= +github.com/lufia/plan9stats v0.0.0-20260330125221-c963978e514e/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg= +github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE= +github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= +github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= +github.com/moby/go-archive v0.2.0 h1:zg5QDUM2mi0JIM9fdQZWC7U8+2ZfixfTYoHL7rWUcP8= +github.com/moby/go-archive v0.2.0/go.mod h1:mNeivT14o8xU+5q1YnNrkQVpK+dnNe/K6fHqnTg4qPU= +github.com/moby/moby/api v1.54.2 h1:wiat9QAhnDQjA7wk1kh/TqHz2I1uUA7M7t9SAl/JNXg= +github.com/moby/moby/api v1.54.2/go.mod h1:+RQ6wluLwtYaTd1WnPLykIDPekkuyD/ROWQClE83pzs= +github.com/moby/moby/client v0.4.0 h1:S+2XegzHQrrvTCvF6s5HFzcrywWQmuVnhOXe2kiWjIw= +github.com/moby/moby/client v0.4.0/go.mod h1:QWPbvWchQbxBNdaLSpoKpCdf5E+WxFAgNHogCWDoa7g= +github.com/moby/patternmatcher v0.6.1 h1:qlhtafmr6kgMIJjKJMDmMWq7WLkKIo23hsrpR3x084U= +github.com/moby/patternmatcher v0.6.1/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= +github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU= +github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko= +github.com/moby/sys/user v0.4.0 h1:jhcMKit7SA80hivmFJcbB1vqmw//wU61Zdui2eQXuMs= +github.com/moby/sys/user v0.4.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs= +github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g= +github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28= +github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ= +github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040= +github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU= +github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= +github.com/shirou/gopsutil/v4 v4.26.5 h1:RPcBXkpz7kOj9PqGFQOlBPZHsyaPvPVQc098y9RmCNM= +github.com/shirou/gopsutil/v4 v4.26.5/go.mod h1:LZ6ewCSkBqUpvSOf+LsTGnRinC6iaNUNMGBtDkJBaLQ= +github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w= +github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/testcontainers/testcontainers-go v0.43.0 h1:oEQx5MW2DGd9z3AeEQfB2lPM0eLs7ztyaGRu75bFo5A= +github.com/testcontainers/testcontainers-go v0.43.0/go.mod h1:+VxkT2NQnKOZPKi6praMuMKYHYyOGXr0XSBSlSMCzFo= +github.com/testcontainers/testcontainers-go/modules/mongodb v0.43.0 h1:RJlAAz8dv61icyHvFmrr1xZHJEWZdvBfVBAU6wnmGPM= +github.com/testcontainers/testcontainers-go/modules/mongodb v0.43.0/go.mod h1:1zaDEZyV1SK+mpz83tmB2KthF6DHaS4Y+lRvy3d2XiE= +github.com/tklauser/go-sysconf v0.4.0 h1:7H0uAN+7RkwWRaxhYXDLqa5V3LPrJeV8wmD9dRUgPQU= +github.com/tklauser/go-sysconf v0.4.0/go.mod h1:8mTNWyog7H+MpKijp4VmKJAd2bbYQ2zuUwkYRbUArPI= +github.com/tklauser/numcpus v0.12.0 h1:NR85qdvHA9pFse3x3weVZ0r0ST8R6l5RHbZrlRaqob4= +github.com/tklauser/numcpus v0.12.0/go.mod h1:ABHeXzJnr/qqwguhClkZKT1/8VABcYrsyUiUGobwWJg= github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= github.com/xdg-go/scram v1.2.0 h1:bYKF2AEwG5rqd1BumT4gAnvwU/M9nBp2pTSxeZw7Wvs= @@ -34,12 +108,16 @@ github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gi github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 h1:ilQV1hzziu+LLM3zUTJ0trRztfwgjqKnBWNtSRkbmwM= github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= +github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= go.mongodb.org/mongo-driver/v2 v2.8.0 h1:CxWDGQYY8QQwNjAl/aq2sfWakdnWZynnqJ9F4DhHbP8= go.mongodb.org/mongo-driver/v2 v2.8.0/go.mod h1:yOI9kBsufol30iFsl1slpdq1I0eHPzybRWdyYUs8K/0= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/v2/mongo/otelmongo v0.0.0-20260623174712-bbae83b5df0c h1:etHDCLakSn0jdNgLzYZ0zGKiwaNMof0R/uA+hVqIXQo= go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/v2/mongo/otelmongo v0.0.0-20260623174712-bbae83b5df0c/go.mod h1:VgtIsrVXKo8KmG2sFvQazHcQ98P2FHQ+ZePXtpTPjqs= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0 h1:8tvICD4vSTOOsNrsI4Ljf6C+6UKvpTEH5XY3JMoyPoo= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0/go.mod h1:z9+yiacE0IHRqM4qFfkbt/JYlmYXgss8GY/jXoNuPJI= go.opentelemetry.io/otel v1.44.0 h1:JjwHmHpA4iZ3wBxluu2fbbE7j4kqlE8jXyAyPXH7HqU= go.opentelemetry.io/otel v1.44.0/go.mod h1:BMgjTHL9WPRlRjL2oZCBTL4whCGtXch2H4BhOPIAyYc= go.opentelemetry.io/otel/metric v1.44.0 h1:1w0gILTcHdr3YI+ixLyjemwrVnsMURbTZFrSYCdDdmc= @@ -91,3 +169,5 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q= +gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA= From 188b5dcf8af51ee101aaac4f04484ea87d48ca1f Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Tue, 4 Aug 2026 16:42:40 +0200 Subject: [PATCH 21/23] test: fix test --- telemetry/context_test.go | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/telemetry/context_test.go b/telemetry/context_test.go index 4259e17..f4c9459 100644 --- a/telemetry/context_test.go +++ b/telemetry/context_test.go @@ -53,20 +53,6 @@ func TestCtx(t *testing.T) { require.Len(t, spanRecorder.Ended(), 1) }) - t.Run("EndSpan Ok", func(t *testing.T) { - spanRecorder.Reset() - - ctx := telemetry.Ctx(t.Context()).StartSpan() - require.Len(t, spanRecorder.Started(), 1) - ctx.EndSpan(nil) - // repeat - ctx.EndSpan(errors.New("error")) - - spans := spanRecorder.Ended() - require.Len(t, spans, 1) - assert.Equal(t, codes.Ok, spans[0].Status().Code) - }) - t.Run("EndSpan Error", func(t *testing.T) { spanRecorder.Reset() From 46804b514816ef127230b1da18837360824bb15d Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Tue, 4 Aug 2026 16:45:19 +0200 Subject: [PATCH 22/23] style: fix lint issues --- integration/gotsrpc/gorpcclientservice.go | 2 ++ integration/gotsrpc/gorpcproxyservice.go | 4 ++++ persistence/mongo/distributedrwlockconfig.go | 11 ----------- 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/integration/gotsrpc/gorpcclientservice.go b/integration/gotsrpc/gorpcclientservice.go index 11abcd8..8b2577f 100644 --- a/integration/gotsrpc/gorpcclientservice.go +++ b/integration/gotsrpc/gorpcclientservice.go @@ -21,6 +21,7 @@ func (s *GoRPCClientService) Start(ctx context.Context) error { s.client.Start() <-ctx.Done() s.client.Stop() + return ctx.Err() } @@ -29,5 +30,6 @@ func (s *GoRPCClientService) Close(ctx context.Context) error { s.cancel() s.cancel = nil } + return nil } diff --git a/integration/gotsrpc/gorpcproxyservice.go b/integration/gotsrpc/gorpcproxyservice.go index 71c7ff2..972c2da 100644 --- a/integration/gotsrpc/gorpcproxyservice.go +++ b/integration/gotsrpc/gorpcproxyservice.go @@ -17,12 +17,15 @@ func NewGoRPCProxyService(proxy GoRPCProxy) *GoRPCProxyService { func (s *GoRPCProxyService) Start(ctx context.Context) error { ctx, cancel := context.WithCancel(ctx) + s.cancel = cancel if err := s.proxy.Start(); err != nil { return err } + <-ctx.Done() s.proxy.Stop() + return ctx.Err() } @@ -31,5 +34,6 @@ func (s *GoRPCProxyService) Close(ctx context.Context) error { s.cancel() s.cancel = nil } + return nil } diff --git a/persistence/mongo/distributedrwlockconfig.go b/persistence/mongo/distributedrwlockconfig.go index d799053..cecc15a 100644 --- a/persistence/mongo/distributedrwlockconfig.go +++ b/persistence/mongo/distributedrwlockconfig.go @@ -1,14 +1,3 @@ -// Package distributedreadwritelock is a small shared/exclusive distributed lock over -// MongoDB (github.com/foomo/mongo-lock) used to coordinate concurrent work -// against a single exclusive operation on one cluster-wide resource. Concurrent -// workers take a shared lock; the exclusive operation takes an exclusive lock. -// While the exclusive lock is held, shared locks cannot be acquired (and are -// rejected); while any shared lock is held, the exclusive lock cannot be -// acquired (and waits/retries until in-flight shared holders drain). -// -// It is configured per use case via DistributedRWLockConfig (collection, resource name, TTLs and -// drain bounds), so the same coordination primitive can back different -// resources. package keelmongo import ( From 839253bff8c4a6bc4ddead4cf3f86b927c11df3f Mon Sep 17 00:00:00 2001 From: Kevin Franklin Kim Date: Tue, 4 Aug 2026 16:47:08 +0200 Subject: [PATCH 23/23] fix: go tidy --- examples/go.sum | 10 ++++++++++ go.sum | 12 ++++++++++++ integration/nats/go.sum | 3 +++ 3 files changed, 25 insertions(+) diff --git a/examples/go.sum b/examples/go.sum index 881082f..0c96d1e 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -175,6 +175,7 @@ github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0 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/googleapis/enterprise-certificate-proxy v0.3.16 h1:F/VPrx0YPBdksZJQdCAp0WUsqnNmZpUZszzfYt0M5Dw= +github.com/googleapis/enterprise-certificate-proxy v0.3.16/go.mod h1:9Yb0eAkH/Xqhvv3zbeKf/+wMJqCeocWc6KIhDvEAuYE= github.com/googleapis/gax-go/v2 v2.22.0 h1:PjIWBpgGIVKGoCXuiCoP64altEJCj3/Ei+kSU5vlZD4= github.com/googleapis/gax-go/v2 v2.22.0/go.mod h1:irWBbALSr0Sk3qlqb9SyJ1h68WjgeFuiOzI4Rqw5+aY= github.com/grafana/otel-profiling-go v0.6.0 h1:W7lOZaJj4IJISXMcM1UBk3fJF3tzF2OD6MJBJaQp1H8= @@ -186,6 +187,7 @@ github.com/grafana/pyroscope-go/godeltaprof v0.1.11/go.mod h1:jl1V8M4cWsXciROCPI github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0 h1:5VipnvEpbqr2gA2VbM+nYVbkIF28c5ZQfqCBQ5g2xfk= github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0/go.mod h1:Hyl3n6Twe1hvtd9XUXDec4pTvgMSEixRuQKPTMH2bNs= github.com/hashicorp/consul/api v1.34.3 h1:OiZaQnwkS6uvutie3CF6NFXj8uScNezDlsU9MEqKT0s= +github.com/hashicorp/consul/api v1.34.3/go.mod h1:A4wKd7yw7Wz4zn07p74+o0bLBi5dXsSDMMcMCEinY40= github.com/hashicorp/consul/sdk v0.18.1 h1:RDTeBvAeOveI2xI86sV+8WkaN7OkP4zz+cG3fOobDCM= github.com/hashicorp/consul/sdk v0.18.1/go.mod h1:XdP2tEJmAvlK4jgoKTTtohGkRJlS4mU44mv9/sjU21s= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -261,6 +263,7 @@ github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3 github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-colorable v0.1.15 h1:+u9SLTRGnXv73cEsnsmoZBom+dMU88B2M0aDcWy0/jY= +github.com/mattn/go-colorable v0.1.15/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.22 h1:j8l17JJ9i6VGPUFUYoTUKPSgKe/83EYU2zBC7YNKMw4= @@ -449,6 +452,7 @@ go.opentelemetry.io/contrib/bridges/otelzap v0.19.0/go.mod h1:cQbV77F0u6HmtZPiQD go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/v2/mongo/otelmongo v0.0.0-20260623174712-bbae83b5df0c h1:etHDCLakSn0jdNgLzYZ0zGKiwaNMof0R/uA+hVqIXQo= go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/v2/mongo/otelmongo v0.0.0-20260623174712-bbae83b5df0c/go.mod h1:VgtIsrVXKo8KmG2sFvQazHcQ98P2FHQ+ZePXtpTPjqs= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.69.0 h1:2yEATaop1/a1I4psnSLgWVPLWwCzkqWakgJy7xTDVy0= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.69.0/go.mod h1:D7J12YRapIekYyPWgGPlA/23pRmpSEZC5xJC/TTLI9U= go.opentelemetry.io/contrib/instrumentation/host v0.69.0 h1:N/wKAdIOKd9U4bwiwY3j95e2ZR48onTMR/NI/SZQ/a4= go.opentelemetry.io/contrib/instrumentation/host v0.69.0/go.mod h1:rE1Bxmu3mwcmyTJV4EQdJ/C6zCUnuT9jCiinhRXLAXc= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0 h1:8tvICD4vSTOOsNrsI4Ljf6C+6UKvpTEH5XY3JMoyPoo= @@ -519,10 +523,12 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.54.0 h1:YLIA59K4fiNzHzjnZt2tUJQjQtUWfWbeHBqKtk3eScw= golang.org/x/crypto v0.54.0/go.mod h1:KWL8ny2AZdGR2cWmzeHrp2azQPGogOv+HeQaVEXC2dk= golang.org/x/exp v0.0.0-20260529124908-c761662dc8c9 h1:4d4PbuBNwaxMXkXI8yiIYjydtMU+04RHeuSxJdgKftM= +golang.org/x/exp v0.0.0-20260529124908-c761662dc8c9/go.mod h1:d2fgXJLVs4dYDHUk5lwMIfzRzSrWCfGZb0ZqeLa/Vcw= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.38.0 h1:MECBjubtXD7yj4HrhIUcywNaGeNVUdfVnxmPajOk4yk= +golang.org/x/mod v0.38.0/go.mod h1:V6Xz0pq8TQ3dGqVQ1FVHuelZpAL0uNhSkk9ogYP3c40= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -592,6 +598,7 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.48.0 h1:3+hClM1aLL5mjMKm5ovokw9epgRXPuu2tILgismM6RE= +golang.org/x/tools v0.48.0/go.mod h1:08xX0orndb/F7jJxGDicx061tyd5pcMto75YMAXr6lk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -599,13 +606,16 @@ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8T gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= google.golang.org/api v0.282.0 h1:WmJiSVqUnKqJCpJOx7YADbXaC+9DDsnGSfllFSj7R2I= +google.golang.org/api v0.282.0/go.mod h1:6Wssta4c5n9qHq5CBhmlai5h/PUa1djdDAIhYEHyvcM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20260526163538-3dc84a4a5aaa h1:mfj8IS4EA4VAR9a6QDVxTQkLY64iBybb5QI1B4pXrpE= +google.golang.org/genproto v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:fuT7yonGw1Iq2oa+YC0fyqPPQJkgo/54gPNC6VitOkI= google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa h1:Kjn0N0tCrDgiAFW+lGO4JZ3ck44CehvJQMAwj9QF0G8= google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:q4lMZS6kskjT5HvCPrnnypcDPVJqT/f4nfxmkE7gryY= google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa h1:mZHHdPZl0dbGHCflZgAq/Q468DWVFcU2whhB2KAo8fk= google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= google.golang.org/grpc v1.82.1 h1:NnAxzGRA0677vCa4BUkOAnO5+FfQqVl9iUXeD0IqcGE= +google.golang.org/grpc v1.82.1/go.mod h1:yzTZ1TB1Z3SG+LIYaI+WiE8D5+PZ3ArnrSp8zF3+/ZA= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= diff --git a/go.sum b/go.sum index 8864c76..42fe1ee 100644 --- a/go.sum +++ b/go.sum @@ -145,6 +145,7 @@ github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0 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/googleapis/enterprise-certificate-proxy v0.3.16 h1:F/VPrx0YPBdksZJQdCAp0WUsqnNmZpUZszzfYt0M5Dw= +github.com/googleapis/enterprise-certificate-proxy v0.3.16/go.mod h1:9Yb0eAkH/Xqhvv3zbeKf/+wMJqCeocWc6KIhDvEAuYE= github.com/googleapis/gax-go/v2 v2.22.0 h1:PjIWBpgGIVKGoCXuiCoP64altEJCj3/Ei+kSU5vlZD4= github.com/googleapis/gax-go/v2 v2.22.0/go.mod h1:irWBbALSr0Sk3qlqb9SyJ1h68WjgeFuiOzI4Rqw5+aY= github.com/grafana/otel-profiling-go v0.6.0 h1:W7lOZaJj4IJISXMcM1UBk3fJF3tzF2OD6MJBJaQp1H8= @@ -156,6 +157,7 @@ github.com/grafana/pyroscope-go/godeltaprof v0.1.11/go.mod h1:jl1V8M4cWsXciROCPI github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0 h1:5VipnvEpbqr2gA2VbM+nYVbkIF28c5ZQfqCBQ5g2xfk= github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0/go.mod h1:Hyl3n6Twe1hvtd9XUXDec4pTvgMSEixRuQKPTMH2bNs= github.com/hashicorp/consul/api v1.34.3 h1:OiZaQnwkS6uvutie3CF6NFXj8uScNezDlsU9MEqKT0s= +github.com/hashicorp/consul/api v1.34.3/go.mod h1:A4wKd7yw7Wz4zn07p74+o0bLBi5dXsSDMMcMCEinY40= github.com/hashicorp/consul/sdk v0.18.1 h1:RDTeBvAeOveI2xI86sV+8WkaN7OkP4zz+cG3fOobDCM= github.com/hashicorp/consul/sdk v0.18.1/go.mod h1:XdP2tEJmAvlK4jgoKTTtohGkRJlS4mU44mv9/sjU21s= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -227,6 +229,7 @@ github.com/lufia/plan9stats v0.0.0-20260330125221-c963978e514e/go.mod h1:autxFIv github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-colorable v0.1.15 h1:+u9SLTRGnXv73cEsnsmoZBom+dMU88B2M0aDcWy0/jY= +github.com/mattn/go-colorable v0.1.15/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.22 h1:j8l17JJ9i6VGPUFUYoTUKPSgKe/83EYU2zBC7YNKMw4= @@ -256,6 +259,7 @@ github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRW github.com/nats-io/nats.go v1.52.0 h1:n3avV4VBsCgsdwh71TppsTwtv+QdPs7ntSKM8qJLGsc= github.com/nats-io/nats.go v1.52.0/go.mod h1:26HypzazeOkyO3/mqd1zZd53STJN0EjCYF9Uy2ZOBno= github.com/nats-io/nkeys v0.4.16 h1:rd5oAuLOb8mnAycB0xleuEBNS1pVVnN0fv/FF34Eypg= +github.com/nats-io/nkeys v0.4.16/go.mod h1:llLgWoI0o4z/Q57q2R1kHfmocyhGV6VG/U18Glg1Afs= github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= @@ -315,6 +319,7 @@ github.com/sagikazarmark/locafero v0.12.0/go.mod h1:sZh36u/YSZ918v0Io+U9ogLYQJ9t github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/shirou/gopsutil/v4 v4.26.5 h1:RPcBXkpz7kOj9PqGFQOlBPZHsyaPvPVQc098y9RmCNM= +github.com/shirou/gopsutil/v4 v4.26.5/go.mod h1:LZ6ewCSkBqUpvSOf+LsTGnRinC6iaNUNMGBtDkJBaLQ= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= @@ -370,6 +375,7 @@ go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbE go.opentelemetry.io/contrib/bridges/otelzap v0.19.0 h1:48Eq3xxFx2KlL/tF7lnl42kKJBDlhNTLRzv0h154JnM= go.opentelemetry.io/contrib/bridges/otelzap v0.19.0/go.mod h1:cQbV77F0u6HmtZPiQD9oxp2esaOEb4uLqIta6OFIKOk= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.69.0 h1:2yEATaop1/a1I4psnSLgWVPLWwCzkqWakgJy7xTDVy0= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.69.0/go.mod h1:D7J12YRapIekYyPWgGPlA/23pRmpSEZC5xJC/TTLI9U= go.opentelemetry.io/contrib/instrumentation/host v0.69.0 h1:N/wKAdIOKd9U4bwiwY3j95e2ZR48onTMR/NI/SZQ/a4= go.opentelemetry.io/contrib/instrumentation/host v0.69.0/go.mod h1:rE1Bxmu3mwcmyTJV4EQdJ/C6zCUnuT9jCiinhRXLAXc= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0 h1:8tvICD4vSTOOsNrsI4Ljf6C+6UKvpTEH5XY3JMoyPoo= @@ -439,9 +445,11 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.54.0 h1:YLIA59K4fiNzHzjnZt2tUJQjQtUWfWbeHBqKtk3eScw= golang.org/x/crypto v0.54.0/go.mod h1:KWL8ny2AZdGR2cWmzeHrp2azQPGogOv+HeQaVEXC2dk= golang.org/x/exp v0.0.0-20260529124908-c761662dc8c9 h1:4d4PbuBNwaxMXkXI8yiIYjydtMU+04RHeuSxJdgKftM= +golang.org/x/exp v0.0.0-20260529124908-c761662dc8c9/go.mod h1:d2fgXJLVs4dYDHUk5lwMIfzRzSrWCfGZb0ZqeLa/Vcw= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.38.0 h1:MECBjubtXD7yj4HrhIUcywNaGeNVUdfVnxmPajOk4yk= +golang.org/x/mod v0.38.0/go.mod h1:V6Xz0pq8TQ3dGqVQ1FVHuelZpAL0uNhSkk9ogYP3c40= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -499,6 +507,7 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.48.0 h1:3+hClM1aLL5mjMKm5ovokw9epgRXPuu2tILgismM6RE= +golang.org/x/tools v0.48.0/go.mod h1:08xX0orndb/F7jJxGDicx061tyd5pcMto75YMAXr6lk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -506,13 +515,16 @@ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8T gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= google.golang.org/api v0.282.0 h1:WmJiSVqUnKqJCpJOx7YADbXaC+9DDsnGSfllFSj7R2I= +google.golang.org/api v0.282.0/go.mod h1:6Wssta4c5n9qHq5CBhmlai5h/PUa1djdDAIhYEHyvcM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20260526163538-3dc84a4a5aaa h1:mfj8IS4EA4VAR9a6QDVxTQkLY64iBybb5QI1B4pXrpE= +google.golang.org/genproto v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:fuT7yonGw1Iq2oa+YC0fyqPPQJkgo/54gPNC6VitOkI= google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa h1:Kjn0N0tCrDgiAFW+lGO4JZ3ck44CehvJQMAwj9QF0G8= google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:q4lMZS6kskjT5HvCPrnnypcDPVJqT/f4nfxmkE7gryY= google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa h1:mZHHdPZl0dbGHCflZgAq/Q468DWVFcU2whhB2KAo8fk= google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= google.golang.org/grpc v1.82.1 h1:NnAxzGRA0677vCa4BUkOAnO5+FfQqVl9iUXeD0IqcGE= +google.golang.org/grpc v1.82.1/go.mod h1:yzTZ1TB1Z3SG+LIYaI+WiE8D5+PZ3ArnrSp8zF3+/ZA= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= diff --git a/integration/nats/go.sum b/integration/nats/go.sum index 6c96248..5a9fbff 100644 --- a/integration/nats/go.sum +++ b/integration/nats/go.sum @@ -447,6 +447,7 @@ golang.org/x/exp v0.0.0-20260529124908-c761662dc8c9/go.mod h1:d2fgXJLVs4dYDHUk5l golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.38.0 h1:MECBjubtXD7yj4HrhIUcywNaGeNVUdfVnxmPajOk4yk= +golang.org/x/mod v0.38.0/go.mod h1:V6Xz0pq8TQ3dGqVQ1FVHuelZpAL0uNhSkk9ogYP3c40= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -505,6 +506,7 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.48.0 h1:3+hClM1aLL5mjMKm5ovokw9epgRXPuu2tILgismM6RE= +golang.org/x/tools v0.48.0/go.mod h1:08xX0orndb/F7jJxGDicx061tyd5pcMto75YMAXr6lk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -521,6 +523,7 @@ google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa/go. google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa h1:mZHHdPZl0dbGHCflZgAq/Q468DWVFcU2whhB2KAo8fk= google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= google.golang.org/grpc v1.82.1 h1:NnAxzGRA0677vCa4BUkOAnO5+FfQqVl9iUXeD0IqcGE= +google.golang.org/grpc v1.82.1/go.mod h1:yzTZ1TB1Z3SG+LIYaI+WiE8D5+PZ3ArnrSp8zF3+/ZA= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=