Skip to content

LabKit

LabKit provides the standardized libraries that every GitLab service builds on: logging, metrics, tracing, and field schemas. It is the library layer that ensures uniform observability and operational behavior across all services regardless of language.

Primary contribution to Theseus: Instrument once, observe everywhere. LabKit encodes GitLab’s operational standards into libraries so teams get correct behavior by default rather than through per-team effort.

What you get for free with LabKit v2

Adopting LabKit v2 gives a service far more than observability plumbing. The v2 modules cover the application concerns that every service otherwise has to build — and debug — for itself:

Application runtime

  • v2/app — application lifecycle management: startup ordering, graceful shutdown, and signal handling in a single composition root
  • v2/httpserver — a production-ready HTTP server with health endpoints, timeouts, and middleware wired in

Observability

  • v2/log — structured logging in the format GitLab’s ClickHouse pipeline expects, with standard field names from v2/fields
  • v2/metrics — Prometheus metrics exposed on the standard /metrics endpoint
  • v2/trace — distributed tracing via OpenTelemetry, connected to the Runway OTel sidecar
  • v2/correlation — correlation ID generation and propagation across service boundaries
  • v2/events — structured event tracking with batching and storage

Configuration, secrets, and flags

  • v2/config — protobuf-first, validated application configuration
  • v2/secret — secret access behind a provider interface, including a rotating file provider that picks up secret rotation without a restart, and redaction guarantees so secrets never leak into logs
  • v2/featureflag — feature flag evaluation against a standard backend

Infrastructure clients

  • v2/postgres, v2/redis, v2/objectstore, v2/httpclient — pre-instrumented clients for the infrastructure every service talks to, with correlation, tracing, and metrics already attached

As a concrete example, this is everything the Go service template needs to stand up its PostgreSQL client:

pgClient, err := postgres.New(ctx, postgres.WithTracer(a.Tracer()))
if err != nil {
	return fmt.Errorf("configure postgres client: %w", err)
}

srv.AddReadinessCheck("postgres", func(ctx context.Context) error {
	return pgClient.DB().PingContext(ctx)
})

a.Register(pgClient)

There is no DSN plumbing in application code: v2/postgres assembles the connection string from the Fairway-delivered infrastructure config (/etc/labkit/infrastructure.yaml plus the connection secret mounted at /secrets/infrastructure/postgresql). Because the dependency is declared in fairway.yaml (spec.infrastructure.postgresql.presence: REQUIRED), a missing or broken database config fails startup immediately instead of shipping a database-less pod. Registering the client with v2/app folds it into graceful shutdown, and the readiness check wires the database into the standard health endpoints. See the exemplar’s cmd/server/main.go for the full composition root.

Because common-template-copier scaffolds services with LabKit v2 wired in from the first commit, a new team gets all of this before writing a line of domain code.

Rust support via labkit-rs

This functionality is being ported to Rust as labkit-rs, so Go and Rust services can both take advantage of the same operational standards. The port is deliberately wire-compatible with Go LabKit — identical header names, gRPC metadata keys, and structured log field names — so Rust and Go services look the same in dashboards and appear seamlessly in the same distributed traces.

labkit-rs currently covers correlation IDs, structured logging, HTTP (Axum/Tower) and gRPC (Tonic) middleware, OpenTelemetry integration, Prometheus /metrics exposure, and event tracking, with functionality gated behind Cargo feature flags so services only pull in the dependencies they use. A rust-service-template demonstrates the full setup, mirroring the role the Go service template plays for Go.

Resources

Last updated on