Aller au contenu
Français

Recording tracer

Ce contenu n’est pas encore disponible dans votre langue.

RecordingTracer is the test counterpart to OtelTracerAdapter. Instead of exporting spans, it stores them in memory — tests assert on the recorded spans.

import { TestKit, RecordingTracer, TracingExtensionId } from 'actor-ts';
const tracer = new RecordingTracer();
const tk = TestKit.create();
tk.system.extension(TracingExtensionId).configure({ tracer });
// ... run the actor ...
ref.tell({ kind: 'process' });
await probe.expectMsg(...);
// Assert on recorded spans:
const spans = tracer.recordedSpans();
expect(spans).toHaveLength(1);
expect(spans[0].name).toBe('actor.receive');
expect(spans[0].attributes['actor.path']).toContain('worker');

Each RecordedSpan:

interface RecordedSpan {
name: string;
context: SpanContext;
parent?: SpanContext;
attributes: Record<string, AttributeValue>;
events: Array<{ name: string; attrs: ... }>;
status: { status: 'ok' | 'error'; message?: string };
startTimeMs: number;
endTimeMs: number;
ended: boolean;
kind: SpanKind;
}

You see what attributes were set, when the span started + ended, its kind, its parent (for verifying causality chains), and its final status.

class RecordingTracer implements Tracer {
// ... full Tracer interface ...
recordedSpans(): RecordedSpan[]; // all spans, including unended
finishedSpans(): RecordedSpan[]; // spans where end() was called
reset(): void; // clear recorded state
}

recordedSpans returns every span the tracer was asked to create. finishedSpans filters to those that ended — useful to detect “started a span and never ended it” bugs.

”Did the framework auto-span this actor’s message?"

Section titled “”Did the framework auto-span this actor’s message?"”
ref.tell({ kind: 'work' });
await probe.expectMsg(...);
const spans = tracer.finishedSpans();
const receive = spans.find(s => s.name === 'actor.receive' && s.attributes['actor.path']?.includes('worker'));
expect(receive).toBeDefined();
expect(receive!.status.status).toBe('ok');

"Did my custom span fire with the right attributes?"

Section titled “"Did my custom span fire with the right attributes?"”
const orderSpan = tracer.finishedSpans().find(s => s.name === 'place-order');
expect(orderSpan).toBeDefined();
expect(orderSpan!.attributes['order.id']).toBe('o-1');
expect(orderSpan!.attributes['order.amount']).toBe(42);
const spans = tracer.finishedSpans();
const parent = spans.find(s => s.name === 'http-request');
const child = spans.find(s => s.name === 'db-query');
expect(child!.parent?.traceId).toBe(parent!.context.traceId);

Useful for verifying trace causality — parent context correctly propagated to child spans.

beforeEach(() => tracer.reset());

Without reset, recorded spans accumulate across tests. Reset on each test to keep assertions on the current test’s spans only.

Recording is cheap — appending to an array. But spans accumulate in memory. For long test runs, periodically reset to avoid memory growth.

  • Tracer API — the interface this implements.
  • OTel adapter — the production alternative.
  • Actor tracing — what the framework auto-spans, observable via this tracer.
  • TestKit — pair with the recording tracer for assertion-friendly tests.

The RecordingTracer API reference covers the full surface.