Skip to content

grackleclub/signals

Repository files navigation

signals

test release

OTel observability: logs, metrics, traces

(replaces grackleclub/log)

install

go get github.com/grackleclub/signals

requires go v1.25+

use

func main() {
	ctx := context.Background()
	shutdown, log, err := signals.Setup(ctx, signals.Config{
		Env:     "prod",
		Version: build.SHA,
	})
	if err != nil {
		panic(fmt.Errorf("setup signals: %w", err)
	}
	defer shutdown(ctx) // flush telemetry on exit
	slog.SetDefault(log) // make log the process-wide default

	log.InfoContext(ctx, "starting", "addr", addr) // contains span details for correlation
}

Setup installs the global tracer, meter, and logger providers (one shared resource) plus the W3C propagator, then returns a ready *slog.Logger. Call it once from main.

Traces and metrics go into OTel's global registry, so any library can summon them with no plumbing:

var tracer = otel.Tracer("github.com/grackleclub/rulette/game")
var meter  = otel.Meter("github.com/grackleclub/rulette/game")

The logger is the exception: Setup returns it rather than calling slog.SetDefault, because a library mutating the caller's process-wide default is a surprising side effect that belongs to main, not to signals. Declare it as the default yourself, once, in main:

slog.SetDefault(log)

Now the same global-registry ergonomics apply to all three signals: use package-level slog.InfoContext(ctx, ...) anywhere, with no logger field to thread and no parameter to pass. Skip the SetDefault call only if you deliberately want to scope the logger and pass log around by hand.

config

Every field falls back to OTEL_* env, then a default.

field purpose default
Env deployment.environment.name OTEL_RESOURCE_ATTRIBUTES, then unknown
Service service.name OTEL_SERVICE_NAME, then argv0
Version service.version none
Endpoint OTLP/HTTP URL OTEL_EXPORTER_OTLP_ENDPOINT
Token bearer auth, merged over OTEL_EXPORTER_OTLP_HEADERS OTLP_INGEST_TOKEN
StderrLevel console threshold INFO
DisableRuntimeMetrics drop Go runtime metrics false
Console pterm console tuning (time, caller, layout) time auto (on when captured); tree on tty/GitHub, else one line

The console is a pterm logger, so anything in the build that imports pterm directly (tables, spinners, boxes) shares signals' styling with no extra wiring. See examples.md.

behavior

topic behavior
logs two sinks: pterm console (pretty, StderrLevel-gated, NO_COLOR aware) and OTLP
correlation a log with a span's context carries trace_id/span_id; console shows a short trace_id
levels console honors StderrLevel; OTLP ships every level, filter in SigNoz
graceful off no endpoint configured: console only, no error
traces ParentBased(AlwaysSample), override via OTEL_TRACES_SAMPLER; tail-sample at the collector
metrics periodic OTLP reader plus Go runtime metrics; host metrics are the collector's

test

command does
bin/test unit fast, no docker
bin/test pretty print the colored console output
bin/test ci collector roundtrip (docker)

About

OTel: logs, metrics, traces

Resources

Stars

0 stars

Watchers

0 watching

Forks

Contributors