Check logfile¶
Overview¶
Scans a logfile for matching patterns or regular expressions and alerts based on the number of matches found. Supports both simple string matching (--warning-pattern, --critical-pattern) and Python regular expressions (--warning-regex, --critical-regex). Lines can be excluded via --ignore-pattern or --ignore-regex.
Important Notes:
- Requires root or sudo to access most system logfiles
- On Linux,
--filenameis confined to/var/log. The check runs as root via sudo, so it refuses a path that resolves outside the system log directory, which stops it from being turned into an arbitrary root file read. To monitor a log stored elsewhere, bind-mount that location under/var/log(a symlink is rejected); see the Troubleshooting section. On Windows, where the check runs as the account of the monitoring agent's service and there is no sudo, it reads any path. - At least one
--warning-pattern,--warning-regex,--critical-pattern, or--critical-regexmust be specified - When using
--icinga-callback, the parameters--icinga-url,--icinga-password,--icinga-username, and--icinga-service-nameare all required. Create an Icinga API user like so:
object ApiUser "linuxfabrik-check-logfile" {
password = "linuxfabrik"
permissions = [
{
permission = "objects/query/service"
}]
}
- For more complex log analysis use cases, consider using a dedicated logging server like Graylog
Data Collection:
- Expands time macros in
--filenameon every run, so logfiles whose name contains the current date ({today}.log,app-{today}.log,{%Y}{%m}{%d}.log, etc.) can be monitored directly. For{today}and{yesterday}, the compact form (YYYYMMDD) is tried first and ISO 8601 (YYYY-MM-DD) is used as fallback. The read offset and pending matches carry over when the filename changes on the next day, so no wrapper script is needed - Scans only the lines that were added since the previous run, and rescans the whole logfile once it was rotated, truncated, or rewritten from the beginning by the application. A rewrite that reproduces the first 256 bytes of the logfile unchanged is not recognized as one
- Keeps its state in a SQLite database. Each combination of logfile and pattern set gets its own database, so two services watching the same logfile for different things do not interfere. Changing a pattern starts a new database, and the next run therefore reports every match the logfile still holds
--warning-patternand--critical-patternsearch for plain substrings and are faster than their regex counterparts- Matches keep alerting across runs, even once the logfile stops growing: for
--alarm-durationminutes (default 60), or, with--icinga-callback, until the service is acknowledged in Icinga. They appear in the output as "Unacknowledged warning/critical matches from previous runs" and count towards the thresholds like new matches do --before-context,--after-contextand--contextprint up to 10 lines around each match, like grep. The lines are shown in the order the logfile holds them, with the matching line marked by>>>. Because only new lines are read, the lines in front of a match often come from the previous run, and the lines after it often only arrive on the following runs; the check keeps the former back and adds the latter to the match as they are written. As in grep, no line is printed twice, so a line between two matches belongs to the first one. Context lines are taken from the logfile as it is, regardless of--matchand--ignore, and a rotation discards what was kept back. The context applies to matches found from then on: a match that was already reported keeps the text it was found with, and the lines around it cannot be added later
Fact Sheet¶
| Fact | Value |
|---|---|
| Check Plugin Download | https://github.com/Linuxfabrik/monitoring-plugins/tree/main/check-plugins/logfile |
| Nagios/Icinga Check Name | check_logfile |
| Check Interval Recommendation | Every minute |
| Can be called without parameters | No (--filename and at least one pattern/regex are required) |
| Runs on | Cross-platform |
| Compiled for Windows | Yes |
| Uses State File | $TEMP/linuxfabrik-monitoring-plugins-logfile-<basename>-<hash>.db (one DB per combination of logfile and pattern set) |
Help¶
usage: logfile [-h] [-V] [--after-context AFTER_CONTEXT]
[--alarm-duration ALARM_DURATION] [--always-ok]
[--before-context BEFORE_CONTEXT] [--context CONTEXT] [-c CRIT]
[--critical-pattern CRIT_PATTERN] [--critical-regex CRIT_REGEX]
--filename FILENAME [--icinga-callback]
[--icinga-password ICINGA_PASSWORD]
[--icinga-service-name ICINGA_SERVICE_NAME]
[--icinga-url ICINGA_URL] [--icinga-username ICINGA_USERNAME]
[--ignore IGNORE] [--insecure] [--match MATCH] [--no-insecure]
[--no-match-severity {ok,warn,crit,unknown}] [--no-perfdata]
[--no-proxy] [--proxy PROXY] [--suppress-lines]
[--timeout TIMEOUT] [-w WARN] [--warning-pattern WARN_PATTERN]
[--warning-regex WARN_REGEX]
Scans a logfile for matching patterns or regular expressions and alerts based
on the number of matches found. Only the lines added since the previous run
are scanned, and the whole file is rescanned whenever it was rotated,
truncated or rewritten in place. Optionally asks the monitoring server whether
the service running this check is acknowledged, and suppresses repeated alerts
for known issues where it is. Configurable alarm duration limits how long
matches trigger alerts. `--filename` accepts time macros, so logfiles whose
name contains the current date (`20260422.log`, `app-2026-04-22.log`, etc.)
can be monitored directly. `{today}` / `{yesterday}` resolve tolerantly:
compact (`YYYYMMDD`) first, ISO 8601 (`YYYY-MM-DD`) as fallback if the compact
file does not exist. Read offset and pending matches carry over when the
filename changes on the next day, no wrapper script needed. Prints the lines
around each match on request, like `grep --context`, including lines the
logfile only receives after the run that found the match. Requires root or
sudo.
options:
-h, --help show this help message and exit
-V, --version show program's version number and exit
--after-context AFTER_CONTEXT
Print this many lines that follow a matching line
along with it, like `grep --after-context`. Lines the
logfile does not hold yet are added on the following
runs. Applies to matches found from then on. Takes
precedence over `--context`. Takes 0 to 10. Default:
the value of `--context`
--alarm-duration ALARM_DURATION
Duration in minutes for how long new matches trigger
an alert. Overwritten by `--icinga-callback`. Default:
60
--always-ok Always returns OK.
--before-context BEFORE_CONTEXT
Print this many lines that precede a matching line
along with it, like `grep --before-context`. Lines
read by the previous run count as well. Applies to
matches found from then on. Takes precedence over
`--context`. Takes 0 to 10. Default: the value of
`--context`
--context CONTEXT Print this many lines before and after a matching line
along with it, like `grep --context`. Sets `--before-
context` and `--after-context` where they are not
given. Applies to matches found from then on. Takes 0
to 10. Default: 0
-c, --critical CRIT CRIT threshold for the number of found critical
matches. Default: 1
--critical-pattern CRIT_PATTERN
Any line containing this pattern will count as a
critical. Can be specified multiple times.
--critical-regex CRIT_REGEX
Any line matching this Python regex will count as a
critical. Can be specified multiple times.
--filename FILENAME Path to the logfile. Supports time macros that are
expanded on every run: `{today}` / `{yesterday}` first
try the compact form `YYYYMMDD`, then fall back to
`YYYY-MM-DD` if that file does not exist. `{%Y}`,
`{%y}`, `{%m}`, `{%d}`, `{%H}`, `{%M}`, `{%S}` render
the matching strftime component of the current time.
Example: `/var/log/app/{today}.log`. Example:
`/var/log/app/app-{today}.log`. Example:
`/var/log/app/{%Y}{%m}{%d}.log`.
--icinga-callback Ask the monitoring server whether the service running
this check is acknowledged. Where it is, what this run
reports is remembered as already handled, so it no
longer raises an alert on the following runs. Requires
`--icinga-url`, `--icinga-username`, `--icinga-
password` and `--icinga-service-name`.
--icinga-password ICINGA_PASSWORD
Monitoring server API password.
--icinga-service-name ICINGA_SERVICE_NAME
Unique name of the service running this check, as the
monitoring server knows it. Take it from the `__name`
service attribute. Example: `monitoring-server!my-
service-name`.
--icinga-url ICINGA_URL
Monitoring server API URL. Example:
`https://monitoring.example.com:5665`.
--icinga-username ICINGA_USERNAME
Monitoring server API username.
--ignore IGNORE Ignore a line matching this Python regular expression,
whichever warning or critical pattern it also matches.
Case-sensitive by default; use `(?i)` for case-
insensitive matching. Can be specified multiple times.
Example: `--ignore='(?i)linuxfabrik'`.
--insecure Applies to the connection to the monitoring server
that `--icinga-callback` makes, which is the only
network connection this check opens. This option
explicitly allows insecure SSL connections.
--match MATCH Only consider a line matching this Python regular
expression. Applied before the warning and critical
patterns decide the severity, so it narrows what is
looked at rather than what counts as a problem. Case-
sensitive by default; use `(?i)` for case-insensitive
matching. Can be specified multiple times. If both
`--match` and `--ignore` are given, an item must match
`--match` AND not match `--ignore` to be reported
(include first, exclude second). Example:
`--match='^\[prod\]'`.
--no-insecure Applies to the connection to the monitoring server
that `--icinga-callback` makes, which is the only
network connection this check opens. Verify the TLS
certificate against the system trust store, overriding
the insecure default of this check. Use it once the
endpoint presents a publicly trusted certificate, or
once its CA has been added to the system trust store.
--no-match-severity {ok,warn,crit,unknown}
State to report when no item matches the filters and
nothing is checked. Default: ok
--no-perfdata Suppress the performance data section from the output.
The status message and the exit code are unaffected,
so alerting keeps working while trending data is
dropped.
--no-proxy Applies to the connection to the monitoring server
that `--icinga-callback` makes, which is the only
network connection this check opens. Do not use a
proxy, not even one the environment names. Overrides
`--proxy`.
--proxy PROXY Applies to the connection to the monitoring server
that `--icinga-callback` makes, which is the only
network connection this check opens. Proxy to reach
the target through. The scheme defaults to `http` when
omitted. Overrides the proxy the environment names
(`http_proxy`, `https_proxy`, `all_proxy`) together
with the exceptions it lists in `no_proxy`, and is
itself overridden by `--no-proxy`. Without either
parameter the environment applies. Credentials belong
into the environment variable rather than here,
because a command-line argument is visible to every
user on the host. Example:
`--proxy=http://proxy.example.com:3128`.
--suppress-lines Suppress the found lines in the output and only report
the number of findings.
--timeout TIMEOUT Network timeout in seconds. Default: 5 (seconds)
-w, --warning WARN WARN threshold for the number of found warning
matches. Default: 1
--warning-pattern WARN_PATTERN
Any line containing this pattern will count as a
warning. Can be specified multiple times.
--warning-regex WARN_REGEX
Any line matching this Python regex will count as a
warning. Can be specified multiple times.
Documentation:
https://linuxfabrik.github.io/monitoring-plugins/check-plugins/logfile/
Usage Examples¶
cat > /tmp/test-logfile << 'EOF'
test0
test1
warning
test2
test
error1
error2
test4
EOF
./logfile --filename=/tmp/test-logfile --critical-pattern='error' --warning-pattern='warn'
Output:
Scanned /tmp/test-logfile (8 lines) using patterns 'warn' (matched 1 line) [WARNING] and 'error' (matched 2 lines) [CRITICAL].
Warning matches:
* warning
Critical matches:
* error1
* error2
The (N lines) figure counts the lines that are new since the previous run, not the length of the logfile. Both are the same on the first run and after a rotation.
With the lines around each match:
./logfile --filename=/var/log/myapp/app.log --critical-regex=' ERROR ' --context=2
Output:
Scanned /var/log/myapp/app.log (9 lines) using patterns ' ERROR ' (matched 1 line) [CRITICAL].
Critical matches:
* 2026-09-21 10:00:00 INFO GET /
2026-09-21 10:00:01 INFO POST /api/order
>>> 2026-09-21 10:00:02 ERROR Request failed
Traceback (most recent call last):
File "app.py", line 12, in handle
States¶
- OK if no matches are found or the number of matches is below both thresholds.
- WARN if the number of warning matches (new + old) is >=
--warning(default: 1). - CRIT if the number of critical matches (new + old) is >=
--critical(default: 1). - UNKNOWN if the logfile does not exist, is not readable, or no pattern/regex is specified.
--always-oksuppresses all alerts and always returns OK.
Perfdata / Metrics¶
| Name | Type | Description |
|---|---|---|
| crit_matches | Number | Number of new critical matches found in this run. |
| scanned_lines | Number | Total number of new lines scanned in this run. |
| warn_matches | Number | Number of new warning matches found in this run. |
Credits, License¶
- Authors: Linuxfabrik GmbH, Zurich
- License: The Unlicense, see LICENSE file.