Skip to main content
RunBook Academy

Git, CI/CD & GitOpsXXXIX · PipelinesPipelines

Pipeline status and observability — what the run page shows and how to read the logs

Intermediate⏱ ~20 mingit

What you'll learn

  • Identify the five sections of a CI run page and what each shows
  • Read a job log line and identify the timestamp, step, runner, and exit code
  • Correlate step duration with wall-clock time to find a slow step
  • Recognise the four early-warning signals in a successful run that predict the next failure
  • Use artifacts, annotations, and job summaries as observability primitives

Prerequisites

Verified against Git 2.55.x teaching target; 2.40+ minimum · GitHub Actions continuous service; Aug 2026 documentation baseline · Argo CD v3.5.x teaching target; v3.0+ minimum · Flux v2.9.x · Sigstore Cosign v3.1.x · SLSA v1.2 · OCI Distribution Specification v1.1 · Git LFS v3.7.1 · Kubernetes (cross-course target) 1.36.x

Not yet marked complete on this device.

A pipeline run produces more than a pass/fail signal. It produces a run page: a structured view of every job, every step, every log line, every artifact, and every timing. The run page is the operational surface for the pipeline. Reading it well is the difference between catching a slow step before it times out and discovering it after.

The five sections of a run page

flowchart TB
    R["Run page"]
    R --> H["1. Header\ncommit, branch, trigger, status"]
    R --> J["2. Jobs list\njob names, statuses, durations"]
    R --> S["3. Step logs\ntimestamped stdout/stderr per step"]
    R --> A["4. Artifacts\nuploaded files with retention"]
    R --> M["5. Annotations\nwarnings and errors pinned to files"]

The header identifies the run: which commit, which branch, which trigger (push, pull request, manual, scheduled), and the overall status. The jobs list shows every job in the DAG with its status (success, failure, skipped, cancelled) and its duration. The step logs are the per-job execution trace. The artifacts list shows every uploaded file with its retention policy. The annotations are file-pinned warnings and errors from the workflow commands.

A green run is a run whose header status is success and whose every job in the jobs list is success. The other sections - logs, artifacts, annotations - are where the operational signal lives.

Reading a step log

A log line in a CI system has four parts:

2026-08-21T14:23:01.234Z [INFO] step: "Run terraform plan" runner: ubuntu-latest job: plan duration: 2m13s exit: 0
  • Timestamp. When the line was emitted by the runner, in UTC. The first line of a step is the step’s start time; the last is the end. The duration is the delta.
  • Step identifier. The name of the step from the workflow file. The name is the search key; filtering the log by step name is faster than scrolling.
  • Runner and job. Which runner image executed the step and which job in the DAG it belonged to. A failure on macos-latest that succeeds on ubuntu-latest is an OS-dependent bug, not an application bug.
  • Exit code. 0 for success; non-zero for failure. The exit code is what the CI system uses to mark the step as failed; a step that exits 0 even after writing an error message is a step the system considers successful.
# Download the artifact for a run from the command line
gh run download $RUN_ID --name terraform-plan
# saves the artifact to ./terraform-plan in the current directory

Correlating step duration with wall-clock time

The jobs list shows the wall-clock duration of each job; the step logs show the duration of each step inside the job. The delta between the two is the overhead: checkout time, runner boot time, artifact upload time.

flowchart LR
    J["Job duration\n8m 42s"] --> S1["step 1: checkout\n12s"]
    J --> S2["step 2: setup-python\n8s"]
    J --> S3["step 3: pip install\n45s"]
    J --> S4["step 4: pytest\n6m 18s"]
    J --> O["overhead\nunaccounted: 59s"]

A job whose steps sum to 7m 43s but whose wall-clock is 8m 42s has 59s of unaccounted time. The unaccounted time is runner boot, image pull, and artifact upload. A job whose overhead is consistently high is a job that is paying a fixed cost the team has not optimised.

The most actionable optimisation is to move the slow step out of the critical path (parallelise it with another job) or to cache its dependencies (Python pip, Node npm, Go modules).

The four early-warning signals

A green run is not necessarily a clean run. Four signals in a successful run predict the next failure:

flowchart TB
    S1["1. Step duration trending up"]
    S2["2. Annotation warnings increasing"]
    S3["3. Artifact size growing"]
    S4["4. Retry count creeping up"]
    S1 --> P["Predicts: timeout or capacity failure"]
    S2 --> P
    S3 --> P
    S4 --> P
  1. Step duration trending up. A test step that took 2 minutes six months ago and takes 5 minutes today is approaching the timeout. The trend is invisible in a pass/fail view; it is visible in a duration graph.
  2. Annotation warnings increasing. A workflow command that emits a warning (::warning::) does not fail the step, but the warning count grows over time as the underlying issue accumulates. A step that emits 50 warnings today emitted 5 six months ago; the next failure is when the warning becomes an error.
  3. Artifact size growing. An artifact that grew from 10MB to 800MB is an artifact whose contents have drifted. The drift is usually a debugging artefact (a full core dump, an entire node_modules tree) that should not be in the artifact.
  4. Retry count creeping up. A flaky test that is retried automatically looks like a green run. The retry count is recorded in the step log; a step that is retried 3 times out of 10 runs is a step that is failing 30% of the time.

Annotations, summaries, and observability primitives

The CI system provides three primitives that turn a log file into structured observability:

# Annotation (file-pinned warning)
- run: |
    if [ "$DRIFT" != "0" ]; then
      echo "::warning file=terraform/main.tf::drift detected: $DRIFT resources"
    fi

# Job summary (markdown rendered on the run page)
- run: |
    echo "## Plan summary" >> $GITHUB_STEP_SUMMARY
    echo "- Resources to add: $ADD" >> $GITHUB_STEP_SUMMARY
    echo "- Resources to change: $CHANGE" >> $GITHUB_STEP_SUMMARY
    echo "- Resources to destroy: $DESTROY" >> $GITHUB_STEP_SUMMARY

# Artifact upload (binary output retained)
- uses: actions/upload-artifact@v4
  with:
    name: terraform-plan
    path: plan.bin
  • Annotation is a warning or error pinned to a file and line number. The annotation appears inline on the pull request; the engineer sees the warning without opening the run page.
  • Job summary is a markdown blob rendered on the run page. The summary is the team’s chance to surface the human-readable outcome of a job (a plan summary, a test report, a vulnerability count) without parsing the log.
  • Artifact upload is the binary output of a job. The artifact is downloadable from the run page; the team uses it for post-mortem analysis.

Production discipline

  1. Treat the run page as production. A change to the step ordering, the log format, or the artifact list is a change to operational tooling; review it.
  2. Surface early-warning signals as graphs, not dashboards. Step duration, annotation count, artifact size, and retry count are time series; plot them.
  3. Use annotations to pin warnings to files. A free-form warning in a log is a warning that gets scrolled past; a file-pinned warning is a warning that blocks the merge.
  4. Write a job summary for every job that produces a human-readable outcome. A plan, a test report, a vulnerability count. The summary is the team’s first read of the run.
  5. Audit artifact retention. An artifact that lives forever is an artifact that fills the storage budget; an artifact that is deleted too soon is an artifact that cannot be inspected post-mortem.

Cross-course references

  • Ansible for Production Sysadmins - Part XXXVII (RepoArch) applies the run-page discipline to AWX job runs: the AWX job detail page is the operational surface for Ansible.
  • Terraform for Production Sysadmins - Part XII (PlanApply) treats the terraform plan output as the job summary: the plan is what the engineer reads on the run page.
  • Linux for Production Sysadmins - Part XXVIII (UnitConf) and XXX (BootProc) apply the same observability discipline to systemd: journalctl is the log; systemctl status is the run page.

Quiz

Knowledge check · 4 questions

  1. Q1. A team's `test` job has been green for six months. Over those six months, the step duration has trended from 2 minutes to 5 minutes, and the maximum job duration is 60 minutes. What is the failure mode and when will it appear?

  2. Q2. A workflow step that exits with code 0 but writes an error message to stderr is considered successful by the CI system.

  3. Q3. Name the five sections of a CI run page and identify the section that surfaces file-pinned warnings on a pull request.

  4. Q4. Diagnose why a flaky test is invisible in the run page and recommend an observability fix.

    Team T's `test` job has been green for months. Engineers occasionally notice that the run took 3 attempts to pass (the first two attempts failed, the third succeeded). The run page shows 'success' but the step log contains three 'attempt N failed' entries followed by 'attempt 3 passed'. The team has been treating the green status as evidence that the test suite is healthy; in fact, the suite is flaky at a 30% rate and only appears stable because of automatic retries.

Passing score: 75%. Answers are checked in this browser.