Tracer Options

All configuration options for Tracer initialization

Complete reference for all Option functions used to configure the Tracer.

Option Type

Options are functions applied to an internal configuration value during New() / MustNew() before the *Tracer is built. The concrete signature is not exported; you only pass values of type Option from this package (for example WithServiceName("api")).

Service Configuration Options

WithServiceName

func WithServiceName(name string) Option

Sets the service name for tracing. This name appears in span attributes as service.name.

Parameters:

  • name: Service identifier like "user-api" or "order-service".

Default: "rivaas-service"

Example:

tracer := tracing.MustNew(
    tracing.WithServiceName("user-api"),
)

WithServiceVersion

func WithServiceVersion(version string) Option

Sets the service version for tracing. This version appears in span attributes as service.version.

Parameters:

  • version: Service version like "v1.2.3" or "dev".

Default: "1.0.0"

Example:

tracer := tracing.MustNew(
    tracing.WithServiceName("user-api"),
    tracing.WithServiceVersion("v1.2.3"),
)

Provider Options

Only one provider can be configured at a time. Configuring multiple providers results in a validation error.

WithNoop

func WithNoop() Option

Configures noop provider. This is the default. No traces are exported. Use for testing or when tracing is disabled.

Example:

tracer := tracing.MustNew(
    tracing.WithServiceName("my-service"),
    tracing.WithNoop(),
)

WithStdout

func WithStdout() Option

Configures stdout provider for development/debugging. Traces are printed to standard output in pretty-printed JSON format.

Example:

tracer := tracing.MustNew(
    tracing.WithServiceName("my-service"),
    tracing.WithStdout(),
)

WithOTLP

func WithOTLP(endpoint string, opts ...OTLPOption) Option

Configures OTLP gRPC provider with endpoint. Use this for production deployments with OpenTelemetry collectors.

Parameters:

  • endpoint: OTLP endpoint in format "host:port" (e.g., "localhost:4317")
  • opts: Optional OTLP-specific options (e.g., OTLPInsecure())

Requires: Call tracer.Start(ctx) before tracing. Forgetting it yields no export and only a one-time log warning when the first span is created (no error at New).

Example:

// Secure (TLS enabled by default)
tracer := tracing.MustNew(
    tracing.WithServiceName("my-service"),
    tracing.WithOTLP("collector.example.com:4317"),
)
if err := tracer.Start(context.Background()); err != nil {
    log.Fatal(err)
}
defer tracer.Shutdown(context.Background())

// Insecure (local development)
tracer := tracing.MustNew(
    tracing.WithServiceName("my-service"),
    tracing.WithOTLP("localhost:4317", tracing.OTLPInsecure()),
)
if err := tracer.Start(context.Background()); err != nil {
    log.Fatal(err)
}
defer tracer.Shutdown(context.Background())

WithOTLPHTTP

func WithOTLPHTTP(endpoint string) Option

Configures OTLP HTTP provider with endpoint. Use this when gRPC is not available or HTTP is preferred.

Parameters:

  • endpoint: OTLP HTTP endpoint with protocol (e.g., "http://localhost:4318", "https://collector:4318")

Requires: Call tracer.Start(ctx) before tracing. Forgetting it yields no export and only a one-time log warning when the first span is created (no error at New).

Example:

// HTTP (insecure - development)
tracer := tracing.MustNew(
    tracing.WithServiceName("my-service"),
    tracing.WithOTLPHTTP("http://localhost:4318"),
)
if err := tracer.Start(context.Background()); err != nil {
    log.Fatal(err)
}
defer tracer.Shutdown(context.Background())

// HTTPS (secure - production)
tracer := tracing.MustNew(
    tracing.WithServiceName("my-service"),
    tracing.WithOTLPHTTP("https://collector.example.com:4318"),
)
if err := tracer.Start(context.Background()); err != nil {
    log.Fatal(err)
}
defer tracer.Shutdown(context.Background())

OTLP Options

OTLPInsecure

func OTLPInsecure() OTLPOption

Enables insecure gRPC for OTLP. Default is false (uses TLS). Set to true for local development.

Example:

tracer := tracing.MustNew(
    tracing.WithServiceName("my-service"),
    tracing.WithOTLP("localhost:4317", tracing.OTLPInsecure()),
)
if err := tracer.Start(context.Background()); err != nil {
    log.Fatal(err)
}
defer tracer.Shutdown(context.Background())

Sampling Options

WithSampleRate

func WithSampleRate(rate float64) Option

Sets the sampling rate (0.0 to 1.0). Values outside this range cause a validation error at tracer creation (e.g. sampleRate: must be between 0.0 and 1.0, got %f).

