Skip to main content
ctx.log records structured, leveled logs from inside a workflow. Unlike a bare console.log - which stays on the runner’s stdout, invisible to Duraton - ctx.log lines flow to Duraton, persist durably with the run, and are readable per run via the API.

Logging a line

ctx.log is callable (info level) and has one method per level:
fields is an optional object of structured context. It is stored as JSON, so prefer structured fields over interpolating values into the message.

Durable under replay

A handler re-runs from the top on every pass (durable execution), so ctx.log is replay-aware:
  • A handler-level log (outside any step) re-emits on every pass, but Duraton gives it a stable identity per attempt and records it exactly once.
  • A log inside a step.run only executes on the pass where that step runs. A step that retries records its logs once per attempt, so you can see what each attempt did:

Redaction

Field values under sensitive key names (password, token, secret, authorization, and similar) are masked to [redacted] before anything is persisted. Redaction is keyed on field names, so prefer putting sensitive values in named fields rather than inlining them into the free-text message.

Reading logs back

Fetch a run’s logs oldest-first:
Each line carries its level, message, fields, scope (the step name, or @root for a handler-level log), and attempt. See the Runs API for pagination and the full response shape.

Limits

Each pass caps how many lines it ships so a pathologically chatty handler cannot overrun the 1 MiB wire-message limit; beyond the cap, a single line records how many were dropped. Logs are part of a run’s data and are removed with the run.
See the logging example running end to end in Examples.