Skip to content

[FEATURE] Structured logs and pipeline health metrics #132

Description

@koydas

🎯 Goal

Make every run fully diagnosable from logs alone — no manual correlation across job outputs required.

📍 Context

  • Repo: autonomous-dev-loop
  • Domain: Operational diagnosability
  • Component: scripts/lib/logger.mjs, scripts/auto_fix_pr.mjs, scripts/generate_issue_change.mjs

🚀 Description

logger.mjs already emits structured JSON lines — a solid foundation. The gaps are:

  • No run_id field: log lines from a single run cannot be correlated across the multi-job workflow (load-labelsauto-fix → commit step).
  • No step field: impossible to know which pipeline stage emitted a given log line.
  • No attempt field: retry context is invisible in logs (Groq 429 retries do log rate_limit_retry with attempt, but this is not standardized).
  • No duration_ms field: no per-step latency data.
  • No error_class field: TRANSIENT/PERMANENT/UNKNOWN (from issue [FEATURE] Unified TRANSIENT/PERMANENT/UNKNOWN error taxonomy #109) never surfaces in logs.
  • No end-of-run summary: a run can complete or fail without emitting a final structured event.

🧩 Scope

In:

  • scripts/lib/logger.mjs: add a module-level context object set once at startup:
    // shape
    { run_id, step, attempt }
    All log() and error() calls automatically merge this context into every emitted line.
  • Expose setLogContext({ run_id, step, attempt }) so entrypoint scripts can set it at the top.
  • run_id: use process.env.GITHUB_RUN_ID ?? crypto.randomUUID() (available in all GitHub Actions jobs).
  • step: free-form string set by the caller ('ai-call', 'label-apply', 'comment-post', etc.).
  • attempt: integer, set by the retry utility (issue [FEATURE] Bounded exponential retry with jitter for external calls #111) when retrying.
  • duration_ms: emitted automatically on logEnd(step, result) using performance.now() delta from logStart(step).
  • error_class: passed explicitly by callers when throwing (logError(msg, { error_class: 'TRANSIENT', ... })).
  • End-of-run summary: each entrypoint script calls logSummary({ success, steps_completed, errors }) in a finally block.

Out:

  • External observability platform (no Datadog, no OpenTelemetry export).
  • Changes to log verbosity defaults (existing log lines must remain unchanged in shape).

🧪 Acceptance criteria

  • Functional

    • Every log line emitted after setLogContext() includes run_id, step, and attempt.
    • logStart('ai-call') / logEnd('ai-call', 'success') pair emits a line with duration_ms populated.
    • The final logSummary() call emits a line with { msg: 'run_summary', success: true|false, steps_completed, errors }.
  • Edge cases

    • Log lines emitted before setLogContext() is called (e.g., during secret validation) still emit without crashing — missing context fields are simply absent, not undefined literals.
    • If logEnd is called without a prior logStart for that step, it emits the line without duration_ms (no throw).
    • If the process exits via unhandledRejection, the summary is still emitted (hook into the existing handler in auto_fix_pr.mjs).
  • Tests

    • Unit: log('foo') after setLogContext({ run_id: 'r1', step: 's1', attempt: 2 }) emits { run_id: 'r1', step: 's1', attempt: 2, msg: 'foo' }.
    • Unit: logStart + logEnd pair emits a line where duration_ms is a non-negative number.
    • Unit: log('foo') before any setLogContext() call does not throw and does not include run_id.
    • Smoke: a full auto-fix run emits exactly one run_summary line as the last structured log event.

⚙️ Constraints

  • Existing log() and error() call sites must require zero changes (context is injected automatically).
  • No new runtime dependencies (crypto.randomUUID and performance.now are built into Node 20).
  • Log output must remain one JSON object per line (no multi-line pretty-print).

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestready-for-devIssue validated and ready for automated implementation

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions