TimelessTraces (timeless_traces v1.3.10)

Copy Markdown View Source

Embedded OpenTelemetry span storage and compression for Elixir applications.

TimelessTraces receives spans from the OpenTelemetry Erlang SDK, compresses them into compressed blocks, and indexes them in ETS for fast querying.

Setup

# config/config.exs
config :timeless_traces,
  data_dir: "priv/span_stream"

# Enable the OTel exporter
config :opentelemetry,
  traces_exporter: {TimelessTraces.Exporter, []}

Querying

# Find error spans
TimelessTraces.query(status: :error)

# Find spans by service and kind
TimelessTraces.query(service: "my_app", kind: :server)

# Find slow spans (> 100ms)
TimelessTraces.query(min_duration: 100_000_000)

Trace Lookup

# Get all spans in a trace
TimelessTraces.trace("abc123def456...")

Summary

Functions

Create a consistent online backup of the span store.

Flush the buffer, writing any pending spans to storage immediately.

Merge multiple small compressed blocks into fewer, larger blocks.

List all distinct operation (span) names for a given service.

Query stored spans. Returns a TimelessTraces.Result struct.

List all distinct service names found in stored spans.

Return aggregate statistics about stored span data.

Subscribe the calling process to receive new spans as they arrive.

Retrieve all spans for a given trace ID, sorted by start time.

Unsubscribe the calling process from span notifications.

Functions

backup(target_dir)

@spec backup(String.t()) :: {:ok, map()} | {:error, term()}

Create a consistent online backup of the span store.

Flushes all in-flight data, writes an ETS index snapshot, and copies block files to the target directory.

Parameters

  • target_dir - Directory to write backup files into (will be created)

Returns

{:ok, %{path: target_dir, files: [filenames], total_bytes: integer()}}

Examples

TimelessTraces.backup("/tmp/span_backup_2024")

flush()

@spec flush() :: :ok

Flush the buffer, writing any pending spans to storage immediately.

merge_now()

@spec merge_now() :: :ok | :noop

Merge multiple small compressed blocks into fewer, larger blocks.

Returns :ok if blocks were merged, :noop if no merge was needed.

operations(service)

@spec operations(String.t()) :: {:ok, [String.t()]}

List all distinct operation (span) names for a given service.

Examples

{:ok, ops} = TimelessTraces.operations("my_app")
#=> {:ok, ["GET /users", "DB query", "cache_lookup"]}

query(filters \\ [])

@spec query(keyword()) :: {:ok, TimelessTraces.Result.t()} | {:error, term()}

Query stored spans. Returns a TimelessTraces.Result struct.

Filters

  • :name - Substring match on span name
  • :service - Match service.name attribute or resource
  • :kind - Span kind atom (:internal, :server, :client, :producer, :consumer)
  • :status - Status atom (:ok, :error, :unset)
  • :min_duration - Minimum duration in nanoseconds
  • :max_duration - Maximum duration in nanoseconds
  • :since - Start time lower bound (DateTime or unix nanos)
  • :until - Start time upper bound (DateTime or unix nanos)
  • :trace_id - Filter to specific trace ID
  • :attributes - Map of attribute key/value pairs to match

Pagination & Ordering

  • :limit - Max entries to return (default 100)
  • :offset - Number of entries to skip (default 0)
  • :order - :desc (newest first, default) or :asc (oldest first)

services()

@spec services() :: {:ok, [String.t()]}

List all distinct service names found in stored spans.

Examples

{:ok, services} = TimelessTraces.services()
#=> {:ok, ["my_app", "api_gateway", "auth_service"]}

stats()

@spec stats() :: {:ok, TimelessTraces.Stats.t()}

Return aggregate statistics about stored span data.

Examples

{:ok, stats} = TimelessTraces.stats()
stats.total_blocks   #=> 42
stats.total_entries   #=> 50000

subscribe(opts \\ [])

@spec subscribe(keyword()) :: {:ok, pid()}

Subscribe the calling process to receive new spans as they arrive.

The subscriber receives messages of the form: {:timeless_traces, :span, %TimelessTraces.Span{}}.

Options

  • :name - Only receive spans with this name
  • :kind - Only receive spans of this kind
  • :status - Only receive spans with this status
  • :service - Only receive spans from this service

trace(trace_id)

@spec trace(String.t()) :: {:ok, [TimelessTraces.Span.t()]}

Retrieve all spans for a given trace ID, sorted by start time.

Examples

{:ok, spans} = TimelessTraces.trace("abc123...")

unsubscribe()

@spec unsubscribe() :: :ok

Unsubscribe the calling process from span notifications.