Files
telemetry/README.md
Rene Nochebuena b583af1973 feat(telemetry): initial implementation — OpenTelemetry traces, metrics, logs (v1.0.0)
Introduces code.nochebuena.dev/einherjar/telemetry — the observability bootstrap
starter for the Einherjar framework. Absorbs the telemetry package from micro-lib,
migrating from OpenCensus to OpenTelemetry SDK v1.42.

Bootstrap functions (not lifecycle.Component — telemetry must be initialized before
the launcher starts, and its shutdown must run after all components stop):
- New(ctx, cfg) (func(context.Context) error, error) — production mode; exports
  traces, metrics, and logs via OTLP over gRPC to the configured endpoint;
  returns a shutdown function to be deferred in main()
- NewConsole(ctx, logger, cfg) (func(context.Context) error, error) — development
  mode; writes structured telemetry to the provided logging.Logger; no network
  dependency; suitable for local development and CI

Config (EINHERJAR_OTEL_* env vars):
  ServiceName(required), ServiceVersion(unknown), Environment(development),
  OTLPEndpoint(required for New), OTLPInsecure(false)

ConsoleConfig (EINHERJAR_OTEL_* env vars):
  ServiceName(required), ServiceVersion(unknown), Environment(development)

- identifiable.go: package-level Module variable (observability.Identifiable) for version
  identification — telemetry bootstraps before the launcher; not registered as a lifecycle component
2026-05-29 16:09:54 +00:00

3.2 KiB

einherjar/telemetry

version license go

Huginn and Muninn fly each day over the world. They see everything. They report back.

code.nochebuena.dev/einherjar/telemetry is the OpenTelemetry bootstrap component of the Einherjar framework. It initializes traces, metrics, and structured logs via OTLP over gRPC — vendor-neutral, compatible with Grafana, Jaeger, Tempo, Datadog, and Honeycomb. A console mode is available for local development without a collector.

Telemetry is not a lifecycle.Component. It must be initialized before the launcher and shut down after all components stop — the returned shutdown function handles this cleanly with a defer.


Usage

Production (OTLP/gRPC)

import (
    "code.nochebuena.dev/einherjar/telemetry"
    "code.nochebuena.dev/einherjar/core/launcher"
    "code.nochebuena.dev/einherjar/core/logz"
)

ctx := context.Background()
logger := logz.New(logz.Config{JSON: true})

// Initialize telemetry BEFORE the launcher.
// Defer the shutdown BEFORE launcher.Run() so it fires after the launcher stops.
shutdown, err := telemetry.New(ctx, telemetry.DefaultConfig())
if err != nil {
    logger.Error("telemetry init failed", err)
    os.Exit(1)
}
defer shutdown(ctx)

lc := launcher.New(logger)
lc.Append(db, cache, srv)
lc.Run()

Development (console / structured log output)

No collector required. Spans and metrics are emitted to the configured logging.Logger.

shutdown, err := telemetry.NewConsole(ctx, logger, telemetry.DefaultConsoleConfig())
if err != nil {
    logger.Error("telemetry init failed", err)
    os.Exit(1)
}
defer shutdown(ctx)

Environment variables

Production (telemetry.New)

Variable Required Default Description
EINHERJAR_OTEL_SERVICE_NAME Yes Service name reported to the collector
EINHERJAR_OTEL_EXPORTER_ENDPOINT Yes OTLP gRPC endpoint (e.g. otel-collector:4317)
EINHERJAR_OTEL_SERVICE_VERSION No unknown Service version tag
EINHERJAR_OTEL_ENVIRONMENT No development Deployment environment tag
EINHERJAR_OTEL_EXPORTER_INSECURE No false Disable TLS for the exporter (dev/local)

Development (telemetry.NewConsole)

Variable Required Default Description
EINHERJAR_OTEL_SERVICE_NAME Yes Service name
EINHERJAR_OTEL_SERVICE_VERSION No unknown Service version tag
EINHERJAR_OTEL_ENVIRONMENT No development Deployment environment tag

Dependency graph

contracts  (zero dependencies)
    ↑
  core
    ↑
telemetry  (contracts, core, otel SDK + OTLP exporters)
    ↑
  your app (initialized before launcher.Run)

Verification

cd telemetry/
go build ./...
go vet ./...
go test ./...
gofmt -l .

Odin gave an eye for wisdom. Observability is the eye that watches the living system.