Logging#

Every request to a webhook endpoint is logged as a JSON line:

Log fileContents
logs/<webhook-id>.logMatched requests for the endpoint with that id.
logs/_unmatched.logRequests that matched no endpoint (responded 404).

The log directory defaults to logs/ — override with --log-dir or the LOG_DIR environment variable.

Log Entry#

{
  "timestamp": "2026-08-18T10:30:00.123Z",
  "request_id": "uuid-v4",
  "webhook": "health",
  "method": "GET",
  "path": "/health",
  "headers": {"User-Agent": "curl/8.7.1"},
  "body": "",
  "query": {},
  "response_status": 200,
  "response_headers": {"Content-Type": "application/json"},
  "response_body": "",
  "latency_ms": 0.02,
  "matched": true
}
FieldDescription
timestampRequest time, RFC3339 with milliseconds (UTC).
request_idUnique request ID (same value available in templates as {{.RequestID}}).
webhookThe endpoint id that matched (absent / empty for unmatched).
methodHTTP method.
pathRequest path.
headersRequest headers (map).
bodyRequest body.
queryQuery parameters (map).
response_statusStatus code returned.
response_headersResponse headers (map).
response_bodyResponse body.
latency_msTotal time to serve the request — includes any configured delay.
matchedtrue if a stub matched, false for a 404.

Capping Stored Bodies#

Large payloads blow up your logs. --max-log-body N (or LOG_MAX_BODY) caps the stored body / response_body at capture time, in bytes:

simuhook --max-log-body 1024
EffectDetail
Limitedbody, response_body in log files and the dashboard are truncated (rune-safe).
Never affectedThe actual HTTP response sent to clients, and echo / template rendering.

Default is 0 = unlimited.

Example — Matched vs Unmatched#

curl http://localhost:8080/health        # → logs/health.log, matched: true
curl http://localhost:8080/nonexistent   # → logs/_unmatched.log, matched: false, 404

Also See#

  • The TUI dashboard shows the same data live, with counts, latency stats, and a filterable feed.