167 lines
5.4 KiB
Bash
Executable File
167 lines
5.4 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
set -e
|
|
|
|
: << =cut
|
|
|
|
=head1 NAME
|
|
|
|
loggrepx - Counts the number of matching log lines by log file
|
|
|
|
=head1 DESCRIPTION
|
|
|
|
This plugin is somewhat of a bash port of the original loggrep plugin,
|
|
except that it displays a breakdown of matches per file, rather than
|
|
aggregating matches across all files. It is intended to answer the
|
|
question, "Which of my logs are reporting concerning events right now?"
|
|
|
|
=head1 CONFIGURATION
|
|
|
|
The plugin can be included multiple times to create graphs for various
|
|
differing kinds of information in your log files. For example, you may
|
|
want to monitor the occurrence of 5xx errors in your webserver logs, but
|
|
also the occurrence of alert|critical|emergency entries in your syslog.
|
|
|
|
You can accomplish this by linking the plugin twice and providing
|
|
different criteria for each instance.
|
|
|
|
Note that most instances will probably work best when run as root, since
|
|
log files are usually (or at least should be) controlled with strict
|
|
permissions.
|
|
|
|
Available config options include the following:
|
|
|
|
env.logfiles - Files to grep (shellglob) (required)
|
|
env.regex - Regex to look for (required)
|
|
env.title - Graph title
|
|
env.warning - Default warning level
|
|
env.critical - Default critical level
|
|
env.[field]_label - Label to use for a specific logfile
|
|
env.[field]_warning - Warning level for specific logfile
|
|
env.[field]_critical - Critical level for specific logfile
|
|
|
|
NOTE: for any variable with [field] in it, [field] is derived from the
|
|
full logfile path by simply removing the preceding slash and replacing
|
|
all non-alphanumerics with underscores. For example, the "warning" field
|
|
for the logfile F</var/log/nginx/errors.log> would be
|
|
F<var_log_nginx_errors_log_warning>.
|
|
|
|
One good way to get these names is to run C<munin-run [plugin-name]>
|
|
after you've configured the required variables and then just copy/paste
|
|
the names from the output.
|
|
|
|
=head1 AUTHOR
|
|
|
|
Kael Shipman <kael.shipman@gmail.com>
|
|
|
|
=head1 LICENSE
|
|
|
|
Copyright 2018 Kael Shipman<kael.shipman@gmail.com>
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a
|
|
copy of this software and associated documentation files (the "Software"),
|
|
to deal in the Software without restriction, including without limitation
|
|
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
and/or sell copies of the Software, and to permit persons to whom the
|
|
Software is furnished to do so, subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be included
|
|
in all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
=head1 MAGIC MARKERS
|
|
|
|
#%# family=manual
|
|
|
|
=cut
|
|
|
|
|
|
. "$MUNIN_LIBDIR/plugins/plugin.sh"
|
|
|
|
regex=${regex:-}
|
|
logfiles=${logfiles:-}
|
|
LOGFILES="$(IFS= ; for f in $logfiles; do echo "$f"; done)"
|
|
title="${title:-Log Matches}"
|
|
|
|
|
|
function config() {
|
|
echo "graph_title ${title}"
|
|
echo "graph_args --base 1000 -l 0"
|
|
echo "graph_vlabel ${title}"
|
|
echo "graph_category other"
|
|
echo "graph_info Lists number of times the given regex is matched in the given log files per period"
|
|
|
|
local var_prefix var logfile lbl
|
|
while read -u 3 -r logfile; do
|
|
var_prefix="$(echo "$logfile" | sed -r 's/^[^a-zA-Z]+//g' | sed -r 's/[^a-zA-Z0-9]+/_/g')"
|
|
var="${var_prefix}_label"
|
|
lbl="${!var:-$logfile}"
|
|
echo "$var_prefix.label $lbl"
|
|
print_warning "$var_prefix"
|
|
print_critical "$var_prefix"
|
|
echo "$var_prefix.info Lines that match '${regex}' in log file '$logfile'"
|
|
done 3< <(echo "$LOGFILES")
|
|
}
|
|
|
|
|
|
function fetch() {
|
|
# Load state
|
|
touch "$MUNIN_STATEFILE"
|
|
local nextstate=()
|
|
local curstate
|
|
curstate="$(cat "$MUNIN_STATEFILE")"
|
|
|
|
local var_prefix logfile prvlines curlines matches
|
|
while read -u 3 -r logfile; do
|
|
# Convert current logfile path to variable prefix
|
|
var_prefix="$(echo "$logfile" | sed -r 's/^[^a-zA-Z]+//g' | sed -r 's/[^a-zA-Z0-9]+/_/g')"
|
|
|
|
# Get running number of lines to determine whether or not the file may have been rotated
|
|
prvlines="$(echo "$curstate" | grep "^${var_prefix}_lines=" | cut -f 2 -d "=")"
|
|
if [ -z "$prvlines" ]; then
|
|
prvlines=0
|
|
fi
|
|
|
|
# Get the current number of lines in the file
|
|
curlines="$(wc -l < "$logfile")"
|
|
if [ -z "$curlines" ]; then
|
|
curlines=0
|
|
fi
|
|
|
|
# If the current line count is less than the previous line count, we've probably rotated.
|
|
# Reset to 0.
|
|
if [ "$curlines" -lt "$prvlines" ]; then
|
|
prvlines=0
|
|
else
|
|
prvlines=$((prvlines + 1))
|
|
fi
|
|
|
|
# Get current number of incidents
|
|
matches="$(tail -n +"$prvlines" "$logfile" | grep -Ec "${regex}" || true)"
|
|
|
|
# Echo the value
|
|
echo "$var_prefix.value $matches"
|
|
|
|
# Push onto next state
|
|
nextstate+=("${var_prefix}_lines=$curlines")
|
|
done 3< <(echo "$LOGFILES")
|
|
|
|
# Write state to munin statefile
|
|
(IFS=$'\n'; echo "${nextstate[*]}" > "$MUNIN_STATEFILE")
|
|
|
|
return 0
|
|
}
|
|
|
|
|
|
case "$1" in
|
|
config) config ;;
|
|
*) fetch ;;
|
|
esac
|