> Section: [9. Nagios compatibility](https://jaque.sh/docs/nagios-compat/overview.md)
> Next: nagios-compat/importer
> Index: https://jaque.sh/llms.txt


Thruk, NagVis and Checkmk are part of a whole ecosystem of consoles that
speaks MK Livestatus (LQL) to read a monitoring engine's state without
caring what that engine actually is. jaque implements that protocol, so those tools
point at it without a single config change on their side. What it costs:
Livestatus inherits the protocol's own gaps, the wait headers
(`WaitTrigger`, `WaitCondition`, `WaitObject`, `WaitTimeout`) and the
`statehist` table.

## 1. Turning it on

Two flags, both empty (protocol off) by default:

```
-livestatus-listen 127.0.0.1:6557   # TCP
-livestatus-socket /tmp/jaque-livestatus.sock  # UNIX socket
```

Either or both can be set at once.

```sh
printf 'GET status\nOutputFormat: json\n\n' | nc -U /tmp/jaque-livestatus.sock
```

## 2. What it reads from

Its own projection of the event log, in parallel with the dashboard's:
same mechanism, separate consumer, so a Livestatus client never blocks or
is blocked by the dashboard.

## 3. The tables

Eleven tables: `hosts`, `services`, `hostgroups`, `servicegroups`,
`contacts`, `downtimes`, `comments`, `status`, `timeperiods`, `log`, plus
the meta-table `columns` describing all of them. Filtering, `Stats:`
aggregation (`sum`/`min`/`max`/`avg`), and both output formats (`csv`,
the Nagios default, and `json`) are supported.

`hosts` and `services` carry `notifications_enabled`; `contacts`
carries `host_notifications_enabled` and `service_notifications_enabled`;
`status.enable_notifications` reports the program-wide toggle.

`hosts` and `services` also carry `active_checks_enabled` (0 for a
passive object or one with active checks stopped),
`accept_passive_checks` (always 1), `flap_detection_enabled` (its own
check configured with flap detection on, and not stopped) and
`event_handler_enabled` (a handler configured, and not stopped), each
folding the object's own switch into its configuration. `status` reads
`execute_host_checks`, `execute_service_checks`, `enable_flap_detection`
and `enable_event_handlers` from the program-wide switches, and
`check_host_freshness` and `check_service_freshness` from the
configuration. `accept_passive_host_checks`,
`accept_passive_service_checks`, `check_external_commands` and
`process_performance_data` have no switch, so they always read 1.
`obsess_over_hosts` and `obsess_over_services` always read 0.

`comments` carries user comments (entry_type 1) beside the
acknowledgement (4) and downtime (2) rows. `timeperiods` carries one row
per configured
timeperiod (`name`, `alias`, `in`); `hosts` and `services` gain
`check_period`, `notification_period`, `in_check_period` and
`in_notification_period`, and `contacts` gains
`host_notification_period` and `service_notification_period`, the
contact's one `notification_period` reported under both.

`downtimes` gains `fixed` (1 for a fixed downtime, 0 for any other kind),
`duration` (seconds, set only on a flexible downtime), `triggered_by`
(the downtime ID a triggered downtime names, empty otherwise) and `type`
(0 while the downtime is currently in effect, 1 otherwise), on top of the
Nagios columns the table already carried. A [recurring
downtime](../config/downtimes.md) is not scheduled, so it has no row of
its own to read back; instead the table adds one row per object per
recurring downtime, for whichever occurrence is currently in effect or
the next one. `scheduled_downtime_depth` on `hosts` and `services` counts
downtimes actually in effect right now, scheduled and recurring alike,
rather than every downtime on file for the object.

```
GET services
Filter: state = 2
Stats: state = 2
OutputFormat: json
```

## 4. The log table

`log` holds twelve kinds of row, each in Nagios's own `message` format,
so a console that already parses Nagios's log understands jaque's rows
unchanged:

| Class | Type | Message |
|---|---|---|
| 0 | `HOST EVENT HANDLER` / `SERVICE EVENT HANDLER` | `host;svc;STATE;trigger;handler;status` |
| 1 | `HOST ALERT` / `SERVICE ALERT` | `host;svc;STATE;HARD or SOFT;attempt;output` |
| 1 | `HOST FLAPPING ALERT` / `SERVICE FLAPPING ALERT` | `host;svc;STARTED;` or `host;svc;STOPPED;` |
| 1 | `HOST ACKNOWLEDGE ALERT` / `SERVICE ACKNOWLEDGE ALERT` | `host;svc;STARTED;author;comment` |
| 1 | `HOST ACKNOWLEDGE ALERT` / `SERVICE ACKNOWLEDGE ALERT` | `host;svc;EXPIRED;author;` |
| 1 | `HOST DOWNTIME ALERT` / `SERVICE DOWNTIME ALERT` | `host;svc;STARTED;` |
| 1 | `HOST DOWNTIME ALERT` / `SERVICE DOWNTIME ALERT` | `host;svc;STOPPED;` |
| 2 | `CONFIG RELOAD` | `generation;added;removed;changed` |
| 2 | `CONFIG RELOAD REJECTED` | the rejection reason |
| 3 | `HOST NOTIFICATION` / `SERVICE NOTIFICATION` | `contact;host;svc;STATE;;output` |
| 4 | `PASSIVE HOST CHECK` / `PASSIVE SERVICE CHECK` | `host;svc;code;output` |
| 5 | `EXTERNAL COMMAND` or `EXTERNAL COMMAND REJECTED` | the verb, then the command's fields or the rejection reason |

A host row's service slot is empty and the separator stays, so a parser
built for Nagios's own log still finds the field it expects. `STATE` is
the Nagios word (`UP`, `DOWN`, `OK`, `WARNING`, `CRITICAL`, `UNKNOWN`).

`log` is a ring of `-livestatus-log-cache` entries, refilled from the
event log every time the process starts and kept current after that.
History older than the ring holds is not here: it lives in the events
sink, when [one is configured](https://jaque.sh/docs/reference/config-schema.md#sinks).
Class 5, the `EXTERNAL COMMAND` rows, comes from the audit log rather
than the ring, so it goes back as far as the audit log itself retains.

## 5. Commands

A `COMMAND` line is the same one line the [external command
FIFO](fifo-external-commands.md) accepts: `[<unix_ts>]
VERB;field;field`, parsed the same way, with the same verbs and the
same field validation. A successful command gets an empty answer, as
Nagios's own Livestatus does. A line that fails to parse answers 400
with the parse error; a process with no command sink wired (`-read-only`
set) answers 403; an audit log that cannot take the record answers 503,
since a command with no audit record does not run.

Every `COMMAND`, accepted or not, is written to the audit log with the
connection's peer address and no principal: the protocol carries no
identity. Section 8 covers what accepting commands means for a
listener reachable beyond a trusted network.

## 6. Verified against a real client

The `status` table implements all 20 columns Thruk's connect probe
(`get_processinfo`) actually requests, taken from Thruk's own traffic
rather than inferred from reading the LQL spec. The exact request/response
sequence Thruk sends on connect is pinned in a replay test against real
Thruk traffic: it is checked against what a production Nagios console does
the moment it connects.

## 7. Who can read it

Any console that already knows how to talk Livestatus, such as Thruk,
NagVis, Checkmk or WOCU, can point at a jaque instance and read its state
without modifying its own configuration at all. Combined with the [exec plugin
protocol](../nagios-compat/exec-plugins.md) and the
[FIFO](https://jaque.sh/docs/nagios-compat/fifo-external-commands.md), this is the third leg
that lets an existing Nagios-adjacent toolchain keep functioning unmodified
while the engine underneath changes.

## 8. Security considerations

As in the original Livestatus protocol, the wire format carries no
authentication: anything that can reach the socket can read full state.
`-livestatus-listen` should bind a trusted interface rather than
`0.0.0.0`, and `-livestatus-socket` should rely on filesystem permissions
to keep the socket restricted: the protocol offers no door of its own to
lock.

Both listeners accept `COMMAND` too, so a reachable TCP listener is a
command surface. See [Security considerations](https://jaque.sh/docs/deployment/security.md)
for what that means and how `-read-only` removes it.
