2013-05-29 18:50:58 +02:00
|
|
|
#!/bin/bash
|
|
|
|
# -*- bash -*-
|
|
|
|
|
2013-06-02 22:49:38 +02:00
|
|
|
: <<=cut
|
2013-05-29 18:50:58 +02:00
|
|
|
|
|
|
|
=head1 NAME
|
|
|
|
|
|
|
|
nginx error - Munin plugin to monitor nginx error rates (http status codes per minute).
|
|
|
|
|
2018-01-20 01:45:26 +01:00
|
|
|
|
2013-05-29 18:50:58 +02:00
|
|
|
=head1 APPLICABLE SYSTEMS
|
|
|
|
|
2018-01-20 01:45:26 +01:00
|
|
|
Any host running nginx, with bash version > 4.0
|
|
|
|
|
2013-05-29 18:50:58 +02:00
|
|
|
|
|
|
|
=head1 CONFIGURATION
|
|
|
|
|
|
|
|
This shows the default configuration of this plugin. You can override
|
|
|
|
the log file path and the logpattern.
|
2018-01-20 01:45:26 +01:00
|
|
|
Additionally you may want to adjust 'group' (or 'user') based on the
|
|
|
|
permissions required for reading the log file.
|
2013-05-29 18:50:58 +02:00
|
|
|
|
|
|
|
[nginx_error]
|
2018-01-20 01:45:26 +01:00
|
|
|
group adm
|
2013-05-29 18:50:58 +02:00
|
|
|
env.logpath /var/log/nginx
|
|
|
|
env.logpattern a.*.log
|
|
|
|
|
|
|
|
Nginx must also be configured to log accesses in "combined" log format (default)
|
|
|
|
|
2018-01-20 01:45:26 +01:00
|
|
|
|
2013-05-29 18:50:58 +02:00
|
|
|
=head1 USAGE
|
|
|
|
|
|
|
|
Link this plugin to /etc/munin/plugins/ and restart the munin-node.
|
|
|
|
|
|
|
|
This plugin also can be used like wildcard-plugin for monitoring particular virtual host log.
|
|
|
|
E.g.
|
|
|
|
ln -s /usr/share/munin/plugins/nginx_error /etc/munin/plugins/nginx_error_mydomaincom
|
|
|
|
will parse the log file /var/log/nginx/a.mydomaincom.log
|
|
|
|
|
|
|
|
You can change 'env.logpattern' using asterisk ('*') to match your logs filenames.
|
|
|
|
|
2018-01-20 01:45:26 +01:00
|
|
|
'env.logpattern' is ignored for a non-symlink configuration.
|
|
|
|
|
|
|
|
|
2013-05-29 18:50:58 +02:00
|
|
|
=head1 INTERPRETATION
|
|
|
|
|
|
|
|
The plugin shows nginx http "error" status rates by parsing access log.
|
|
|
|
|
2018-01-20 01:45:26 +01:00
|
|
|
|
2013-05-29 18:50:58 +02:00
|
|
|
=head1 MAGIC MARKERS
|
|
|
|
|
|
|
|
#%# family=auto
|
|
|
|
#%# capabilities=autoconf
|
|
|
|
|
2018-01-20 01:45:26 +01:00
|
|
|
|
2013-05-29 18:50:58 +02:00
|
|
|
=head1 BUGS
|
|
|
|
|
|
|
|
None known.
|
|
|
|
|
2018-01-20 01:45:26 +01:00
|
|
|
|
2013-05-29 18:50:58 +02:00
|
|
|
=head1 VERSION
|
|
|
|
|
2018-01-20 01:00:12 +01:00
|
|
|
1.1 - 2018/01/20
|
2018-01-20 01:36:03 +01:00
|
|
|
* add 'dirty config' capability support
|
2018-01-20 01:02:19 +01:00
|
|
|
* fix shell style issues reported by shellcheck
|
2018-01-20 01:00:12 +01:00
|
|
|
* improve readability of symlink configuration code
|
|
|
|
|
2018-01-20 00:54:20 +01:00
|
|
|
1.0 - 2017/02/21
|
2013-05-29 18:50:58 +02:00
|
|
|
|
2018-01-20 01:00:12 +01:00
|
|
|
|
2013-05-29 18:50:58 +02:00
|
|
|
=head1 AUTHOR
|
|
|
|
|
|
|
|
vovansystems@gmail.com, 2013
|
|
|
|
|
2018-01-20 01:45:26 +01:00
|
|
|
|
2013-05-29 18:50:58 +02:00
|
|
|
=head1 LICENSE
|
|
|
|
|
|
|
|
GPLv3
|
|
|
|
|
|
|
|
=cut
|
|
|
|
|
|
|
|
|
2018-01-20 01:49:15 +01:00
|
|
|
set -eu
|
|
|
|
|
|
|
|
|
2018-01-20 01:00:12 +01:00
|
|
|
# default environment variable values
|
|
|
|
logpath=${logpath:-/var/log/nginx}
|
2013-05-29 18:50:58 +02:00
|
|
|
|
2018-01-20 01:00:12 +01:00
|
|
|
|
|
|
|
# derive the name of the log file from a potential symlink-configured virtual host
|
|
|
|
script_name=$(basename "$0")
|
|
|
|
plugin_suffix=${script_name#nginx_error}
|
|
|
|
if [ -n "${plugin_suffix#_}" ]; then
|
|
|
|
# a domain was given via symlink configuration: adjust the logpattern
|
|
|
|
domain=${plugin_suffix#_}
|
|
|
|
# default logpattern for symlink configuration mode
|
|
|
|
logpattern=${logpattern:-a.*.log}
|
|
|
|
log_filename=${logpattern/\*/$domain}
|
2013-05-29 18:50:58 +02:00
|
|
|
else
|
2018-01-20 01:00:12 +01:00
|
|
|
log_filename='access.log'
|
2013-05-29 18:50:58 +02:00
|
|
|
fi
|
|
|
|
|
2018-01-20 01:00:12 +01:00
|
|
|
log="$logpath/$log_filename"
|
2013-05-29 18:50:58 +02:00
|
|
|
|
|
|
|
# declaring an array with http status codes, we are interested in
|
|
|
|
declare -A http_codes
|
|
|
|
http_codes[400]='Bad Request'
|
|
|
|
http_codes[401]='Unauthorized'
|
|
|
|
http_codes[403]='Forbidden'
|
|
|
|
http_codes[404]='Not Found'
|
|
|
|
http_codes[405]='Method Not Allowed'
|
|
|
|
http_codes[406]='Not Acceptable'
|
|
|
|
http_codes[408]='Request Timeout'
|
|
|
|
http_codes[429]='Too Many Requests'
|
|
|
|
http_codes[499]='Client Connection Terminated'
|
|
|
|
http_codes[500]='Internal Server Error'
|
|
|
|
http_codes[502]='Bad Gateway'
|
|
|
|
http_codes[503]='Service Unavailable'
|
|
|
|
|
2018-01-20 01:02:19 +01:00
|
|
|
|
|
|
|
# parse error counts from log file
|
2018-01-20 01:36:03 +01:00
|
|
|
do_fetch () {
|
2018-01-20 01:25:14 +01:00
|
|
|
local count status_code
|
2015-02-05 06:44:53 +01:00
|
|
|
declare -A line_counts
|
2018-01-20 01:25:14 +01:00
|
|
|
while read -r count status_code; do
|
|
|
|
line_counts[$status_code]=$count
|
|
|
|
done <<< "$(awk '{print $9}' "$log" | sort | uniq -c)"
|
|
|
|
|
|
|
|
for status_code in "${!http_codes[@]}"; do
|
|
|
|
echo "error${status_code}.value ${line_counts[$status_code]:-0}"
|
2013-05-29 18:50:58 +02:00
|
|
|
done
|
|
|
|
}
|
|
|
|
|
2018-01-20 01:02:19 +01:00
|
|
|
|
2013-05-29 18:50:58 +02:00
|
|
|
do_config () {
|
2018-01-20 01:25:14 +01:00
|
|
|
local status_code
|
2018-01-20 01:00:12 +01:00
|
|
|
echo "graph_title $(basename "$log") - Nginx errors per minute"
|
2018-01-20 01:02:19 +01:00
|
|
|
echo "graph_vlabel pages with http error codes / \${graph_period}"
|
2017-02-21 17:11:23 +01:00
|
|
|
echo "graph_category webserver"
|
2013-05-29 18:50:58 +02:00
|
|
|
echo "graph_period minute"
|
2018-01-20 01:45:26 +01:00
|
|
|
echo "graph_info This graph shows nginx error rate per minute"
|
2018-01-20 01:25:14 +01:00
|
|
|
for status_code in "${!http_codes[@]}"; do
|
|
|
|
echo "error${status_code}.type DERIVE"
|
|
|
|
echo "error${status_code}.min 0"
|
|
|
|
echo "error${status_code}.label $status_code ${http_codes[$status_code]}"
|
2013-05-29 18:50:58 +02:00
|
|
|
done
|
|
|
|
}
|
|
|
|
|
2018-01-20 01:02:19 +01:00
|
|
|
|
2013-05-29 18:50:58 +02:00
|
|
|
do_autoconf () {
|
|
|
|
echo yes
|
|
|
|
}
|
|
|
|
|
2018-01-20 01:02:19 +01:00
|
|
|
|
2018-01-20 01:49:15 +01:00
|
|
|
case ${1:-} in
|
2018-01-20 01:36:03 +01:00
|
|
|
config)
|
|
|
|
do_config
|
|
|
|
# support "dirty config" capability
|
|
|
|
if [ "${MUNIN_CAP_DIRTYCONFIG:-}" = "1" ]; then do_fetch; fi
|
|
|
|
;;
|
|
|
|
autoconf)
|
|
|
|
do_autoconf
|
|
|
|
;;
|
|
|
|
'')
|
|
|
|
do_fetch
|
|
|
|
;;
|
2013-05-29 18:50:58 +02:00
|
|
|
esac
|
|
|
|
|
2013-06-02 22:49:38 +02:00
|
|
|
exit $?
|