Skip to content

Events ​

Everything that happens while a job runs — a run's steps, a monitor's messages, a burst's numbers, the Inspector's frames, a job's end — is sent as an event. In a browser, the server's page gets them on one WebSocket, /api/events; a script can listen on the same socket. The desktop app gets the same events, with the same names and payloads, inside the app.

Subscribing ​

Open a WebSocket to /api/events on the server:

bash
websocat -H "Authorization: Bearer $TOKEN" ws://127.0.0.1:1430/api/events
  • Authentication is the rest of the API's: the token as Authorization: Bearer, or a browser's session cookie. Without it the upgrade is refused with 401 auth.required.
  • Origin: a client that sends an Origin header must send the server's own (host and port equal to Host), or the upgrade is refused with 403auth.origin. Most WebSocket libraries outside a browser send none.
  • Every event to every client. There is nothing to subscribe to: each socket gets every event of every job, whoever started it. Pick what you need by event, and by job_id in the payload.
  • Listen only. The server ignores what a client sends, except a close; a message larger than 64 KiB closes the socket.
  • Keep-alive. The server pings every 20 s, so a quiet socket stays open through proxies. When the server stops, it closes every socket.
  • Nothing is replayed. Events sent while a client was not connected are lost to it. A client that reconnects should read the current state with commands (jobs_list, inspect_snapshot, emulator_exchanges…).
  • Falling behind. Up to 4096 events wait for one socket. A client that falls further behind gets server://lagged with how many it missed.

Message format ​

Each event is one text message holding one JSON object:

json
{ "event": "scan://open", "payload": { "job_id": 9, "ts": 1759600000123, "port": 8080, "banner": null } }
FieldWhat it is
eventThe channel, below
payloadThe event's values; its shape depends on the channel

