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-context.mddocs/

SpanContext and Identifiers

SpanContext contains the immutable identifying information about a span. It includes the trace ID, span ID, trace flags, and trace state required for distributed trace propagation.

SpanContext

type SpanContext struct {
    // contains unexported fields
}

SpanContext is immutable and thread-safe. It represents the portion of a span that must be propagated to child spans and across process boundaries.

Creating SpanContext

// SpanContextConfig contains mutable fields usable for constructing an
// immutable SpanContext.
type SpanContextConfig struct {
    TraceID    TraceID
    SpanID     SpanID
    TraceFlags TraceFlags
    TraceState TraceState
    Remote     bool
}

// NewSpanContext constructs a SpanContext using values from the provided
// SpanContextConfig.
func NewSpanContext(config SpanContextConfig) SpanContext

Usage Example

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

// Parse trace context from W3C headers
traceID, _ := trace.TraceIDFromHex("4bf92f3577b34da6a3ce929d0e0e4736")
spanID, _ := trace.SpanIDFromHex("00f067aa0ba902b7")

sc := trace.NewSpanContext(trace.SpanContextConfig{
    TraceID:    traceID,
    SpanID:     spanID,
    TraceFlags: trace.FlagsSampled,
    Remote:     true,
})

SpanContext Methods

// TraceID returns the TraceID from the SpanContext.
func (sc SpanContext) TraceID() TraceID

// SpanID returns the SpanID from the SpanContext.
func (sc SpanContext) SpanID() SpanID

// TraceFlags returns the flags from the SpanContext.
func (sc SpanContext) TraceFlags() TraceFlags

// TraceState returns the TraceState from the SpanContext.
func (sc SpanContext) TraceState() TraceState

// IsValid reports whether the SpanContext is valid. A valid span context has a
// valid TraceID and SpanID.
func (sc SpanContext) IsValid() bool

// HasTraceID reports whether the SpanContext has a valid TraceID.
func (sc SpanContext) HasTraceID() bool

// HasSpanID reports whether the SpanContext has a valid SpanID.
func (sc SpanContext) HasSpanID() bool

// IsSampled reports whether the sampling bit is set in the SpanContext's
// TraceFlags.
func (sc SpanContext) IsSampled() bool

// IsRemote reports whether the SpanContext represents a remotely-created Span.
func (sc SpanContext) IsRemote() bool

// Equal reports whether two SpanContext values are equal.
func (sc SpanContext) Equal(other SpanContext) bool

// MarshalJSON implements a custom marshal function to encode a SpanContext.
func (sc SpanContext) MarshalJSON() ([]byte, error)

Deriving New SpanContext

// WithTraceID returns a new SpanContext with the TraceID replaced.
func (sc SpanContext) WithTraceID(traceID TraceID) SpanContext

// WithSpanID returns a new SpanContext with the SpanID replaced.
func (sc SpanContext) WithSpanID(spanID SpanID) SpanContext

// WithTraceFlags returns a new SpanContext with the TraceFlags replaced.
func (sc SpanContext) WithTraceFlags(flags TraceFlags) SpanContext

// WithTraceState returns a new SpanContext with the TraceState replaced.
func (sc SpanContext) WithTraceState(state TraceState) SpanContext

// WithRemote returns a copy of sc with the Remote property set to remote.
func (sc SpanContext) WithRemote(remote bool) SpanContext

Getting SpanContext from Context

// SpanContextFromContext returns the current Span's SpanContext.
func SpanContextFromContext(ctx context.Context) SpanContext

TraceID

TraceID uniquely identifies a trace. It is a 16-byte array.

type TraceID [16]byte

// TraceIDFromHex returns a TraceID from a hex string if it is
// compliant with the W3C trace-context specification.
func TraceIDFromHex(h string) (TraceID, error)

// IsValid reports whether the trace TraceID is valid. A valid trace ID does
// not consist of zeros only.
func (t TraceID) IsValid() bool

// String returns the hex string representation form of a TraceID.
func (t TraceID) String() string

// MarshalJSON implements a custom marshal function to encode TraceID as a hex
// string.
func (t TraceID) MarshalJSON() ([]byte, error)

Usage Example

// From hex string (W3C format: 32 hex characters)
traceID, err := trace.TraceIDFromHex("4bf92f3577b34da6a3ce929d0e0e4736")
if err != nil {
    // handle error
}

// Check validity
if traceID.IsValid() {
    fmt.Println("Trace ID:", traceID.String())
}

// Create from bytes
var tid trace.TraceID
copy(tid[:], []byte{0x4b, 0xf9, 0x2f, /* ... 16 bytes total */})

SpanID

SpanID uniquely identifies a span within a trace. It is an 8-byte array.

type SpanID [8]byte

// SpanIDFromHex returns a SpanID from a hex string if it is
// compliant with the w3c trace-context specification.
func SpanIDFromHex(h string) (SpanID, error)

// IsValid reports whether the SpanID is valid. A valid SpanID does not consist
// of zeros only.
func (s SpanID) IsValid() bool

// String returns the hex string representation form of a SpanID.
func (s SpanID) String() string

// MarshalJSON implements a custom marshal function to encode SpanID as a hex
// string.
func (s SpanID) MarshalJSON() ([]byte, error)

Usage Example

// From hex string (W3C format: 16 hex characters)
spanID, err := trace.SpanIDFromHex("00f067aa0ba902b7")
if err != nil {
    // handle error
}

// Check validity
if spanID.IsValid() {
    fmt.Println("Span ID:", spanID.String())
}

TraceFlags

TraceFlags contains flags that can be set on a SpanContext. The most common flag is the sampling bit.

type TraceFlags byte

const (
    // FlagsSampled is a bitmask with the sampled bit set. A SpanContext
    // with the sampling bit set means the span is sampled.
    FlagsSampled = TraceFlags(0x01)
)

// IsSampled reports whether the sampling bit is set in the TraceFlags.
func (tf TraceFlags) IsSampled() bool

// WithSampled sets the sampling bit in a new copy of the TraceFlags.
func (tf TraceFlags) WithSampled(sampled bool) TraceFlags

// String returns the hex string representation form of TraceFlags.
func (tf TraceFlags) String() string

// MarshalJSON implements a custom marshal function to encode TraceFlags as a
// hex string.
func (tf TraceFlags) MarshalJSON() ([]byte, error)

Usage Example

// Check if sampled
var flags trace.TraceFlags = trace.FlagsSampled
if flags.IsSampled() {
    fmt.Println("Span is sampled")
}

// Set sampling flag
flags = flags.WithSampled(true)

// Clear sampling flag
flags = flags.WithSampled(false)

TraceState

TraceState provides vendor-specific trace identification information across distributed tracing systems. It conforms to the W3C Trace Context specification.

type TraceState struct {
    // contains unexported fields
}

// ParseTraceState attempts to decode a TraceState from the passed string.
// It returns an error if the input is invalid according to the W3C Trace
// Context specification.
func ParseTraceState(ts string) (TraceState, error)

TraceState is immutable - all operations return a new TraceState. It maintains:

  • Valid key/value pairs only
  • No duplicate keys
  • Maximum of 32 list-members

TraceState Methods

// Get returns the value paired with key from the corresponding TraceState
// list-member if it exists, otherwise an empty string is returned.
func (ts TraceState) Get(key string) string

// Insert adds a new list-member defined by the key/value pair to the
// TraceState. If a list-member already exists for the given key, that
// list-member's value is updated. The new or updated list-member is always
// moved to the beginning of the TraceState as specified by the W3C Trace
// Context specification.
//
// If key or value are invalid according to the W3C Trace Context specification
// an error is returned with the original TraceState.
//
// If adding a new list-member means the TraceState would have more members
// then is allowed, the new list-member will be inserted and the right-most
// list-member will be dropped in the returned TraceState.
func (ts TraceState) Insert(key, value string) (TraceState, error)

// Delete returns a copy of the TraceState with the list-member identified by
// key removed.
func (ts TraceState) Delete(key string) TraceState

// Len returns the number of list-members in the TraceState.
func (ts TraceState) Len() int

// String encodes the TraceState into a string compliant with the W3C Trace
// Context specification. The returned string will be invalid if the TraceState
// contains any invalid members.
func (ts TraceState) String() string

// Walk walks all key value pairs in the TraceState by calling f
// Iteration stops if f returns false.
func (ts TraceState) Walk(f func(key, value string) bool)

// MarshalJSON marshals the TraceState into JSON.
func (ts TraceState) MarshalJSON() ([]byte, error)

Usage Example

// Parse from W3C header format
ts, err := trace.ParseTraceState("vendor1=value1,vendor2=value2")
if err != nil {
    // handle error
}

// Get vendor-specific value
value := ts.Get("vendor1")

// Add or update vendor data
ts, err = ts.Insert("myvendor", "myvalue")
if err != nil {
    // handle invalid key/value
}

// Delete vendor data
ts = ts.Delete("vendor2")

// Iterate over all members
ts.Walk(func(key, value string) bool {
    fmt.Printf("%s=%s\n", key, value)
    return true // continue iteration
})

