SymptomExtractor

Reads symptoms from normalized log text; never throws.

The text is GitHub Actions output, either raw (<timestamp> <text> per line) or as printed by gh run view --log (<job>\t<step>\t<timestamp> <text>). Lines end at \n, \r\n or a lone \r, and only the first MAX_LINE characters of a line are read. A job<TAB>step prefix counts from the first timestamped line that carries it (at most 64 distinct prefixes), so a tab inside ordinary output is not taken for one. Color codes (ESC or the literal ^[[) are dropped, and lines the runner echoes in cyan (script bodies) are skipped by every matcher below.

Matching is plain string scanning on ASCII-lowercased text, no regex:

  • SIGNATURE: the first line of a ##[error] annotation, except Process completed with exit code; with no annotation in the whole text, lines shaped like XError: ..., XException: ..., error: ... or fatal: ... instead. Both go through Signature.normalize.

  • EXIT: a non-zero number after exit code , exited with code or exit status .

  • SIGNAL: a SIG plus uppercase token on a line that also says signal, killed or terminated.

  • STEP and DURATION: for each step (a ##[group]Run header up to the next header or Post job cleanup.) that holds an annotation, the header command and the milliseconds from the header's timestamp to the step's last timestamped line.

  • TRANSPORT: the phrases in transport, each mapped to one canonical value.

Equal job, kind and value merge into one symptom with a count (a STEP or DURATION also needs the same header line, so two steps stay two symptoms). At most MAX_SYMPTOMS distinct symptoms are kept, in line order.

Properties

Link copied to clipboard
const val MAX_LINE: Int = 4096
Link copied to clipboard
const val MAX_SYMPTOMS: Int = 500

Functions

Link copied to clipboard
fun extract(text: String): List<Symptom>