models.monitor¶
Pydantic boundary models for the monitor subsystem.
Two seams:
MetricPoint— the in-memory series element (replaces the old(ts, value, meta)3-tuple inMetricCollector._series). It is anOttoModel(extra='forbid') because otto is the only thing that builds it: the live append path usesmodel_construct(no validation, hot loop) and the import path usesmodel_validate.MetricRecord/EventRecord— flat records at the JSON--fileand SQLite import/export boundary. These read historical, external data, so they are deliberately lenient (extra='ignore', viaRowModel): an unknown column from a newer schema is dropped, not rejected, exactly as the old.get()/[]parsing did. Field names follow the JSON spelling; avalidation_aliasalso accepts the SQLite column spelling (ts/end_ts) so one model validates both seams.
Leaf isolation: this module imports only otto.models.base, pydantic, and
the stdlib — no runtime or otto.monitor edge — so it stays a pure leaf inside
the models package.
-
class otto.models.monitor.MetricPoint(*, ts: datetime, value: float, meta: dict[str, Any] | None =
None)¶ Bases:
OttoModelA single charted sample: timestamp, numeric value, optional hover meta.
Replaces the
(datetime, float, dict | None)tuple stored per series. Consumers read.ts/.value/.metainstead of unpacking.
- class otto.models.monitor.RowModel¶
Bases:
BaseModelLenient base for historical-data import/export rows.
Unlike
OttoModel(extra='forbid', which exists to turn a config typo into an error), data read-back is tolerant: an unexpected key/column from a newer schema is ignored rather than rejected. This matches the pre-pydantic.get()/[]parsing and keeps older otto builds able to import exports written by newer ones.
-
class otto.models.monitor.MetricRecord(*, timestamp: datetime, host: str =
'', label: str, value: float, meta: dict[str, Any] | None =None)¶ Bases:
RowModelOne
metricsrow at the JSON / SQLite import-export boundary.The JSON
--fileformat spells the time keytimestamp; the SQLitemetricstable column ists. Thevalidation_aliasaccepts both, so a single model validates either seam.hostis optional for the pre-host-column schema;metarides only in JSON (the DB has no meta column). Exporting withmodel_dump(mode='json', exclude_none=True)emits the JSON spelling and omitsmetawhenNone(host=''is still emitted — empty string is notNone).
-
class otto.models.monitor.EventRecord(*, id: int | None =
None, timestamp: datetime, end_timestamp: datetime | None =None, label: str ='', source: str ='manual', color: str ='#888888', dash: str ='dash')¶ Bases:
RowModelOne
eventsrow at the JSON / SQLite import boundary.Mirrors the
MonitorEventfields. Used to validate external event data before constructing the (unchanged, mutable)MonitorEventdataclass — event export staysMonitorEvent.to_dict().timestampis required (a row without one is skipped, as before); everything else defaults.idisNonewhen absent so the collector can assign its running id.