#!/bin/bash # -*- bash -*- : <<=cut =head1 NAME nginx error - Munin plugin to monitor nginx error rates (http status codes per minute). =head1 APPLICABLE SYSTEMS Any Linux host, running nginx, with bash version > 4.0 =head1 CONFIGURATION This shows the default configuration of this plugin. You can override the log file path and the logpattern. [nginx_error] env.logpath /var/log/nginx env.logpattern a.*.log Nginx must also be configured to log accesses in "combined" log format (default) =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. =head1 INTERPRETATION The plugin shows nginx http "error" status rates by parsing access log. =head1 MAGIC MARKERS #%# family=auto #%# capabilities=autoconf =head1 BUGS None known. =head1 VERSION 1.1 - 2018/01/20 * fix shell style issues reported by shellcheck * improve readability of symlink configuration code 1.0 - 2017/02/21 =head1 AUTHOR vovansystems@gmail.com, 2013 =head1 LICENSE GPLv3 =cut # default environment variable values logpath=${logpath:-/var/log/nginx} # 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} else log_filename='access.log' fi log="$logpath/$log_filename" # 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' # parse error counts from log file do_ () { local k values declare -A line_counts values=$(awk '{print $9}' "$log" | sort | uniq -c) if [ -n "$values" ]; then while read -r line; do read -r -a tmp <<< "$line" line_counts[${tmp[1]}]=${tmp[0]} done <<< "$values" fi for k in "${!http_codes[@]}"; do echo "error$k.value ${line_counts[$k]:-0}" done exit 0 } do_config () { local k echo "graph_title $(basename "$log") - Nginx errors per minute" echo "graph_vlabel pages with http error codes / \${graph_period}" echo "graph_category webserver" echo "graph_period minute" echo "graph_info This graph shows nginx error amount per minute" for k in "${!http_codes[@]}"; do echo "error$k.type DERIVE" echo "error$k.min 0" echo "error$k.label $k ${http_codes[$k]}" done exit 0 } do_autoconf () { echo yes exit 0 } case $1 in config|autoconf|'') eval "do_$1" esac exit $?