From 36f0408bc987296d0a2610e4fdecd06b091a68a7 Mon Sep 17 00:00:00 2001 From: Dylan Myers Date: Thu, 6 Aug 2026 09:06:49 -0400 Subject: [PATCH] feat(embed): add TelemetrySettings provider bundle + NopTelemetry (PIPE-1066) Assisted-by: Claude Opus 4.8 --- embed/telemetry.go | 49 +++++++++++++++++++++++++++++++++++++++++ embed/telemetry_test.go | 30 +++++++++++++++++++++++++ go.mod | 2 +- 3 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 embed/telemetry.go create mode 100644 embed/telemetry_test.go diff --git a/embed/telemetry.go b/embed/telemetry.go new file mode 100644 index 0000000..90889aa --- /dev/null +++ b/embed/telemetry.go @@ -0,0 +1,49 @@ +package embed + +import ( + "go.opentelemetry.io/otel/metric" + metricnoop "go.opentelemetry.io/otel/metric/noop" + "go.opentelemetry.io/otel/trace" + tracenoop "go.opentelemetry.io/otel/trace/noop" + "go.uber.org/zap" +) + +// TelemetrySettings bundles the OTel providers and logger blitz uses to emit +// its own self-telemetry. It is the single value threaded from a host (or the +// standalone CLI) down through module construction, so every generator, output, +// and the runtime records to the same providers. +// +// Every field is optional. A nil provider means "fall back to the process +// global" (via the generated NewMetrics and, in later phases, the tracer and +// logger constructors), so a zero-value bundle behaves exactly as blitz did +// before providers were injectable. +type TelemetrySettings struct { + // Logger is blitz's internal diagnostic logger. Nil means callers supply + // their own fallback (a nop logger). + Logger *zap.Logger + + // MeterProvider is the source of blitz's internal metric instruments. Nil + // falls back to otel.GetMeterProvider(). + MeterProvider metric.MeterProvider + + // TracerProvider is the source of blitz's internal spans. Nil falls back to + // otel.GetTracerProvider(). + TracerProvider trace.TracerProvider + + // PerBatchSpans enables the higher-volume per-emit-cycle spans. Off by + // default; the always-on coarse spans do not depend on it. + PerBatchSpans bool +} + +// NopTelemetry returns a TelemetrySettings wired to no-op providers and a nop +// logger. Use it where a caller has no telemetry to route, most commonly in +// tests and in construction paths that record nothing. It is distinct from a +// zero-value bundle: NopTelemetry emits to no-op providers, while a zero-value +// bundle's nil fields fall back to the process globals. +func NopTelemetry() TelemetrySettings { + return TelemetrySettings{ + Logger: zap.NewNop(), + MeterProvider: metricnoop.NewMeterProvider(), + TracerProvider: tracenoop.NewTracerProvider(), + } +} diff --git a/embed/telemetry_test.go b/embed/telemetry_test.go new file mode 100644 index 0000000..fcbdfe3 --- /dev/null +++ b/embed/telemetry_test.go @@ -0,0 +1,30 @@ +package embed + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestNopTelemetry(t *testing.T) { + tel := NopTelemetry() + + // Every provider and the logger must be non-nil so callers can use the + // bundle without nil checks. + require.NotNil(t, tel.Logger) + require.NotNil(t, tel.MeterProvider) + require.NotNil(t, tel.TracerProvider) + + // Per-batch spans default off. + require.False(t, tel.PerBatchSpans) +} + +func TestTelemetrySettings_zeroValueFieldsAreNil(t *testing.T) { + // A zero-value bundle leaves providers nil; components and NewMetrics are + // responsible for the nil->global fallback. This documents that contract. + var tel TelemetrySettings + + require.Nil(t, tel.Logger) + require.Nil(t, tel.MeterProvider) + require.Nil(t, tel.TracerProvider) +} diff --git a/go.mod b/go.mod index 03b5873..8d7e540 100644 --- a/go.mod +++ b/go.mod @@ -24,6 +24,7 @@ require ( go.opentelemetry.io/otel/metric v1.44.0 go.opentelemetry.io/otel/sdk v1.44.0 go.opentelemetry.io/otel/sdk/metric v1.44.0 + go.opentelemetry.io/otel/trace v1.44.0 go.opentelemetry.io/proto/otlp v1.11.0 go.uber.org/zap v1.28.0 golang.org/x/sys v0.47.0 @@ -86,7 +87,6 @@ require ( github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect - go.opentelemetry.io/otel/trace v1.44.0 // indirect go.uber.org/multierr v1.10.0 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect golang.org/x/crypto v0.54.0 // indirect