Logs#
micromux captures each service’s output two ways at once:
- an in-memory tail — bounded and fast, backing the TUI and the default log stream;
- disk-backed run logs — the newest 64 MiB segment of recent runs, retained so you can inspect crash output after a restart.
logs:
retained_runs: 5 # bounded disk-backed runs kept, including the current one
memory:
max_lines: 1000
max_bytes: 67108864 # 64 MiB
services:
api:
command: "./run-api"
logs:
retained_runs: 10 # overrides the global default for this serviceRetained runs#
retained_runs (aliases: runs, history; default 5) is how many service runs are kept on disk, counting the current run. Each restart starts a new run; when the count is exceeded the oldest run is dropped. This is what lets an agent read the logs of the run that crashed even though the service has since restarted. A run file rotates in place at 64 MiB, preserving its newest segment so a single long-lived or noisy process cannot consume disk without limit.
List the retained runs and read a specific one with the control plane:
micromux ctl log-runs api
micromux ctl logs api --run-generation 2 --tail 200In-memory tail#
memory.max_lines and memory.max_bytes bound the in-memory tail that the TUI and default log stream use, so a chatty service can’t grow memory without limit. Each accepts a positive integer or an explicit unbounded (synonyms: unlimited, none):
logs:
memory:
max_lines: unbounded # keep every line in memory
max_bytes: 134217728logs.max_lines and logs.max_bytes are accepted as shorthand for the nested memory.* form.
Inheritance#
Like restart and healthcheck timing, logs set at the top level is inherited by every service, and a service’s logs block overrides only the fields it sets — the rest fall back to the global values.
Structured JSON logs#
Services that emit JSON logs are rendered in the TUI as compact, colored log lines by default, while the raw JSON is preserved for the control plane and MCP tools. Turn the pretty rendering off per run with --no-pretty-json-logs, or globally:
ui:
pretty_json_logs: falseViewing structured logs#
Let a service log verbosely and decide in the TUI how much of it to see. level sets the initial level threshold, timestamps whether lines lead with their local time, fields which field keys to leave out of the display, and filter_fields whether they start out left out. Top-level values are defaults for every service:
logs:
level: debug # all, debug, info, warn, or error; trace means all
timestamps: true # the default
filter_fields: true # the default; false starts with every field shown
fields: {filename: hide, line_number: hide, span: hide, spans: hide}
services:
api:
command: "RUST_LOG=trace ./run-api"
logs:
timestamps: false # level, timestamps, and filter_fields replace the default
fields: # fields merge into the default key by key
span: show # undo an inherited hide
latency: hide # hide one moreLines without a structured level, such as build output and panic messages, are never hidden. fields keys match top-level keys and the keys of a tracing-style nested fields object exactly. In the TUI, L changes the threshold, T toggles the timestamps, and F shows the hidden fields again, each for the selected service. A config reload applies new logs display settings without restarting the service.
These settings affect only the TUI. Agents reading logs always get every record, field, and timestamp.
Over MCP, JSON logs can be filtered by structured level (min_level) and returned in a token-efficient compact form; each entry carries its detected level, timestamps, message, and typed fields.