The Event Log #

The event log is Litmus's unified record of everything that happens during testing — sessions, instrument connections, measurements, diagnostics, and more.

One stream, in order #

Every significant action emits a typed event into a single ordered stream. That stream lets you reconstruct what happened during a test, line up instrument reads with measurements, and watch a test live as it runs.

Event Hierarchy #

Every event carries the same common fields:

FieldTypeDescription
idUUIDUnique event identifier
occurred_atdatetimeWhen the event happened
received_atdatetimeWhen the log processed it for storage
session_idUUIDWhich session this event belongs to
run_idUUIDWhich test run (if applicable)

Each event also carries an event_type string (e.g. test.measurement) naming which kind of event it is.

Event Categories #

Litmus defines events across 12 categories.

Session (2 events) #

EventType StringDescription
SessionStartedsession.startedSession-wide metadata: station, operator, fixture
SessionEndedsession.endedSession outcome

Run (3 events) #

EventType StringDescription
RunStartedrun.startedFull run context: UUT, part, operator, config snapshots
RunEndedrun.endedRun outcome
RunMaterializedrun.materializedEmitted after the run's Parquet file is durably written; signals that the run is ready for downstream consumers

Slot (2 events — multi-UUT) #

EventType StringDescription
SlotStartedslot.startedA multi-UUT slot subprocess begins
SlotCompletedslot.completedA multi-UUT slot subprocess finishes

Sync (2 events — multi-UUT) #

EventType StringDescription
SyncArrivedsync.arrivedA worker reached a synchronization barrier
SyncReleasesync.releaseAll workers arrived; barrier released

Route (2 events — signal switching) #

EventType StringDescription
RouteClosedroute.closedSwitch route closed (signal connected)
RouteOpenedroute.openedSwitch route opened (signal disconnected)

Fixture (5 events) #

EventType StringDescription
InstrumentConnectedfixture.instrument_connectedInstrument identified and connected
IdentityVerifiedfixture.identity_verifiedExpected vs actual instrument identity
CalibrationWarningfixture.calibration_warningCalibration due date approaching
UutScannedfixture.uut_scannedUUT serial barcode scanned
InstrumentDisconnectedfixture.instrument_disconnectedInstrument released during teardown

Test (7 events) #

EventType StringDescription
StepsDiscoveredtest.steps_discoveredFull list of collected test items
StepStartedtest.step_startedA test step begins execution
MeasurementRecordedtest.measurementA single measurement with limits and outcome
StepEndedtest.step_endedA test step finishes
Observationtest.observationAn environmental or contextual reading recorded during a step
VectorStartedtest.vector_startedA parametric sweep vector begins
VectorEndedtest.vector_endedA parametric sweep vector finishes

Instrument (2 events) #

EventType StringDescription
InstrumentSetinstrument.setDriver set via proxy
InstrumentConfigureinstrument.configureDriver configure via proxy

Diagnostic (2 events) #

EventType StringDescription
DiagnosticWarningdiagnostic.warningNon-fatal warning
DiagnosticErrordiagnostic.errorError condition

Channel (3 events) #

EventType StringDescription
ChannelStartedchannel.startedA channel received its first sample in this session
ChannelEndedchannel.endedA channel was sealed for this session
ChannelCheckpointchannel.checkpointLiveness + progress marker from an active channel producer

File (3 events) #

EventType StringDescription
FileStartedfile.startedA data stream begins
FileEndedfile.endedA data stream ends
FileCheckpointfile.checkpointLiveness + progress marker from an active file sink

Dialog (2 events) #

EventType StringDescription
DialogOpeneddialog.openedOperator dialog shown, execution paused
DialogRespondeddialog.respondedOperator responded to dialog

Event Timeline #

A typical test session emits events in this order:

SessionStarted          # Session-wide metadata (station, operator)
├── RunStarted          # Run context (UUT, part, config snapshots)
├── InstrumentConnected # One per instrument role
├── IdentityVerified    # Optional identity check
├── StepsDiscovered     # Full list of collected test items
├── StepStarted         # First test step
│   ├── InstrumentSet
│   └── MeasurementRecorded
├── StepEnded
├── StepStarted         # Next test step...
│   └── ...
├── StepEnded
├── RunEnded            # All steps complete
├── RunMaterialized     # Parquet file durably written
├── InstrumentDisconnected
└── SessionEnded        # Cleanup complete

How the log is written #

When an event is written:

  1. received_at is stamped and the event is buffered for batched writes to an Arrow file (a fast columnar on-disk format)
  2. On RunEnded the run's Parquet file is written. The same path runs when you replay stored events with litmus export.
  3. Flush happens every 50 events (configurable), writing a batch to the Arrow file

The set of writers (Parquet, the live UI feed) is built in; adding a new output format is a change to Litmus itself, not a drop-in plugin.

Storage #

Events are stored as Arrow files, date-partitioned:

<data_dir>/events/
├── 2026-03-10/
│   ├── {session_id}-{pid}.arrow
│   └── {session_id}-{pid}_0001.arrow   # rotation for large sessions
└── 2026-03-11/
    └── ...

Each Arrow file contains index columns (id, event_type, occurred_at, received_at, session_id, run_id) plus a json column with the full serialized event for lossless replay.

Dual-Write Pattern #

Events are also loaded into an in-memory database as they're written, so you can query them with SQL right away:

  1. Arrow file — crash-safe append-only storage
  2. In-memory DuckDB — immediate SQL queryability

Each batch is loaded into an in-memory SQL database as it's written, so a query sees an event the instant after it's written.

What stays stable across releases #

Once an event type and its fields exist, they don't change or disappear within 0.x. Only new event types and new optional fields are added. A query or report you write today keeps working as the platform evolves.

See also #

Same topic, other quadrants:

Sibling concepts:

  • Event sourcing — why the platform is event-sourced rather than mutation-based
  • Data stores — how EventStore fits with ChannelStore, FileStore, and RunStore
  • Sessions — the observation window the event log keys events by