Distributed Tracing with Cloud Trace
Runway provides built-in distributed tracing for Kubernetes services using LabKit v2 and OpenTelemetry (OTLP). Spans are exported to the in-cluster OpenTelemetry Collector and forwarded to Google Cloud Trace in the shared Runway tenant GCP project (gitlab-runway-production or gitlab-runway-staging), where you filter by your service.name.
Overview
Section titled “Overview”Runway injects the OTLP connection string automatically — you do not set it yourself:
GITLAB_TRACING=otlp://agent-otelcol-collector.monitoring.svc.cluster.local:4318?service_name=<runway_service_id>From there, tracing is a two-part contract:
- Your application builds a tracer from
GITLAB_TRACING(automatic when you use the LabKitapp.Appframework; a one-liner otherwise). - You hand that tracer to the LabKit components you use (database, Redis, HTTP server/client, feature flags). Those components then emit spans automatically. A component only produces spans when it is given the tracer — LabKit does not auto-instrument globally.
Runtime Support
Section titled “Runtime Support”| Runtime | Status | Notes |
|---|---|---|
| GKE | ✅ Supported | OTLP → in-cluster collector → Cloud Trace |
| EKS | ✅ Supported | Same path; the collector authenticates to GCP with a mounted key |
Getting Started (Go)
Section titled “Getting Started (Go)”If your service uses the LabKit app.App framework (recommended)
Section titled “If your service uses the LabKit app.App framework (recommended)”app.New / app.NewWithConfig initializes the tracer for you from GITLAB_TRACING — you do not call trace.New. Retrieve it with a.Tracer() and pass it into each component’s config:
import ( "gitlab.com/gitlab-org/labkit/v2/app" "gitlab.com/gitlab-org/labkit/v2/postgres" "gitlab.com/gitlab-org/labkit/v2/redis" "gitlab.com/gitlab-org/labkit/v2/httpserver")
a, err := app.New(ctx) // reads GITLAB_TRACING, builds the tracer + OTLP exporter
// Postgres — every query emits a "db SELECT" / "db INSERT" span.pg, err := postgres.NewWithConfig(&postgres.Config{DSN: dsn, Tracer: a.Tracer()})
// Redis — every command emits a "db SET" / "db GET" span.rdb, err := redis.NewWithConfig(&redis.Config{Addrs: addrs, Tracer: a.Tracer()})
// HTTP server — one server span per request; incoming W3C trace context is// extracted automatically. The tracing middleware is wired for you.srv := httpserver.NewWithConfig(&httpserver.Config{ Addr: ":8080", Handler: mux, Tracer: a.Tracer(), Logger: a.Logger(),})
a.Register(pg)a.Register(rdb)a.Register(srv)Without the LabKit app framework
Section titled “Without the LabKit app framework”Build the tracer yourself and pass it the same way:
import "gitlab.com/gitlab-org/labkit/v2/trace"
tracer, shutdown, err := trace.New(ctx) // reads GITLAB_TRACINGdefer shutdown(context.Background()) // flushes buffered spans on exit
pg, err := postgres.New(ctx, postgres.WithTracer(tracer))For a non-LabKit HTTP server (e.g. the standard library), use otelhttp and pass the provider explicitly — LabKit does not register a global TracerProvider:
import "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
server := &http.Server{ Addr: ":8080", Handler: otelhttp.NewHandler(mux, "my-service", otelhttp.WithTracerProvider(tracer.Provider())),}Sampling
Section titled “Sampling”The default sample rate is 1% (defaultSampleRate = 0.01). Sampling is decided head-based in the SDK; the collector does not re-sample.
To change it, set SampleRate in the trace config. Runway still supplies the collector endpoint via GITLAB_TRACING — the env var only fills fields left at their zero value, so you provide the endpoint from the environment and the sample rate from config:
// With the app framework:a, err := app.NewWithConfig(ctx, &app.Config{ Trace: &trace.Config{SampleRate: 0.05}, // sample 5%})
// Standalone:tracer, shutdown, err := trace.NewWithConfig(ctx, &trace.Config{SampleRate: 0.05})See the LabKit tracing configuration for all options.
How it works
Section titled “How it works”- Agent collector (
agent-otelcol, a DaemonSet) receives your OTLP spans on:4318, enriches them withk8sattributes(pod, namespace, deployment), and forwards to the gateway. - Gateway collector (
gateway-otelcol) exports to Cloud Trace via thegooglecloudexporter, targeting your tenant projectgitlab-runway-{staging,production}.
Viewing traces
Section titled “Viewing traces”- Open the Cloud Trace console.
- Select the tenant project —
gitlab-runway-productionorgitlab-runway-staging. - Filter by
service.namematching yourrunway_service_id.
Additional Resources
Section titled “Additional Resources”Support
Section titled “Support”Reach out to the Runway team in the #f_runway Slack channel.