Skip to content

Logging & Log Rotation

Madhyamas writes log events to both stdout (for tail and docker logs) and a rotating file at <log_path>/madhyamas.log (default ~/.madhyamas/logs/madhyamas.log). The binary manages its own rotation, so you don't need an external log-rotation daemon.

Why Rotation?

Without rotation, a long-running proxy can produce an unbounded log file (100 GB+ has been observed on busy deployments). The built-in RotatingFileWriter caps file size and prunes old archives automatically, so disk usage stays bounded.

Configuration

Log rotation is configured via the log_config section of the proxy config, the PATCH /api/logs endpoint, the madhyamas logs config CLI subcommand, or the madhyamas_update_log_config MCP tool.

FieldTypeDefaultDescription
enabledbooltrueMaster switch. When false, logs go to stdout only.
rotationobject{"mode": "daily"}Rotation strategy (see below)
max_filesint7Max archived files to keep (oldest pruned first)
max_file_size_mbint100Hard per-file size cap (MB) — safety net for time-based modes
json_formatboolfalseWrite structured JSON instead of human-readable text (restart required)

Rotation Modes

The rotation field is a tagged enum:

json
{"mode": "never"}                      // no time/size rotation (not recommended)
{"mode": "hourly"}                     // rotate at the top of each hour
{"mode": "daily"}                      // rotate at midnight local time (default)
{"mode": "size", "size_mb": 50}        // rotate when the file exceeds 50 MB

Even with time-based rotation (hourly/daily), the max_file_size_mb cap is enforced as a safety net — a single file that exceeds the cap is rotated immediately, so a file can never grow unbounded between scheduled rotations.

On-Demand Rotation

Rotate the current log file immediately, regardless of the configured mode:

bash
# REST API
curl -X POST http://localhost:3001/api/logs/rotate -H 'Content-Type: application/json' -d '{}'

# CLI
madhyamas logs rotate

The current madhyamas.log is renamed to madhyamas.log.<YYYY-MM-DD_HH-MM-SS> and a fresh file is opened. Archived files are pruned to max_files.

Inspecting Status

bash
# REST API
curl http://localhost:3001/api/logs

# CLI
madhyamas logs status

Returns the current config, the active log file path and size, and the list of archived (rotated) files with their sizes and modification times.

Updating Configuration at Runtime

bash
# CLI: switch to size-based rotation, 50 MB per file, keep 3 archives
madhyamas logs config --rotation size --size-mb 50 --max-files 3

# REST API
curl -X PATCH http://localhost:3001/api/logs \
  -H 'Content-Type: application/json' \
  -d '{"rotation":{"mode":"size","size_mb":50},"max_files":3}'

Changes to max_files and max_file_size_mb take effect immediately. Changes to rotation mode and json_format take effect on the next restart (the tracing subscriber layer is installed once at startup). All changes are persisted to ~/.madhyamas/config.json and survive restarts.

Log Levels

Control verbosity with the RUST_LOG environment variable:

ValueWhat you see
errorOnly errors
warnWarnings and errors
infoInfo, warnings, errors (default)
debugDebug, info, warnings, errors
traceEverything, including very verbose internal events
bash
RUST_LOG=debug madhyamas serve

For targeted verbosity (e.g. only the proxy engine):

bash
RUST_LOG=madhyamas_core::proxy=debug,info madhyamas serve

Proxied-Traffic Debug Logging

Madhyamas can also write per-request diagnostic events for the traffic flowing through the proxy — method, host, path, status, timing, and (optionally) headers and bodies — into the same main log. This is separate from the traffic list in the web UI: it is plain structured logging, meant for tail/grep, docker logs, or shipping to a log aggregator.

Toggle it in the web UI (Settings -> Debug Logging) or via the API:

bash
curl -X PATCH http://localhost:3001/api/logs \
  -H 'Content-Type: application/json' \
  -d '{"debug_logging": {"enabled": true, "level": "headers", "host_filter": ["api.example.com"]}}'

Settings (all applied immediately, no restart):

SettingDefaultDescription
enabledfalseMaster switch.
levelsummarysummary (one line per request/response), headers (adds all headers), full (adds bodies).
host_filterall hostsOne pattern per line; supports example.com, *.example.com, and *api* globs.
redact_headersAuthorization, Cookie, Set-CookieHeaders replaced with [REDACTED] before logging.
redact_bodiesfalseNever log body content — size placeholder only.

At full verbosity, bodies are capped at the capture Max Body Size setting, compressed bodies are decompressed first, and non-text binaries (images, protobuf, ...) are logged as a size/content-type placeholder.

How It Works

  • A custom RotatingFileWriter (in madhyamas-core/src/log_rotation.rs) implements std::io::Write and is wrapped as a tracing_subscriber MakeWriter so it can be used as a fmt layer alongside the stdout layer.
  • A background Tokio task wakes every 60 seconds to perform time-based rotation (hourly/daily) and prune archived files.
  • Size-based rotation is checked on every write (per-event), so a burst of logs that exceeds the cap triggers rotation immediately.
  • The LogHandle is stored in the API AppState, enabling on-demand rotation and config updates from HTTP handlers.

MCP Mode

In MCP mode, logs go to stderr only — writing to stdout would corrupt the JSON-RPC stream that the AI agent reads. File rotation still works if enabled.

See also

Released under the MIT OR Apache-2.0 License.