// Encode to W3C format
headerValue := ts.String()

// Check size
if ts.Len() > 30 {
    fmt.Println("Warning: TraceState approaching 32 member limit")
}

Context Propagation

Functions for managing SpanContext in Go's context.Context:

// ContextWithSpanContext returns a copy of parent with sc as the current Span.
// The Span implementation that wraps sc is non-recording and performs no
// operations other than to return sc as the SpanContext from the SpanContext
// method.
func ContextWithSpanContext(parent context.Context, sc SpanContext) context.Context

// ContextWithRemoteSpanContext returns a copy of parent with rsc set
// explicitly as a remote SpanContext and as the current Span. The Span
// implementation that wraps rsc is non-recording and performs no operations
// other than to return rsc as the SpanContext from the SpanContext method.
func ContextWithRemoteSpanContext(parent context.Context, rsc SpanContext) context.Context

Usage Example

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

// Extract trace context from incoming request headers
traceID, _ := trace.TraceIDFromHex(req.Header.Get("traceparent-traceid"))
spanID, _ := trace.SpanIDFromHex(req.Header.Get("traceparent-spanid"))
flags := trace.FlagsSampled

sc := trace.NewSpanContext(trace.SpanContextConfig{
    TraceID:    traceID,
    SpanID:     spanID,
    TraceFlags: flags,
    Remote:     true,
})

// Inject into context
ctx := trace.ContextWithRemoteSpanContext(context.Background(), sc)

// Create child span - automatically uses sc as parent
ctx, span := tracer.Start(ctx, "handleRequest")
defer span.End()

Complete Example: Distributed Trace Propagation

package main

import (
    "context"
    "fmt"
    "net/http"

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

// HTTP server receiving traced request
func handleRequest(w http.ResponseWriter, r *http.Request) {
    // Extract trace context from headers (simplified)
    traceparent := r.Header.Get("traceparent")
    sc := extractSpanContext(traceparent)

    // Inject into context
    ctx := trace.ContextWithRemoteSpanContext(r.Context(), sc)

    // Start new span as child of remote span
    tracer := otel.Tracer("http-server")
    ctx, span := tracer.Start(ctx, "handleRequest",
        trace.WithSpanKind(trace.SpanKindServer),
    )
    defer span.End()

    // Process request...
    processRequest(ctx)

    // Get span context for response headers
    sc = span.SpanContext()
    w.Header().Set("traceresponse", sc.TraceID().String())
}

// HTTP client making traced request
func makeRequest(ctx context.Context, url string) error {
    tracer := otel.Tracer("http-client")

    ctx, span := tracer.Start(ctx, "makeRequest",
        trace.WithSpanKind(trace.SpanKindClient),
    )
    defer span.End()

    // Get span context for propagation
    sc := span.SpanContext()

    // Create request and inject trace context
    req, _ := http.NewRequestWithContext(ctx, "GET", url, nil)
    injectSpanContext(req, sc)

    // Make request...
    resp, err := http.DefaultClient.Do(req)
    if err != nil {
        return err
    }
    defer resp.Body.Close()

    return nil
}

func extractSpanContext(traceparent string) trace.SpanContext {
    // Parse W3C traceparent header
    // Format: 00-<trace-id>-<span-id>-<flags>
    // Simplified for example
    return trace.SpanContext{}
}

func injectSpanContext(req *http.Request, sc trace.SpanContext) {
    // Inject W3C traceparent header
    traceparent := fmt.Sprintf("00-%s-%s-%s",
        sc.TraceID().String(),
        sc.SpanID().String(),
        sc.TraceFlags().String(),
    )
    req.Header.Set("traceparent", traceparent)

    // Inject tracestate if present
    if sc.TraceState().Len() > 0 {
        req.Header.Set("tracestate", sc.TraceState().String())
    }
}

func processRequest(ctx context.Context) {
    // Process with trace context
}

Validation

Always validate trace context before using:

if !sc.IsValid() {
    // Invalid context - create new trace
    ctx, span := tracer.Start(ctx, "operation", trace.WithNewRoot())
    defer span.End()
} else if !sc.HasTraceID() || !sc.HasSpanID() {
    // Missing required IDs
    return errors.New("invalid trace context")
}

Best Practices

  1. Always validate: Check IsValid() before using extracted SpanContext
  2. Mark remote spans: Use WithRemote(true) or ContextWithRemoteSpanContext for spans from other services
  3. Preserve TraceState: Don't discard vendor-specific state when propagating context
  4. Use immutable operations: All SpanContext modifications return new instances
  5. Handle errors: TraceState operations may fail validation - always check errors