diff --git a/.gitea/CODEOWNERS b/.gitea/CODEOWNERS new file mode 100644 index 0000000..ae1f67b --- /dev/null +++ b/.gitea/CODEOWNERS @@ -0,0 +1 @@ +* @go/CoreDevelopers @go/Agents diff --git a/CHANGELOG.md b/CHANGELOG.md index cb8aaea..dca4106 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,24 @@ All notable changes to this module will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this module adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.0.0] - 2026-05-12 + +### Changed + +- Go directive bumped from 1.25 to 1.26 +- Shutdown function now wraps each provider error with a `providerErr` type that + prefixes the signal name (`"telemetry: trace provider shutdown: …"`, + `"telemetry: metric provider shutdown: …"`, `"telemetry: log provider shutdown: …"`). + The combined error is still joined with `errors.Join`; individual causes remain + unwrappable via `errors.As`. Previously, the three errors were joined without labels. + +### Stabilization + +- API committed as stable. `Config`, `New`, and the shutdown function signature + (`func(context.Context) error`) are unchanged from v0.9.0. + +[1.0.0]: https://code.nochebuena.dev/go/telemetry/compare/v0.9.0...v1.0.0 + ## [0.9.0] - 2026-03-18 ### Added @@ -17,7 +35,7 @@ and this module adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0. ### Design Notes -- This module is Tier 5 (application bootstrap only) and must never be imported by framework libraries; those libraries use only the OTel API, which defaults to no-ops until `New` is called and sets the global providers +- This module is Tier 1 (no micro-lib dependencies) and must never be imported by framework libraries; those libraries use only the OTel API, which defaults to no-ops until `New` is called and sets the global providers - All three signals share a single OTLP gRPC endpoint, matching the standard Grafana LGTM stack topology where Grafana Alloy receives all signals and fans them out to Tempo, Mimir, and Loki - The module intentionally does not implement `launcher.Component`; the returned shutdown function is deferred directly in `main`, keeping the dependency graph free of `launcher` and the interface as simple as a single function call diff --git a/COMMIT.md b/COMMIT.md new file mode 100644 index 0000000..1ec4407 --- /dev/null +++ b/COMMIT.md @@ -0,0 +1,5 @@ +feat(telemetry)!: promote to v1.0.0 — named shutdown errors per provider, Go 1.26 + +Label each provider shutdown failure with its signal name (trace/metric/log). +Errors remain joined via errors.Join; individual causes still unwrappable. +Go directive bumped from 1.25 to 1.26. API committed as stable. diff --git a/RELEASE.md b/RELEASE.md new file mode 100644 index 0000000..2a276d3 --- /dev/null +++ b/RELEASE.md @@ -0,0 +1,46 @@ +# v1.0.0 + +> `code.nochebuena.dev/go/telemetry` + +## Overview + +`telemetry` bootstraps the full OpenTelemetry SDK with OTLP gRPC exporters targeting +a Grafana Alloy collector. A single call to `New` sets all three OTel global providers +(traces → Tempo, metrics → Mimir, logs → Loki) and returns a shutdown function the +caller defers in `main`. + +v1.0.0 adds named per-provider shutdown errors, bumps the Go directive to 1.26, and +commits the API as stable. No micro-lib dependencies are added. + +## What Changed Since v0.9.0 + +### Named per-provider shutdown errors + +The shutdown function now labels each provider failure individually: + +``` +telemetry: trace provider shutdown: +telemetry: metric provider shutdown: +telemetry: log provider shutdown: +``` + +Errors are still joined with `errors.Join`; individual causes remain accessible via +`errors.As`. Previously, provider shutdown failures were joined without labels, making +it impossible to identify which signal pipeline failed. + +### Go directive bumped to 1.26 + +## Full API (stable) + +- `Config` — `ServiceName`, `ServiceVersion`, `Environment`, `OTLPEndpoint`, `OTLPInsecure` +- `New(ctx, cfg) (func(context.Context) error, error)` + +## Installation + +``` +go get code.nochebuena.dev/go/telemetry@v1.0.0 +``` + +## Changelog + +See [CHANGELOG.md](CHANGELOG.md#100---2026-05-12). diff --git a/go.mod b/go.mod index 136d155..22f718b 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module code.nochebuena.dev/go/telemetry -go 1.25.0 +go 1.26 require ( go.opentelemetry.io/otel v1.42.0 diff --git a/telemetry.go b/telemetry.go index 737ae82..190340c 100644 --- a/telemetry.go +++ b/telemetry.go @@ -105,15 +105,30 @@ func New(ctx context.Context, cfg Config) (func(context.Context) error, error) { global.SetLoggerProvider(lp) shutdown := func(ctx context.Context) error { - return errors.Join( - tp.Shutdown(ctx), - mp.Shutdown(ctx), - lp.Shutdown(ctx), - ) + var errs []error + if err := tp.Shutdown(ctx); err != nil { + errs = append(errs, &providerErr{"trace", err}) + } + if err := mp.Shutdown(ctx); err != nil { + errs = append(errs, &providerErr{"metric", err}) + } + if err := lp.Shutdown(ctx); err != nil { + errs = append(errs, &providerErr{"log", err}) + } + return errors.Join(errs...) } return shutdown, nil } +// providerErr labels a shutdown error with the provider name. +type providerErr struct { + provider string + err error +} + +func (e *providerErr) Error() string { return "telemetry: " + e.provider + " provider shutdown: " + e.err.Error() } +func (e *providerErr) Unwrap() error { return e.err } + // newResource builds an OTel resource with service identity and environment attributes. func newResource(cfg Config) *resource.Resource { r, _ := resource.Merge(