Documentation
¶
Overview ¶
Package trace provides a thin, ergonomic wrapper around OpenTelemetry distributed tracing for GitLab Go services.
Engineers must use this package to create and manage spans so that trace data is emitted consistently across all GitLab services.
The package exposes three core constructs:
- Config and New / NewWithConfig for TracerProvider initialisation - Tracer and Span for creating and annotating spans - SpanFromContext for retrieving the active span from a context
Quick start ¶
tracer, shutdown, err := trace.New(ctx)
if err != nil {
log.Fatal(err)
}
defer shutdown(ctx)
ctx, span := tracer.Start(ctx, "my-operation")
defer span.End()
span.SetAttribute("user.id", userID)
Error recording ¶
result, err := doWork(ctx)
if err != nil {
span.RecordError(err) // records exception event AND sets status=Error
return err
}
Propagating context downstream ¶
The context returned by Tracer.Start carries the active span. Pass it to downstream calls so that child spans are nested correctly:
ctx, span := tracer.Start(ctx, "parent") defer span.End() ctx, child := tracer.Start(ctx, "child") defer child.End()
Using the full OpenTelemetry API ¶
Span embeds go.opentelemetry.io/otel/trace.Span, so any OTEL method not wrapped by labkit is accessible directly:
span.AddEvent("cache-miss", oteltrace.WithAttributes(attribute.String("key", k)))
span.AddLink(oteltrace.Link{SpanContext: remoteCtx})
sc := span.SpanContext() // retrieve trace-id / span-id
Where labkit's helper methods shadow an OTEL method with a different signature, reach the original via the embedded field:
span.Span.End(oteltrace.WithTimestamp(t)) // End with explicit timestamp span.Span.RecordError(err, oteltrace.WithAttributes(...)) // RecordError with options
Similarly, Tracer.OTELTracer returns the underlying go.opentelemetry.io/otel/trace.Tracer for passing to third-party instrumented libraries:
oteltracer := tracer.OTELTracer()
Environment-based configuration (GITLAB_TRACING) ¶
The GITLAB_TRACING environment variable can be used to configure the tracer without changing code. It uses a URL-style connection string:
GITLAB_TRACING="otlp://collector.example.com:4318?service_name=my-api&sampler=probabilistic&sampler_param=0.01"
Scheme:
- otlp — HTTP (insecure)
- otlps — HTTPS (secure)
Query parameters:
- service_name — overrides [Config.ServiceName]
- sampler — "probabilistic" or "const"
- sampler_param — rate (0.0–1.0) for probabilistic; 0 or 1 for const
When a non-nil Config is also passed to NewWithConfig, explicit Config fields take priority: Endpoint and ServiceName fill in only if they are empty; SampleRate in the Config is always used as-is.
Testing ¶
Use NewWithProvider together with the tracetest package to capture spans without a live collector:
import "gitlab.com/gitlab-org/labkit/v2/testing/tracetest" tracer, rec := tracetest.NewRecorder() ctx, span := tracer.Start(context.Background(), "op") span.End() spans := rec.Ended() assert.Equal(t, "op", spans[0].Name)
Index ¶
Constants ¶
const SampleRateDropAll float64 = -1
SampleRateDropAll may be assigned to [Config.SampleRate] to explicitly configure a TracerProvider that never samples spans. Setting SampleRate to 0 has the same effect.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Config ¶
type Config struct {
// ServiceName is the service.name resource attribute included on all spans.
// Default: path.Base(os.Args[0])
ServiceName string
// ServiceVersion is the service.version resource attribute.
// Omitted from the resource when empty.
ServiceVersion string
// Endpoint is the base URL of the OTLP HTTP collector (no path suffix).
// Example: "https://collector.example.com:4318"
// Default: "" — the SDK honours OTEL_EXPORTER_OTLP_ENDPOINT or falls back
// to http://localhost:4318.
Endpoint string
// Insecure disables TLS when connecting to the OTLP collector.
// Useful for local development. Only applied when Endpoint is also set.
Insecure bool
// Headers are additional HTTP headers sent with every export request,
// for example authentication tokens required by managed collectors.
Headers map[string]string
// SampleRate controls the fraction of traces that are sampled, in the
// range [0.0, 1.0]. 0 disables sampling entirely. Values >= 1.0 sample
// every trace. [SampleRateDropAll] (-1) is an alias for 0 kept for
// clarity. Default when Config is nil: 0.01 (1%).
SampleRate float64
// DisableGlobalProvider prevents New from registering the TracerProvider
// as the global OTEL provider. The zero value (false) sets the global,
// which is the safe default for services that use third-party libraries
// instrumented with OTEL.
DisableGlobalProvider bool
}
Config holds the configuration for creating a new Tracer. A nil Config passed to NewWithConfig produces sensible defaults: 1% sampling, OTLP/HTTP export to localhost:4318, and the service name derived from the process binary.
type Span ¶
Span represents an active trace span. Always call Span.End when the operation is complete, typically via defer.
Span embeds oteltrace.Span so the full OpenTelemetry span API is available directly — for example oteltrace.Span.AddEvent, oteltrace.Span.AddLink, and oteltrace.Span.SpanContext. The labkit helper methods (SetAttribute, RecordError, End, IsRecording) shadow their OTEL counterparts where they add value; reach the raw OTEL methods via the embedded field when needed:
span.Span.End(oteltrace.WithTimestamp(t)) span.Span.RecordError(err, oteltrace.WithAttributes(...))
func SpanFromContext ¶
SpanFromContext retrieves the active Span from ctx. If no span is present, a no-op Span is returned — all methods are safe to call on it.
func (*Span) End ¶
func (s *Span) End()
End marks the span as complete. It is safe to call on a nil Span.
func (*Span) IsRecording ¶
IsRecording reports whether the span is actively recording events. Returns false for nil or no-op spans.
func (*Span) RecordError ¶
RecordError records err as an exception span event and sets the span status to codes.Error with err.Error() as the description. It is a no-op when err is nil or when called on a nil Span.
Note: the raw OTEL oteltrace.Span.RecordError records the exception event but does not set the span status. This method does both, which is almost always what you want.
func (*Span) SetAttribute ¶
SetAttribute records a key-value attribute on the span. Supported value types are: bool, int, int32, int64, float32, float64, string, fmt.Stringer, and slice variants of each. Values of any other type are converted to their fmt.Sprintf("%v") string representation. Safe to call on a nil Span.
type Tracer ¶
type Tracer struct {
// contains filtered or unexported fields
}
Tracer creates spans for tracing operations. Obtain one from New or NewWithConfig, then call Tracer.Start to begin each operation you want to trace.
func New ¶
New returns a Tracer and a shutdown function using default Config. The shutdown function must be called on application exit to flush any buffered spans before the process terminates.
tracer, shutdown, err := trace.New(ctx)
if err != nil { ... }
defer shutdown(ctx)
func NewWithConfig ¶
NewWithConfig returns a Tracer and a shutdown function using the provided Config. A nil cfg causes all values to be derived from the [GITLAB_TRACING] environment variable (when set) or built-in defaults.
When cfg is non-nil, [GITLAB_TRACING] fills in any fields that are left at their zero value (empty string for Endpoint / ServiceName). SampleRate in the explicit Config always takes precedence; set it to the SampleRateDropAll sentinel if you want to disable sampling regardless of the environment.
func NewWithProvider ¶
func NewWithProvider(provider *sdktrace.TracerProvider) *Tracer
NewWithProvider wraps an existing sdktrace.TracerProvider in a Tracer. It is intended for testing (via the tracetest package) and advanced use cases where the caller manages the provider lifecycle directly.
func (*Tracer) OTELTracer ¶
Start begins a new span named name. It returns an enriched context — which carries the span and should be passed to all downstream calls — and the new Span. Always pair Start with a deferred Span.End:
ctx, span := tracer.Start(ctx, "do-work") defer span.End()
OTELTracer returns the underlying oteltrace.Tracer. Use this when passing a tracer to third-party OTEL-instrumented code that expects the raw interface.