# health

Reports the **health of the server** as a set of **checks**, each with the status `pass`, `warn`, or `fail`.

- **Route:** `QUERY /api/v2/system/health`, and `GET` as well
- **Category:** `system`
- **Authentication:** required, with the API token
- **Answer:** the **[Health Check Response Format for HTTP APIs](https://datatracker.ietf.org/doc/html/draft-inadarei-api-health-check-06)**, or **OpenMetrics** if you ask for it, not wrapped in an envelope

The checks cover the **license**, the **process**, the **store**, and the **system** the server runs on, such as the number of stored events, the operation mode of the database, and the free space on its disk. The **overall status** is the **worst status of all checks**, and it decides the status code, so that a load balancer can take an instance whose health fails out of service. **[Logging and Monitoring](/docs/eventsourcingdb/logging-and-monitoring)** lists **every check**, says when each one warns or fails, and shows how **Prometheus** scrapes the route.

## Request

The route takes **no body**, and ignores one that is sent. Besides `QUERY`, it answers `GET`, which load balancers, probes, and scrapers such as Prometheus send. The **`Accept` header** chooses the format:

- **`application/health+json`**, the default, answers in the health-check format. A request without an `Accept` header, with `*/*`, or with a type that the route does not offer gets this format as well.
- **`application/openmetrics-text`** answers with the same values in the **OpenMetrics** format, which Prometheus reads, if the header prefers it over the health-check format.

To get the health in the health-check format:

```shell
curl \
  -H "authorization: Bearer secret" \
  http://localhost:3000/api/v2/system/health
```

## Answer

In the health-check format, with the content type `application/health+json`, the body is a JSON object:

| Field | Meaning |
| --- | --- |
| `status` | The overall status, `pass`, `warn`, or `fail`, which is the worst status of all checks. |
| `checks` | The checks, each by its name, such as `store:eventCount`, as a list of entries with its `status`, its `observedValue`, and, where it has one, its `observedUnit`. A check that reports a value for each of several components, such as `store:writes`, holds an entry for each of them, named by its `componentId`. |

A check whose value **has not been measured** yet, or could not be, goes **without an `observedValue`**, and a check whose value the platform does not provide, such as the resident memory on macOS, is **left out**.

In **OpenMetrics**, with the content type `application/openmetrics-text; version=1.0.0; charset=utf-8`, the body holds the same values as **metrics**, named as listed in **[Checks](/docs/eventsourcingdb/logging-and-monitoring#checks)**.

Shortened to three of its checks, the request above is answered for a server whose license expires within the next 30 days, which makes its overall status `warn`, with:

```json
{
  "status": "warn",
  "checks": {
    "license:remaining": [
      {
        "status": "warn",
        "observedValue": 172732.498122292,
        "observedUnit": "seconds"
      }
    ],
    "store:eventCount": [
      {
        "status": "pass",
        "observedValue": 2
      }
    ],
    "store:operationMode": [
      {
        "status": "pass",
        "observedValue": "read-write"
      }
    ]
  }
}
```

## Status Codes

The overall status decides the status code: `pass` and `warn` are answered with `200`, and `fail` with `503`, since the health-check format requires a status code of `4xx` or `5xx` for it. In OpenMetrics, the route **always answers with `200`**, whatever the status of its checks. Beyond that, the server answers with a status code other than `200` where it cannot take the request at all, as described in **[Errors](/docs/eventsourcingdb/api#errors)**:

- **`401`**: The API token is missing or wrong.
- **`429`**: Too many requests were sent; the answer says when to try again. The route counts against the limit per client only, not against the global one, see **[Rate Limiting](/docs/eventsourcingdb/rate-limiting)**.
- **`500`**: The server failed unexpectedly.
- **`503`**: The health fails, and the body is the health report with the status `fail`. Or the server is shutting down, and the body is a message rather than a health report.
