or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

embedded.mdindex.mdnoop.mdspan-context.mdspan-options.mdspan.mdtracer-provider-tracer.md
tile.json

span-options.mddocs/

Span Configuration and Options

This document covers all configuration options for customizing span behavior at creation, during execution, and at completion.

Span Options Overview

Options control span behavior at different lifecycle stages:

  • SpanStartOption: Options applied when creating a span
  • SpanEndOption: Options applied when ending a span
  • SpanOption: Options applicable at both start and end
  • EventOption: Options for events
  • SpanStartEventOption: Options for span start or events
  • SpanEndEventOption: Options for span end or events
  • SpanEventOption: Options for spans or events

SpanStartOption

Options for span creation via Tracer.Start().

type SpanStartOption interface {
    // contains unexported methods
}

Available SpanStartOptions

// WithNewRoot specifies that the Span should be treated as a root Span.
// Any existing parent span context will be ignored when defining the Span's
// trace identifiers.
func WithNewRoot() SpanStartOption

// WithSpanKind sets the SpanKind of a Span.
func WithSpanKind(kind SpanKind) SpanStartOption

// WithLinks adds links to a Span. The links are added to the existing Span
// links, i.e. this does not overwrite. Links with invalid span context are
// ignored.
func WithLinks(links ...Link) SpanStartOption

// WithAttributes adds the attributes related to a span life-cycle event.
// These attributes are used to describe the work a Span represents when this
// option is provided to a Span's start event. Otherwise, these attributes
// provide additional information about the event being recorded (e.g. error,
// state change, processing progress, system event).
//
// If multiple of these options are passed the attributes of each successive
// option will extend the attributes instead of overwriting. There is no
// guarantee of uniqueness in the resulting attributes.
func WithAttributes(attributes ...attribute.KeyValue) SpanStartEventOption

// WithTimestamp sets the time of a Span or Event life-cycle moment (e.g.
// started, stopped, errored).
func WithTimestamp(t time.Time) SpanEventOption

Usage Example

import (
    "context"
    "time"
    "go.opentelemetry.io/otel/trace"
    "go.opentelemetry.io/otel/attribute"
)

ctx, span := tracer.Start(ctx, "processOrder",
    // Force new root trace (ignore parent)
    trace.WithNewRoot(),

    // Set span kind
    trace.WithSpanKind(trace.SpanKindServer),

    // Add initial attributes (visible to samplers)
    trace.WithAttributes(
        attribute.String("order.id", orderID),
        attribute.String("customer.id", customerID),
        attribute.Int("order.items", itemCount),
    ),

    // Add links to related spans
    trace.WithLinks(
        trace.Link{
            SpanContext: relatedSpanContext,
            Attributes: []attribute.KeyValue{
                attribute.String("link.type", "related-order"),
            },
        },
    ),

    // Custom start time
    trace.WithTimestamp(customStartTime),
)
defer span.End()

SpanEndOption

Options for completing a span via Span.End().

type SpanEndOption interface {
    // contains unexported methods
}

Available SpanEndOptions

// WithStackTrace sets the flag to capture the error with stack trace (e.g.
// true, false).
func WithStackTrace(b bool) SpanEndEventOption

// WithTimestamp sets the time of a Span or Event life-cycle moment (e.g.
// started, stopped, errored).
func WithTimestamp(t time.Time) SpanEventOption

Usage Example

// End span with custom timestamp
customEndTime := time.Now().Add(-5 * time.Second)
span.End(trace.WithTimestamp(customEndTime))

// Or just defer with no options (most common)
defer span.End()

SpanOption

Options that can be used at both span start and end.

type SpanOption interface {
    SpanStartOption
    SpanEndOption
}

Currently, options implementing both interfaces:

  • WithTimestamp(t time.Time) - Can set start or end time

EventOption

Options for span events via Span.AddEvent() or Span.RecordError().

type EventOption interface {
    // contains unexported methods
}

Available EventOptions

// WithAttributes adds the attributes related to a span life-cycle event.
func WithAttributes(attributes ...attribute.KeyValue) SpanStartEventOption

// WithTimestamp sets the time of an Event.
func WithTimestamp(t time.Time) SpanEventOption

// WithStackTrace sets the flag to capture the error with stack trace.
func WithStackTrace(b bool) SpanEndEventOption

Usage Example

// Add event with attributes and custom timestamp
span.AddEvent("cache-miss",
    trace.WithAttributes(
        attribute.String("cache.key", "user:123"),
        attribute.String("cache.backend", "redis"),
    ),
    trace.WithTimestamp(time.Now()),
)

