Server log
The Server logs one line per event: what it admitted, refused and measured. This page lists every event, field and reason. Hosting a Server shows how to set the log up.
Event names, field keys and the values below settle during 0.x and become stable from 1.0, as Stable interfaces explains. New ones may appear, so ignore those you don’t know.
Format
The log is human-readable by default:
2026-09-26T14:46:25.579954Z INFO listening on 0.0.0.0:24700 event="Listening" address=0.0.0.0:24700
2026-09-26T14:46:26.621011Z INFO Test Connection admitted event="TestConnectionAdmitted" test_connection_id=1 client="127.0.0.1:51801" mc_ident=60798
2026-09-26T14:46:26.621208Z INFO Test Connection activated event="TestConnectionActivated" test_connection_id=1 direction="Downstream"
2026-09-26T14:46:37.129642Z INFO the Test Connection's Data Phase completed event="DataPhaseEnded" test_connection_id=1 reason="Completed" fast_paths="sendmmsg,UdpGso,recvmmsg,KernelRxTimestamps,epoll"
2026-09-26T14:46:37.129734Z INFO Test ended: Completed event="TestSummary" client=127.0.0.1:51801 mc_ident=60798 test_connections=1 direction="Downstream" test_interval=10 … bytes_sent=1144801422 bytes_received=1110936104 ip_layer_sender_bit_rate=933913704 result="Completed"
With log_format = "json", each line is one JSON object:
{"timestamp":"2026-09-26T14:51:10.061951Z","level":"INFO","message":"Setup Request refused","event":"SetupRequestRejected","client":"anon-63d4269f2e4b0c0d","reason":"MaxBandwidthRequired"}
Every event has an event name and its data in fields. A field means one thing wherever it appears, and is left out when an event has nothing for it. The message is for people and may change, so filter on event and the fields.
In a terminal, the human log colours its level labels: INFO cyan, WARN yellow and ERROR red. --color auto|always|never controls this, as Terminal color describes. JSON logs and log files are always plain.
Where it goes
The log goes to standard output, and startup warnings and errors to standard error. With log_file set, the Server writes a new file each day named from it, so /var/log/udpstp/server.log gives server.2026-10-01.log (the date in UTC). It keeps the last 14, and copies its startup errors and warnings into them as StartupError and StartupWarning.
Give log_file a folder of its own: the Server deletes the oldest file whose name starts and ends as the log’s does, whatever wrote it. A Windows service always logs to files. Elsewhere, leave the log to the service manager: logrotate’s renames would fight the Server’s own files, and SIGHUP stops the Server rather than reopening them.
Events an attacker can cause are rate-limited, ten of a kind every 10 s, so a flood can’t fill the disk. The rest are counted in a Suppressed event.
Fields
| Field | Type | What |
|---|---|---|
test_connection_id | integer | The Test Connection, the same in each of its events; left out for the Standard Port |
client | string | The Client’s address, as address_privacy shows it |
mc_ident | integer | The Test’s mcIdent. With client, it identifies the Test |
key_id | integer | The keyId of the Key Table row that authenticated the Test |
reason | string | Why, a name from a fixed set (below) |
count | integer | How many times it happened since the last such event |
error | string | The operating system’s error, in its words: free text |
direction | string | Upstream or Downstream |
parameter, requested, coerced | string, integer, integer | An Activation parameter by its RFC 9946 name, the value the Client asked for, and the value the Server gave |
row | integer | A Sending Rate Table row |
requested_bytes, receive_bytes, send_bytes | integer | Socket buffer sizes: asked for, and what the OS gave |
bursts, datagrams, bytes | integer | Bursts not sent, their Load PDUs, and their UDP payload bytes |
executor, engine_threads, grouping_us | string, integer, integer | How the Data Phase Engines run (DataPhaseEngines) |
fast_paths | string | The fast paths a Test Connection used (DataPhaseEnded) |
receive_buffer_overflows | integer | On Linux, datagrams the OS discarded at the socket before the Server read them, mostly for a full receive buffer |
send_lag_samples, send_lag_p50_us, send_lag_p99_us, send_lag_max_us, burst_lateness_p99_us | integer | Experimental send timing, in µs (DataPhaseEnded) |
Events
Starting and stopping
| Event | When | Fields |
|---|---|---|
DataPhaseEngines | At start: how the Data Phase Engines run (below) | executor, grouping_us, engine_threads, error |
Listening | The Server listens on an address | address |
NoIpv6Listener | The host has no IPv6, so the Server listens on IPv4 alone | error |
TroubleshootingModeOn | At start, and every minute while Troubleshooting Mode is on | |
StartupError | With log_file set: the Server couldn’t start | error, the message (free text); exit_status |
StartupWarning | With log_file set: a warning at startup | reason: DscpAskedAsZero, DscpCoercedToZero, DontFragmentUnsupported, AdmittedRateCapWithoutMaxBandwidth, NoTestAdmissible, TroubleshootingModeOn, SocketBuffersShort, SocketBuffersUnknown, MaxHopsNotSet or TestsPerSource |
Stopping | The Server was asked to stop. It ignores new Setup Requests, sends STOP to its active Test Connections and ends them | reason: SIGTERM, SIGINT or SIGHUP; on Windows CtrlC, CtrlBreak, CtrlClose or CtrlShutdown; as a Windows service ServiceStop or ServiceShutdown |
Setup and Activation
| Event | When | Fields |
|---|---|---|
TestConnectionAdmitted | A Setup Request was accepted | test_connection_id, client, mc_ident, and key_id in an authenticated mode |
SetupRequestRejected | A Setup Request was refused with a Setup Response | client, reason |
SetupRequestSilentlyRejected | A Setup Request was refused without a response (Silent Rejection) | client, reason |
SetupRequestIgnored | A Setup Request was ignored: DuplicateSetupRequest, a copy of one already answered; ArrivalAddressUnknown, which the Client retries; or ServerStopping | client, reason |
TestConnectionActivated | An Activation Request was accepted | test_connection_id, direction |
ActivationParameterCoerced | The Activation Response changed a parameter | test_connection_id, parameter, requested, coerced |
ActivationRequestRejected | An Activation Request was refused | test_connection_id, reason, and parameter for UnacceptableParameter |
ActivationRequestSilentlyRejected | An Activation Request was refused without a response | test_connection_id, reason |
ActivationWatchdogExpired | No valid Activation Request came within 3 s | test_connection_id |
UnactivatedTestConnectionEvicted | The Unactivated Test Connections filled their share, so the oldest of the Key Table row holding the most was closed to make room | test_connection_id |
The Data Phase
| Event | When | Fields |
|---|---|---|
FirstLoadPduReceived, FirstStatusPduReceived, StopReceived | The first Load PDU or Status PDU, and the STOP exchange | test_connection_id |
BurstsSkipped | This host fell behind sending load, so the Server, not the path, limited the Test | test_connection_id, bursts, datagrams, bytes |
BurstsWithheld | The send buffer was full | test_connection_id, bursts, datagrams, bytes |
InvalidLoadPdus, IgnoredLoadPdus, InvalidStatusPdus, StaleStatusPdus, StatusPdusFailedVerification, StatusPdusMissing, PeerMissedStatusPdus, PeerRxStopped, DelaySamplesDropped, IcmpErrors | PDUs ignored or missing, and ICMP errors, counted | test_connection_id, count |
PathMtuExceeded, HopLimitExceeded | Datagrams too large for the path with DF set, or expired on the way because max_hops is too small | test_connection_id, count |
LostStatusBackoff | No Status PDU came in time, so a Downstream Search Test backed off as for an Errored Interval | test_connection_id, row |
TrafficStopped | Nothing arrived for 1 s, so this end stopped sending | test_connection_id |
DataPhaseEnded | A Test Connection’s Data Phase ended (below) | test_connection_id, reason, fast_paths, receive_buffer_overflows, error |
TestConnectionReleased | A Test Connection ended and its Admission was released | test_connection_id |
TestSummary | A Test ended (below) |
Problems and counts
| Event | When | Fields |
|---|---|---|
SocketError, NoEphemeralPort | A socket failed, or no Ephemeral Port was free | test_connection_id (none for the Standard Port), error |
SocketBuffersShort | The OS held a Test Connection’s socket buffers below socket_buffer_size | test_connection_id, requested_bytes, receive_bytes, send_bytes |
DatagramsDropped | The Server’s Control Phase fell behind and discarded datagrams its socket readers had received. This is udpstp’s own queue, not a Receive Buffer Overflow | test_connection_id (none for the Standard Port), count |
Statistics, StatisticsRefusals | Every statistics_interval seconds, and once more when the Server stops (below) | |
Suppressed | Events of one kind beyond ten every 10 s, counted rather than logged | suppressed_event, count, and the sums of what they carried: bursts, datagrams and bytes, or suppressed_count for events with a count |
DataPhaseEngines
executor is pool on Linux, where Engine Threads each serve many Test Connections, or per_test_connection on Windows and macOS, where each Test Connection has an Engine Thread of its own.
For pool, engine_threads is the most it starts: one for each CPU the process may use, with a fractional cgroup CPU quota rounded down, so a container limited to 1.9 CPUs gets 1. error is a warning when the CPUs the process may use couldn’t be found.
grouping_us is the pool’s wake-up grouping window, 0 by default and for per_test_connection. The experimental variables UDPSTP_ENGINE_THREADS and UDPSTP_ENGINE_GROUPING_US override engine_threads and grouping_us.
DataPhaseEnded
reason says how the Data Phase ended (below). error names the failure when the Data Phase Engine failed.
fast_paths lists, comma-separated, the fast paths the engine sent Load PDUs, read datagrams and waited with. It is empty except on Linux, where it can hold:
sendmmsgandUdpGsowhen the Server sent Load PDUs (not in an Upstream Test);recvmmsgandKernelRxTimestamps;epollwhen one of the Server’s Engine Threads served the Test Connection.
With the experimental UDPSTP_KERNEL_TX_TIMESTAMPS=1 on Linux 6.13 and later, each message goes with a sendmsg call of its own, so UdpGso appears without sendmmsg, unless the kernel refuses the timestamps. A Load Sender’s event then adds send_lag_samples, send_lag_p50_us, send_lag_p99_us and send_lag_max_us: how much later than its lpduTime the kernel sent the Load PDUs it stamped. burst_lateness_p99_us, also experimental, is how late a Load Sender wrote its Send Plans, 99th percentile.
receive_buffer_overflows, on Linux, counts datagrams the OS discarded at the socket before the Server read them. In an Upstream Test the Client counts them as lost.
TestSummary
A TestSummary has:
client,mc_ident,key_id(in an authenticated mode) andtest_connections;bytes_sentandbytes_received, the UDP payload bytes of the Load PDUs the Server sent and received;ip_layer_sender_bit_rate, in bit/s, when the Server was the Load Sender;- what the Server didn’t send as Load Sender, over all its Test Connections:
skipped_bursts,skipped_datagramsandskipped_byteswhen it fell behind, andwithheld_bursts,withheld_datagramsandwithheld_byteswhen the send buffer was full; receive_buffer_overflows, on Linux, summed over its Test Connections;result:Completed;ServerStoppingfor a Test cut short when the Server stopped; how the first Test Connection that didn’t complete ended (aDataPhaseEndedreason,ActivationWatchdogExpired,UnactivatedTestConnectionEvicted, orActivationRequestRejectedwith itsreason); orNotActivated.
A Test that was activated adds its direction and parameters: test_interval (s), sub_interval and trial_interval (ms), low_thresh and upper_thresh (ms), seq_err_thresh, slow_adj_thresh, high_speed_delta, ignore_ooo_dup, one_way_delay_variation and random_payload (booleans), rate_adj_algo (B or C), dscp, sr_index_conf and sr_index_is_start.
Statistics
Statistics counts since the Server started: tests, test_connections, active_test_connections, authentication_failures (requests, and Status PDUs in mode 2), rate_limited (Setup Requests over a budget), stale_status_pdus, setup_requests_ignored and unactivated_test_connections_evicted.
It has a report number. One StatisticsRefusals line with the same report follows for each kind of refusal counted so far, with kind (the event that logged it), its reason and count. The counts overlap: a request refused for its authentication counts in authentication_failures and in its StatisticsRefusals, and one over a budget in rate_limited too.
Reasons
- For
DataPhaseEnded, how it ended:Completed,Unconfirmed(the Client didn’t confirm the STOP),StoppedByClient,Watchdog,OverRate(the Client sent above 1.5 times its rate),Stopped(the Server stopped it) orDataPhaseEngineFailed. - For a Setup Request:
TestsPerSource,TestConnectionsPerTest,TestConnections,MaxBandwidthRequired,CapacityExceeded,SocketUnavailable,QuotaExceeded,SourceBudgetExhausted,BadVersion,JumboMismatch,TraditionalMtuMismatch,Malformed,MulticastOrBroadcast,ChecksumFailed,Replayed,ReplayCacheFull,UnverifiedBudgetExhausted, or a Multi-Connection field’s fault:MultiConnectionIdentZero,MultiConnectionIndexNotBelowCount,MultiConnectionIndexInUse,MultiConnectionCountDiffers,MultiConnectionAuthModeDiffers,MultiConnectionKeyIdDiffers. - For an Activation Request:
InvalidCommand,MixedDirection,UnacceptableParameter,FixedRateNeedsOperatorKey,TestsPerSource,TestConnections,MaxBandwidthDirection,CapacityExceeded,QuotaExceeded,AuthModeMismatch,KeyIdMismatch,MulticastOrBroadcast,ChecksumFailed,Replayed,ReplayCacheFull,NotFromClient,Malformed. - For an authentication failure, whether Troubleshooting Mode answered it or not:
AuthenticationRequired,AuthenticationNotConfigured,AuthenticationModeInvalid,AuthenticationUnknownKeyId,AuthenticationKeyOutsideLifetime,AuthenticationDigestFailed,AuthenticationTimeOutOfWindow.