CheckEventLog¶
Available on Windows only.
Check for errors and warnings in the event log.
Standard event-logs¶
The default command will monitor the application/system/security logs which usually have the generic errors.
check_eventlog
L cli CRITICAL: CRITICAL: 5 message(s) Application Bonjour Service (Task Scheduling Error: ... e DNS-servrarna svarade.)
L cli Performance data: 'problem_count'=5;0;0
Time and date¶
The default time frame is 24 hours. This can be configured via the scan-range which specifies the number of hours from now to look.
This might seem a bit off at first but all date and time ranges which reflect past times are “negative” in NSClient++.
Thus the default is: check_eventlog scan-range=-24h
If you instead wish to check the past week you would change this to: check_eventlog scan-range=-1w
The other option you can use for defining time is the filter keyword written. This can be used much the same but is used if you wish to use the time in the filter so you still need to specify scan-range. But if you for instance want to get an error if the message is 24 hours old and a warning if it is 1 week you would do:
check_eventlog scan-range=-1w "warn=count gt 0" "critical=written > -24h"
Checking for specific messages¶
There are many ways to find messages but the optimum solution is to filter on log, source (provider), and id. This is as this combination is guaranteed to be unique and still quick to look for. Another option it so look for messages which will obviously work as well but it will be magnitudes slower in terms of performance.
To find the source and event id you can easily look at the messages property in the event viewer.

With this information in hand we can easily create a filter for a specific message like so:
check_eventlog "filter=provider = 'Microsoft-Windows-Security-SPP' and id = 903"
Sometimes, rarely, the message is important and then it is best to add that as a last check to the above filter as it will be faster.
check_eventlog "filter=provider = 'Microsoft-Windows-Security-SPP' and id = 903 and message like 'foo'"
Modern windows (channels)¶
NSClient++ also has had the ability to check all logs on modern windows machines. This works out of the box and you specify the path of the channel you want to look for with the file command. A slight snag here is that the separator for “folders” is - not \ r / as one might expect this is unfortunately a windows flaw most likely related to the fact that event logs can also be read from the file system.
A simple way to find the actual name of an event log channel is to view its properties (right-click the channel and click properties):

check_eventlog scan-range=-100w show-all filter=none "file=Microsoft-Windows-AAD/Operational"
Checking for non errors¶
The default filters are filtering out only warnings, errors and critical messages:
| Property | Default value |
|---|---|
| filter | level in (‘warning’, ‘error’, ‘critical’) |
| warning | level = ‘warning’ or problem_count > 0 |
| critical | level in (‘error’, ‘critical’) |
Thus if you want to find a message which is not warnings, errors and critical messages you need to either change or disable the default filter like so:
check_eventlog filter=none
Severity/Level/Error¶
In the previous event-log API it was common for people to use severity to filter out errors. This has never worked as severity was never message severity, it remains however, a common thing. Regardless of version of API and version of NSClient++ the proper way to find errors is to use the level keyword like so:
check_eventlog "filter=level = 'error'"
While we have never been able to find an official list of the meaning of the levels, the mapping NSClient++ uses between the numeric values and the keywords (critical, error, warning, …) is documented on the level keyword in the filter keywords table below.
Thus if you run into a non standard level you can check this like so:
check_eventlog "filter=level = 42"
Using Real-time monitoring¶
The benefit of real-time monitoring of the event-log is that it is often significantly faster and more resources efficient. The drawback is that it is more complex to setup and normally requires passive monitoring (via NSCA/NRDP)
The basic idea is depict in the following figure.