// Record error with stack trace
if err != nil {
    span.RecordError(err,
        trace.WithStackTrace(true),
        trace.WithAttributes(
            attribute.String("error.source", "database"),
            attribute.String("query", sqlQuery),
        ),
    )
}

SpanConfig

SpanConfig holds the configuration of a span. It's typically used by SDK implementations to query span settings.

type SpanConfig struct {
    // contains unexported fields
}

// NewSpanStartConfig applies all the options to a returned SpanConfig.
// No validation is performed on the returned SpanConfig (e.g. no uniqueness
// checking or bounding of data), it is left to the SDK to perform this action.
func NewSpanStartConfig(options ...SpanStartOption) SpanConfig

// NewSpanEndConfig applies all the options to a returned SpanConfig.
// No validation is performed on the returned SpanConfig (e.g. no uniqueness
// checking or bounding of data), it is left to the SDK to perform this action.
func NewSpanEndConfig(options ...SpanEndOption) SpanConfig

SpanConfig Methods

// Timestamp is a time in a Span life-cycle.
func (cfg *SpanConfig) Timestamp() time.Time

// StackTrace reports whether stack trace capturing is enabled.
func (cfg *SpanConfig) StackTrace() bool

// Attributes describe the associated qualities of a Span.
func (cfg *SpanConfig) Attributes() []attribute.KeyValue

// Links are the associations a Span has with other Spans.
func (cfg *SpanConfig) Links() []Link

// NewRoot identifies a Span as the root Span for a new trace. This is commonly
// used when an existing trace crosses trust boundaries and the remote parent
// span context should be ignored for security.
func (cfg *SpanConfig) NewRoot() bool

// SpanKind is the role a Span has in a trace.
func (cfg *SpanConfig) SpanKind() SpanKind

Usage Example (SDK Implementation)

// SDK implementations use SpanConfig to query configuration
func (t *tracer) Start(ctx context.Context, name string, opts ...trace.SpanStartOption) (context.Context, trace.Span) {
    config := trace.NewSpanStartConfig(opts...)

    // Check if this should be a new root
    if config.NewRoot() {
        // Start new trace
    }

    // Get span kind
    kind := config.SpanKind()

    // Get initial attributes for sampling decision
    attrs := config.Attributes()

    // Get links
    links := config.Links()

    // Get custom start timestamp if provided
    timestamp := config.Timestamp()

    // Create span...
}

EventConfig

EventConfig holds the configuration of an event.

type EventConfig struct {
    // contains unexported fields
}

// NewEventConfig applies all the EventOptions to a returned EventConfig. If no
// timestamp option is passed, the returned EventConfig will have a Timestamp
// set to the call time, otherwise no validation is performed on the returned
// EventConfig.
func NewEventConfig(options ...EventOption) EventConfig

EventConfig Methods

// Timestamp is a time in an Event life-cycle.
func (cfg *EventConfig) Timestamp() time.Time

// StackTrace reports whether stack trace capturing is enabled.
func (cfg *EventConfig) StackTrace() bool

// Attributes describe the associated qualities of an Event.
func (cfg *EventConfig) Attributes() []attribute.KeyValue

Link Type

Links connect spans within or across traces.

type Link struct {
    // SpanContext of the linked Span.
    SpanContext SpanContext

    // Attributes describe the aspects of the link.
    Attributes []attribute.KeyValue
}

// LinkFromContext returns a link encapsulating the SpanContext in the provided
// ctx.
func LinkFromContext(ctx context.Context, attrs ...attribute.KeyValue) Link

Usage Examples

// Create link from span context
link := trace.Link{
    SpanContext: remoteSpanContext,
    Attributes: []attribute.KeyValue{
        attribute.String("link.type", "continuation"),
        attribute.String("link.source", "batch-job"),
    },
}

// Create link from context
link := trace.LinkFromContext(relatedCtx,
    attribute.String("link.type", "related"),
)

// Add links at span creation (preferred for sampling)
ctx, span := tracer.Start(ctx, "batchProcess",
    trace.WithLinks(
        trace.LinkFromContext(jobCtx1),
        trace.LinkFromContext(jobCtx2),
        trace.LinkFromContext(jobCtx3),
    ),
)
defer span.End()

// Or add link after creation
span.AddLink(link)

Complete Configuration Example

package main

