[go-fan] Go Module Review: go.opentelemetry.io/otel

Go Fan ยท issue ยท open

Filter2mode:review mode:live
All recorded Export JSON
github-actions[bot]

published Aug 27, 2026, 10:27 AM ยท updated Aug 27, 2026, 10:27 AM

๐Ÿน Go Fan Report: go.opentelemetry.io/otel

Module Overview

go.opentelemetry.io/otel is the official Go implementation of the OpenTelemetry API/SDK โ€” the vendor-neutral standard for distributed tracing, metrics, and (beta) logs. gh-aw-mcpg uses it to instrument the MCP Gateway's request/tool-call pipeline and export spans via OTLP/HTTP.

Current Usage in gh-aw

  • Files: 19 files reference go.opentelemetry.io/otel* packages (mostly under internal/tracing/, plus internal/server, internal/proxy, internal/cmd).
  • Import Count: core packages used โ€” otel, otel/trace, otel/trace/noop, otel/attribute, otel/codes, otel/propagation, otel/sdk/resource, otel/sdk/trace (aliased sdktrace), plus the otlptracehttp exporter.
  • Key APIs Used:
    • sdktrace.NewTracerProvider + sdktrace.WithBatcher (custom-tuned: batch size 256, 2s timeout, vs. SDK defaults of 512/5s)
    • sdktrace.TraceIDRatioBased / AlwaysSample / NeverSample samplers, chosen dynamically from config
    • resource.New with WithTelemetrySDK, WithContainer, WithProcessPID, WithHost detectors, with a documented fallback/merge path on error
    • noop.NewTracerProvider for zero-overhead disabled tracing
    • propagation.NewCompositeTextMapPropagator(TraceContext{}, Baggage{}) registered globally, even when tracing is disabled โ€” nice touch for future extensibility
    • Custom fan-out SpanExporter (internal/tracing/fanout.go) to support multiple simultaneous OTLP endpoints (GH_AW_OTLP_ENDPOINTS) โ€” this is not a built-in OTel feature, it's a well-built custom wrapper
    • trace.WithStackTrace(true) on RecordError, consistent status-setting helpers (RecordSpanError, RecordSpanErrorSafe) to avoid inconsistent error-recording across call sites
    • trace.NewSpanContext + trace.ContextWithRemoteSpanContext for constructing W3C remote parent contexts from CLI flags

Research Findings

Recent Updates

  • Latest commit (2026-08-27) on main: "Drop support for Go 1.25" โ€” the project now requires Go 1.26+ across all otel modules. gh-aw-mcpg is already on Go 1.26.4 in go.mod, so no compatibility risk here, but it signals the otel project is moving fast on the Go-version floor and gh-aw should keep an eye on the next "drop Go 1.26" release before bumping again.
  • Traces and Metrics signals are Stable; Logs is Beta โ€” if gh-aw ever wants to unify its custom file/stderr logger (internal/logger) with OTel, the Logs Bridge API (go.opentelemetry.io/otel/log) is now viable to prototype, though still marked beta upstream.
  • The SDK's sdktrace.WithBatcher batch processor and panic-recording (added v1.44.0) are both already accounted for in the code โ€” the comment in provider.go explicitly documents why panic recording is left enabled, which is excellent self-documentation.

Best Practices

  • OTel recommends registering the global TracerProvider and TextMapPropagator once, exactly as gh-aw does in InitProvider/registerPropagator.
  • Official guidance encourages using resource.New with auto-detectors (host, process, container) rather than hand-rolling resource attributes โ€” already followed.
  • Exporter construction failures should not silently succeed; gh-aw's errors.Join aggregation across multiple endpoint construction failures matches the "fail loud, but degrade gracefully with the resource that constructed successfully" pattern outlined in OTel Go's contrib exporters.

Improvement Opportunities

