diff --git a/README.md b/README.md index 3bcfffc..73a145a 100755 --- a/README.md +++ b/README.md @@ -48,6 +48,7 @@ The core module is the base module for cold brew and provides the base implement - [func SetupLogger\(logLevel string, jsonlogs bool\) error](<#SetupLogger>) - [func SetupNROpenTelemetry\(serviceName, license, version string, ratio float64\) error](<#SetupNROpenTelemetry>) - [func SetupNewRelic\(serviceName, apiKey string, tracing bool\) error](<#SetupNewRelic>) +- [func SetupOpenTelemetry\(config OTLPConfig\) error](<#SetupOpenTelemetry>) - [func SetupReleaseName\(rel string\)](<#SetupReleaseName>) - [func SetupSentry\(dsn string\)](<#SetupSentry>) - [type CB](<#CB>) @@ -55,10 +56,11 @@ The core module is the base module for cold brew and provides the base implement - [type CBGracefulStopper](<#CBGracefulStopper>) - [type CBService](<#CBService>) - [type CBStopper](<#CBStopper>) +- [type OTLPConfig](<#OTLPConfig>) -## func [ConfigureInterceptors]() +## func [ConfigureInterceptors]() ```go func ConfigureInterceptors(DoNotLogGRPCReflection bool, traceHeaderName string) @@ -67,7 +69,7 @@ func ConfigureInterceptors(DoNotLogGRPCReflection bool, traceHeaderName string) ConfigureInterceptors configures the interceptors package with the provided DoNotLogGRPCReflection is a boolean that indicates whether to log the grpc.reflection.v1alpha.ServerReflection service calls in logs traceHeaderName is the name of the header to use for tracing \(e.g. X\-Trace\-Id\) \- if empty, defaults to X\-Trace\-Id -## func [InitializeVTProto]() +## func [InitializeVTProto]() ```go func InitializeVTProto() @@ -78,7 +80,7 @@ InitializeVTProto initializes the vtproto package for use with the service https://github.com/planetscale/vtprotobuf?tab=readme-ov-file#mixing-protobuf-implementations-with-grpc -## func [SetupAutoMaxProcs]() +## func [SetupAutoMaxProcs]() ```go func SetupAutoMaxProcs() @@ -96,7 +98,7 @@ func SetupEnvironment(env string) SetupEnvironment sets the environment This is used to identify the environment in Sentry and New Relic env is the environment to set for the service \(e.g. prod, staging, dev\) -## func [SetupHystrixPrometheus]() +## func [SetupHystrixPrometheus]() ```go func SetupHystrixPrometheus() @@ -114,13 +116,22 @@ func SetupLogger(logLevel string, jsonlogs bool) error SetupLogger sets up the logger It uses the coldbrew logger to log messages to stdout logLevel is the log level to set for the logger jsonlogs is a boolean to enable or disable json logs -## func [SetupNROpenTelemetry]() +## func [SetupNROpenTelemetry]() ```go func SetupNROpenTelemetry(serviceName, license, version string, ratio float64) error ``` -setupOpenTelemetry sets up the OpenTelemetry tracing It uses the New Relic OTLP exporter to send traces to New Relic One APM and Insights serviceName is the name of the service license is the New Relic license key version is the version of the service ratio is the sampling ratio to use for traces +SetupNROpenTelemetry sets up OpenTelemetry tracing with New Relic + +This function configures OpenTelemetry to send traces to New Relic's OTLP endpoint. It's a convenience wrapper around SetupOpenTelemetry with New Relic\-specific configuration. + +Parameters: + +- serviceName: the name of the service +- license: the New Relic license key +- version: the version of the service +- ratio: the sampling ratio to use for traces \(0.0 to 1.0\) ## func [SetupNewRelic]() @@ -131,6 +142,44 @@ func SetupNewRelic(serviceName, apiKey string, tracing bool) error SetupNewRelic sets up the New Relic tracing and monitoring agent for the service It uses the New Relic Go Agent to send traces to New Relic One APM and Insights serviceName is the name of the service apiKey is the New Relic license key tracing is a boolean to enable or disable tracing + +## func [SetupOpenTelemetry]() + +```go +func SetupOpenTelemetry(config OTLPConfig) error +``` + +SetupOpenTelemetry sets up OpenTelemetry tracing with a generic OTLP exporter + +This function provides a flexible way to configure OpenTelemetry tracing with any OTLP\-compatible backend. It sets up the trace provider, configures sampling, and optionally sets up an OpenTracing bridge for compatibility. + +Example usage with Jaeger: + +``` +config := OTLPConfig{ + Endpoint: "localhost:4317", + ServiceName: "my-service", + ServiceVersion: "v1.0.0", + SamplingRatio: 0.1, + UseOpenTracingBridge: true, + Insecure: true, // for local development +} +err := SetupOpenTelemetry(config) +``` + +Example usage with Honeycomb: + +``` +config := OTLPConfig{ + Endpoint: "api.honeycomb.io:443", + Headers: map[string]string{"x-honeycomb-team": "your-api-key"}, + ServiceName: "my-service", + ServiceVersion: "v1.0.0", + SamplingRatio: 0.2, +} +err := SetupOpenTelemetry(config) +``` + ## func [SetupReleaseName]() @@ -171,7 +220,7 @@ type CB interface { ``` -### func [New]() +### func [New]() ```go func New(c config.Config) CB @@ -223,4 +272,47 @@ type CBStopper interface { } ``` + +## type [OTLPConfig]() + +OTLPConfig holds configuration for OpenTelemetry OTLP exporter + +This struct provides a flexible way to configure OpenTelemetry tracing with any OTLP\-compatible backend \(e.g., Jaeger, Honeycomb, New Relic, etc.\) + +```go +type OTLPConfig struct { + // Endpoint is the OTLP gRPC endpoint to send traces to + // Examples: "localhost:4317", "otlp.nr-data.net:4317", "api.honeycomb.io:443" + Endpoint string + + // Headers are custom headers to send with each request + // Examples: + // New Relic: {"api-key": "your-license-key"} + // Honeycomb: {"x-honeycomb-team": "your-api-key"} + Headers map[string]string + + // ServiceName is the name of the service sending traces + ServiceName string + + // ServiceVersion is the version of the service + ServiceVersion string + + // SamplingRatio is the ratio of traces to sample (0.0 to 1.0) + // 1.0 means sample all traces, 0.1 means sample 10% of traces + SamplingRatio float64 + + // Compression specifies the compression type (e.g., "gzip", "none") + // If empty, defaults to "gzip" + Compression string + + // UseOpenTracingBridge determines whether to set up OpenTracing compatibility bridge + // This allows using OpenTracing instrumentation with OpenTelemetry + UseOpenTracingBridge bool + + // Insecure disables TLS verification for the connection + // Only use this for local development or testing + Insecure bool +} +``` + Generated by [gomarkdoc]() diff --git a/config/README.md b/config/README.md index 5b0143c..fff074f 100755 --- a/config/README.md +++ b/config/README.md @@ -16,7 +16,7 @@ import "github.com/go-coldbrew/core/config" -## type [Config]() +## type [Config]() Config is the configuration for the Coldbrew server It is populated from environment variables and has sensible defaults for all fields so that you can just use it as is without any configuration The following environment variables are supported and can be used to override the defaults for the fields @@ -116,6 +116,31 @@ type Config struct { // DisableVTProtobuf disables the use of the vtprotobuf marshaller and unmarshaller for GRPC // https://github.com/planetscale/vtprotobuf DisableVTProtobuf bool `envconfig:"DISABLE_VT_PROTOBUF" default:"false"` + // GRPCMaxSendMsgSize and GRPCMaxRecvMsgSize are the maximum message + // sizes for sending and receiving messages over GRPC + GRPCMaxSendMsgSize int `envconfig:"GRPC_MAX_SEND_MSG_SIZE" default:"2147483647"` // Unlimited + GRPCMaxRecvMsgSize int `envconfig:"GRPC_MAX_RECV_MSG_SIZE" default:"4194304"` // 4MB + + // OTLPEndpoint is the OTLP gRPC endpoint to send traces to + // Examples: "localhost:4317", "api.honeycomb.io:443", "otel-collector:4317" + // When set, this takes precedence over NewRelic OpenTelemetry configuration + OTLPEndpoint string `envconfig:"OTLP_ENDPOINT" default:""` + // OTLPHeaders are custom headers to send with each OTLP request + // Format: "key1=value1,key2=value2" (comma-separated key=value pairs) + // Example: "x-honeycomb-team=your-api-key" or "api-key=your-key,dataset=your-dataset" + OTLPHeaders string `envconfig:"OTLP_HEADERS" default:""` + // OTLPCompression specifies the compression type for OTLP requests + // Options: "gzip", "none". Defaults to "gzip" if not specified + OTLPCompression string `envconfig:"OTLP_COMPRESSION" default:"gzip"` + // OTLPInsecure disables TLS verification for OTLP connection + // Only use this for local development or testing with self-signed certificates + OTLPInsecure bool `envconfig:"OTLP_INSECURE" default:"false"` + // OTLPSamplingRatio is the ratio of traces to sample (0.0 to 1.0) + // 1.0 means sample all traces, 0.1 means sample 10% of traces + OTLPSamplingRatio float64 `envconfig:"OTLP_SAMPLING_RATIO" default:"0.2"` + // OTLPUseOpenTracingBridge determines whether to set up OpenTracing compatibility bridge + // This allows using existing OpenTracing instrumentation with OpenTelemetry + OTLPUseOpenTracingBridge bool `envconfig:"OTLP_USE_OPENTRACING_BRIDGE" default:"true"` } ``` diff --git a/config/config.go b/config/config.go index 1e6bd3c..4ec9b88 100644 --- a/config/config.go +++ b/config/config.go @@ -102,4 +102,28 @@ type Config struct { // sizes for sending and receiving messages over GRPC GRPCMaxSendMsgSize int `envconfig:"GRPC_MAX_SEND_MSG_SIZE" default:"2147483647"` // Unlimited GRPCMaxRecvMsgSize int `envconfig:"GRPC_MAX_RECV_MSG_SIZE" default:"4194304"` // 4MB + + // Custom OpenTelemetry OTLP Configuration + // When OTLPEndpoint is set, it takes precedence over NewRelic OpenTelemetry configuration + + // OTLPEndpoint is the OTLP gRPC endpoint to send traces to + // Examples: "localhost:4317", "api.honeycomb.io:443", "otel-collector:4317" + // When set, this takes precedence over NewRelic OpenTelemetry configuration + OTLPEndpoint string `envconfig:"OTLP_ENDPOINT" default:""` + // OTLPHeaders are custom headers to send with each OTLP request + // Format: "key1=value1,key2=value2" (comma-separated key=value pairs) + // Example: "x-honeycomb-team=your-api-key" or "api-key=your-key,dataset=your-dataset" + OTLPHeaders string `envconfig:"OTLP_HEADERS" default:""` + // OTLPCompression specifies the compression type for OTLP requests + // Options: "gzip", "none". Defaults to "gzip" if not specified + OTLPCompression string `envconfig:"OTLP_COMPRESSION" default:"gzip"` + // OTLPInsecure disables TLS verification for OTLP connection + // Only use this for local development or testing with self-signed certificates + OTLPInsecure bool `envconfig:"OTLP_INSECURE" default:"false"` + // OTLPSamplingRatio is the ratio of traces to sample (0.0 to 1.0) + // 1.0 means sample all traces, 0.1 means sample 10% of traces + OTLPSamplingRatio float64 `envconfig:"OTLP_SAMPLING_RATIO" default:"0.2"` + // OTLPUseOpenTracingBridge determines whether to set up OpenTracing compatibility bridge + // This allows using existing OpenTracing instrumentation with OpenTelemetry + OTLPUseOpenTracingBridge bool `envconfig:"OTLP_USE_OPENTRACING_BRIDGE" default:"true"` } diff --git a/core.go b/core.go index 200d4ed..aba3666 100644 --- a/core.go +++ b/core.go @@ -60,6 +60,26 @@ func (c *cb) SetOpenAPIHandler(handler http.Handler) { c.openAPIHandler = handler } +// parseHeaders parses a comma-separated string of key=value pairs into a map +// Example: "key1=value1,key2=value2" -> map[string]string{"key1": "value1", "key2": "value2"} +func parseHeaders(headerString string) map[string]string { + headers := make(map[string]string) + if headerString == "" { + return headers + } + + pairs := strings.SplitSeq(headerString, ",") + for pair := range pairs { + kv := strings.SplitN(strings.TrimSpace(pair), "=", 2) + if len(kv) == 2 { + headers[strings.TrimSpace(kv[0])] = strings.TrimSpace(kv[1]) + } else { + log.Warn(context.Background(), "msg", "Ignoring malformed header pair Expected format 'key=value'", "pair", pair) + } + } + return headers +} + // processConfig processes the config and sets up the logger, newrelic, sentry, environment, release name, jaeger, hystrix prometheus and signal handler func (c *cb) processConfig() { SetupLogger(c.config.LogLevel, c.config.JSONLogs) @@ -94,13 +114,35 @@ func (c *cb) processConfig() { if c.config.EnablePrometheusGRPCHistogram { grpc_prometheus.EnableHandlingTimeHistogram() } - if c.config.NewRelicOpentelemetry { - SetupNROpenTelemetry( + + // Setup OpenTelemetry - custom OTLP takes precedence over New Relic + if c.config.OTLPEndpoint != "" { + // Use custom OTLP configuration + headers := parseHeaders(c.config.OTLPHeaders) + otlpConfig := OTLPConfig{ + Endpoint: c.config.OTLPEndpoint, + Headers: headers, + ServiceName: c.config.AppName, + ServiceVersion: c.config.ReleaseName, + SamplingRatio: c.config.OTLPSamplingRatio, + Compression: c.config.OTLPCompression, + UseOpenTracingBridge: c.config.OTLPUseOpenTracingBridge, + Insecure: c.config.OTLPInsecure, + } + if err := SetupOpenTelemetry(otlpConfig); err != nil { + log.Error(context.Background(), "msg", "Failed to setup custom OTLP", "err", err) + } + } else if c.config.NewRelicOpentelemetry { + // Fall back to New Relic OpenTelemetry if no custom OTLP is configured + err := SetupNROpenTelemetry( nrName, c.config.NewRelicLicenseKey, c.config.ReleaseName, c.config.NewRelicOpentelemetrySample, ) + if err != nil { + log.Error(context.Background(), "msg", "Failed to setup New Relic OpenTelemetry", "err", err) + } } } @@ -395,7 +437,10 @@ func (c *cb) close() { for _, closer := range c.closers { if closer != nil { log.Info(context.Background(), "closing", closer) - closer.Close() + err := closer.Close() + if err != nil { + log.Error(context.Background(), "msg", "Failed to close resource", "err", err, "resource", closer) + } } } } @@ -426,7 +471,12 @@ func (c *cb) Stop(dur time.Duration) error { } log.Info(context.Background(), "msg", "Server shut down started, bye bye") if c.httpServer != nil { - go c.httpServer.Shutdown(ctx) + go func(ctx context.Context, c *cb) { + err := c.httpServer.Shutdown(ctx) + if err != nil { + log.Error(context.Background(), "msg", "http server shutdown error", "err", err) + } + }(ctx, c) // shutdown http server gracefully } if c.grpcServer != nil { timedCall(ctx, c.grpcServer.GracefulStop) diff --git a/go.mod b/go.mod index 39e1973..68205c7 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/go-coldbrew/core -go 1.23.0 +go 1.24.0 toolchain go1.24.1 @@ -9,27 +9,27 @@ require ( github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5 github.com/go-coldbrew/errors v0.2.1 github.com/go-coldbrew/hystrixprometheus v0.1.1 - github.com/go-coldbrew/interceptors v0.1.7 - github.com/go-coldbrew/log v0.2.3 + github.com/go-coldbrew/interceptors v0.1.8 + github.com/go-coldbrew/log v0.2.4 github.com/go-coldbrew/options v0.2.3 github.com/go-coldbrew/tracing v0.0.6 github.com/golang/protobuf v1.5.4 github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 - github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 + github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 github.com/jaegertracing/jaeger-lib v2.4.1+incompatible - github.com/newrelic/go-agent/v3 v3.38.0 + github.com/newrelic/go-agent/v3 v3.40.1 github.com/opentracing/opentracing-go v1.2.0 - github.com/prometheus/client_golang v1.21.1 + github.com/prometheus/client_golang v1.23.2 github.com/uber/jaeger-client-go v2.30.0+incompatible - go.opentelemetry.io/otel v1.35.0 - go.opentelemetry.io/otel/bridge/opentracing v1.35.0 - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0 - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0 - go.opentelemetry.io/otel/sdk v1.35.0 + go.opentelemetry.io/otel v1.38.0 + go.opentelemetry.io/otel/bridge/opentracing v1.38.0 + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 + go.opentelemetry.io/otel/sdk v1.38.0 go.uber.org/automaxprocs v1.6.0 - google.golang.org/grpc v1.71.0 - google.golang.org/protobuf v1.36.6 + google.golang.org/grpc v1.75.1 + google.golang.org/protobuf v1.36.9 ) require ( @@ -37,13 +37,14 @@ require ( github.com/bugsnag/bugsnag-go v2.5.0+incompatible // indirect github.com/bugsnag/panicwrap v1.3.4 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect + github.com/cenkalti/backoff/v5 v5.0.3 // indirect github.com/certifi/gocertifi v0.0.0-20210507211836-431795d63e8d // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/getsentry/raven-go v0.2.0 // indirect github.com/go-kit/kit v0.13.0 // indirect github.com/go-kit/log v0.2.1 // indirect github.com/go-logfmt/logfmt v0.6.0 // indirect - github.com/go-logr/logr v1.4.2 // indirect + github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/gofrs/uuid v4.4.0+incompatible // indirect github.com/google/uuid v1.6.0 // indirect @@ -51,24 +52,25 @@ require ( github.com/klauspost/compress v1.18.0 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/newrelic/go-agent/v3/integrations/nrgrpc v1.4.5 // indirect + github.com/newrelic/go-agent/v3/integrations/nrgrpc v1.4.7 // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/prometheus/client_model v0.6.1 // indirect - github.com/prometheus/common v0.63.0 // indirect - github.com/prometheus/procfs v0.16.0 // indirect + github.com/prometheus/client_model v0.6.2 // indirect + github.com/prometheus/common v0.66.1 // indirect + github.com/prometheus/procfs v0.17.0 // indirect github.com/stvp/rollbar v0.5.1 // indirect github.com/uber/jaeger-lib v2.4.1+incompatible // indirect - go.opentelemetry.io/auto/sdk v1.1.0 // indirect + go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.17.0 // indirect - go.opentelemetry.io/otel/metric v1.35.0 // indirect - go.opentelemetry.io/otel/trace v1.35.0 // indirect - go.opentelemetry.io/proto/otlp v1.5.0 // indirect + go.opentelemetry.io/otel/metric v1.38.0 // indirect + go.opentelemetry.io/otel/trace v1.38.0 // indirect + go.opentelemetry.io/proto/otlp v1.8.0 // indirect go.uber.org/atomic v1.11.0 // indirect - golang.org/x/net v0.37.0 // indirect - golang.org/x/sys v0.31.0 // indirect - golang.org/x/text v0.23.0 // indirect + go.yaml.in/yaml/v2 v2.4.3 // indirect + golang.org/x/net v0.44.0 // indirect + golang.org/x/sys v0.36.0 // indirect + golang.org/x/text v0.29.0 // indirect google.golang.org/genproto v0.0.0-20240903143218-8af14fe29dc1 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20250324211829-b45e905df463 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250324211829-b45e905df463 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250922171735-9219d122eba9 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250922171735-9219d122eba9 // indirect gopkg.in/airbrake/gobrake.v2 v2.0.9 // indirect ) diff --git a/go.sum b/go.sum index af168a0..4fcb322 100644 --- a/go.sum +++ b/go.sum @@ -1412,6 +1412,8 @@ github.com/cenkalti/backoff/v4 v4.1.3 h1:cFAlzYUlVYDysBEH2T5hyJZMh3+5+WCBvSnK6Q8 github.com/cenkalti/backoff/v4 v4.1.3/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= 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/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= +github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= @@ -1548,12 +1550,16 @@ github.com/go-coldbrew/interceptors v0.1.4 h1:hMEOVp9VMGhtzpDsPjE29N+I2BqYyRzeHs github.com/go-coldbrew/interceptors v0.1.4/go.mod h1:nTMDG1Hkei7GLZU3+RJf+PrySF1b21GCFhAnfdN9S7E= github.com/go-coldbrew/interceptors v0.1.7 h1:hZi4rCeOAWGdLW6lIouisdtXOH8obY88qtiY7DWzAs8= github.com/go-coldbrew/interceptors v0.1.7/go.mod h1:lJqhdBQzP27EHcb+dZgQEt0wExQU+xDxWHtmAiBqjTY= +github.com/go-coldbrew/interceptors v0.1.8 h1:nycMHSKlkP+dp0HJYWfjHFBgBdMJaaNUTwxv3YmvcxQ= +github.com/go-coldbrew/interceptors v0.1.8/go.mod h1:o7G3THCenR5ai5NNOsoqNbvcD9YydcbZ1SWFG2JhP9s= github.com/go-coldbrew/log v0.0.0-20210108160031-027cd625aad3/go.mod h1:oKY0UIgGN6xe5ZoHEDuVkt2j81IRVRSj5e+lKd/mTr0= github.com/go-coldbrew/log v0.1.0 h1:8k4LzNsuV8jujpLi9cl+9luJOYw/vQZ8xVtz897hLDA= github.com/go-coldbrew/log v0.1.0/go.mod h1:qIlJAwY07jjjz5bnuMBlG7PUnmibB66uEBvfQC6bA8s= github.com/go-coldbrew/log v0.2.0/go.mod h1:G826qsaI8s4ZGMKk3vv0n2ncLlUN2M2I3XMmsIJO5RQ= github.com/go-coldbrew/log v0.2.3 h1:1DowpkPtqOF/HYTuGr2gwJv4jb0XXXIA4J7edlpsk2E= github.com/go-coldbrew/log v0.2.3/go.mod h1:T/c+n/lHl3Z7KtuWWStWuc0y8Y0yYMnPDOPSGgwLE5g= +github.com/go-coldbrew/log v0.2.4 h1:4C1zBh8jVHhUbRNAsnX80zZM/RQJcGNgIaOQVviOVKc= +github.com/go-coldbrew/log v0.2.4/go.mod h1:IAVI11/g5ub44cHKCigVbIl5W1Ybuw/Kvl3sg3jzvIc= github.com/go-coldbrew/options v0.0.0-20210109113138-49c7e5781276/go.mod h1:WUs8KmARMBkoNGAuGQRZMYS5aQ1GlkqTmpeBwPz302E= github.com/go-coldbrew/options v0.1.0 h1:szMyJf7zHlBrYtb6gnkRG94S4edTCaiTZmBgtiNMWmg= github.com/go-coldbrew/options v0.1.0/go.mod h1:34WzkOP6nsxfRwI/MRSesbJqmPcl7K5GEYHp3vSUB6E= @@ -1606,6 +1612,8 @@ github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ4 github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-pdf/fpdf v0.5.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= @@ -1810,6 +1818,8 @@ github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 h1:asbCHRVmodnJTuQ3qamDwqVOIjw github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0/go.mod h1:ggCgvZ2r7uOoQjOyu2Y1NhHmEPPzzuhWgcza5M1Ji1I= github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 h1:5ZPtiqj0JL5oKWmcsq4VMaAW5ukBEgSGXEN89zeH1Jo= github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3/go.mod h1:ndYquD05frm2vACXE1nsccT4oJzjhw2arTS2cpUD1PI= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 h1:8Tjv8EJ+pM1xP8mK6egEbD1OgnVTyacbefKhmbLhIhU= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2/go.mod h1:pkJQ2tZHJ0aFOVEEot6oZmaVEZcRme73eIFmhiVuRWs= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= github.com/hashicorp/consul/api v1.10.1/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M= @@ -2022,12 +2032,16 @@ github.com/newrelic/go-agent/v3 v3.34.0 h1:jhtX+YUrAh2ddgPGIixMYq4+nCBrEN4ETGyi2 github.com/newrelic/go-agent/v3 v3.34.0/go.mod h1:VNsi+XA7YsgF4fHES8l/U6OhAHhU3IdLDFkB/wpevvA= github.com/newrelic/go-agent/v3 v3.38.0 h1:Oms49R8NpCQ007UMm26dZq6qpHXGq/uDeyxlHEZFsnE= github.com/newrelic/go-agent/v3 v3.38.0/go.mod h1:4QXvru0vVy/iu7mfkNHT7T2+9TC9zPGO8aUEdKqY138= +github.com/newrelic/go-agent/v3 v3.40.1 h1:8nb4R252Fpuc3oySvlHpDwqySqaPWL5nf7ZVEhqtUeA= +github.com/newrelic/go-agent/v3 v3.40.1/go.mod h1:X0TLXDo+ttefTIue1V96Y5seb8H6wqf6uUq4UpPsYj8= github.com/newrelic/go-agent/v3/integrations/nrgrpc v1.3.1 h1:/ar1Omo9luapTJYWXt86oQGBpWwpWF92x+UuYU9v/7o= github.com/newrelic/go-agent/v3/integrations/nrgrpc v1.3.1/go.mod h1:2q0u6qkNJ4ClDt920A4r+NpcO370lFze1NF4OPJjAks= github.com/newrelic/go-agent/v3/integrations/nrgrpc v1.4.4 h1:W2ieA1YqYINmo1CrHTmG48I+WQ8F9tiG85kIGKJcEmI= github.com/newrelic/go-agent/v3/integrations/nrgrpc v1.4.4/go.mod h1:rSwAuMNUCW8w5uLIQ46h0mV44yv53yuRgZIW6wylA7c= github.com/newrelic/go-agent/v3/integrations/nrgrpc v1.4.5 h1:wekCqkQLJbYHim2exa1K+Rqsl07J3e3NlnfrYc7pwV4= github.com/newrelic/go-agent/v3/integrations/nrgrpc v1.4.5/go.mod h1:dDoaVvDchfHQjY9uZxARWym0hquX+80nCQHRNu0RN3c= +github.com/newrelic/go-agent/v3/integrations/nrgrpc v1.4.7 h1:QE9VlVJZBWmFr5/LxbOegDXW5QZMmk1lK5eu48Dyn1M= +github.com/newrelic/go-agent/v3/integrations/nrgrpc v1.4.7/go.mod h1:CFe6nTKFh4CznvfJ23tb7wBplhXJjFr53s9Au5AcUq8= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nishanths/predeclared v0.0.0-20200524104333-86fad755b4d3/go.mod h1:nt3d53pc1VYcphSCIaYAJtnPYnr3Zyn8fMq2wvPGPso= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= @@ -2122,6 +2136,8 @@ github.com/prometheus/client_golang v1.20.3 h1:oPksm4K8B+Vt35tUhw6GbSNSgVlVSBH0q github.com/prometheus/client_golang v1.20.3/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= github.com/prometheus/client_golang v1.21.1 h1:DOvXXTqVzvkIewV/CDPFdejpMCGeMcbGCQ8YOmu+Ibk= github.com/prometheus/client_golang v1.21.1/go.mod h1:U9NM32ykUErtVBxdvD3zfi+EuFkkaBvMb09mIfe0Zgg= +github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o= +github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= @@ -2134,6 +2150,8 @@ github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJ github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= +github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= +github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= @@ -2151,6 +2169,8 @@ github.com/prometheus/common v0.59.1 h1:LXb1quJHWm1P6wq/U824uxYi4Sg0oGvNeUm1z5dJ github.com/prometheus/common v0.59.1/go.mod h1:GpWM7dewqmVYcd7SmRaiWVe9SSqjf0UrwnYnpEZNuT0= github.com/prometheus/common v0.63.0 h1:YR/EIY1o3mEFP/kZCD7iDMnLPlGyuU2Gb3HIcXnA98k= github.com/prometheus/common v0.63.0/go.mod h1:VVFF/fBIoToEnWRVkYoXEkq3R3paCoxG9PXP74SnV18= +github.com/prometheus/common v0.66.1 h1:h5E0h5/Y8niHc5DlaLlWLArTQI7tMrsfQjHV+d9ZoGs= +github.com/prometheus/common v0.66.1/go.mod h1:gcaUsgf3KfRSwHY4dIMXLPV0K/Wg1oZ8+SbZk/HH/dA= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= @@ -2166,6 +2186,8 @@ github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0leargg github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= github.com/prometheus/procfs v0.16.0 h1:xh6oHhKwnOJKMYiYBDWmkHqQPyiY40sny36Cmx2bbsM= github.com/prometheus/procfs v0.16.0/go.mod h1:8veyXUu3nGP7oaCxhX6yeaM5u4stL2FeMXnCqhDthZg= +github.com/prometheus/procfs v0.17.0 h1:FuLQ+05u4ZI+SS/w9+BWEM2TXiHKsUQ9TADiRH7DuK0= +github.com/prometheus/procfs v0.17.0/go.mod h1:oPQLaDAMRbA+u8H5Pbfq+dl3VDAvHxMUOVhe0wYB2zw= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= @@ -2307,6 +2329,8 @@ go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +go.opentelemetry.io/auto/sdk v1.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/google.golang.org/grpc/otelgrpc v0.46.1/go.mod h1:4UoMYEZOC0yN/sPGH76KPkkU7zgiEWYWL9vwmbnTJPE= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.47.0/go.mod h1:r9vWsPS/3AQItv3OSlEJ/E4mbrhUbbw18meOjArPtKQ= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.48.0/go.mod h1:tIKj3DbO8N9Y2xo52og3irLsPI4GW02DSMtrVgNMgxg= @@ -2326,12 +2350,16 @@ go.opentelemetry.io/otel v1.30.0 h1:F2t8sK4qf1fAmY9ua4ohFS/K+FUuOPemHUIXHtktrts= go.opentelemetry.io/otel v1.30.0/go.mod h1:tFw4Br9b7fOS+uEao81PJjVMjW/5fvNCbpsDIXqP0pc= go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ= go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y= +go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= +go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= go.opentelemetry.io/otel/bridge/opentracing v1.9.0 h1:jlrWaQ/BRcf7C1+LldCcTcqwANsfc1E5HmOv4kE7EZc= go.opentelemetry.io/otel/bridge/opentracing v1.9.0/go.mod h1:QYKRAmt+MWDoudzsVKYSutcVs9scYhc2K6YspGV/LLw= go.opentelemetry.io/otel/bridge/opentracing v1.30.0 h1:T1r66CoVeejjxHo+2viKc9NxqpL635q7n864jj7/TZ4= go.opentelemetry.io/otel/bridge/opentracing v1.30.0/go.mod h1:oAj/5hnks4TcCJnmrqsLKV/02dN+8NB+Kkh3n+HCtHY= go.opentelemetry.io/otel/bridge/opentracing v1.35.0 h1:qT4jl1fYl0hHuRopNcwS94QosLFhGYcS0HacPUeXmT4= go.opentelemetry.io/otel/bridge/opentracing v1.35.0/go.mod h1:p5CbIL4v7uQz7mnQD6T/AZc1pPUzwz+2wZ1zrGY9Kgs= +go.opentelemetry.io/otel/bridge/opentracing v1.38.0 h1:D90TIU3MD4BohrGvLW2ZGXeiFrgFL3c1tMcSFPSX0Lc= +go.opentelemetry.io/otel/bridge/opentracing v1.38.0/go.mod h1:0FOr06rtmkVGtQHeG8eTVS2rOmHkmz04peq5+VYNKzc= go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.9.0 h1:ggqApEjDKczicksfvZUCxuvoyDmR6Sbm56LwiK8DVR0= go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.9.0/go.mod h1:78XhIg8Ht9vR4tbLNUhXsiOnE2HOuSeKAiAcoVQEpOY= go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.17.0 h1:eU0ffpYuEY7eQ75K+nKr9CI5KcY8h+GPk/9DDlEO1NI= @@ -2342,12 +2370,16 @@ go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.30.0 h1:lsInsfvhVIfOI6qHVyy go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.30.0/go.mod h1:KQsVNh4OjgjTG0G6EiNi1jVpnaeeKsKMRwbLN+f1+8M= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0 h1:1fTNlAIJZGWLP5FVu0fikVry1IsiUnXjf7QFvoNN3Xw= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0/go.mod h1:zjPK58DtkqQFn+YUMbx0M2XV3QgKU0gS9LeGohREyK4= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 h1:GqRJVj7UmLjCVyVJ3ZFLdPRmhDUp2zFmQe3RHIOsw24= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0/go.mod h1:ri3aaHSmCTVYu2AWv44YMauwAQc0aqI9gHKIcSbI1pU= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.9.0 h1:M0/hqGuJBLeIEu20f89H74RGtqV2dn+SFWEz9ATAAwY= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.9.0/go.mod h1:K5G92gbtCrYJ0mn6zj9Pst7YFsDFuvSYEhYKRMcufnM= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.30.0 h1:m0yTiGDLUvVYaTFbAvCkVYIYcvwKt3G7OLoN77NUs/8= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.30.0/go.mod h1:wBQbT4UekBfegL2nx0Xk1vBcnzyBPsIVm9hRG4fYcr4= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0 h1:m639+BofXTvcY1q8CGs4ItwQarYtJPOWmVobfM1HpVI= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0/go.mod h1:LjReUci/F4BUyv+y4dwnq3h/26iNOeC3wAIqgvTIZVo= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 h1:lwI4Dc5leUqENgGuQImwLo4WnuXFPetmPpkLi2IrX54= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0/go.mod h1:Kz/oCE7z5wuyhPxsXDuaPteSWqjSBD5YaSdbxZYGbGk= go.opentelemetry.io/otel/metric v1.19.0/go.mod h1:L5rUsV9kM1IxCj1MmSdS+JQAcVm319EUrDVLrt7jqt8= go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM= go.opentelemetry.io/otel/metric v1.22.0/go.mod h1:evJGjVpZv0mQ5QBRJoBF64yMuOf4xCWdXjK8pzFvliY= @@ -2357,6 +2389,8 @@ go.opentelemetry.io/otel/metric v1.30.0 h1:4xNulvn9gjzo4hjg+wzIKG7iNFEaBMX00Qd4Q go.opentelemetry.io/otel/metric v1.30.0/go.mod h1:aXTfST94tswhWEb+5QjlSqG+cZlmyXy/u8jFpor3WqQ= go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M= go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE= +go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= +go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/sdk v1.9.0 h1:LNXp1vrr83fNXTHgU8eO89mhzxb/bbWAsHG6fNf3qWo= go.opentelemetry.io/otel/sdk v1.9.0/go.mod h1:AEZc8nt5bd2F7BC24J5R0mrjYnpEgYHyTcM/vrSple4= go.opentelemetry.io/otel/sdk v1.19.0/go.mod h1:NedEbbS4w3C6zElbLdPJKOpJQOrGUJ+GfzpjUvI0v1A= @@ -2366,6 +2400,8 @@ go.opentelemetry.io/otel/sdk v1.30.0 h1:cHdik6irO49R5IysVhdn8oaiR9m8XluDaJAs4DfO go.opentelemetry.io/otel/sdk v1.30.0/go.mod h1:p14X4Ok8S+sygzblytT1nqG98QG2KYKv++HE0LY/mhg= go.opentelemetry.io/otel/sdk v1.35.0 h1:iPctf8iprVySXSKJffSS79eOjl9pvxV9ZqOWT0QejKY= go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg= +go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= +go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= go.opentelemetry.io/otel/trace v1.9.0 h1:oZaCNJUjWcg60VXWee8lJKlqhPbXAPB51URuR47pQYc= go.opentelemetry.io/otel/trace v1.9.0/go.mod h1:2737Q0MuG8q1uILYm2YYVkAyLtOofiTNGg6VODnOiPo= go.opentelemetry.io/otel/trace v1.19.0/go.mod h1:mfaSyvGyEJEI0nyV2I4qhNQnbBOUUmYZpYojqMnX2vo= @@ -2377,6 +2413,8 @@ go.opentelemetry.io/otel/trace v1.30.0 h1:7UBkkYzeg3C7kQX8VAidWh2biiQbtAKjyIML8d go.opentelemetry.io/otel/trace v1.30.0/go.mod h1:5EyKqTzzmyqB9bwtCCq6pDLktPK6fmGf/Dph+8VI02o= go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs= go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc= +go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= +go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= go.opentelemetry.io/proto/otlp v0.18.0 h1:W5hyXNComRa23tGpKwG+FRAc4rfF6ZUg1JReK+QHS80= @@ -2387,6 +2425,8 @@ go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeX go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4= go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4= +go.opentelemetry.io/proto/otlp v1.8.0 h1:fRAZQDcAFHySxpJ1TwlA1cJ4tvcrw7nXl9xWWC8N5CE= +go.opentelemetry.io/proto/otlp v1.8.0/go.mod h1:tIeYOeNBU4cvmPqpaji1P+KbB4Oloai8wN4rWzRrFF0= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= @@ -2416,6 +2456,8 @@ go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= +go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0= +go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -2620,6 +2662,8 @@ golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c= golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= +golang.org/x/net v0.44.0 h1:evd8IRDyfNBMBTTY5XRF1vaZlD+EmWx6x8PkhR04H/I= +golang.org/x/net v0.44.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY= golang.org/x/oauth2 v0.0.0-20170912212905-13449ad91cb2/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -2821,6 +2865,8 @@ golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k= +golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY= @@ -2873,6 +2919,8 @@ golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= +golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk= +golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4= golang.org/x/time v0.0.0-20170424234030-8be79e1e0910/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -3273,6 +3321,8 @@ google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 h1: google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:qpvKtACPCQhAdu3PyQgV4l3LMXZEtft7y8QcarRsp9I= google.golang.org/genproto/googleapis/api v0.0.0-20250324211829-b45e905df463 h1:hE3bRWtU6uceqlh4fhrSnUyjKHMKB9KrTLLG+bc0ddM= google.golang.org/genproto/googleapis/api v0.0.0-20250324211829-b45e905df463/go.mod h1:U90ffi8eUL9MwPcrJylN5+Mk2v3vuPDptd5yyNUiRR8= +google.golang.org/genproto/googleapis/api v0.0.0-20250922171735-9219d122eba9 h1:jm6v6kMRpTYKxBRrDkYAitNJegUeO1Mf3Kt80obv0gg= +google.golang.org/genproto/googleapis/api v0.0.0-20250922171735-9219d122eba9/go.mod h1:LmwNphe5Afor5V3R5BppOULHOnt2mCIf+NxMd4XiygE= google.golang.org/genproto/googleapis/bytestream v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:ylj+BE99M198VPbBh6A8d9n3w8fChvyLK3wwBOjXBFA= google.golang.org/genproto/googleapis/bytestream v0.0.0-20230807174057-1744710a1577/go.mod h1:NjCQG/D8JandXxM57PZbAJL1DCNL6EypA0vPPwfsc7c= google.golang.org/genproto/googleapis/bytestream v0.0.0-20231030173426-d783a09b4405/go.mod h1:GRUCuLdzVqZte8+Dl/D4N25yLzcGqqWaYkeVOwulFqw= @@ -3320,6 +3370,8 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1: google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= google.golang.org/genproto/googleapis/rpc v0.0.0-20250324211829-b45e905df463 h1:e0AIkUUhxyBKh6ssZNrAMeqhA7RKUj42346d1y02i2g= google.golang.org/genproto/googleapis/rpc v0.0.0-20250324211829-b45e905df463/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250922171735-9219d122eba9 h1:V1jCN2HBa8sySkR5vLcCSqJSTMv093Rw9EJefhQGP7M= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250922171735-9219d122eba9/go.mod h1:HSkG/KdJWusxU1F6CNrwNDjBMgisKxGnc5dAZfT0mjQ= google.golang.org/grpc v1.2.1-0.20170921194603-d4b75ebd4f9f/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= @@ -3389,6 +3441,8 @@ google.golang.org/grpc v1.66.2 h1:3QdXkuq3Bkh7w+ywLdLvM56cmGvQHUMZpiCzt6Rqaoo= google.golang.org/grpc v1.66.2/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y= google.golang.org/grpc v1.71.0 h1:kF77BGdPTQ4/JZWMlb9VpJ5pa25aqvVqogsxNHHdeBg= google.golang.org/grpc v1.71.0/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec= +google.golang.org/grpc v1.75.1 h1:/ODCNEuf9VghjgO3rqLcfg8fiOP0nSluljWFlDxELLI= +google.golang.org/grpc v1.75.1/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.0.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= @@ -3419,6 +3473,8 @@ google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6h google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= +google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw= +google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= gopkg.in/VividCortex/ewma.v1 v1.1.1/go.mod h1:TekXuFipeiHWiAlO1+wSS23vTcyFau5u3rxXUSXj710= gopkg.in/airbrake/gobrake.v2 v2.0.9 h1:7z2uVWwn7oVeeugY1DtlPAy5H+KYgB1KeKTnqjNatLo= gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= diff --git a/initializers.go b/initializers.go index 4e31d6e..982e00e 100644 --- a/initializers.go +++ b/initializers.go @@ -34,6 +34,7 @@ import ( semconv "go.opentelemetry.io/otel/semconv/v1.12.0" "go.uber.org/automaxprocs/maxprocs" "google.golang.org/grpc/encoding" + _ "google.golang.org/grpc/encoding/gzip" "google.golang.org/protobuf/proto" ) @@ -131,25 +132,101 @@ func setupJaeger(serviceName string) io.Closer { return closer } -// setupOpenTelemetry sets up the OpenTelemetry tracing -// It uses the New Relic OTLP exporter to send traces to New Relic One APM and Insights -// serviceName is the name of the service -// license is the New Relic license key -// version is the version of the service -// ratio is the sampling ratio to use for traces -func SetupNROpenTelemetry(serviceName, license, version string, ratio float64) error { - if serviceName == "" || license == "" { - log.Info(context.Background(), "msg", "not initializing NR opentelemetry tracing") +// OTLPConfig holds configuration for OpenTelemetry OTLP exporter +// +// This struct provides a flexible way to configure OpenTelemetry tracing +// with any OTLP-compatible backend (e.g., Jaeger, Honeycomb, New Relic, etc.) +type OTLPConfig struct { + // Endpoint is the OTLP gRPC endpoint to send traces to + // Examples: "localhost:4317", "otlp.nr-data.net:4317", "api.honeycomb.io:443" + Endpoint string + + // Headers are custom headers to send with each request + // Examples: + // New Relic: {"api-key": "your-license-key"} + // Honeycomb: {"x-honeycomb-team": "your-api-key"} + Headers map[string]string + + // ServiceName is the name of the service sending traces + ServiceName string + + // ServiceVersion is the version of the service + ServiceVersion string + + // SamplingRatio is the ratio of traces to sample (0.0 to 1.0) + // 1.0 means sample all traces, 0.1 means sample 10% of traces + SamplingRatio float64 + + // Compression specifies the compression type (e.g., "gzip", "none") + // If empty, defaults to "gzip" + Compression string + + // UseOpenTracingBridge determines whether to set up OpenTracing compatibility bridge + // This allows using OpenTracing instrumentation with OpenTelemetry + UseOpenTracingBridge bool + + // Insecure disables TLS verification for the connection + // Only use this for local development or testing + Insecure bool +} + +// SetupOpenTelemetry sets up OpenTelemetry tracing with a generic OTLP exporter +// +// This function provides a flexible way to configure OpenTelemetry tracing +// with any OTLP-compatible backend. It sets up the trace provider, configures +// sampling, and optionally sets up an OpenTracing bridge for compatibility. +// +// Example usage with Jaeger: +// +// config := OTLPConfig{ +// Endpoint: "localhost:4317", +// ServiceName: "my-service", +// ServiceVersion: "v1.0.0", +// SamplingRatio: 0.1, +// UseOpenTracingBridge: true, +// Insecure: true, // for local development +// } +// err := SetupOpenTelemetry(config) +// +// Example usage with Honeycomb: +// +// config := OTLPConfig{ +// Endpoint: "api.honeycomb.io:443", +// Headers: map[string]string{"x-honeycomb-team": "your-api-key"}, +// ServiceName: "my-service", +// ServiceVersion: "v1.0.0", +// SamplingRatio: 0.2, +// } +// err := SetupOpenTelemetry(config) +func SetupOpenTelemetry(config OTLPConfig) error { + if config.ServiceName == "" || config.Endpoint == "" { + log.Info( + context.Background(), + "msg", + "not initializing opentelemetry tracing: missing serviceName or endpoint", + ) return nil } - headers := map[string]string{ - "api-key": license, + + // Default compression to gzip if not specified + if config.Compression == "" { + config.Compression = "gzip" } + // Build client options clientOpts := []otlptracegrpc.Option{ - otlptracegrpc.WithEndpoint("otlp.nr-data.net:4317"), - otlptracegrpc.WithHeaders(headers), - otlptracegrpc.WithCompressor("gzip"), + otlptracegrpc.WithEndpoint(config.Endpoint), + otlptracegrpc.WithHeaders(config.Headers), + } + + // Add compression if specified + if config.Compression != "none" { + clientOpts = append(clientOpts, otlptracegrpc.WithCompressor(config.Compression)) + } + + // Add insecure option if needed + if config.Insecure { + clientOpts = append(clientOpts, otlptracegrpc.WithInsecure()) } otlpExporter, err := otlptrace.New(context.Background(), otlptracegrpc.NewClient(clientOpts...)) @@ -162,8 +239,8 @@ func SetupNROpenTelemetry(serviceName, license, version string, ratio float64) e res, err := resource.New(context.Background(), resource.WithAttributes( // the service name used to display traces in backends - semconv.ServiceNameKey.String(serviceName), - semconv.ServiceVersionKey.String(version), + semconv.ServiceNameKey.String(config.ServiceName), + semconv.ServiceVersionKey.String(config.ServiceVersion), ), ) if err != nil { @@ -175,22 +252,61 @@ func SetupNROpenTelemetry(serviceName, license, version string, ratio float64) e log.Error(context.Background(), "msg", "merging OTLP resource", "err", err) return err } + // Clamp/Default sampling ratio + ratio := config.SamplingRatio + if ratio <= 0 || ratio > 1 { + ratio = 0.2 + } tracerProvider := sdktrace.NewTracerProvider( - sdktrace.WithSampler(sdktrace.ParentBased(sdktrace.TraceIDRatioBased(ratio))), // sample 20% + sdktrace.WithSampler(sdktrace.ParentBased(sdktrace.TraceIDRatioBased(ratio))), sdktrace.WithBatcher(otlpExporter), sdktrace.WithResource(r), ) - otelTracer := tracerProvider.Tracer("") - // Use the bridgeTracer as your OpenTracing tracer. - bridgeTracer, wrapperTracerProvider := otelBridge.NewTracerPair(otelTracer) - otel.SetTracerProvider(wrapperTracerProvider) - opentracing.SetGlobalTracer(bridgeTracer) - log.Info(context.Background(), "msg", "Initialized NR opentelemetry tracing") + if config.UseOpenTracingBridge { + otelTracer := tracerProvider.Tracer(config.ServiceName) + // Use the bridgeTracer as your OpenTracing tracer. + bridgeTracer, wrapperTracerProvider := otelBridge.NewTracerPair(otelTracer) + + otel.SetTracerProvider(wrapperTracerProvider) + opentracing.SetGlobalTracer(bridgeTracer) + } else { + otel.SetTracerProvider(tracerProvider) + } + + log.Info(context.Background(), "msg", "Initialized opentelemetry tracing", "endpoint", config.Endpoint) return nil } +// SetupNROpenTelemetry sets up OpenTelemetry tracing with New Relic +// +// This function configures OpenTelemetry to send traces to New Relic's OTLP endpoint. +// It's a convenience wrapper around SetupOpenTelemetry with New Relic-specific configuration. +// +// Parameters: +// - serviceName: the name of the service +// - license: the New Relic license key +// - version: the version of the service +// - ratio: the sampling ratio to use for traces (0.0 to 1.0) +func SetupNROpenTelemetry(serviceName, license, version string, ratio float64) error { + if strings.TrimSpace(license) == "" { + log.Info(context.Background(), "msg", "not initializing opentelemetry (nr): missing license key") + return nil + } + // Use the generic SetupOpenTelemetry with New Relic specific configuration + config := OTLPConfig{ + Endpoint: "otlp.nr-data.net:4317", + Headers: map[string]string{"api-key": license}, + ServiceName: serviceName, + ServiceVersion: version, + SamplingRatio: ratio, + Compression: "gzip", + UseOpenTracingBridge: true, + } + return SetupOpenTelemetry(config) +} + // SetupHystrixPrometheus sets up the hystrix metrics // This is a workaround for hystrix-go not supporting the prometheus registry func SetupHystrixPrometheus() { @@ -203,7 +319,10 @@ func SetupHystrixPrometheus() { // traceHeaderName is the name of the header to use for tracing (e.g. X-Trace-Id) - if empty, defaults to X-Trace-Id func ConfigureInterceptors(DoNotLogGRPCReflection bool, traceHeaderName string) { if DoNotLogGRPCReflection { - interceptors.FilterMethods = append(interceptors.FilterMethods, "grpc.reflection.v1alpha.ServerReflection") + interceptors.FilterMethods = append( + interceptors.FilterMethods, + "grpc.reflection.v1alpha.ServerReflection", + ) } if traceHeaderName != "" { notifier.SetTraceHeaderName(traceHeaderName)