Times (ts, a peer's first_ms and last_ms) are milliseconds since 1970; latencies and other durations (*_latency_ms, p50_ms…, ms) are milliseconds. Errors in payloads are EngineError objects; their codes are listed in error messages.

Channels ​

ChannelSent byWhen
experiment://stepA runA step starts, passes, fails, retries, repeats or reports load
experiment://endedA runOnce, when the run ends on its own
job://endedEvery jobOnce, when the job ends on its own or fails
osc://messageOSC monitorEvery packet
osc://gen-tickOSC generatorEvery message, or 30 to 45 times a second above 60 messages a second
http://burst-progressHTTP burstEvery 100 ms, and at the end
ws://stateWebSocket connectionConnected, closed
ws://messagesWebSocket connectionEvery 100 ms with something new
mqtt://stateMQTT connectionConnected, subscribed, closed
mqtt://messagesMQTT connectionEvery 100 ms with something new
mqtt://ackMQTT connectionA QoS 1/2 publish completed; an unsubscribe answered
broadcast://emit-statBeaconEvery 250 ms, and at the end
broadcast://peersDiscovery listenerEvery 400 ms
netsim://statImpairment relayEvery 250 ms
storm://statStormEvery 250 ms, and at the end
scan://openScannerEvery open port
scan://progressScannerAbout every 1 % of the range, and at the end
emulator://activityEmulator jobEvery 200 ms with something new
inspect://batchInspectorEvery 120 ms with new frames, about once a second when quiet, while capture is armed
server://laggedThe serverA client fell behind

experiment://step ​

One step of a run: a node starting, passing, failing, waiting to try again, repeating, or reporting a load's progress. A run started with /api/run sends the same steps on its response (see runs).

FieldTypeMeaning
job_idnumberThe run's job
tsnumberWhen
node_idstringThe node
statestringrunning, passed, failed, retry (an attempt failed and the step runs again after a pause), repeating (a repeating action's progress, at most once a second) or load (a load's progress, at most once a second)
detailstringWhat happened, in English; empty for running and failed (see error)
message_keystring or nullThe interface's text for it, as a key of its dictionary
message_paramsobject or nullThe values message_key names
varsobjectVariables the step wrote; left out when none
errorEngineErrorWhy it failed, or why the attempt did (retry); left out otherwise
framenumberThe Inspector frame of the message a wait (or a send's expected reply) matched, when capture was armed; left out otherwise
loadobjectWhat a load measured, its thresholds read — on a load step's last event, passed or failed; left out otherwise. See load

A run's End node shows running when the first branch reaches it and passed once every branch has finished without a failure. Secret values are masked in every field.

experiment://ended ​

A run ended on its own: it passed, failed or ran out of time. Sent right after the same payload on job://ended. A run stopped with job_stop or Stop all sends neither and saves no report.

FieldTypeMeaning
job_idnumberThe run's job
kindstringexperiment
seednumberThe seed it ran with
profilestring or nullIts profile
overriddenbooleanSome parameter values came from Run with… or overrides
errorEngineError or nullThe run's first failure; null when it passed
report_pathstring or nullIts report, in runs/ of the data folder
report_errorEngineError or nullWhy the report could not be written

job://ended ​

A job ended on its own or failed. A job stopped with job_stop or jobs_stop_all does not send it.

FieldTypeMeaning
job_idnumberThe job
kindstringosc-monitor, osc-gen, http-burst, netsim, storm, scan, beacon, discovery, mqtt, websocket, emulator or experiment
errorEngineError or nullWhy it ended, when something went wrong

A run's job://ended carries the fields of experiment://ended too. What ends each kind:

kindEnds whenerror
osc-monitorThe socket can no longer receivewait.receive_failed
osc-genIts duration is over, or a send failsnull, or transport.*
http-burstIts total or duration is reachednull
stormIts duration is overnull
scanEvery port of the range was triednull
beaconIts rounds or duration are over, or more than 32 sends failed with none sentnull, or transport.*
discoveryThe socket can no longer receivewait.receive_failed
mqttThe broker closed the connection or it was losttransport.* (transport.reset when the broker closed it), or mqtt.protocol
websocketThe connection closednull, or why it was lost
netsimThe relay can no longer workwhy
emulatorIts socket failswhy
experimentThe run endsthe run's failure, or null

osc://message ​

One UDP packet an OSC monitor received, decoded. Sent for every packet, without batching.

FieldTypeMeaning
job_idnumberThe monitor's job
tsnumberWhen it arrived
fromstringThe sender, IP:port
bytesnumberThe packet's size
messagesobject[]Each message of the packet (a bundle has several): address and args (OscArg[])
errorEngineError or nullosc.packet_malformed when the packet did not decode (then messages is empty)

osc://gen-tick ​

An OSC generator's progress: for every message below 60 messages a second; above that for every n-th, n being the rate divided by 30 and rounded down — 30 to 45 times a second.

FieldTypeMeaning
job_idnumberThe generator's job
tsnumberWhen
valuenumberThe value just sent, before it is rounded to an integer or to a 32-bit float
sentnumberMessages sent so far

http://burst-progress ​

An HTTP burst's numbers, every 100 ms while it runs, and once more with done: true when it ends on its own.

FieldTypeMeaning
job_idnumberThe burst's job
tsnumberWhen
sentnumberRequests answered or failed so far
oknumberOf those, answered with a 2xx status
failednumberOf those, any other status or no answer
missednumberA paced burst's requests that waited too long for a free worker and were skipped
rpsnumberRequests per second over the last 100 ms; in the last event, over the whole burst
last_latency_ms, min_latency_ms, max_latency_ms, avg_latency_msnumberLatencies so far
p50_ms, p90_ms, p95_ms, p99_msnumberPercentiles of every request so far, failures included, within 0.5 %
donebooleanThe last event of the burst

ws://state ​

A WebSocket connection opened by ws_connect connected, or closed. A connection whose job was stopped sends no closed.

FieldTypeMeaning
job_idnumberThe connection's job
tsnumberWhen
statestringconnected or closed
handshakeobjecturl, peer, local, protocol (the subprotocol the server chose, or null) and ms (connecting and the upgrade)
closedobject or nullWith closed: code, reason, by (client, server or lost) and error

ws://messages ​

What a WebSocket connection sent and received since the last event, every 100 ms when there is something.

FieldTypeMeaning
job_idnumberThe connection's job
tsnumberWhen
messagesobject[]In order: ts, dir (rx received, tx sent), kind (text or binary), text (the first 64 KiB as UTF-8, a binary message's too; bytes that are not become �), hex (a binary message's first 4096 bytes as hex, else null), bytes (the full size) and truncated (more than was shown: past 64 KiB of text, past 4096 bytes of binary)
droppednumberMessages left out of this event because there were more than 2000; the oldest go first

mqtt://state ​

An MQTT connection's state changed.

FieldTypeMeaning
job_idnumberThe connection's job
tsnumberWhen
statestringconnected; subscribed after each answer to a subscribe; closed when the connection ended (not when its job was stopped)
brokerstringhost:port
errorEngineError or nullWhy a closed connection ended (transport.reset when the broker closed it); null otherwise
grantsobject[]With subscribed: each filter asked for, with filter, qos (granted) and accepted; empty otherwise

mqtt://messages ​

What an MQTT connection received since the last event, every 100 ms when there is something. A redelivered QoS 2 message is shown once.

FieldTypeMeaning
job_idnumberThe connection's job
tsnumberWhen
messagesobject[]ts, topic, payload (as UTF-8; bytes that are not become �), bytes, qos, retain, dup
droppednumberMessages left out because more than 4000 arrived in 100 ms; the oldest go first

mqtt://ack ​

The broker completed something the connection asked for.

FieldTypeMeaning
job_idnumberThe connection's job
tsnumberWhen
kindstringpublished (a QoS 1 or 2 publish is complete) or unsubscribed
packet_idnumberThe MQTT packet id
topicstring or nullThe published topic; null for unsubscribed

broadcast://emit-stat ​

A beacon's counters, every 250 ms, and once more when it ends on its own with pps 0.

FieldTypeMeaning
job_idnumberThe beacon's job
tsnumberWhen
targetsnumberDestinations in each round
roundsnumberRounds sent
packets, bytesnumberDatagrams and bytes sent
errorsnumberSends that failed
ppsnumberDatagrams per second over the last 250 ms

broadcast://peers ​

What a discovery listener has heard, every 400 ms.

FieldTypeMeaning
job_idnumberThe listener's job
tsnumberWhen
peersobject[]Most recently heard first: addr, proto, packets, bytes, first_ms, last_ms, last_summary, responded (its packets that were answered, counted as they arrived); at most 512
packets, bytesnumberEverything received
responsesnumberAnswers sent

netsim://stat ​

An impairment relay's counters, every 250 ms. Relays of a run's Impairment nodes report in the run's report instead.

FieldTypeMeaning
job_idnumberThe relay's job
tsnumberWhen
received, forwardednumberDatagrams or chunks in and out
droppednumberLost to loss, bursts or offline (UDP; a TCP relay holds a stream while offline and drops nothing)
throttlednumberUDP: dropped by the bandwidth limit, or because too many were already on their way. TCP: chunks that held their stream back for the bandwidth limit
duplicated, corrupted, reorderednumberWhat the profile did to them
bytesnumberBytes passed on
connections, reset, stallednumberTCP: connections taken, reset, left half-open; left out while 0
profilestringThe profile it impairs with now, as the timeline names it: its name, or what it does (60 ms ±25 · loss 2%)

storm://stat ​

A storm's counters, every 250 ms, and once more when it ends on its own with pps and mbps 0.

FieldTypeMeaning
job_idnumberThe storm's job
tsnumberWhen
packets, bytesnumberDatagrams (or TCP connections) and bytes sent
errorsnumberSends or connections that failed
ppsnumberPer second over the last 250 ms
mbpsnumberMegabits per second over the last 250 ms

scan://open ​

The scanner found an open port.

FieldTypeMeaning
job_idnumberThe scan's job
tsnumberWhen
portnumberThe port
bannerstring or nullWhat the service sent first, when banners were asked for and it said something within 400 ms

scan://progress ​

How far a scan is: about every 1 % of the range, and when it ends on its own with done equal to total (that one can arrive twice).

FieldTypeMeaning
job_idnumberThe scan's job
tsnumberWhen
donenumberPorts tried
totalnumberPorts in the range
opennumberOpen ports found

emulator://activity ​

What an emulator started with emulator_start received and answered since the last event, every 200 ms when something changed (an exchange, being taken down or brought up, or a message the MQTT broker could not deliver). The Emulator nodes of a run do not send it; their counters are in the run's report.

FieldTypeMeaning
job_idnumberThe emulator's job
tsnumberWhen
countsobjecttotal, unmatched, failed, down, hits (per rule), and missed (MQTT; left out while 0) — as emulator_exchanges
forcedstringunavailable, reset or timeout while it is taken down; left out otherwise
exchangesobject[]The new exchanges, as emulator_exchanges lists them but without data; at most 200
droppednumberExchanges past the first 200 of the interval, not sent here; emulator_exchanges still has the last 500

inspect://batch ​

New Inspector frames. Sent only while capture is armed: every 120 ms when there are new frames, and about once a second when there are none, so the counters stay current.

FieldTypeMeaning
framesobject[]The new frames, oldest first, at most 250; without their bytes (use inspect_payload)
statsobjectThe capture's counters, CaptureStats
skipped_nownumberFrames captured since the last batch but not in this one — more than 250 arrived, or the buffer let them go. They are still in an export while the buffer holds them

server://lagged ​

Server only. This client fell more than 4096 events behind and missed some. Read the state again with commands.

FieldTypeMeaning
skippednumberHow many events it missed