gitlab.com/phpboyscout/go/observability — opinionated OpenTelemetry wiring for
Go services. Build hardened OTLP/HTTP providers for the three signals (logs, metrics,
traces) from a single typed Settings,
with a shared-plus-per-signal config resolution and graceful fallback to the standard
OTEL_EXPORTER_OTLP_* environment variables.
It is the observability layer extracted from
go-tool-base, which uses it for its
service telemetry. It is framework-free: it carries the OpenTelemetry SDK (that is
its job) but nothing else — no config framework, no TUI, no go-tool-base.
Design
- Framework-free, OTel-native. The only non-OTel dependency is
cockroachdb/errors. A depfootprint_test.go guard allows go.opentelemetry.io
but forbids go-tool-base, Viper/Cobra, Charm, and the cloud SDKs.
- Typed values in, providers out.
otelcore works from a typed Settings; you
own how those are sourced (flags, env, a config file). ResolveSettings merges a
shared config with per-signal overrides so one endpoint can serve all three signals
with targeted exceptions.
- Signal packages are independent.
logs, metrics, and tracing each build
their own exporter, so a service that only traces never links the log/metric
exporters.
- Graceful env fallback. An empty
Endpoint is intentional, not an error: the SDK
then reads the standard OTEL_EXPORTER_OTLP_* variables. Explicitly-configured
Headers and Insecure are still applied on this path — and applied after the env
vars, so they replace rather than merge with them. Supplying the endpoint via
OTEL_EXPORTER_OTLP_ENDPOINT while keeping an auth token in config never silently
drops the token, but a configured Headers map does discard
OTEL_EXPORTER_OTLP_HEADERS entirely. See
Environment variables.
- Slash-normalised endpoints. A configured
Endpoint with a trailing slash
(https://collector:4318/) is normalised before the per-signal suffix is joined,
so the exported path is /v1/logs, never //v1/logs (which strict collectors 404).
Install
go get gitlab.com/phpboyscout/go/observability
Quick start
package main
import (
"context"
"gitlab.com/phpboyscout/go/observability/otelcore"
"gitlab.com/phpboyscout/go/observability/tracing"
)
func main() {
ctx := context.Background()
res := otelcore.Resource("my-service", "1.4.0")
settings := otelcore.Settings{
Enabled: true,
Endpoint: "https://otel-collector.internal:4318", // empty ⇒ OTEL_* env fallback
}
tp, err := tracing.NewProvider(ctx, res, settings, tracing.WithSampling(0.1))
if err != nil {
panic(err)
}
defer tp.Shutdown(ctx)
// otel.SetTracerProvider(tp) ...
}
What's inside
otelcore — the transport-neutral core: Resource, ParseEndpoint, the typed
Settings, and the shared-plus-per-signal ResolveSettings merge (Config +
SignalConfig + SignalOverrides). No signal exporters.
tracing — NewProvider(ctx, res, settings, WithSampling(ratio)) →
*sdktrace.TracerProvider over the OTLP/HTTP trace exporter.
metrics — NewProvider(ctx, res, settings, WithInterval(d)) →
*sdkmetric.MeterProvider over the OTLP/HTTP metric exporter.
logs — NewProvider(ctx, res, settings) → *sdklog.LoggerProvider, plus
Handler(lp, name) for a ready slog.Handler bridged to OTel.
What it does not do
OTLP/HTTP only — no gRPC exporter, and grpc:// endpoints are rejected at startup.
No Prometheus, stdout or Jaeger exporter, and the exporter cannot be substituted. It
produces no telemetry of its own (no HTTP, gRPC, runtime or database instrumentation),
registers nothing globally, and does not act on Settings.Enabled. OTEL_TRACES_SAMPLER
and OTEL_METRIC_EXPORT_INTERVAL have no effect, because the corresponding SDK option is
always passed.
Full list with reasoning:
What this module does not do.
Compatibility
The OpenTelemetry dependency versions are pinned and kept in lockstep with
go-tool-base (currently otel/sdk
v1.44.0, the OTLP exporters, and contrib/bridges/otelslog v0.19.0) so a service and
this module share one OTel build graph. Grouped Renovate updates keep them aligned, and
gRPC plus the split genproto modules are pinned for the same reason. Why, and what it
costs:
OTel version lockstep.
Documentation
Tutorials, how-to guides, the reference tier and the config model:
observability.go.phpboyscout.uk.
API reference: pkg.go.dev.
License
See LICENSE.