We have a filter which listens to event log entries. These entries are (when they matched) turned into messages and statuses which is then sent onward to various channels. On the other end of these channels are (hopefully) someone who is interested in the message.
In most cases the first channel you are interested in is NSCA which is the default name where the NSCAClient listens. It will in turn forward all incoming messages on to Nagios via NSCA.
So in short we need to configure three things
- Activate real time filtering
- Add a filter which listens for events
- Setup a destination
Enabling real-time filtering¶
To setup real time filtering we only need a single flag (as well as the eventlog module).
configuration:
[/modules]
CheckEventLog=enabled
[/settings/eventlog/real-time]
enabled = true
Adding this will not do much since we don’t have a filter yet but adding one is pretty simple as well so lets go ahead and do that.
To make life simple we set the destination in this filter to “log” which means the information only ends up in the NSClient++ log file. Not very useful in reality but very useful when we are debugging as it removes possible errors sources.
configuration:
[/settings/eventlog/real-time/filters/my_alert]
log=application
destination=log
filter=level='error'
maximum age=30s
debug=true
Going through the configuration line by line we have:
log=applicationis the log we listen to.destination=logis where the message is sentfilter=level='error'means we only want to receive error messages.maximum age=30ssets a repeating “ok” messages every 30 seconds.debug=truewill increase the debug level for this filter
If we were to test this (and please do go ahead) we would start getting warning on the console about no one listening to our events.
To be able to test this we need to inject some messages in the eventlog. This we can do with the eventcreate command.
Add error to eventlog:
eventcreate /ID 1 /L application /T ERROR /SO MYEVENTSOURCE /D "My first log"
Add info to eventlog:
eventcreate /ID 1 /L application /T INFORMATION /SO MYEVENTSOURCE /D "My first log"
If we check the log we should see something similar to this:

- 1: Always make sure there are not errors and that the parsed tree looks like you want it. If the filter has syntax issues nothing will work
- 2: This is how it looks when we inject an error message, it is caught and we get the
Notification 0: Application: 1 (error: My first log)in the log. - 3: This is the periodical “ok” message we get when there are not errors:
Notification 0: eventlog found no records - 4: Here we can see the output when there is a message but it does not match our filter.
Enabling cache to check actively¶
TODO
Enable module¶
To enable this module and and allow using the commands you need to ass CheckEventLog = enabled to the [/modules] section in nsclient.ini:
[/modules]
CheckEventLog = enabled
Queries¶
A quick reference for all available queries (check commands) in the CheckEventLog module.
List of commands:
A list of all available queries (check commands)
| Command | Description |
|---|---|
| check_eventlog | Check for errors in the event log. |
check_eventlog¶
Check for errors in the event log.
Filtering by account SID (user / sid)¶
Each event carries the security identifier (SID) of the account associated with
it. The user keyword (alias sid) exposes that SID as a string (e.g.
S-1-5-18 for LOCAL SYSTEM), so you can scope a check to a specific account.
check_eventlog file=Security "filter=user = 'S-1-5-18'" "detail-syntax=${id}: ${message}"
user/sid is populated by the modern Windows Event Log API
(EvtSystemUserID). On the legacy ReadEventLog API (pre-Vista, or when the
modern API is unavailable) it renders as an empty string.
“Since last check” scanning¶
To avoid re-scanning and double-counting the same events on every poll, use the
bookmark option. With bookmark=auto (or a shared bookmark name) the check
resumes after the last event it saw, rather than re-walking the whole
scan-range window each time:
check_eventlog file=Application bookmark=auto "filter=level = 'error'"
The bookmark position is persisted across restarts (stored under
eventlog.bookmarks), so a monitoring cycle only ever reports genuinely new
events. Without a bookmark the check falls back to the time-window scan-range
(default -24h), which is stateless and may re-report events inside the window.
Jump to section:
Command-line Arguments¶
| Option | Default Value | Description |
|---|---|---|
| file | File to read (can be specified multiple times to check multiple files. | |
| log | Same as file | |
| scan-range | Date range to scan. | |
| truncate-message | Maximum length of message for each event log message text. | |
| unique | true | Shorthand for setting default unique index: ${log}-${source}-${id}. |
| bookmark | auto | Use bookmarks to only look for messages since last check (with the same bookmark name). If you set this to auto or leave it empty the bookmark name will be derived from your logs, filters, warn and crit. |
file:
File to read (can be specified multiple times to check multiple files. Notice that specifying multiple files will create an aggregate set you will not check each file individually.In other words if one file contains an error the entire check will result in error.
scan-range:
Date range to scan. A negative value (e.g. -1h) scans backward through historical events; a positive value (e.g. +1h) scans forward into future events. The value is a relative offset from now using the suffixes s (seconds), m (minutes), h (hours), d (days) or w (weeks); a bare number is treated as seconds. This is used as an approximate time window to limit how far the scan walks the log and significantly speeds up large logs, but messages are not guaranteed to be returned in order. Defaults to -24h when omitted.
unique:
Shorthand for setting default unique index: ${log}-${source}-${id}.
Default Value: true
bookmark:
Use bookmarks to only look for messages since last check (with the same bookmark name). If you set this to auto or leave it empty the bookmark name will be derived from your logs, filters, warn and crit.
Default Value: auto
Common options:
These options are shared by all filter based commands and are described on the common options page; the default values below are specific to this command.
| Option | Default Value |
|---|---|
| filter | level in (‘warning’, ‘error’, ‘critical’) |
| warning | level = ‘warning’, problem_count > 0 |
| warn | |
| critical | level in (‘error’, ‘critical’) |
| crit | |
| ok | |
| debug | false |
| show-all | false |
| empty-state | ok |
| perf-config | level(ignored:true) |
| escape-html | false |
| list-separator | , |
| top-syntax | ${status}: ${count} message(s) ${problem_list} |
| ok-syntax | %(status): Event log seems fine |
| empty-syntax | %(status): No entries found |
| detail-syntax | ${file} ${source} (${message}) |
| perf-syntax | ${file}_${source} |
| unique-index | |
| byte-unit | |
| decimal-separator | |
| decimals | -1 |
| thousands-separator |
This command also accepts the standard help options: help, help-pb, show-default, help-short.
Filter keywords¶
| Option | Description |
|---|---|
| category | TODO |
| computer | Which computer generated the message |
| customer | TODO |
| file | The logfile name |
| guid | The logfile name |
| id | Eventlog id |
| keyword | The keyword associated with this event |
| level | Severity level: critical (1), error (2), warning/warn (3), informational/info/information/success/auditSuccess (4), debug/verbose (5); use the raw number for other values (e.g. level = 42) |
| log | alias for file |
| message | The message rendered as a string. |
| opcode | The opcode associated with this event |
| provider | Source system. |
| rawid | Raw message id (contains many other fields all baked into a single number) |
| sid | Alias for user (the event’s account SID) |
| source | Source system. |
| task | The type of event (task) |
| type | alias for level (old, deprecated) |
| user | SID of the account associated with the event (e.g. S-1-5-18); empty on the legacy API. Enables filtering by SID. |
| written | When the message was written to file |
| written_str | When the message was written to file as an absolute date string |
| xml | Get event as XML message. |
This command also supports the common filter keywords: count, total, ok_count, warn_count, crit_count, problem_count, list, ok_list, warn_list, crit_list, problem_list, detail_list, sep, status.
Configuration¶
| Path / Section | Description |
|---|---|
| /settings/eventlog | Eventlog |
| /settings/eventlog/real-time | Real-time eventlog monitoring |
| /settings/eventlog/real-time/filters | Real-time eventlog filters |
Eventlog ¶
Section for the EventLog Checker (CheckEventLog.dll).
| Key | Default Value | Description |
|---|---|---|
| buffer size | 131072 | Default buffer size |
| debug | false | Enable debugging |
| lookup names | true | Lookup eventlog names |
| syntax | Default syntax |
# Section for the EventLog Checker (CheckEventLog.dll).
[/settings/eventlog]
buffer size=131072
debug=false
lookup names=true
Default buffer size ¶
The size of the buffer to use when getting messages this affects the speed and maximum size of messages you can receive.
| Key | Description |
|---|---|
| Path: | /settings/eventlog |
| Key: | buffer size |
| Default value: | 131072 |
Sample:
[/settings/eventlog]
# Default buffer size
buffer size=131072
Enable debugging ¶
Log more information when filtering (useful to detect issues with filters) not useful in production as it is a bit of a resource hog.
| Key | Description |
|---|---|
| Path: | /settings/eventlog |
| Key: | debug |
| Default value: | false |
Sample:
[/settings/eventlog]
# Enable debugging
debug=false
Lookup eventlog names ¶
Lookup the names of eventlog files
| Key | Description |
|---|---|
| Path: | /settings/eventlog |
| Key: | lookup names |
| Default value: | true |
Sample:
[/settings/eventlog]
# Lookup eventlog names
lookup names=true
Default syntax ¶
Set this to use a specific syntax string for all commands (that don’t specify one).
| Key | Description |
|---|---|
| Path: | /settings/eventlog |
| Key: | syntax |
| Default value: | N/A |
Sample:
[/settings/eventlog]
# Default syntax
syntax=
Real-time eventlog monitoring ¶
A set of options to configure the real time checks
| Key | Default Value | Description |
|---|---|---|
| debug | false | Enable debugging |
| enabled | false | Enable realtime monitoring |
| log | application,system | Logs to check |
| startup age | 30m | Read old records at startup |
# A set of options to configure the real time checks
[/settings/eventlog/real-time]
debug=false
enabled=false
log=application,system
startup age=30m
Enable debugging ¶
Log missed records (useful to detect issues with filters) not useful in production as it is a bit of a resource hog.
| Key | Description |
|---|---|
| Path: | /settings/eventlog/real-time |
| Key: | debug |
| Default value: | false |
Sample:
[/settings/eventlog/real-time]
# Enable debugging
debug=false
Enable realtime monitoring ¶
Spawns a background thread which detects issues and reports them back instantly.
| Key | Description |
|---|---|
| Path: | /settings/eventlog/real-time |
| Key: | enabled |
| Default value: | false |
Sample:
[/settings/eventlog/real-time]
# Enable realtime monitoring
enabled=false
Logs to check ¶
Comma separated list of logs to check
| Key | Description |
|---|---|
| Path: | /settings/eventlog/real-time |
| Key: | log |
| Default value: | application,system |
Sample:
[/settings/eventlog/real-time]
# Logs to check
log=application,system
Read old records at startup ¶
The initial age to scan when starting NSClient++
| Key | Description |
|---|---|
| Path: | /settings/eventlog/real-time |
| Key: | startup age |
| Default value: | 30m |
Sample:
[/settings/eventlog/real-time]
# Read old records at startup
startup age=30m
Real-time eventlog filters ¶
A set of filters to use in real-time mode
This is a section of objects. This means that you will create objects below this point by adding sections which all look the same.
Keys:
| Key | Default Value | Description |
|---|---|---|
| byte unit | BYTE UNIT | |
| command | COMMAND NAME | |
| critical | CRITICAL FILTER | |
| debug | DEBUG | |
| decimal separator | DECIMAL SEPARATOR | |
| decimals | -1 | DECIMALS |
| destination | DESTINATION | |
| detail syntax | SYNTAX | |
| empty message | eventlog found no records | EMPTY MESSAGE |
| escape html | ESCAPE HTML | |
| filter | FILTER | |
| list separator | LIST SEPARATOR | |
| log | FILE | |
| logs | FILES | |
| maximum age | 5m | MAXIMUM AGE |
| ok | OK FILTER | |
| ok syntax | SYNTAX | |
| perf config | PERF CONFIG | |
| run on startup | RUN ON STARTUP | |
| severity | SEVERITY | |
| silent period | false | Silent period |
| source id | SOURCE ID | |
| target | DESTINATION | |
| target id | TARGET ID | |
| thousands separator | THOUSANDS SEPARATOR | |
| top syntax | SYNTAX | |
| truncate | Truncate | |
| warning | WARNING FILTER |
Sample:
# An example of a Real-time eventlog filters section
[/settings/eventlog/real-time/filters/sample]
#byte unit=...
#command=...
#critical=...
#debug=...
#decimal separator=...
decimals=-1
#destination=...
#detail syntax=...
empty message=eventlog found no records
#escape html=...
#filter=...
#list separator=...
#log=...
#logs=...
maximum age=5m
#ok=...
#ok syntax=...
#perf config=...
#run on startup=...
#severity=...
silent period=false
#source id=...
#target=...
#target id=...
#thousands separator=...
#top syntax=...
#truncate=...
#warning=...