class Logit::Span

Overview

Represents a traced operation with timing, attributes, and trace context.

Spans are the core building block of Logit's tracing system. Each instrumented method call creates a span that tracks:

Spans are stored in a fiber-local stack, allowing safe concurrent tracing across multiple fibers without interference.

Accessing the Current Span

Inside an instrumented method, you can access the current span to add custom attributes:

class OrderService
  @[Logit::Log]
  def process_order(order_id : Int32) : Bool
    # Add custom attributes to the current span
    if span = Logit::Span.current?
      span.attributes.set("order.priority", "high")
      span.attributes.set("order.items_count", 5_i64)
    end

    # ... process the order
    true
  end
end

Trace Context

Nested method calls automatically share the same trace ID and form a parent-child relationship through span IDs:

class PaymentService
  @[Logit::Log]
  def charge(amount : Float64) : Bool
    validate_amount(amount)  # Child span, same trace_id
    process_payment(amount)  # Child span, same trace_id
    true
  end

  @[Logit::Log]
  def validate_amount(amount : Float64) : Bool
    amount > 0
  end

  @[Logit::Log]
  def process_payment(amount : Float64) : Bool
    # ...
    true
  end
end

Defined in:

logit/tracing/span.cr

Constructors

Class Method Summary

Instance Method Summary

Constructor Detail

def self.current : Span #

Returns the current span for this fiber.

Raises an exception if no span is active. Prefer .current? unless you're certain a span exists.


[View source]
def self.new(name : String, span_id : String = Utils::IDGenerator.span_id, parent_span_id : Nil | String = nil) #

Creates a new span with the given name.

Automatically inherits the trace ID from the current span (if any), or generates a new trace ID for root spans. The parent span ID is set to the current span's ID.


[View source]

Class Method Detail

def self.current? : Span | Nil #

Returns the current span for this fiber, or nil if none is active.

Use this to safely access the current span without raising an exception.

if span = Logit::Span.current?
  span.attributes.set("custom.field", "value")
end

[View source]
def self.pop(fiber_stack : Array(Span)) : Span | Nil #

Optimized version that takes the span stack directly to avoid repeated Fiber.current access. Used internally by the instrumentation macros.


[View source]
def self.pop : Span | Nil #

Pops the current span from the fiber-local span stack.

This is called automatically by the instrumentation macros. You typically don't need to call this directly.


[View source]
def self.push(span : Span, fiber_stack : Array(Span)) : Nil #

Optimized version that takes the span stack directly to avoid repeated Fiber.current access. Used internally by the instrumentation macros.


[View source]
def self.push(span : Span) : Nil #

Pushes a span onto the fiber-local span stack.

This is called automatically by the instrumentation macros. You typically don't need to call this directly.


[View source]

Instance Method Detail

def add_event(name : String, **attributes) : Nil #

Adds a span event (intermediate log within a span).

This allows logging important events during long-running operations without creating separate spans. Events are attached to this span and included when the span is converted to an Event.

Usage

@[Logit::Log]
def process_large_file(path : String) : Result
  span = Logit::Span.current

  span.add_event("file.opened", path: path)

  results = process_chunks(path)

  span.add_event("file.processed",
    path: path,
    chunks: results.size
  )

  results
end

OpenTelemetry Compatibility

Span events map directly to OpenTelemetry Span Events, allowing for rich observability without creating separate spans for every operation.


[View source]
def attributes : Event::Attributes #

Structured attributes attached to this span.


[View source]
def attributes=(attributes : Event::Attributes) #

Structured attributes attached to this span.


[View source]
def end_time : Time | Nil #

When this span ended (set when the span completes).


[View source]
def end_time=(end_time : Time | Nil) #

When this span ended (set when the span completes).


[View source]
def events : Array(SpanEvent) #

Span events that occurred during this span's lifetime.

These are intermediate logs attached to a span, similar to OpenTelemetry's Span Events. Use #add_event to add events.


[View source]
def exception : ExceptionInfo | Nil #

Exception information if an error occurred during this span.


[View source]
def exception=(exception : ExceptionInfo | Nil) #

Exception information if an error occurred during this span.


[View source]
def name : String #

Name of this span (typically the method name).


[View source]
def name=(name : String) #

Name of this span (typically the method name).


[View source]
def parent_span_id : String | Nil #

Span ID of the parent span, or nil if this is a root span.


[View source]
def parent_span_id=(parent_span_id : String | Nil) #

Span ID of the parent span, or nil if this is a root span.


[View source]
def span_id : String #

Unique identifier for this span (64-bit hex string).


[View source]
def span_id=(span_id : String) #

Unique identifier for this span (64-bit hex string).


[View source]
def start_time : Time #

When this span started.


[View source]
def start_time=(start_time : Time) #

When this span started.


[View source]
def to_event(trace_id : String, level : LogLevel, code_file : String, code_line : Int32, method_name : String, class_name : String) : Event #

Converts this span to an Event for logging.

Called automatically when a span completes. You typically don't need to call this directly.


[View source]
def trace_id : String #

W3C trace ID (128-bit hex string) shared across all spans in a trace.


[View source]
def trace_id=(trace_id : String) #

W3C trace ID (128-bit hex string) shared across all spans in a trace.


[View source]