# Output and reports

> What shutdown-check prints and writes: the text timeline, every timeline event, the --json result, the shutdown-check JUnit report and the exit codes.

Source: https://shutdown.jscrate.dev/docs/output
Last updated: 2026-09-23

Every shutdown-check run produces one result with a verdict, diagnostic code,
message, timeline, duration, and captured service output. Choose text for
people, JSON for scripts, or JUnit XML for CI reports.

## Choose an output format

| Format    | Command option | Destination | Best for                      |
| --------- | -------------- | ----------- | ----------------------------- |
| Text      | default        | stdout      | Local debugging and CI logs   |
| JSON      | `--json`       | stdout      | Scripts and structured logs   |
| JUnit XML | `--junit FILE` | file        | CI test-report interfaces     |
| Exit code | always         | process     | Passing or failing the caller |

You can write JUnit while printing either text or JSON:

```bash
npx shutdown-check test --json --junit shutdown-result.xml
```

## Read the text output

A passing result contains a verdict and timeline:

```text
PASS SC000: Graceful shutdown verified

Timeline:
  +    5 ms  process launched — pid=67911
  +  113 ms  service ready — HTTP 200
  +  113 ms  work request sent — #1 GET /slow
  +  113 ms  work request sent — #2 GET /slow
  +  114 ms  work confirmed active — 2 response(s) sent headers; bodies still in progress
  +  114 ms  signal sent — SIGTERM
  +  115 ms  readiness withdrawn — HTTP 503
  +  115 ms  new request rejected — HTTP 503
  + 2117 ms  work request finished — #1 HTTP 200
  + 2117 ms  work request finished — #2 HTTP 200
  + 2120 ms  process exited — code=0, signal=none
  + 2121 ms  shutdown verified — work completed and service exited before deadline
```

The number after `+` is milliseconds since the run began. Read the lines in
order to see what happened before and after `SIGTERM`.

A failure ends with `check failed`:

```text
FAIL SC201: In-flight request was interrupted: aborted

Timeline:
  +    6 ms  process launched — pid=73692
  +  112 ms  service ready — HTTP 200
  +  113 ms  work request sent — #1 GET /slow
  +  113 ms  work confirmed active — 1 response(s) sent headers; bodies still in progress
  +  113 ms  signal sent — SIGTERM
  +  116 ms  process exited — code=null, signal=SIGTERM
  +  116 ms  work request finished — #1 aborted
  +  116 ms  check failed — SC201: In-flight request was interrupted: aborted
```

