boltZharp Docs
searchMonitors

Log Monitors

Watch the logs you send to Zharp and open an incident as soon as a line matches one of your patterns.

A log monitor doesn't probe anything. It reads the log lines already stored in Zharp — collected by the Zharp agent, drained from your hosting provider, or sent from your code or the API — and goes down when a line from the services you chose matches a pattern.

Before you start

  • Logs must already be arriving. You choose services from the names Zharp has seen, so send some logs first — see Logs. Until then the service list says No log services found.

Create a log monitor

  1. 1
    Pick the type

    On the Monitors page click New, open Monitor type and choose Log monitor.

  2. 2
    Choose the services

    In Log service names, pick one or more services from the list — the service you send with each log entry through the API, or the name the agent reports: the --service name given to it for a log file, the Compose service (or container name) for a Docker container, the unit name without .service for a systemd service, and the app name for a PM2 app. Only services Zharp has already received logs from can be picked; typing a new name does nothing.

  3. 3
    Write the patterns

    In Alert when these appear, enter one pattern per line. A pattern is a keyword or a regular expression:

    ERROR
    Failed to connect
    OutOfMemoryError
    HTTP/1\.[01]" 50[0-9]
    payment (declined|timed out)
  4. 4
    Create it

    Click Create monitor. At least one service and one pattern are required. The monitor scans on its Check frequency (under Advanced settings, 3 minutes by default).

How patterns match

  • Every pattern is a regular expression, matched against the line's text and its level — the two you see side by side on the Logs page — anywhere and ignoring case. So ERROR catches every line logged at the error level whatever its text says, and also text such as no errors found. Anchor or extend a pattern when that's too broad: ^ERROR only matches text that starts with it (and the level error).
  • A line matches when it matches any of the patterns. There is no count or threshold: one matching line is enough.
  • Write the expression on its own. If you wrap it in slashes the JavaScript way, as in /timeout/i, Zharp removes the slashes and any trailing flags when you save — matching always ignores case anyway.
  • Characters such as . ( [ ? + * have regex meaning. Escape them with a backslash to match them literally, as in HTTP/1\.1.
  • Only the text and the level are searched — not the service name or metadata. To narrow by those, use the scope below.
warning
Invalid patterns are refused

Saving fails with Invalid log pattern: … naming the pattern and the problem when one of them isn't a valid regular expression — an unclosed ( or [, for example — or uses a named group such as (?<code>\d+), which the matcher doesn't support. If a pattern saved earlier is still invalid, the scan skips it and keeps matching the others.

Scope by environment, source and fields

Three optional fields on the form narrow what a monitor scans, on top of its services. Leave them empty to scan everything, as before. All of them must hold for a line to count, and a line that matches the scope still has to match a pattern — use . as the pattern to alert on every line in the scope.

FieldWhat it doesExample
EnvironmentsOnly lines tagged with one of these environments (unified service tagging). Untagged lines are left out once any is set.prod
SourcesOnly lines from these technologies — declared, or detected from the line's format.nginx, postgresql
Field conditionsOne condition per line on the fields Zharp parsed from the line or the attributes it was sent with.http.status_code>=500

A field condition is one field, an operator and a value:

WriteMatches lines where
http.method=POSTthe field equals the value, compared as text (client.ip:10.0.0.4 means the same)
http.method!=GETthe field differs from the value, or the line doesn't have it
duration_ms>1000the field is a number and compares so — also >= < <=. Lines where it isn't a number don't match
error.type:*the line has the field at all

Up to 10 conditions; a condition that doesn't parse is refused when you save, with Invalid field filter: … saying why. The incident records the environments and sources the monitor was scoped to, and the incident's log view and the monitor page's stream show only those environments and sources. On the Logs screen, type the same conditions into the search box with an @ in front — payment @http.status_code>=500 searches for “payment” on lines whose status code is 500 or more.

Log levels

Levels are stored in one spelling whatever case or synonym the log used, so ERROR, Error and err are all the same level, and filters in the log viewer treat them alike:

Stored asAlso accepted
fatalFATAL, critical, crit, emerg, alert, panic
errorERROR, Error, err, severe
warnWARN, warning, Warning
infoINFO, notice, and lines sent without a level or with one Zharp doesn't recognise
debugDEBUG, trace is kept as its own level below debug

Syslog severity numbers (0–7) and OpenTelemetry severity text such as ERROR2 are folded the same way. A log monitor scans info, warn, error and fatal lines — everything except debug and trace.

The agent sets the level where the source states one: a systemd service's priority (0–2 fatal, 3 error, 4 warn, 5–6 info, 7 debug), or for a container a JSON level/severity field, level=… or a leading ERROR/WARN/INFO/DEBUG. Anything else — including whatever a program writes to stderr — is stored as info, so match on the message to catch errors that don't say so.

When it scans

Each scan covers the log lines timestamped since the previous scan, up to 5 seconds before the scan starts; the first scan looks back 60 seconds. Lines are found by their own timestamp — the one you send, the one the agent reads from the start of the line, or the time Docker or the journal recorded it — so a line that reaches Zharp after a scan has already passed its timestamp isn't picked up.

Down, and back up

When a scan finds matching lines, the monitor goes down and opens an incident:

FieldExample
Monitor messageLog Pattern Matched: Failed to connect
Incident titlePattern Match: "Failed to connect" in Checkout logs
Incident causePattern "Failed to connect" matched 4 times in 3 min

The count is every matching line in the scan, and the time is the span that scan actually covered — normally your check frequency, so a monitor checking every 3 minutes says in 3 min. The incident lists up to 20 of the matching lines, newest first, with the pattern each one matched; the count isn't limited to those 20, and a line that matches several patterns counts once. The monitor page shows the same count and window for the latest scan. While the incident is open, later matches are added to its timeline instead of opening new incidents.

info
A log monitor doesn't recover by itself

Unlike a check that starts passing again, quiet logs don't prove the problem is gone. The monitor stays down as long as its incident is open. Once you click Resolve on the incident, the next scan with no matches brings the monitor back up.

Maintenance windows

Log monitors follow maintenance windows like every other monitor, including recurring ones. While a window covers the monitor it shows Maintenance: nothing is scanned, it doesn't go down, no incident opens and no alert goes out. Lines logged during the window are skipped for good — the first scan after it ends only looks at what came in after the window.