Skip to content

v2.17.0: Structured Logs and Readiness Timeouts

Choose a tag to compare

@jdx jdx released this 17 Jul 11:07
· 153 commits to main since this release
Immutable release. Only release title and notes can be modified.
3c7d6a6

This release brings structured log parsing, filtering, and colorized highlighting to pitchfork logs, adds opt-in timeouts for every readiness check type, extends Tera templates to the remaining ready-check fields, and lets you drop the start subcommand for a quick shorthand.

Highlights

  • Structured logs land in pitchfork logs — auto-detected JSON/logfmt parsing, hl-style colorized rendering, and rich filtering by level, field, or jq expression (#584, #592, #595) — @gaojunran.
  • Readiness checks get overall timeouts and full template support so slow or hung startups fail cleanly and check fields can reference other daemons' resolved ports (#597, #600).

Added

  • Structured log parsing and filtering (#584) — @gaojunran. pitchfork now understands structured daemon output. A new logs.log_format setting (auto/json/logfmt/text, with per-daemon overrides in pitchfork.toml) controls parsing, and pitchfork logs gains structured filters:

    pitchfork logs api --level warn                 # minimum severity: warn and error
    pitchfork logs api --field status=500           # repeatable KEY=VALUE field match
    pitchfork logs api --jq '.duration_ms > 100'    # jq expression over parsed fields

    JSON output (--json) now includes parsed level, msg, logger, and fields.

  • hl-style structured log highlighting (#592, #595) — @gaojunran. Structured entries render with color-coded level badges, dim logger names, and key=value fields (keys in blue, numbers in green, booleans and null colored) instead of raw JSON. A configurable logs.timestamp_format setting (chrono strftime, default %m-%d %H:%M:%S, also settable via PITCHFORK_LOG_TIMESTAMP_FORMAT) controls the text-mode timestamp. --raw output is now honored even when combined with --jq, and pitchfork logs (no daemon named) always shows the daemon id label so you can tell lines apart. PTY control sequences are stripped from all log output to prevent pager corruption for pty = true daemons.

  • Optional overall timeout for readiness checks (#597, closes #545) — @gaojunran. All four check types accept an optional timeout in their object form, using humantime durations. Omitting it preserves the current unbounded polling. When every configured check exhausts its deadline, the daemon is killed and startup fails with exit code 124, so retry, hooks, and depends propagate as usual.

    [daemons.api]
    run = "node server.js"
    ready_http = { url = "HOST/health", status = [200], timeout = "30s" }
    
    [daemons.cache]
    run = "redis-server"
    ready_port = { port = 6379, timeout = "10s" }
  • Tera templates in the remaining ready-check fields (#600) — @disintegrator. ready_http, ready_port, and ready_output now render through the template pipeline, joining ready_cmd, so readiness checks can reference other daemons' resolved values:

    [daemons.worker]
    ready_http = "HOST:{{ daemons.redis.port }}/health"
    ready_port = "{{ daemons.redis.port }}"
    ready_output = "listening on {{ daemons.redis.port }}"
    depends = ["redis"]

    ready_port accepts a plain integer or a string/template that must resolve to a valid port (1-65535); a template that renders to an invalid port now fails the start with a clear error.

  • Implicit start shorthand (#593) — @gaojunran. When the first argument isn't a known subcommand, it's treated as a daemon id and forwarded to start, so pitchfork api is shorthand for pitchfork start api. All start flags, validation, and help output are reused.

    pitchfork api                  # same as: pitchfork start api
    pitchfork api redis --force

Fixed

  • Global config no longer requires a daemons field (#605) — @senekor. Settings-only global config files (with no daemons) now validate and load correctly, defaulting daemons to an empty set instead of failing.

Breaking Changes

  • ready_port = 0 now fails config parsing at load time, whereas it was previously accepted and produced a TCP check against port 0 (#600). Numeric strings such as ready_port = "8080" are now accepted and normalized.

New Contributors

Full Changelog: v2.16.0...v2.17.0

💚 Sponsor pitchfork

pitchfork is maintained by @jdx, an open source developer for entire.io, the title sponsor of the jdx.dev open source tools including mise, aube, hk, and more. Development is sustained by sponsorships.

If pitchfork has a place in your dev workflow, please consider sponsoring at jdx.dev. Individual and company sponsorships are what keep the project healthy and moving forward.