diff --git a/internal/telemetry/trace/client.go b/internal/telemetry/trace/client.go index 0dcf332f9..f72d66d11 100644 --- a/internal/telemetry/trace/client.go +++ b/internal/telemetry/trace/client.go @@ -13,6 +13,8 @@ import ( "go.opentelemetry.io/otel/exporters/otlp/otlptrace" "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc" "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp" + oteltrace "go.opentelemetry.io/otel/trace" + "go.opentelemetry.io/otel/trace/noop" v1 "go.opentelemetry.io/proto/otlp/trace/v1" ) @@ -226,6 +228,36 @@ func (n NoopClient) UploadTraces(context.Context, []*v1.ResourceSpans) error { return nil } +// ValidNoopSpan is the same as noop.Span, except with a "valid" span context +// (has a non-zero trace and span ID). +// +// Adding this into a context as follows: +// +// ctx = oteltrace.ContextWithSpan(ctx, trace.ValidNoopSpan{}) +// +// will prevent some usages of the global tracer provider by libraries such +// as otelhttp, which only uses the global provider if the context's span +// is "invalid". +type ValidNoopSpan struct { + noop.Span +} + +var noopTraceID = oteltrace.TraceID{ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +} + +var noopSpanID = oteltrace.SpanID{ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +} + +// SpanContext implements trace.Span. +func (n ValidNoopSpan) SpanContext() oteltrace.SpanContext { + return n.Span.SpanContext().WithTraceID(noopTraceID).WithSpanID(noopSpanID) +} + +var _ oteltrace.Span = ValidNoopSpan{} + func IsDisabledViaEnvironment() bool { if os.Getenv("OTEL_SDK_DISABLED") == "true" { return true diff --git a/internal/testutil/minio.go b/internal/testutil/minio.go index 69ee9828c..2b0d7e57e 100644 --- a/internal/testutil/minio.go +++ b/internal/testutil/minio.go @@ -6,8 +6,10 @@ import ( "github.com/minio/minio-go/v7" "github.com/minio/minio-go/v7/pkg/credentials" + "github.com/pomerium/pomerium/internal/telemetry/trace" "github.com/testcontainers/testcontainers-go" "github.com/testcontainers/testcontainers-go/wait" + oteltrace "go.opentelemetry.io/otel/trace" ) // WithTestMinIO starts a test MinIO server @@ -15,6 +17,7 @@ func WithTestMinIO(t *testing.T, bucket string, handler func(endpoint string)) { t.Helper() ctx := GetContext(t, maxWait) + ctx = oteltrace.ContextWithSpan(ctx, trace.ValidNoopSpan{}) container, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{ ContainerRequest: testcontainers.ContainerRequest{ diff --git a/internal/testutil/postgres.go b/internal/testutil/postgres.go index fedc417e3..15bb70826 100644 --- a/internal/testutil/postgres.go +++ b/internal/testutil/postgres.go @@ -8,8 +8,10 @@ import ( "github.com/google/uuid" "github.com/jackc/pgx/v5" + "github.com/pomerium/pomerium/internal/telemetry/trace" "github.com/testcontainers/testcontainers-go" "github.com/testcontainers/testcontainers-go/wait" + oteltrace "go.opentelemetry.io/otel/trace" ) // WithTestPostgres starts a postgres database. @@ -17,6 +19,7 @@ func WithTestPostgres(t *testing.T, handler func(dsn string)) { t.Helper() ctx := GetContext(t, maxWait) + ctx = oteltrace.ContextWithSpan(ctx, trace.ValidNoopSpan{}) container, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{ ContainerRequest: testcontainers.ContainerRequest{