Logs
spx_core/system/logs.py adds a logs component to every model and instance. It captures records emitted by the component’s logger into an in-memory deque so that the REST API and UI can stream diagnostics per instance without tailing external files.
When it is created
The
Modelloader (model.py) instantiates alogschild automatically, using the optionalmodel.logssection from your YAML as configuration.Each model instance inherits its own
logschild, so/api/v3/system/logsreturns system-level output while/api/v3/system/instances/<name>/logsscopes to a specific instance.The component attaches a custom
logging.Handlerto the parent logger. It survivesstop()so post-run faults are still captured untildestroy().
Configuration example
model:
name: ble_demo
logs:
max_entries: 2000 # retain 2k most recent entries
level: DEBUG # capture everything at DEBUG or higher
format: "%(asctime)s %(levelname)s %(message)s"
datefmt: "%Y-%m-%d %H:%M:%S"
include_exception: true
include_stack: false
extra_fields: ["correlation_id", "request_id"]
# ... the rest of the model definition ...{
"model": {
"name": "ble_demo",
"logs": {
"max_entries": 2000,
"level": "DEBUG",
"format": "%(asctime)s %(levelname)s %(message)s",
"datefmt": "%Y-%m-%d %H:%M:%S",
"include_exception": true,
"include_stack": false,
"extra_fields": [
"correlation_id",
"request_id"
]
}
}
}Configuration fields
max_entries / capacity / size
integer
500
Maximum number of records kept in memory. Older entries are evicted FIFO.
level
string or int
INFO
Minimum severity captured. Accepts logging names (DEBUG, WARNING, …) or numeric levels.
format
string
%(asctime)s %(levelname)s %(name)s %(message)s
Renderer passed to logging.Formatter.
datefmt / date_format
string
None
Optional date format fed to the formatter.
include_exception
boolean
true
Store formatted tracebacks when exc_info is present.
include_stack
boolean
false
Preserve stack_info for records that capture it.
extra_fields
sequence of strings
[]
Additional LogRecord attributes to persist (e.g., correlation_id). Non-JSON values are stringified.
You can adjust max_entries at runtime via the API (PATCH /.../logs with {"attr": {"max_entries": {"value": 1000}}}) and the component resizes its internal deque without dropping the most recent entries.
Entry schema
The logs.tail() API returns a list of dictionaries with the following keys:
id: monotonically increasing sequence number.timestamp: Unix epoch seconds (float).asctime: UTC ISO-8601 string with millisecond precision.relative_ms: milliseconds since the logging system started.level/levelno: severity name and numeric value.logger:logging.Loggername that emitted the record.thread,process: human-readable thread and process names.message: plain message (record.getMessage()).rendered: final formatter output (includes format template).exception: formatted traceback wheninclude_exceptionis true and the record hasexc_info.stack: captured stack trace wheninclude_stackis true.Custom fields listed in
extra_fieldsplus common diagnostics (correlation_id,component,path) when present on the record.
All payloads are JSON-safe; non-serialisable values are converted to their repr().
API surface
Two public methods are exposed via the component API:
tail(limit=50, level=None): return the most recent entries up tolimit. Whenlevelis provided, only entries at or above that severity are returned.clear(): wipe the buffer. Equivalent toreset(), but leaves the handler attached so collecting resumes immediately.
Typical REST calls:
The same interface is used by the CLI and UI panels, enabling per-instance log viewers without shell access to the host.
Usage tips
Set
level: DEBUGtemporarily during QA to capture verbose diagnostics, then revert toINFOorWARNINGto avoid filling the buffer.Populate
extra_fieldswith identifiers (e.g.,correlation_id) to correlate simulator logs with API requests or external tooling.Combine instance-level logs with scenarios: trigger a scenario that emits warnings, then query
/logs/method/tailinside automated tests to assert the right message appeared.Use
include_exception: falsewhen you need to keep payloads compact (for embedded dashboards) and rely onmessage+renderedfor context.
Testing references
Integration tests in tests/test_spx_server/test_api_v3/test_basic_model.py cover:
tail()against the system-level component (test_logs_component_tail).Severity filtering via the
levelargument (test_logs_component_level_filter).Instance-scoped retrieval (
test_instance_logs_tail).
Consult those tests for end-to-end examples of exercising the API through HTTP.
Last updated