A rate of 1.0 samples all requests, 0.5 samples 50%, and 0.0 samples none. Sampling decisions are made per-request based on the configured rate.

Parameters:

  • rate: Sampling rate between 0.0 and 1.0

Default: 1.0 (100% sampling)

Example:

// Sample 10% of requests
tracer := tracing.MustNew(
    tracing.WithServiceName("my-service"),
    tracing.WithSampleRate(0.1),
)

Hook Options

WithSpanStartHook

func WithSpanStartHook(hook SpanStartHook) Option

Sets a callback that is invoked when an HTTP request span is started (standalone tracing.Middleware or StartRequestSpan). It is not called for spans created with StartSpan. The hook receives the context, span, and HTTP request, allowing custom attribute injection, dynamic sampling decisions, or integration with APM tools.

Type:

type SpanStartHook func(ctx context.Context, span trace.Span, req *http.Request)

Example:

startHook := func(ctx context.Context, span trace.Span, req *http.Request) {
    if tenantID := req.Header.Get("X-Tenant-ID"); tenantID != "" {
        span.SetAttributes(attribute.String("tenant.id", tenantID))
    }
}

tracer := tracing.MustNew(
    tracing.WithServiceName("my-service"),
    tracing.WithSpanStartHook(startHook),
)

WithSpanFinishHook

func WithSpanFinishHook(hook SpanFinishHook) Option

Sets a callback that is invoked when an HTTP request span is finished (same scope as WithSpanStartHook). The hook receives the span and HTTP status code, allowing custom metrics recording, logging, or post-processing.

Type:

type SpanFinishHook func(span trace.Span, statusCode int)

Example:

finishHook := func(span trace.Span, statusCode int) {
    if statusCode >= 500 {
        metrics.IncrementServerErrors()
    }
}

tracer := tracing.MustNew(
    tracing.WithServiceName("my-service"),
    tracing.WithSpanFinishHook(finishHook),
)

Logging Options

WithLogger

func WithLogger(logger *slog.Logger) Option

Sets the logger for internal operational events (errors, warnings, info, debug). Events are logged at the appropriate slog level. If logger is nil or WithLogger is not called, no internal output is produced (a discard logger is used). For Sentry or custom behavior, use a custom [slog.Handler] and pass the resulting logger to WithLogger.

Parameters:

  • logger: *slog.Logger for logging internal events

Example:

import "log/slog"

logger := slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
    Level: slog.LevelDebug,
}))

tracer := tracing.MustNew(
    tracing.WithServiceName("my-service"),
    tracing.WithLogger(logger),
)

Advanced Options

WithTracerProvider

func WithTracerProvider(provider trace.TracerProvider) Option

Allows you to provide a custom OpenTelemetry TracerProvider. When using this option, the package will NOT set the global otel.SetTracerProvider() by default. Use WithGlobalTracerProvider() if you want global registration.

Use cases:

  • Manage tracer provider lifecycle yourself
  • Need multiple independent tracing configurations
  • Want to avoid global state in your application

Validation: Combining WithTracerProvider with any provider option (WithOTLP, WithOTLPHTTP, WithStdout, WithNoop) is invalid. New() returns an error; use only one of WithTracerProvider or a provider option. Passing nil as the provider is also invalid (tracerProvider: cannot be nil when using WithTracerProvider); MustNew() panics with that error.

Example:

import sdktrace "go.opentelemetry.io/otel/sdk/trace"

tp := sdktrace.NewTracerProvider(
    // Your custom configuration
    sdktrace.WithSampler(sdktrace.AlwaysSample()),
)

tracer := tracing.MustNew(
    tracing.WithServiceName("my-service"),
    tracing.WithTracerProvider(tp),
)

// You manage tp.Shutdown() yourself
defer tp.Shutdown(context.Background())

WithCustomTracer

func WithCustomTracer(tracer trace.Tracer) Option

Allows using a custom OpenTelemetry tracer. This is useful when you need specific tracer configuration or want to use a tracer from an existing OpenTelemetry setup.

Example:

import sdktrace "go.opentelemetry.io/otel/sdk/trace"

tp := sdktrace.NewTracerProvider()
customTracer := tp.Tracer("my-tracer")

tracer := tracing.MustNew(
    tracing.WithServiceName("my-service"),
    tracing.WithCustomTracer(customTracer),
)

WithCustomPropagator

func WithCustomPropagator(propagator propagation.TextMapPropagator) Option

