tetrak_ocr.telemetry

Append-only run log: what was processed, by which backend, and how long it took.

A long batch is otherwise silent about its own cost. auto-local prints its score table only once every backend has finished, so a file that takes forty minutes looks identical to one that has hung – and when it does finish, the table says which backend won but not which one spent the time.

This module records that as it happens. Every event is one JSON object on one line, flushed immediately, so tail -f on the log is a live progress view and the finished file is a dataset:

{“ts”: “…”, “run”: “20260822T115103Z-7f3a”, “event”: “backend_finish”,

“file”: “camera-1919.pdf”, “backend”: “marker”, “seconds”: 2246.8, …}

JSON Lines rather than CSV because the fields differ per event and will grow; rather than a database because appending a line is atomic enough for a sequential pipeline and needs nothing installed to read it back.

The sink is process-global. That is deliberate: backends expose a fixed ocr_image(path) -> str signature with nowhere to thread a logger through, and the fan-out is documented as sequential, so there is no concurrent writer to coordinate. When no run has been started every call is a cheap no-op, which is what keeps the library usable as a library.

Functions

active()

describe_file(path)

The file facts worth having on every record about it.

finish_run(**fields)

Close out the current run and detach the sink.

log_path()

record(event, **fields)

Emit an event if a run is active, otherwise do nothing.

start_run([path])

Begin recording, returning the log (or None when disabled).

timed(event, **fields)

Time a block and emit event with its duration, success or not.

Classes

TelemetryLog(path, run_id)

One run's worth of events, appended to a JSON Lines file.