Talaria

Signals · 3 min read · Updated 2026-08-14

Transactions, traces, and spans

A trace is one request’s path. A span is a timed unit of work. A transaction is the root span Talaria meters.

APM without a data model is a stopwatch. The unit of work has to be named, nested, and queryable — otherwise you cannot ask “which route got slower after the deploy?”

The problem

A single HTTP request is not one timer. It is a tree: the server handler, each SQL statement, each outbound HTTP call, each Redis get, each queued job enqueue. Flatten that tree into one duration and you know the request was slow. Keep the tree and you know why.

What it is

OpenTelemetry defines a trace as a directed acyclic graph of spans. Each span has a name, a start and end time, a kind, optional parent, and attributes. Semantic conventions fix those attribute names so backends can query portably: http.request.method, http.route, http.response.status_code, db.system.name, db.query.text.

Span kinds describe the role, not the technology:

  • server — inbound work (PHP middleware, a pageload transaction).
  • client — outbound calls (Guzzle, fetch, TalariaHttpClient).
  • internal — in-process work that is neither.
  • producer / consumer — queues and jobs.

In Talaria a transaction is a sampled root span — a span with no parent. That is the billable unit. Child spans travel with it and are not metered separately. See sampling and metering.

What it gives a team

  • Route-level timing: GET /checkout as a name you can sort, not a raw URL with IDs.
  • A parent/child tree you can open as a waterfall when p95 moves.
  • Correlation: errors carry traceId and spanId so an issue is not an orphan stack.

How Talaria does it

SDKs send OTel-shaped batches to POST /spans/ingestBatch with API key scope spansWrite. Identifiers follow W3C: 32-hex traceId, 16-hex spanId. Resources map service.name from your project, service.version from release, and deployment.environment from environment.

What official SDKs start as transactions:

  • PHP / Silverstripe — HTTPMiddleware wraps the request (server span named like GET /product).
  • Browser — a pageload transaction, plus fetch/XHR as client spans.
  • Flutter — TalariaNavigatorObserver starts a transaction per route; TalariaHttpClient records outbound HTTP.
  • Dart — manual Talaria.startTransaction / startSpan when you are not on Flutter navigation.

Child instrumentation on PHP includes PDO / Silverstripe MySQL, Guzzle, Redis, and queued jobs when those modules are present. Dart does not auto-instrument databases. Browser Web Vitals are separate spans — see Web Vitals.

How to read it

On Performance, the transaction table groups sampled roots by name and shows count, error rate, and p95. Tap a row to open a sample waterfall. Prefer route names over raw URLs; high-cardinality paths (IDs in the path) make the table noisy and the RED series less useful.

Turn it on

Tracing is off by default. Opt in on the SDK, then send a request. The dashboard lists transactions only after sampled roots arrive in ClickHouse.

javascript
Talaria.init({
  dsn: 'https://api.newtalaria.com',
  apiKey: 'tal_live_…',
  environment: 'production',
  enableTracing: true,
  tracesSampleRate: 0.1, // 10% of successful navigations; errors always traced
});

What this is not

Talaria stores up to 200 child spans per transaction at ingest, and the waterfall loads up to 500 spans per trace. There is no flame graph, no span-to-log product, and no custom span schema — attributes follow OpenTelemetry conventions on purpose, so a later OTLP path stays coherent.

Related guides

  • Signals · 3 min

    How to read a request waterfall

    A waterfall is the trace drawn as time. The critical path is the longest chain of parent-to-child work — that is usually the fix.

  • Signals · 3 min

    Sampling you can explain

    Keep every failing transaction. Sample a tenth of the rest. Bill the root, not every query. That is the whole policy.

  • In the request · 3 min

    Distributed tracing with W3C Trace Context

    One trace ID from the browser, through PHP, into the query that failed — carried on a standard header named traceparent.

Turn tracing on

Opt into enableTracing on an official SDK, then inspect transactions next to the issues they belong to.