import (
    "context"
    "errors"
    "time"

    "go.opentelemetry.io/otel"
    "go.opentelemetry.io/otel/attribute"
    "go.opentelemetry.io/otel/codes"
    "go.opentelemetry.io/otel/trace"
)

func processBatchJob(ctx context.Context, jobID string, relatedJobs []context.Context) error {
    tracer := otel.Tracer("batch-processor")

    // Collect links to related jobs
    links := make([]trace.Link, len(relatedJobs))
    for i, jobCtx := range relatedJobs {
        links[i] = trace.LinkFromContext(jobCtx,
            attribute.Int("job.index", i),
        )
    }

    // Create span with comprehensive configuration
    startTime := time.Now()
    ctx, span := tracer.Start(ctx, "processBatchJob",
        // Span kind
        trace.WithSpanKind(trace.SpanKindInternal),

        // Initial attributes (available to samplers)
        trace.WithAttributes(
            attribute.String("job.id", jobID),
            attribute.String("job.type", "batch"),
            attribute.Int("job.size", len(relatedJobs)),
            attribute.String("processor.version", "v2.1.0"),
        ),

        // Links to related jobs
        trace.WithLinks(links...),

        // Custom start timestamp
        trace.WithTimestamp(startTime),
    )
    defer func() {
        // End with custom timestamp
        endTime := time.Now()
        span.End(trace.WithTimestamp(endTime))
    }()

    // Add progress event
    span.AddEvent("job-started",
        trace.WithAttributes(
            attribute.String("stage", "initialization"),
        ),
    )

    // Simulate work with error
    if err := performWork(ctx); err != nil {
        // Record error with full context
        span.RecordError(err,
            trace.WithStackTrace(true),
            trace.WithAttributes(
                attribute.String("error.phase", "processing"),
                attribute.Bool("error.recoverable", false),
            ),
            trace.WithTimestamp(time.Now()),
        )
        span.SetStatus(codes.Error, "batch job failed")
        return err
    }

    // Add completion event
    span.AddEvent("job-completed",
        trace.WithAttributes(
            attribute.String("stage", "finalization"),
            attribute.Int("processed.items", 100),
        ),
    )

    span.SetStatus(codes.Ok, "")
    return nil
}

func performWork(ctx context.Context) error {
    return errors.New("simulated error")
}

Best Practices

Span Creation

  1. Add attributes at creation: Samplers only see attributes provided at span start

    ctx, span := tracer.Start(ctx, "operation",
        trace.WithAttributes(/* sampling-relevant attributes */),
    )
  2. Use links at creation: Prefer WithLinks() over AddLink() for sampling decisions

    ctx, span := tracer.Start(ctx, "batch",
        trace.WithLinks(links...),
    )
  3. Set appropriate span kind: Helps backends classify and visualize traces

    trace.WithSpanKind(trace.SpanKindServer) // or Client, Producer, Consumer, Internal

Events

  1. Add meaningful events: Mark significant milestones in span execution

    span.AddEvent("cache-hit")
    span.AddEvent("database-query-started")
    span.AddEvent("validation-completed")
  2. Include event context: Add attributes to explain what happened

    span.AddEvent("retry-attempted",
        trace.WithAttributes(
            attribute.Int("retry.attempt", attemptNum),
            attribute.String("retry.reason", reason),
        ),
    )

Error Recording

  1. Always include stack traces for errors: Helps debugging

    span.RecordError(err, trace.WithStackTrace(true))
  2. Set status after recording error: RecordError() doesn't change status

    span.RecordError(err)
    span.SetStatus(codes.Error, "operation failed")

Custom Timestamps

  1. Use sparingly: Let SDK capture timestamps unless you have a specific need

    // Only when you need to backdate or adjust timing
    trace.WithTimestamp(customTime)
  2. Consistent timing: If you use custom start time, consider custom end time

    startTime := parseEventTime(event)
    ctx, span := tracer.Start(ctx, "historical",
        trace.WithTimestamp(startTime),
    )
    // ...
    span.End(trace.WithTimestamp(endTime))

Root Spans

  1. Use for untrusted contexts: Create new trace for security

    ctx, span := tracer.Start(ctx, "publicEndpoint",
        trace.WithNewRoot(), // Ignore potentially malicious parent
    )
  2. Link to original context: Maintain relationship while securing trace

    originalLink := trace.LinkFromContext(untrustedCtx,
        attribute.String("link.type", "untrusted-parent"),
    )
    ctx, span := tracer.Start(ctx, "publicEndpoint",
        trace.WithNewRoot(),
        trace.WithLinks(originalLink),
    )