๐Ÿƒ Quick Wins

  • The schema-URL pinning comment in provider.go ("Keep tracing/semconv.go in lockstep with the otel/sdk pin in go.mod") is a manual invariant with no automated check. Consider adding a small unit test that asserts semconv.SchemaURL used in internal/tracing/semconv.go matches the schema URL baked into the pinned go.opentelemetry.io/otel/sdk version, so a future dependency bump doesn't silently reintroduce the "conflicting Schema URL" resource-merge error the comment warns about.
  • mergeOTLPHeaders header-merging logic is manually reimplemented; OTel's otlptracehttp.WithHeaders already accepts a map directly, so the only actual value-add is the shared+per-endpoint merge, which is fine, but could be unit-tested explicitly if not already (verify coverage of empty/overlapping key cases).

โœจ Feature Opportunities

  • Since Logs is now further along (v1.45.0 corresponds to a fairly mature Logs Bridge API), gh-aw could consider optionally piping the existing per-server file logger (internal/logger) into an OTel LoggerProvider for correlated trace+log export to the same OTLP backend โ€” this would let operators view backend RPC logs ({serverID}.log) alongside spans in one observability platform, matching the "traces stable, logs beta" status without a stability regression.
  • The custom fan-out exporter (internal/tracing/fanout.go) duplicates general functionality that the OTel community has discussed adding upstream as a "multi-exporter" processor; keep an eye on go.opentelemetry.io/contrib for noopspanprocessor/multiexporter helpers that might eventually let gh-aw retire the custom fan-out in favor of an officially maintained processor once/if that lands.

๐Ÿ“ Best Practice Alignment

  • Usage is already highly idiomatic: noop fallback, single global registration, consistent resource detection, and safe error scrubbing (RecordSpanErrorSafe) for security-sensitive paths are all patterns the OTel Go maintainers explicitly recommend in their instrumentation guidelines.
  • sdktrace.WithBatcher tuning (256/2s) is a deliberate deviation from SDK defaults (512/5s), documented inline โ€” good practice, but consider making these two constants configurable via env var (similar to other gateway tunables) if operators start reporting different throughput/latency tradeoffs in production, rather than requiring a code change.

๐Ÿ”ง General Improvements

  • No redundant or inefficient usage was found โ€” imports are scoped precisely to what's needed (no wildcard imports of speculative sub-packages), and there's no dead code invoking unused OTel APIs.
  • The CachedTracer/GetCachedOrGlobal pattern for lazily resolving a tracer avoids repeated otel.Tracer(...) global-registry lookups on hot paths โ€” a solid, otel-idiomatic micro-optimization already in place.

Module Summary

Field Value
Module go.opentelemetry.io/otel (+ otel/sdk, otel/trace, otel/exporters/otlp/otlptrace/otlptracehttp)
Version v1.45.0
Repository https://github.com/open-telemetry/opentelemetry-go
Latest Release main branch active development; v1.45.0 is current stable pin
Last Reviewed 2026-08-27

Key Features

  • Stable Traces and Metrics APIs; Beta Logs API (otel/log bridge)
  • OTLP/HTTP and OTLP/gRPC exporters, resource auto-detection (host/process/container/telemetry-SDK)
  • Configurable samplers (AlwaysSample, NeverSample, TraceIDRatioBased, parent-based composition)
  • W3C TraceContext + Baggage propagators built in

References

Recommendations

  1. Add a regression test/assertion tying internal/tracing/semconv.go's SchemaURL to the otel/sdk version pin, per the existing code comment's warning.
  2. Evaluate the OTel Logs Bridge API as an optional path to unify file-based and OTLP-based logging in a future iteration (not urgent โ€” logs API is still beta upstream).
  3. Continue monitoring open-telemetry/opentelemetry-go releases for Go-version floor bumps, since the maintainers are actively dropping older Go support (most recently Go 1.25) shortly after each new Go release.

Next Steps

  • Optional: prototype an OTel-backed log exporter behind a feature flag once the Logs API stabilizes.
  • Optional: add the schema-URL consistency test as a lightweight guard against dependency-bump regressions.

Generated by Go Fan

Generated by Go Fan ยท auto ยท 47.5 AIC ยท โŠž 12.1K ยท โ—ท

  • expires on Sep 3, 2026, 10:27 AM UTC