MetricsTracker
MetricsTracker(writers: list[MetricsWriter] | None = None, min_write_interval_seconds: float = 1.0) -> NoneTracker for logging metrics to one or more MetricsWriters.
Writes are time-gated per tag: a tag is written through at most once per min_write_interval_seconds, with the latest suppressed value written on flush / close or when the tag's gate reopens. Totals, percentages and rolling-window aggregates lose nothing from this — at episode rates of tens per second, per-episode writes add file volume but no information to a chart — while infrequent tags are never delayed because the first write after an idle period always passes the gate.
Safe to call concurrently from multiple threads (for example learner, actor, tester, and the system-metrics thread all log through the same tracker); internal state is guarded by a lock.
Initialize the MetricsTracker.
Parameters:
writers(list[MetricsWriter] | None) – List of MetricsWriter instances to write metrics to.min_write_interval_seconds(float) – Minimum interval between writes of the same tag; 0 disables the gate.
Properties
writers
writers: list[MetricsWriter]Get the list of active writers.
Returns:
list[MetricsWriter]– The list of MetricsWriter instances.
Methods
add
add(tag: str, value: float, step: int) -> NoneLog a scalar value to all writers.
Writes are time-gated per tag; a value suppressed by the gate is kept and written when the gate reopens or the tracker is flushed, so the latest value is never lost.
Parameters:
tag(str) – The metric tag.value(float) – The scalar value.step(int) – The global step.
add_averaged
add_averaged(tag_prefix: str, value: float, step: int, window_size: int = 100) -> NoneAdd a value to a rolling window and log average/min/max/std to all writers.
Parameters:
tag_prefix(str) – Prefix for metric tags.value(float) – The scalar value.step(int) – The global step.window_size(int) – Size of the rolling window.
add_buffered
add_buffered(tag_prefix: str, value: float) -> NoneAdd a value to a deferred scalar-stat accumulator.
Unlike add_averaged, this does not emit immediately. Call flush_buffered later to write _Avg / _Min / _Max / _Std.
Parameters:
tag_prefix(str) – Prefix for metric tags.value(float) – The scalar value.
add_histogram
add_histogram(tag: str, bin_edges: Sequence[float], bin_counts: Sequence[float], step: int) -> NoneLog a pre-binned histogram to all writers. Not time-gated; callers emit these once per rollout.
Parameters:
tag(str) – The metric tag.bin_edges(Sequence[float]) – Then + 1bin boundaries, ascending.bin_counts(Sequence[float]) – Thenbin heights.step(int) – The global step.
add_windowed
add_windowed(tag_prefix: str, outcome: str, step: int, outcomes: list[str], window_size: int = 100) -> NoneAdd an outcome to a rolling window and log percentages for each tracked outcome to all writers.
Internally manages a WindowedMetric per tag_prefix. For each outcome in the outcomes list, logs a percentage scalar with the tag {tag_prefix}/{Outcome}/Last-{window_size}/Percentage.
Parameters:
tag_prefix(str) – Prefix for metric tags.outcome(str) – The outcome category to add (for example, "win", "loss", "truncated").step(int) – The global step.outcomes(list[str]) – List of outcome categories to log percentages for.window_size(int) – Size of the rolling window.
close
close() -> NoneWrite any gate-suppressed values, then close all writers and release resources.
flush
flush() -> NoneWrite any gate-suppressed values and flush all writers.
flush_buffered
flush_buffered(tag_prefixes: Iterable[str], step: int) -> NoneEmit and clear one or more deferred scalar-stat accumulators.
Missing tags are ignored so callers can keep a stable set of known tags.
Parameters:
tag_prefixes(Iterable[str]) – Metric tag prefixes to flush.step(int) – The global step.
get_average
get_average(tag_prefix: str) -> float | NoneGet the last computed rolling average for a metric.
Parameters:
tag_prefix(str) – The metric tag prefix.
Returns:
float | None– The last computed average value, or None if no values have been recorded.
log_config
log_config(config: BaseModel) -> NoneLog the experiment configuration to all writers.
Parameters:
config(BaseModel) – The configuration object to log.
should_write
should_write(tag: str) -> boolCheck whether a write for a tag would currently pass the time gate, without consuming it.
Use this to skip computing expensive metric values whose write would only be held as a pending value anyway; skipped values are simply not pending, so the previously written value stands until the gate reopens.
Parameters:
tag(str) – The metric tag.
Returns:
bool– True when anaddfor the tag would write through now.