root / plugins / apache / apache_users @ 8589c6df
Historique | Voir | Annoter | Télécharger (4,5 ko)
| 1 |
#!/bin/bash |
|---|---|
| 2 |
# |
| 3 |
# apache_users - Munin plugin, displays traffic by user |
| 4 |
# |
| 5 |
# Version: 03.06.2009 |
| 6 |
# Author: Rainer Wolff <rainer.wolff@gmx.com> |
| 7 |
# |
| 8 |
# ################################################################################ MAGIC MARKERS |
| 9 |
|
| 10 |
#%# family=contrib |
| 11 |
#%# capabilities=autoconf |
| 12 |
|
| 13 |
# ####################################################################################### CONFIG |
| 14 |
|
| 15 |
DIRECTORY=${MUNIN_PLUGINSTATE:-/var/lib/munin/plugin-state/apache_users}
|
| 16 |
TIMESTAMP=$DIRECTORY/.apache_users |
| 17 |
ACCESSLOG=/var/log/apache2/access_log |
| 18 |
|
| 19 |
# ##################################################################################### AUTOCONF |
| 20 |
|
| 21 |
if [ "$1" = "autoconf" ] |
| 22 |
then |
| 23 |
if ! ls $ACCESSLOG > /dev/null |
| 24 |
then |
| 25 |
echo "no (could not find apache access log \"$ACCESSLOG\")" |
| 26 |
exit 1 |
| 27 |
elif ! ls $DIRECTORY > /dev/null |
| 28 |
then |
| 29 |
echo "no (could not find munin plugins directory \"$DIRECTORY\")" |
| 30 |
exit 2 |
| 31 |
|
| 32 |
else |
| 33 |
echo "yes" |
| 34 |
exit 0 |
| 35 |
fi |
| 36 |
fi |
| 37 |
|
| 38 |
# ######################################################################################### INIT |
| 39 |
|
| 40 |
# Define regex for all possible timestamps of last 5 minutes block |
| 41 |
REGEX=$(LC_ALL=en_US date -d "5 minutes ago" "+\[%d\/%b\/%Y:%H: %M :[0-5][0-9] %z\]" \ |
| 42 |
| awk '{ printf "%s(%02d|%02d|%02d|%02d|%02d)%s", $1, $2-$2%5, $2-$2%5+1, $2-$2%5+2, $2-$2%5+3, $2-$2%5+4, $3 }')
|
| 43 |
|
| 44 |
|
| 45 |
# Analyse logfile |
| 46 |
while read REQUEST_ADDR REQUEST_USERNAME REQUEST_BYTES |
| 47 |
do |
| 48 |
# Name resolution for known addresses |
| 49 |
REQUEST_DOMAIN=$( awk '/^'"$REQUEST_ADDR"'/ { print $2 }' /etc/hosts )
|
| 50 |
REQUEST_ADDR=${REQUEST_DOMAIN:-$REQUEST_ADDR}
|
| 51 |
|
| 52 |
|
| 53 |
# Scan for known addresses, if found, sum up traffic |
| 54 |
FOUND=false |
| 55 |
for (( I=${#ADDR[@]}-1; I>=0; I-- ))
|
| 56 |
do |
| 57 |
# Address known, name maybe, anonymous access (again) |
| 58 |
if [ "${ADDR[I]}" == "$REQUEST_ADDR" -a "$REQUEST_USERNAME" == "-" ]
|
| 59 |
then |
| 60 |
FOUND=true |
| 61 |
BYTES[$I]=$(( ${BYTES[I]} + $REQUEST_BYTES ))
|
| 62 |
break |
| 63 |
|
| 64 |
# Known address and name |
| 65 |
elif [ "${ADDR[I]}" == "$REQUEST_ADDR" -a "${USERNAME[I]}" == "$REQUEST_USERNAME" ]
|
| 66 |
then |
| 67 |
FOUND=true |
| 68 |
BYTES[$I]=$(( ${BYTES[I]} + $REQUEST_BYTES ))
|
| 69 |
break |
| 70 |
|
| 71 |
# Known address, previous access anonymous |
| 72 |
elif [ "${ADDR[I]}" == "$REQUEST_ADDR" -a "${USERNAME[I]}" == "-" ]
|
| 73 |
then |
| 74 |
FOUND=true |
| 75 |
USERNAME[$I]="$REQUEST_USERNAME" |
| 76 |
BYTES[$I]=$(( ${BYTES[I]} + $REQUEST_BYTES ))
|
| 77 |
break |
| 78 |
fi |
| 79 |
done |
| 80 |
|
| 81 |
# Combination of address and name unknown, create new entry |
| 82 |
if [ "$FOUND" == "false" ] |
| 83 |
then |
| 84 |
ADDR[${#ADDR[@]}]=$REQUEST_ADDR
|
| 85 |
USERNAME[${#USERNAME[@]}]="$REQUEST_USERNAME"
|
| 86 |
BYTES[${#BYTES[@]}]=$REQUEST_BYTES
|
| 87 |
fi |
| 88 |
|
| 89 |
done < <( awk '/'"$REGEX"'/ { printf "%s %s %d\n", $1, $3, $10 }' $ACCESSLOG )
|
| 90 |
|
| 91 |
|
| 92 |
# Assign anonymous access when possible and correct identifiers |
| 93 |
for (( I=0; I<${#USERNAME[@]}; I++ ))
|
| 94 |
do |
| 95 |
if [ "${USERNAME[I]}" == "-" ]
|
| 96 |
then |
| 97 |
if $( echo "${ADDR[I]}" | egrep -q "[^0-9.]" )
|
| 98 |
then |
| 99 |
USERNAME[$I]="${ADDR[I]}"
|
| 100 |
else |
| 101 |
USERNAME[$I]="anonymous" |
| 102 |
fi |
| 103 |
NAME[$I]="_${USERNAME[I]}" # Output sort order
|
| 104 |
else |
| 105 |
NAME[$I]="${USERNAME[I]}"
|
| 106 |
fi |
| 107 |
|
| 108 |
NAME[$I]="$( echo "${NAME[I]}" \
|
| 109 |
| sed "s/^[^A-Za-z_]/_/" | sed "s/[^A-Za-z0-9_]/_/g" \ |
| 110 |
| sed "s/^\(.\{,19\}\).*/\1/" )"
|
| 111 |
done |
| 112 |
|
| 113 |
# Create timestamp |
| 114 |
mkdir -p $DIRECTORY |
| 115 |
touch -d "-1 second" $TIMESTAMP # find needs time span |
| 116 |
|
| 117 |
# Aggregate parallel traffic |
| 118 |
for (( I=0; I<${#NAME[@]}; I++ ))
|
| 119 |
do |
| 120 |
if [ -z "$( find $DIRECTORY -name "${NAME[I]}" -newer $TIMESTAMP )" ]
|
| 121 |
then |
| 122 |
echo "${NAME[I]} ${BYTES[I]} ${USERNAME[I]}" > $DIRECTORY/${NAME[I]}
|
| 123 |
else |
| 124 |
awk '{ printf "%s %d %s", $1, $2+${BYTES[I]}, $3 }' $DIRECTORY/${NAME[I]} > $DIRECTORY/${NAME[I]}
|
| 125 |
fi |
| 126 |
done |
| 127 |
|
| 128 |
|
| 129 |
# ####################################################################################### CONFIG |
| 130 |
|
| 131 |
if [ "$1" = "config" ] |
| 132 |
then |
| 133 |
echo "graph_title Apache users" |
| 134 |
echo "graph_vlabel bytes per five minute period" |
| 135 |
echo "graph_args --lower-limit 1 --base 1024 --logarithmic" |
| 136 |
echo "graph_category webserver" |
| 137 |
echo "graph_total total" |
| 138 |
echo "graph_info Webserver traffic by user." |
| 139 |
|
| 140 |
FILENAMES=$( find $DIRECTORY -type f -not -wholename $TIMESTAMP | sort) |
| 141 |
|
| 142 |
awk '{ printf "%s.label %s\n%s.draw AREA\n", $1, $3, $1 }' $( echo "$FILENAMES" | head -n1 )
|
| 143 |
|
| 144 |
for FILENAME in $( echo "$FILENAMES" | tail -n+2) |
| 145 |
do |
| 146 |
awk '{ printf "%s.label %s\n%s.draw STACK\n", $1, $3, $1 }' $FILENAME
|
| 147 |
done |
| 148 |
|
| 149 |
exit 0 |
| 150 |
fi |
| 151 |
|
| 152 |
|
| 153 |
# ######################################################################################## VALUE |
| 154 |
|
| 155 |
{
|
| 156 |
|
| 157 |
for FILENAME in $( find $DIRECTORY -type f -newer $TIMESTAMP -not -wholename $TIMESTAMP ) |
| 158 |
do |
| 159 |
awk '{ printf "%s.value %d\n", $1, $2 }' $FILENAME
|
| 160 |
done |
| 161 |
|
| 162 |
for FILENAME in $( find $DIRECTORY -type f -not -newer $TIMESTAMP -not -wholename $TIMESTAMP ) |
| 163 |
do |
| 164 |
awk '{ printf "%s.value 0\n", $1 }' $FILENAME
|
| 165 |
done |
| 166 |
|
| 167 |
} | sort |
| 168 |
|
| 169 |
exit 0 |
| 170 |
|
