syslog_facets
Top-N value counts for ONE syslog field over a window — 'what are the top actions/reasons on this FortiGate in the last 2 hours' in a single call, instead of pulling rows and counting them yourself. Wraps GET /api/syslog/facets (permission: logs); tag-scoped server-side.
group_by takes one of two kinds of field:
COLUMN (indexed, may run fleet-wide — device_id optional): facility, severity, source
MESSAGE FIELD (parsed out of the message text at read time — device_id REQUIRED): action, reason, devname, type, subtype, level, logdesc, msg, service, policyid, srccountry, dstcountry, srcintf, dstintf, user, group, status, app, appcat, vpntunnel, eventtype, proto
Message fields have no index and cannot get one — they are pulled out of free text — so every message pivot is a sequential scan of the window (~37x the per-row cost of a column pivot). device_id is mandatory for them and the server rejects a fleet-wide message pivot outright.
devname and source are DIFFERENT keys and are deliberately not merged: source is the column syslog arrived with (a relay may have rewritten it to its own name), devname is what the device wrote about itself inside the message. Ask for the one you mean.
Window: hours (1-168, default 24) OR start_time+end_time (ISO-8601 UTC); a window wider than 168h is refused either way. limit is the top-N cut (1-50, default 20).
Reading the result: facets is the top-N; other is everything below the cut, so facets + other sums to matched_rows. rows_without_field counts rows in the window where the field is absent entirely — a large value is normal (a FortiGate emits many message types) and is NOT a failure.
Errors are structured, and two of them are instructions:
error='window_too_large' — the row pre-check refused before scanning. Lower hours (halve it and retry) or add/narrow device_id. rows_in_window and max_rows tell you how far over you are. Do NOT retry the same window.
error='query_timeout' — the scan passed the 10s server budget. Same remedy: narrow the window, or pivot a column instead.
Example: syslog_facets({group_by: "action", device_id: 372, hours: 2})
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| hours | No | Lookback window in hours (1-168). Default 24. | |
| limit | No | Top-N cut (1-50). Default 20; the rest is folded into `other`. | |
| end_time | No | ISO-8601 UTC. Must be paired with start_time. | |
| group_by | Yes | Field to pivot on. Columns: facility, severity, source (device_id optional). Message fields: action, reason, devname, type, subtype, level, logdesc, msg, service, policyid, srccountry, dstcountry, srcintf, dstintf, user, group, status, app, appcat, vpntunnel, eventtype, proto (device_id REQUIRED). | |
| device_id | No | Device id to pivot within. Required for every message-field group_by; optional for facility/severity/source. | |
| start_time | No | ISO-8601 UTC (e.g. 2026-04-23T10:00:00Z). Must be paired with end_time. |