Open the page for the code—in this case
[SC201](https://shutdown.jscrate.dev/docs/codes/sc201)—to see causes and fixes.

## Service stdout and stderr

On a failed check, text output adds the last 8 KiB of each non-empty service
stream:

```text
Service stderr (last 8 KiB):
Error: database close timed out

Service stdout (last 8 KiB):
SIGTERM received
closing HTTP server
```

Earlier output is discarded when a stream grows beyond 8 KiB. Keep shutdown
logs concise and write important state near the failure.

The service output is captured, not streamed live. It appears after the result
so the timeline remains readable.

## Timeline events

| Event                   | Meaning                                                   |
| ----------------------- | --------------------------------------------------------- |
| `process launched`      | The configured command started                            |
| `service ready`         | The readiness route returned its expected status          |
| `work request sent`     | A workload request was opened                             |
| `work confirmed active` | The selected start barrier passed                         |
| `signal sent`           | The first `SIGTERM` was delivered                         |
| `signal repeated`       | The optional second `SIGTERM` was delivered               |
| `readiness withdrawn`   | The readiness route stopped reporting ready               |
| `new request rejected`  | New work returned an allowed status or connection refusal |
| `work request finished` | A workload response completed or failed                   |
| `process exited`        | The launched process stopped                              |
| `shutdown verified`     | Every configured check passed                             |
| `check failed`          | The run ended with the displayed diagnostic code          |

An event appears only when that part of the config runs. For example,
`readiness withdrawn` is absent unless `shutdown.readinessWithdrawal` is
enabled.

## JSON output

Run:

```bash
npx shutdown-check test --json
```

The command prints one JSON object. A shortened passing example:

```json
{
  "pass": true,
  "code": "SC000",
  "message": "Graceful shutdown verified",
  "startedAt": "2026-09-23T10:00:00.000Z",
  "durationMs": 2121,
  "timeline": [
    { "ms": 5, "event": "process launched", "detail": "pid=67911" },
    { "ms": 114, "event": "signal sent", "detail": "SIGTERM" },
    {
      "ms": 2121,
      "event": "shutdown verified",
      "detail": "work completed and service exited before deadline"
    }
  ],
  "stdout": "",
  "stderr": ""
}
```

| Option | Type | Default | Description |
| --- | --- | --- | --- |
| `pass` (required) | `boolean` | — | `true` only for `SC000`. |
| `code` (required) | `string` | — | The [diagnostic code](https://shutdown.jscrate.dev/docs/codes): `SC000` on a pass, the first failure otherwise. |
| `message` (required) | `string` | — | What happened, in one sentence, with the values observed. |
| `timeline` (required) | `TimelineEvent[]` | — | Every step of the check in order, with milliseconds since it started. |
| `stdout` (required) | `string` | — | The last 8 KiB the service wrote to stdout. |
| `stderr` (required) | `string` | — | The last 8 KiB the service wrote to stderr. |

The `timeline` array contains:

| Option | Type | Default | Description |
| --- | --- | --- | --- |
| `ms` (required) | `number` | — | Milliseconds since the check started, rounded. |
| `event` (required) | `string` | — | What happened: `"process launched"`, `"service ready"`, `"signal sent"`, `"work request finished"`, `"process exited"` and so on. |
| `detail` | `string` | — | The values behind it, such as `"HTTP 503"` or `"code=0, signal=none"`. |

JSON uses the same exit codes as text. A failure still exits with `1`, so a
shell step may need to preserve stdout before reacting to the exit.

## JUnit report

Run:

```bash
npx shutdown-check test --junit reports/shutdown.xml
```

The parent directory must exist. shutdown-check writes one test suite with one
test case:

- a pass has no failure element;
- a failed shutdown adds the diagnostic code and message as the failure;
- the timeline is included in system output;
- captured service stdout and stderr are included when available;
- the suite time uses the run duration.

The default suite name is `shutdown-check`. From the Node API, pass a second
argument to `junitXml(result, name)` to choose another name.

The report is written before the CLI prints text or JSON. A normal check
failure therefore still produces the file. A setup or config error produces
no report because no `CheckResult` exists.

## Exit codes

| Exit code | Meaning |
| --- | --- |
| `0` | passed |
| `1` | shutdown check failed |
| `2` | setup/configuration error |

| Code | Meaning                                     | Output available                 |
| ---- | ------------------------------------------- | -------------------------------- |
| `0`  | The configured shutdown contract passed     | Text/JSON and optional JUnit     |
| `1`  | The test ran and returned a failing SC code | Text/JSON and optional JUnit     |
| `2`  | Arguments, setup, or config stopped the run | Error on stderr; no JUnit result |

CI should fail on any nonzero code. Treat `2` as a broken test setup and `1`
as a service behavior that needs investigation.

## Use the result from code

`checkShutdown()` and `runCheck()` return the same `CheckResult` object used by
JSON output. `junitXml()` creates the same XML as the CLI.

```ts
import { checkShutdown, junitXml } from "shutdown-check";

const result = await checkShutdown(config);
const xml = junitXml(result, "orders-api shutdown");
```

See the [Node API](https://shutdown.jscrate.dev/docs/node-api) for a complete custom runner.

## Related

- [CLI reference](https://shutdown.jscrate.dev/docs/cli)
- [Diagnostic codes](https://shutdown.jscrate.dev/docs/codes)
- [Run in CI](https://shutdown.jscrate.dev/docs/ci)
- [Node API](https://shutdown.jscrate.dev/docs/node-api)
- [Troubleshooting](https://shutdown.jscrate.dev/docs/troubleshooting)
