Skip to content

Latest commit

 

History

9 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ci-log-triage

Turn a failing CI log into three useful sentences, using DigitalOcean serverless inference.

A failing job log is thousands of lines of things that worked and a few dozen that did not. This finds the few dozen, sends only those, and tells you what broke, why, and what to try first.

export DO_INFERENCE_KEY=...
cat build.log | npx ci-log-triage --stats
**What failed:** Applying migration `20260727130000_team_scoped_unique_constraints`
failed because the PostgreSQL relation `Segment` does not exist.

**Why:** The migration references the table `Segment`, but PostgreSQL reports
`ERROR: relation "Segment" does not exist`. Either the table was never created,
was dropped, or the name differs (case sensitivity, or a mis-named migration).

**Try this first:** Open the migration file and check which statement uses
`Segment`, then verify the table exists with `psql -c "\d"`.

---
openai-gpt-oss-20b · 4949ms · 753 prompt + 527 completion tokens ·
log reduced 92.5% (272 lines to 26)

That output is from a real failing deploy, not a mock.

Why the log reduction matters

Sending the whole log works and is the obvious thing to do. It is also worse in both directions: you pay for every token, and the actual error gets buried in dependency-resolution noise, which makes the answer less accurate.

src/extract.mjs does the reduction:

  • strips the per-line job⇥step⇥timestamp prefixes GitHub adds, and ANSI colour codes, both of which repeat on every line and cost tokens
  • keeps a window around every error signal, plus the tail of the log, where failures usually land
  • marks the gaps (... 41 lines omitted ...) so the model does not assume two unrelated lines are adjacent

On the example above that is 25,534 characters down to 1,926.

Usage

ci-log-triage build.log                 # from a file
cat build.log | ci-log-triage           # from stdin
ci-log-triage build.log --stats         # add latency, tokens, reduction
ci-log-triage build.log --json          # machine-readable
ci-log-triage build.log --model llama3.3-70b-instruct

--help lists everything.

Notes from building this

Reasoning models need headroom. openai-gpt-oss-20b puts its thinking in reasoning_content and the answer in content. Set max_tokens too low and reasoning consumes the whole budget: you get HTTP 200, finish_reason: "length", and an empty string, which looks exactly like a broken API key. The client raises a specific error for that case rather than letting you debug it twice.

Commercial models are tier-gated. Requesting an Anthropic model on a base account returns 403 this model is not available for your subscription tier. The open-source models work without that.

Triage must never fail the build. A tool that explains failures should not create them, so any error exits 0 with a message on stderr.

Use it as a GitHub Action

  triage:
    needs: build
    if: always() && needs.build.result == 'failure'
    runs-on: ubuntu-latest
    permissions:
      actions: read          # to read the failing job's log
      pull-requests: write   # only if you want a PR comment
    steps:
      - uses: The-DevOps-Daily/ci-log-triage@main
        with:
          do-api-key: ${{ secrets.DO_INFERENCE_KEY }}
          pr-number: ${{ github.event.pull_request.number }}

It writes the report to the job summary, and upserts a single PR comment rather than stacking one per run. .github/workflows/demo.yml is a job that fails on purpose so you can watch it work.

Configuration

Variable Purpose
DO_INFERENCE_KEY required, a DigitalOcean model access key
DO_INFERENCE_BASE_URL optional, defaults to https://inference.do-ai.run/v1

Licence

MIT

About

Turn a failing CI log into three useful sentences, using DigitalOcean serverless inference.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages