Event logs

Event-log levels, fingerprints, event and trace tables.

handoverlab.eventlog

Event logs: fingerprints and tables.

An event log has one row per handover attempt and per link failure without a handover (see EVENT_FIELDS). Times are rounded to 0.1 ms, gains and offsets to 0.001 dB and positions to 0.1 m when the engine writes a row.

Fingerprint The SHA-256 of the canonical CSV of a log: a header with the field names, then one line per row in log order, fields separated by commas, numbers written with Python's shortest round-trip representation (repr(float); -0.0 is written as 0.0), lines ending in \n. It does not depend on how the log was stored (CSV, Parquet, memory), so a stored log can be checked against a recomputed one on any machine.

Levels How much a run keeps (LEVELS, event_level):

off      metrics and the fingerprint only (the default; tuning stages);
summary  the event log above (RunResult.events);
full     the event log plus a *trace* of the procedure
             (RunResult.trace, TRACE_FIELDS): the initial
             serving cell of every user, measurement reports,
             preparations, releases, configurations reaching the UE or
             lost, executions, attachments after a handover or a
             re-establishment, and failures.  The trace gives the serving
             cell of every user at any time (serving_cells).

The level never changes a result or the fingerprint: the fingerprint is
always that of the summary log.

Tables write_events writes the logs of several runs as one table with the columns seed, rule and EVENT_FIELDS: Parquet (typed columns, needs pyarrow) for a .parquet file name, CSV otherwise. read_events reads either back; write_trace and read_trace do the same for traces.

event_level(value: Any) -> str

Normalise an event-log level.

False/None -> "off", True -> "summary", or a name of LEVELS.

canonical_csv(events: Iterable) -> str

Canonical CSV text of an event log (rows as dictionaries or tuples in EVENT_FIELDS order).

fingerprint(events: Iterable) -> str

SHA-256 (hex) of the canonical CSV of an event log.

parquet_available() -> bool

True if pyarrow can be imported (needed for Parquet files).

to_columns(results: Sequence) -> Dict[str, list]

Event logs of results (RunResult with events) as columns.

write_events(results: Sequence, path: str) -> str

Write the event logs of results to path and return the path written.

.parquet writes Parquet if pyarrow is installed; without it the table is written as CSV next to it (.csv instead of .parquet) and a warning is issued. Any other name writes CSV.

read_events(path: str) -> List[dict]

Rows of an event table written by write_events (typed values, in file order).

write_trace(results: Sequence, path: str) -> str

Write the traces of results (runs at level full) as one table; returns the path written.

Columns: seed, rule and TRACE_FIELDS; Parquet or CSV as in write_events.

read_trace(path: str) -> List[dict]

Rows of a trace table written by write_trace (typed values, in file order).

trace_path(events_path: str) -> str

Name of the trace table that goes with an event table: events.parquet -> events-trace.parquet.

serving_cells(trace: Iterable[dict], n_users: int, times: Sequence[float])

Serving cell of every user at times from a trace: an array (len(times), n_users).

-1 while a user is executing a handover or re-establishing (not connected).

group_logs(rows: Iterable[dict]) -> Dict[Tuple[int, str], List[dict]]

Rows of an event table -> {(seed, rule): event log}.