Allows using a custom OpenTelemetry propagator. This is useful for custom trace context propagation formats. By default, uses the global propagator from otel.GetTextMapPropagator() (W3C Trace Context).

Example:

import "go.opentelemetry.io/otel/propagation"

// Use W3C Trace Context explicitly
prop := propagation.TraceContext{}

tracer := tracing.MustNew(
    tracing.WithServiceName("my-service"),
    tracing.WithCustomPropagator(prop),
)

Using B3 propagation:

import "go.opentelemetry.io/contrib/propagators/b3"

tracer := tracing.MustNew(
    tracing.WithServiceName("my-service"),
    tracing.WithCustomPropagator(b3.New()),
)

WithGlobalTracerProvider

func WithGlobalTracerProvider() Option

Registers the tracer provider as the global OpenTelemetry tracer provider via otel.SetTracerProvider(). By default, tracer providers are not registered globally to allow multiple tracing configurations to coexist in the same process.

Use when:

  • You want otel.GetTracerProvider() to return your tracer
  • Integrating with libraries that use the global tracer
  • Single tracer for entire application

Example:

tracer := tracing.MustNew(
    tracing.WithServiceName("my-service"),
    tracing.WithOTLP("localhost:4317"),
    tracing.WithGlobalTracerProvider(), // Register globally
)
if err := tracer.Start(context.Background()); err != nil {
    log.Fatal(err)
}
defer tracer.Shutdown(context.Background())

Option Combinations

Development Configuration

tracer := tracing.MustNew(
    tracing.WithServiceName("my-api"),
    tracing.WithServiceVersion("dev"),
    tracing.WithStdout(),
    tracing.WithSampleRate(1.0),
    tracing.WithLogger(slog.Default()),
)

Production Configuration

tracer := tracing.MustNew(
    tracing.WithServiceName("user-api"),
    tracing.WithServiceVersion(os.Getenv("VERSION")),
    tracing.WithOTLP(os.Getenv("OTLP_ENDPOINT")),
    tracing.WithSampleRate(0.1),
    tracing.WithSpanStartHook(enrichSpan),
    tracing.WithSpanFinishHook(recordMetrics),
)
if err := tracer.Start(context.Background()); err != nil {
    log.Fatal(err)
}
defer tracer.Shutdown(context.Background())

Testing Configuration

tracer := tracing.MustNew(
    tracing.WithServiceName("test-service"),
    tracing.WithServiceVersion("v1.0.0"),
    tracing.WithNoop(),
    tracing.WithSampleRate(1.0),
)

Validation Errors

Configuration is validated when calling New() or MustNew(). Common validation errors:

Multiple Providers

// ✗ Error: multiple providers configured
tracer, err := tracing.New(
    tracing.WithServiceName("my-service"),
    tracing.WithStdout(),
    tracing.WithOTLP("localhost:4317"), // Error!
)
// Returns: "validation errors: provider: multiple providers configured"

Solution: Only configure one provider.

Empty Service Name

// ✗ Error: service name cannot be empty
tracer, err := tracing.New(
    tracing.WithServiceName(""),
)
// Returns: "invalid configuration: serviceName: cannot be empty"

Solution: Always provide a service name.

Invalid Sample Rate

// Out-of-range rate causes validation error
tracer, err := tracing.New(
    tracing.WithServiceName("my-service"),
    tracing.WithSampleRate(1.5),
)
// err: "validation errors: sampleRate: must be between 0.0 and 1.0, got 1.500000"

// MustNew panics on out-of-range rate
tracer := tracing.MustNew(
    tracing.WithServiceName("my-service"),
    tracing.WithSampleRate(1.5),
) // panics

Sample rates outside 0.0-1.0 are rejected at tracer creation; they are not clamped.

Complete Option Reference

OptionDescriptionDefault
WithServiceName(name)Set service name"rivaas-service"
WithServiceVersion(version)Set service version"1.0.0"
WithNoop()Noop providerYes (default)
WithStdout()Stdout provider-
WithOTLP(endpoint, opts...)OTLP gRPC provider-
WithOTLPHTTP(endpoint)OTLP HTTP provider-
WithSampleRate(rate)Sampling rate (0.0-1.0); out-of-range rejected at init1.0
WithSpanStartHook(hook)Span start callback-
WithSpanFinishHook(hook)Span finish callback-
WithLogger(logger)Set slog logger for internal events; nil or omit = no output-
WithTracerProvider(provider)Custom tracer provider-
WithCustomTracer(tracer)Custom tracer-
WithCustomPropagator(prop)Custom propagatorW3C Trace Context
WithGlobalTracerProvider()Register globallyNo

Next Steps