Diagnostics

Opt-in logging, instrumentation, and progress reporting. pytcl is silent by default; see Diagnostics Guide for the narrative guide and the opt-in policy.

Diagnostics: opt-in logging, instrumentation, and progress reporting.

pytcl is completely silent by default: importing it disables the pytcl loguru namespace and installs no handlers. Call enable_debug_logging() to see gating rejections, association decisions, filter-health symptoms, and data-file resolution at DEBUG level; disable_debug_logging() returns to silence. This module is the redesigned successor to the pytcl.logging_config module removed in v2.0.0; no compatibility is provided.

Examples

>>> import pytcl
>>> pytcl.diagnostics.diagnostics_enabled()
False
pytcl.diagnostics.diagnostics_enabled()[source]

Whether diagnostic logging is currently enabled.

Hot paths consult this before constructing log payloads, so the disabled path costs one boolean check.

pytcl.diagnostics.enable_debug_logging(level='DEBUG')[source]

Enable pytcl’s diagnostic logging with a rich-formatted handler.

Parameters:

level (str, optional) – Minimum level to emit (“DEBUG”, “INFO”, “WARNING”, …).

Notes

Idempotent: calling again replaces the previous handler rather than stacking a second one. Output goes to stderr, ASCII-safe.

A bad level raises before anything is touched: the new handler is added first, so the failure happens while state is still exactly what it was before the call (namespace disabled, or however a prior successful call last left it).

loguru installs a default stderr handler (id 0) at import time; left alive, it double-prints every record next to the one pytcl’s own handler emits. This function removes it the first time diagnostics are enabled and remembers that it did so; disable_debug_logging() then puts an equivalent handler back (logger.add(sys.stderr), loguru’s own default configuration) so the host application’s logging is not left worse off than before pytcl touched it. That replacement is loguru’s stock handler, not a byte-for-byte restoration of whatever the host had configured at id 0 – if the host had customized it, this function has no way to know and does not try to reproduce it.

pytcl.diagnostics.disable_debug_logging()[source]

Return the library to complete silence. Idempotent.

If enable_debug_logging() removed loguru’s default stderr handler to prevent double-printing, this restores an equivalent one (see that function’s docstring for the exact caveat).

pytcl.diagnostics.track_table(tracks, console=None)[source]

Render a summary table of tracks to the console.

Parameters:
  • tracks (sequence) – Track objects with id, status, state (and optionally covariance) attributes, e.g. from MultiTargetTracker.process.

  • console (rich.console.Console, optional) – Target console; defaults to stderr. Output is ASCII-only (box.ASCII) to satisfy the console-encoding contract.

pytcl.diagnostics.progress_bar(iterable, description='working', total=None)[source]

Wrap an iterable in an ASCII progress bar on stderr.

Yields the items unchanged; the bar completes when iteration ends.

Notes

Uses a pure-text progress display (no Unicode block-bar column): rich’s default BarColumn renders with Unicode block characters that are not cp1252-encodable, which the console-encoding contract forbids.

pytcl.diagnostics.log_filter_health(track_id, nis_value, nis_window, cov_condition)[source]

Log a per-track filter-health snapshot (NIS + covariance condition).

Guarded internally by diagnostics_enabled() – callers on a hot path may call this bare without checking first, since a disabled namespace makes the call a single boolean-check no-op. Plain floats/sequences only; this module takes no dependency on pytcl’s tracker types.

Parameters:
  • track_id (Any) – Identifier of the track this health snapshot belongs to.

  • nis_value (float) – Normalized innovation squared for the current update.

  • nis_window (sequence of float) – Recent NIS history used as the local baseline for outlier detection. Includes the current sample, per call-site convention.

  • cov_condition (float) – Condition number of the track’s state covariance.

Notes

Symptomatic (logged at WARNING instead of DEBUG) when either:

  • nis_value exceeds NIS_OUTLIER_FACTOR times the mean of nis_window AND that mean is positive – with an empty or all-zero window the NIS branch cannot fire regardless of nis_value, since any threshold scaled from a zero mean would flag everything – or

  • cov_condition exceeds CONDITION_WARN (covariance going numerically singular).

The caller owns nis_window’s lifecycle; this function only reads it. Callers that keep a rolling window across an enable/disable toggle (as MultiTargetTracker does) will blend pre-disable history into the first post-re-enable call – that’s a call-site persistence choice, not something this function corrects.

Rendering

Rich-based track tables and progress bars, ASCII-safe for redirected stdout on Windows.

Rich-based rendering: track tables and progress bars, ASCII-safe.

pytcl.diagnostics.render.track_table(tracks, console=None)[source]

Render a summary table of tracks to the console.

Parameters:
  • tracks (sequence) – Track objects with id, status, state (and optionally covariance) attributes, e.g. from MultiTargetTracker.process.

  • console (rich.console.Console, optional) – Target console; defaults to stderr. Output is ASCII-only (box.ASCII) to satisfy the console-encoding contract.

pytcl.diagnostics.render.progress_bar(iterable, description='working', total=None)[source]

Wrap an iterable in an ASCII progress bar on stderr.

Yields the items unchanged; the bar completes when iteration ends.

Notes

Uses a pure-text progress display (no Unicode block-bar column): rich’s default BarColumn renders with Unicode block characters that are not cp1252-encodable, which the console-encoding contract forbids.