Alternc  latest
Alternc logiel libre pour l'hébergement
top_http_users
Go to the documentation of this file.
1 #!/bin/bash
2 #
3 # $Id: top_http_users 22 2005-04-11 17:21:15Z jerome $
4 # ----------------------------------------------------------------------
5 # AlternC - Web Hosting System
6 # Copyright (C) 2003 by the AlternC Development Team.
7 # http://alternc.org
8 # ----------------------------------------------------------------------
9 # Based on:
10 # Valentin Lacambre's web hosting softwares: http://altern.org/
11 # ----------------------------------------------------------------------
12 # LICENSE
13 #
14 # This program is free software; you can redistribute it and/or
15 # modify it under the terms of the GNU General Public License (GPL)
16 # as published by the Free Software Foundation; either version 2
17 # of the License, or (at your option) any later version.
18 #
19 # This program is distributed in the hope that it will be useful,
20 # but WITHOUT ANY WARRANTY; without even the implied warranty of
21 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 # GNU General Public License for more details.
23 #
24 # To read the license please visit http://www.gnu.org/copyleft/gpl.html
25 # ----------------------------------------------------------------------
26 # Original Author of file: Jerome Moinet
27 # Purpose of file: Parse the apache logs to give the n most active users
28 # ----------------------------------------------------------------------
29 #
30 echo "This script does not work with this AlternC version"
31 exit 1
32 PATH=""
33 PROG_NAME=top_http_users
34 PROG_VERSION=0.1.0
35 ALTERNC_ROOT=/var/alternc
36 ALTERNC_ETC=/etc/alternc
37 ALTERNC_LIB=/usr/lib/alternc
38 ALTERNC_CONF_FILE=$ALTERNC_ETC/local.sh
39 LOG_DIR=/var/log/apache
40 TMP_ROOT=$ALTERNC_ROOT/tmp
41 RES_FILE=$TMP_ROOT/$PROG_NAME.res.$$
42 INTERMEDIATE_FILE=$TMP_ROOT/$PROG_NAME.int.$$
43 LOCK_FILE=/run/$PROG_NAME
44 export TEXTDOMAIN=alternc-admintools
45 YES=yes
46 NO=no
47 
48 # Be sure to use the right programs
49 # and be sure they are there
50 awk=/usr/bin/awk
51 grep=/bin/grep
52 cat=/bin/cat
53 zcat=/bin/zcat
54 head=/usr/bin/head
55 id=/usr/bin/id
56 sort=/usr/bin/sort
57 rm=/bin/rm
58 mysql=/usr/bin/mysql
59 sed=/bin/sed
60 cut=/usr/bin/cut
61 tail=/usr/bin/tail
62 ls=/bin/ls
63 gettext=/usr/bin/gettext
64 printf=/usr/bin/printf
65 lockfileremove=/usr/bin/lockfile-remove
66 lockfilecreate=/usr/bin/lockfile-create
67 lockfiletouch=/usr/bin/lockfile-touch
68 
69 # Must have gettext first to display error messages
70 [ -x "$gettext" ] || { echo "Cannot execute $gettext"; exit 1 ; }
71 
72 for i in $awk $grep $cat $zcat $head $id $sort $rm $mysql $sed $cut $tail $ls $printf $lockfileremove $lockfilecreate $lockfiletouch
73 do
74  [ -x "$i" ] || { echo "$($gettext "Unable to execute") ${i}."; exit 1 ; }
75 done
76 
77 
78 #-------------------------
79 set_messages()
80 #-------------------------
81 {
82  # Language-dependent messages
83  # Uses gettext and mo files.
84  # Don't change these messages, change the .po file instead.
85 
86  USAGE=$($gettext -e "Usage: top_http_users [ options ] number\n\ntop_http_users is a program that gives brief statistics\non apache usage by parsing the apache logs.\n\nOptions:\n -h, --help This help text.\n -v, --version Show version.\n -z, --use-gz-logs Parse gzipped and .1, ...n apache logs instead of just parsing the current log.\n -s, --ssl Parse the apache-ssl logs instead of parsing the non-ssl apache logs.\n -n, --number=NUMBER parse the NUMBER last lines of the current log.\n This option is not compatible with the --use-gz-logs option.\nSee the top_http_users(8) manual page for more information.")
87  NOT_FOUND_MSG=$($gettext "does not exist.")
88  NON_NUM_MSG=$($gettext "The \"number\" argument must be a number.")
89  NON_COMPATIBLE_MSG=$($gettext "The -n and -z options are not compatible.")
90  NON_NUM_MSG_FOR_N=$($gettext "The -n option requieres a number as argument.")
91  LOCKFILE_CREATION_FAILED=`$printf "$($gettext "%s is allready beeing executed.")" $PROG_NAME`
92  NON_ROOT_MSG=$($gettext "You have to be root (uid 0) to execute this program.")
93  MISSING_PROG=$($gettext "Unable to execute")
94  HIT_RES_MSG=`$printf "$($gettext "Top %s domains served by apache, sorted by number of lines in log (using gzipped logs: %s):")" $NB_USERS $($gettext "$USE_GZ_LOGS")`
95  SIZE_RES_MSG=`$printf "$($gettext "Top %s domains served by apache, sorted by size (using gzipped logs: %s):")" $NB_USERS $($gettext "$USE_GZ_LOGS")`
96  TIME_RES_MSG=`$printf "$($gettext "Top %s domains served by apache, sorted by execution time in seconds (using gzipped logs: %s):")" $NB_USERS $($gettext "$USE_GZ_LOGS")`
97  ACCOUNT_HIT_RES_MSG=`$printf "$($gettext "Top %s AlternC accounts served by apache, sorted by number of lines in logs (using gzipped logs: %s):")" $NB_USERS $($gettext "$USE_GZ_LOGS")`
98  ACCOUNT_SIZE_RES_MSG=`$printf "$($gettext "Top %s AlternC accounts served by apache, sorted by size (using gzipped logs: %s):")" $NB_USERS $($gettext "$USE_GZ_LOGS")`
99  ACCOUNT_TIME_RES_MSG=`$printf "$($gettext "Top %s AlternC accounts served by apache, sorted by execution time in seconds (using gzipped logs: %s):")" $NB_USERS $($gettext "$USE_GZ_LOGS")`
100  DEBUG_1_MSG=$($gettext "Parsing")
101  DEBUG_2_MSG=$($gettext "Getting account for each domain")
102  DEBUG_3_MSG=$($gettext "Printing results")
103  MISSING_CONF_FILE=`$printf "$($gettext "Can't find %s. Are you sure AlterncC is properly installed?")" $ALTERNC_CONF_FILE`
104  MYSQL_UNREACHABLE_DATABASE=`$printf "$($gettext "Cannot access accounts database. Please check either %s or Mysql state.")" $ALTERNC_CONF_FILE`
105  SQL_ERROR_MSG=$($gettext -e "Sorry, an sql error appeared. The error message is:\n%s")
106  UNKNOWN_OPTION=$($gettext "Unknown %s option.")
107 }
108 
109 
110 #-------------------------
111 trap_EXIT()
112 #-------------------------
113 {
114  # Does some cleaning
115  $rm -f $RES_FILE
116  $rm -f $INTERMEDIATE_FILE
117  $lockfileremove $LOCK_FILE
118  exit
119 }
120 trap trap_EXIT INT KILL TERM QUIT ABRT STOP HUP
121 
122 
123 #-------------------------
124 # Main
125 #-------------------------
126 set_messages
127 # Must be root
128 [ "`$id -u`" -ne 0 ] && { echo $NON_ROOT_MSG ; exit 1 ; }
129 
130 # Parse args
131 IS_N_PARAM=false
132 USE_GZ_LOGS="$NO"
133 N_PARAM=""
134 COMMAND=$cat
135 for ARG in "$@" ; do
136  [ "$IS_N_PARAM" = "true" ] && { shift ; IS_N_PARAM=false ; continue ; }
137  [ "`$printf "$ARG\n" | $cut -c1`" != "-" ] && [ "$IS_N_PARAM" = "false" ] && break
138 
139  case $ARG in
140  -h | --help ) echo $PROG_NAME version $PROG_VERSION ; $printf "$USAGE\n" ; exit ;;
141  -v | --version ) echo $PROG_NAME version $PROG_VERSION ; exit ;;
142  -s | --ssl ) LOG_DIR=/var/log/apache-ssl ;;
143  -z | --use-gz-logs ) USE_GZ_LOGS="$YES" ;;
144  -n | --number=* )
145  if [ "$ARG" != "-n" ] ; then
146  N_PARAM=`echo $ARG | $cut -d"=" -f2`
147  else
148  N_PARAM=$2
149  IS_N_PARAM=true
150  fi
151  [ `echo "$N_PARAM" | $grep -c [^0-9]` != 0 ] && { echo "$NON_NUM_MSG_FOR_N" ; exit 1 ; }
152  COMMAND="$tail -n $N_PARAM"
153  ;;
154  *) $printf "${UNKNOWN_OPTION}\n" $ARG ; exit 1 ;;
155  esac
156  shift
157 done
158 LOG_FILE=$LOG_DIR/access.log
159 
160 # -n and -z options are not compatible
161 [ "$USE_GZ_LOGS" = "$YES" ] && ! [ -z "$N_PARAM" ] && { echo $NON_COMPATIBLE_MSG ; exit 1 ; }
162 # Must have only 1 parameter
163 [ -z "$1" ] || [ "$#" -gt 1 ] && { $printf "$USAGE\n" ; exit 1 ; }
164 # Argument "number" must be numeric
165 [ `echo "$1" | $grep -c [^0-9]` != 0 ] && { echo "$NON_NUM_MSG" ; exit 1 ; } || NB_USERS=$1
166 # These dirs/files must exist
167 [ -d "$LOG_DIR" ] || { echo "$LOG_DIR $NOT_FOUND_MSG" ; exit 1 ; }
168 [ -d "$TMP_ROOT" ] || { echo "$TMP_ROOT $NOT_FOUND_MSG" ; exit 1 ; }
169 [ -f "$LOG_FILE" ] || { echo "$LOG_FILE $NOT_FOUND_MSG" ; exit 1 ; }
170 # Have to get AlternC conf file :
171 [ -f "$ALTERNC_CONF_FILE" ] || { echo $MISSING_CONF_FILE ; exit 1 ; } && . $ALTERNC_CONF_FILE
172 # Must have access to mysql to retreive accounts owning domains :
173 mysql="$mysql --defaults-file=/etc/alternc/my.cnf -B -N -e"
174 $mysql "desc domaines;" > /dev/null 2>&1
175 [ "$?" != 0 ] && { echo "$MYSQL_UNREACHABLE_DATABASE" ; exit 1 ; }
176 # Prevents executing more than one shell at the same time
177 $lockfilecreate --retry 1 $LOCK_FILE
178 if [ $? != 0 ]
179 then
180  echo $LOCKFILE_CREATION_FAILED
181  exit 1
182 fi
183 $lockfiletouch $LOCK_FILE &
184 BADGER="$!"
185 
186 
187 # Does the stuff
188 set_messages
189 # Have to parse files one by one or else system wil go on knees
190 [ "$DEBUG" ] && echo "$DEBUG_1_MSG $LOG_FILE" ; $COMMAND $LOG_FILE | $awk '{z=NF-1 ; domaine[$NF]++ ; if ($10 != "-") size[$NF]+=$10 ; time[$NF]+=$z} END {for (item in domaine) print item" "domaine[item]" "size[item]" "time[item]}' > $RES_FILE
191 for FILE in `$ls -1 $LOG_FILE.* | $grep -v "\.gz$"`; do
192  [ "$USE_GZ_LOGS" = "$YES" ] && [ -f $FILE ] && { [ "$DEBUG" ] && echo "$DEBUG_1_MSG $FILE" ; $cat $FILE | $awk '{z=NF-1 ; domaine[$NF]++ ; if ($10 != "-") size[$NF]+=$10 ; time[$NF]+=$z} END {for (item in domaine) print item" "domaine[item]" "size[item]" "time[item]}' >> $RES_FILE ; }
193 done
194 if [ "$USE_GZ_LOGS" = "$YES" ]
195 then
196  for GZLOG in $LOG_FILE.*.gz
197  do
198  [ "$DEBUG" ] && echo "$DEBUG_1_MSG $GZLOG"
199  $zcat $GZLOG | $awk '{z=NF-1 ; domaine[$NF]++ ; if ($10 != "-") size[$NF]+=$10 ; time[$NF]+=$z} END {for (item in domaine) print item" "domaine[item]" "size[item]" "time[item]}' >> $RES_FILE
200  done
201 fi
202 
203 
204 # show results
205 $cat $RES_FILE | $awk '{domaine[$1]+=$2 ; size[$1]+=$3 ; time[$1]+=$4} END {for (item in domaine) print item" "domaine[item]" "size[item]" "time[item]}' > $INTERMEDIATE_FILE
206 
207 [ "$DEBUG" ] && echo $DEBUG_2_MSG
208 > $RES_FILE
209 for i in `$cat $INTERMEDIATE_FILE | $sed s/" "/"@@@@"/g`
210  do
211  TMP=`echo $i | $sed s/"@@@@"/" "/g`
212  DOMAIN=`echo $TMP | $cut -d " " -f1 | $sed s/\"//g | $sed s/"\\\\\\\\"/""/g`
213  [ "$DEBUG" ] && echo DOMAIN : $DOMAIN
214  ACCOUNT=`$mysql "select a.login, a.mail from membres a, sub_domaines b where a.uid = b.compte and concat(if(sub=\"\", \"\", concat(sub, \".\")), domaine) = \"${DOMAIN}\";" 2>&1`
215  [ "$?" != 0 ] && { $printf "$SQL_ERROR_MSG\n" " $ACCOUNT" ; kill "${BADGER}" ; trap_EXIT ; }
216  ! [ -z "$ACCOUNT" ] && [ `echo $ACCOUNT | $grep -c "^ERROR"` = 0 ] && echo "$ACCOUNT $TMP" >> $RES_FILE
217  done
218 
219 
220 [ "$DEBUG" ] && echo $DEBUG_3_MSG
221 echo $HIT_RES_MSG
222 $cat $INTERMEDIATE_FILE | $awk {'printf ("%20.0f %s\n", $2, $1)'} | $sort -gr | $head -n$NB_USERS
223 echo ""
224 echo $SIZE_RES_MSG
225 $cat $INTERMEDIATE_FILE | $awk {'printf ("%20.0f %s\n", $3, $1)'} | $sort -gr | $head -n$NB_USERS
226 echo ""
227 echo $TIME_RES_MSG
228 $cat $INTERMEDIATE_FILE | $awk {'printf ("%20.0f %s\n", $4, $1)'} | $sort -gr | $head -n$NB_USERS
229 
230 $cat $RES_FILE | $awk '{size[$1]+=$5 ; time[$1]+=$6 ; hit[$1]+=$4 ; mail[$1]=$2} END {for (item in size) print size[item]" "time[item]" "hit[item]" "item" "mail[item]}' > $INTERMEDIATE_FILE
231 
232 echo ""
233 echo $ACCOUNT_HIT_RES_MSG
234 $cat $INTERMEDIATE_FILE | $awk {'printf ("%20.0f %s (%s)\n", $3, $4, $5)'} | $sort -gr | $head -n$NB_USERS
235 echo ""
236 echo $ACCOUNT_SIZE_RES_MSG
237 $cat $INTERMEDIATE_FILE | $awk {'printf ("%20.0f %s (%s)\n", $1, $4, $5)'} | $sort -gr | $head -n$NB_USERS
238 echo ""
239 echo $ACCOUNT_TIME_RES_MSG
240 $cat $INTERMEDIATE_FILE | $awk {'printf ("%20.0f %s (%s)\n", $2, $4, $5)'} | $sort -gr | $head -n$NB_USERS
241 
242 
243 # cleanly exit and remove temp files
244 kill "${BADGER}"
245 trap_EXIT
246 
247