fix(otel)!: do not use a global client

Signed-off-by: Adphi <philippe.adrien.nousse@gmail.com>
This commit is contained in:
2025-06-09 10:28:42 +02:00
parent b6f8257981
commit 52083569c5
7 changed files with 64 additions and 64 deletions

View File

@ -41,15 +41,15 @@ func run(ctx context.Context, opts ...service.Option) {
done := make(chan struct{})
ready := make(chan struct{})
otel.Configure(
// otel.WithDSN("http://127.0.0.1:4318"),
p := otel.Configure(
ctx,
otel.WithServiceName(name),
otel.WithServiceVersion(version),
otel.WithDeploymentEnvironment("tests"),
otel.WithTraceSampler(sdktrace.AlwaysSample()),
otel.WithMetricPrometheusBridge(),
)
defer otel.Shutdown(context.WithoutCancel(ctx))
defer p.Shutdown(ctx)
address := "0.0.0.0:9991"

View File

@ -15,6 +15,17 @@ import (
const dummySpanName = "__dummy__"
type Provider interface {
TraceURL(span trace.Span) string
ReportError(ctx context.Context, err error, opts ...trace.EventOption)
ReportPanic(ctx context.Context, val any)
Shutdown(ctx context.Context) error
ForceFlush(ctx context.Context) error
TracerProvider() *sdktrace.TracerProvider
MeterProvider() *sdkmetric.MeterProvider
LoggerProvider() *sdklog.LoggerProvider
}
type client struct {
dsn *DSN
tracer trace.Tracer
@ -32,6 +43,7 @@ func newClient(dsn *DSN) *client {
}
func (c *client) Shutdown(ctx context.Context) (lastErr error) {
ctx = context.WithoutCancel(ctx)
if c.tp != nil {
if err := c.tp.Shutdown(ctx); err != nil {
lastErr = err
@ -99,6 +111,30 @@ func (c *client) ReportPanic(ctx context.Context, val any) {
}
}
func (c *client) TracerProvider() *sdktrace.TracerProvider {
if c.tp == nil {
return sdktrace.NewTracerProvider(
sdktrace.WithSampler(sdktrace.AlwaysSample()),
sdktrace.WithIDGenerator(newIDGenerator()),
)
}
return c.tp
}
func (c *client) MeterProvider() *sdkmetric.MeterProvider {
if c.mp == nil {
return sdkmetric.NewMeterProvider()
}
return c.mp
}
func (c *client) LoggerProvider() *sdklog.LoggerProvider {
if c.lp == nil {
return sdklog.NewLoggerProvider()
}
return c.lp
}
func (c *client) reportPanic(ctx context.Context, val interface{}) {
span := trace.SpanFromContext(ctx)
if !span.IsRecording() {

View File

@ -12,6 +12,8 @@ import (
"go.opentelemetry.io/otel/sdk/resource"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
semconv "go.opentelemetry.io/otel/semconv/v1.21.0"
"go.linka.cloud/grpc-toolkit/logger"
)
type config struct {
@ -62,7 +64,8 @@ func newConfig(opts []Option) *config {
return conf
}
func (conf *config) newResource() *resource.Resource {
func (conf *config) newResource(ctx context.Context) *resource.Resource {
log := logger.C(ctx)
if conf.resource != nil {
if len(conf.resourceAttributes) > 0 {
log.Warnf("WithResource overrides WithResourceAttributes (discarding %v)",
@ -75,8 +78,6 @@ func (conf *config) newResource() *resource.Resource {
return conf.resource
}
ctx := context.TODO()
res, err := resource.New(ctx,
resource.WithFromEnv(),
resource.WithTelemetrySDK(),

View File

@ -7,11 +7,14 @@ import (
"go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp"
"go.opentelemetry.io/otel/log/global"
sdklog "go.opentelemetry.io/otel/sdk/log"
"go.linka.cloud/grpc-toolkit/logger"
)
func configureLogging(ctx context.Context, conf *config) *sdklog.LoggerProvider {
log := logger.C(ctx)
var opts []sdklog.LoggerProviderOption
if res := conf.newResource(); res != nil {
if res := conf.newResource(ctx); res != nil {
opts = append(opts, sdklog.WithResource(res))
}

View File

@ -10,11 +10,14 @@ import (
"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp"
sdkmetric "go.opentelemetry.io/otel/sdk/metric"
"go.opentelemetry.io/otel/sdk/metric/metricdata"
"go.linka.cloud/grpc-toolkit/logger"
)
func configureMetrics(ctx context.Context, conf *config) *sdkmetric.MeterProvider {
log := logger.C(ctx)
opts := conf.metricOptions
if res := conf.newResource(); res != nil {
if res := conf.newResource(ctx); res != nil {
opts = append(opts, sdkmetric.WithResource(res))
}

View File

@ -4,17 +4,14 @@ import (
"context"
"os"
"strings"
"sync/atomic"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/propagation"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
"go.opentelemetry.io/otel/trace"
"go.linka.cloud/grpc-toolkit/logger"
)
var log = logger.StandardLogger().WithField("name", "otel")
var dummy = newClient(&DSN{})
// Configure configures OpenTelemetry.
// By default, it:
@ -23,27 +20,28 @@ var log = logger.StandardLogger().WithField("name", "otel")
// - sets tracecontext + baggage composite context propagator.
//
// You can use OTEL_DISABLED env var to completely skip otel configuration.
func Configure(opts ...Option) {
func Configure(ctx context.Context, opts ...Option) Provider {
if _, ok := os.LookupEnv("OTEL_DISABLED"); ok {
return
return dummy
}
ctx := context.TODO()
log := logger.C(ctx)
conf := newConfig(opts)
if !conf.tracingEnabled && !conf.metricsEnabled && !conf.loggingEnabled {
return
return dummy
}
if len(conf.dsn) == 0 {
log.Warn("no DSN provided (otel-go is disabled)")
return
return dummy
}
dsn, err := ParseDSN(conf.dsn[0])
if err != nil {
log.Warnf("invalid DSN: %s (otel is disabled)", err)
return
return dummy
}
if strings.HasSuffix(dsn.Host, ":4318") {
@ -63,7 +61,7 @@ func Configure(opts ...Option) {
client.lp = configureLogging(ctx, conf)
}
atomicClient.Store(client)
return client
}
func configurePropagator(conf *config) {
@ -76,47 +74,3 @@ func configurePropagator(conf *config) {
}
otel.SetTextMapPropagator(textMapPropagator)
}
// ------------------------------------------------------------------------------
var (
fallbackClient = newClient(&DSN{})
atomicClient atomic.Value
)
func activeClient() *client {
v := atomicClient.Load()
if v == nil {
return fallbackClient
}
return v.(*client)
}
func TraceURL(span trace.Span) string {
return activeClient().TraceURL(span)
}
func ReportError(ctx context.Context, err error, opts ...trace.EventOption) {
activeClient().ReportError(ctx, err, opts...)
}
func ReportPanic(ctx context.Context, val any) {
activeClient().ReportPanic(ctx, val)
}
func Shutdown(ctx context.Context) error {
return activeClient().Shutdown(ctx)
}
func ForceFlush(ctx context.Context) error {
return activeClient().ForceFlush(ctx)
}
func TracerProvider() *sdktrace.TracerProvider {
return activeClient().tp
}
// SetLogger sets the logger to the given one.
func SetLogger(logger logger.Logger) {
log = logger
}

View File

@ -15,15 +15,18 @@ import (
"go.opentelemetry.io/otel/exporters/stdout/stdouttrace"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
"go.opentelemetry.io/otel/trace"
"go.linka.cloud/grpc-toolkit/logger"
)
func configureTracing(ctx context.Context, conf *config) *sdktrace.TracerProvider {
log := logger.C(ctx)
provider := conf.tracerProvider
if provider == nil {
var opts []sdktrace.TracerProviderOption
opts = append(opts, sdktrace.WithIDGenerator(newIDGenerator()))
if res := conf.newResource(); res != nil {
if res := conf.newResource(ctx); res != nil {
opts = append(opts, sdktrace.WithResource(res))
}
if conf.traceSampler != nil {