summaryrefslogtreecommitdiff
path: root/src/pmdas/weblog
diff options
context:
space:
mode:
Diffstat (limited to 'src/pmdas/weblog')
-rw-r--r--src/pmdas/weblog/GNUmakefile75
-rw-r--r--src/pmdas/weblog/Install694
-rw-r--r--src/pmdas/weblog/README205
-rw-r--r--src/pmdas/weblog/Remove43
-rw-r--r--src/pmdas/weblog/Web.Alarms.pmchart22
-rwxr-xr-xsrc/pmdas/weblog/Web.Allservers.pmchart90
-rwxr-xr-xsrc/pmdas/weblog/Web.Perserver.Bytes.pmchart90
-rwxr-xr-xsrc/pmdas/weblog/Web.Perserver.Requests.pmchart91
-rw-r--r--src/pmdas/weblog/Web.Requests.pmchart27
-rw-r--r--src/pmdas/weblog/Web.Volume.pmchart25
-rw-r--r--src/pmdas/weblog/check_match.c414
-rw-r--r--src/pmdas/weblog/help654
-rw-r--r--src/pmdas/weblog/pmda.c1205
-rw-r--r--src/pmdas/weblog/pmns306
-rw-r--r--src/pmdas/weblog/root10
-rwxr-xr-xsrc/pmdas/weblog/server.sh1228
-rw-r--r--src/pmdas/weblog/sproc.c39
-rw-r--r--src/pmdas/weblog/weblog.c3132
-rw-r--r--src/pmdas/weblog/weblog.h140
-rwxr-xr-xsrc/pmdas/weblog/weblogconv.sh62
20 files changed, 8552 insertions, 0 deletions
diff --git a/src/pmdas/weblog/GNUmakefile b/src/pmdas/weblog/GNUmakefile
new file mode 100644
index 0000000..aa68c72
--- /dev/null
+++ b/src/pmdas/weblog/GNUmakefile
@@ -0,0 +1,75 @@
+#
+# Copyright (c) 2000-2001,2004 Silicon Graphics, Inc. All Rights Reserved.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+
+TOPDIR = ../../..
+include $(TOPDIR)/src/include/builddefs
+
+IAM = weblog
+DOMAIN = WEBSERVER
+TARGETS = $(IAM)$(EXECSUFFIX) check_match$(EXECSUFFIX)
+CFILES = weblog.c pmda.c sproc.c
+HFILES = weblog.h
+SCRIPTS = Install Remove server.sh weblogconv.sh
+CHARTS = Web.Alarms.pmchart Web.Requests.pmchart Web.Volume.pmchart \
+ Web.Allservers.pmchart Web.Perserver.Bytes.pmchart \
+ Web.Perserver.Requests.pmchart
+DFILES = README
+LSRCFILES = pmns help $(DFILES) root $(SCRIPTS) check_match.c $(CHARTS)
+
+LDIRT = domain.h $(TARGETS) check_match.o
+
+PMDADIR = $(PCP_PMDAS_DIR)/weblog
+PMCHARTDIR = $(PCP_VAR_DIR)/config/pmchart
+CONFDIR = $(PCP_VAR_DIR)/config/web
+
+LDLIBS = $(PCP_PMDALIB) $(LIB_FOR_PTHREADS)
+
+default: build-me
+
+include $(BUILDRULES)
+
+ifneq "$(TARGET_OS)" "mingw"
+build-me: $(TARGETS)
+
+install: build-me
+ # $(INSTALL) -d $(CONFDIR)
+ # $(INSTALL) -m 644 weblog.conf $(CONFDIR)/weblog.conf
+ $(INSTALL) -d $(PMDADIR)
+ $(INSTALL) -m 755 $(IAM) $(PMDADIR)/pmda$(IAM)
+ $(INSTALL) -m 755 check_match $(SCRIPTS) $(PMDADIR)
+ $(INSTALL) -m 644 $(DFILES) root help pmns domain.h $(PMDADIR)
+ $(INSTALL) -m 644 Web.Alarms.pmchart $(PMCHARTDIR)/Web.Alarms
+ $(INSTALL) -m 644 Web.Requests.pmchart $(PMCHARTDIR)/Web.Requests
+ $(INSTALL) -m 644 Web.Volume.pmchart $(PMCHARTDIR)/Web.Volume
+ $(INSTALL) -m 755 Web.Allservers.pmchart $(PMCHARTDIR)/Web.Allservers
+ $(INSTALL) -m 755 Web.Perserver.Bytes.pmchart $(PMCHARTDIR)/Web.Perserver.Bytes
+ $(INSTALL) -m 755 Web.Perserver.Requests.pmchart $(PMCHARTDIR)/Web.Perserver.Requests
+else
+build-me:
+install:
+endif
+
+weblog$(EXECSUFFIX): $(OBJECTS)
+
+weblog.o: domain.h
+
+check_match$(EXECSUFFIX): check_match.o
+ $(CCF) -o $@ $(LDFLAGS) check_match.o $(LDLIBS)
+
+domain.h: ../../pmns/stdpmid
+ $(DOMAIN_MAKERULE)
+
+default_pcp: default
+
+install_pcp: install
diff --git a/src/pmdas/weblog/Install b/src/pmdas/weblog/Install
new file mode 100644
index 0000000..dcc86a1
--- /dev/null
+++ b/src/pmdas/weblog/Install
@@ -0,0 +1,694 @@
+#! /bin/sh
+#
+# Copyright (c) 2000,2003,2004 Silicon Graphics, Inc. All Rights Reserved.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# Install the weblog PMDA and/or PMNS
+#
+
+. $PCP_DIR/etc/pcp.env
+. $PCP_SHARE_DIR/lib/pmdaproc.sh
+
+# Override function from pmdaproc.sh
+__choose_mode()
+{
+ if [ -n "$QUIET_INSTALL" ] ; then
+ do_pmda=true
+ else
+ __def=m
+ $do_pmda && __def=b
+ echo \
+'You will need to choose an appropriate configuration for installation of
+the "'$iam'" Performance Metrics Domain Agent (PMDA).
+
+ collector collect performance statistics on this system
+ monitor allow this system to monitor local and/or remote systems
+ both collector and monitor configuration for this system
+'
+ while true
+ do
+ $PCP_ECHO_PROG $PCP_ECHO_N 'Please enter c(ollector) or m(onitor) or b(oth) ['$__def'] '"$PCP_ECHO_C"
+ read ans
+ case "$ans"
+ in
+ "") break
+ ;;
+ c|collector|b|both)
+ do_pmda=true
+ break
+ ;;
+ m|monitor)
+ do_pmda=false
+ break
+ ;;
+ *) echo "Sorry, that is not acceptable response ..."
+ ;;
+ esac
+ done
+ echo
+
+ fi
+}
+
+iam=weblog
+pmda_interface=2
+forced_restart=false
+
+pmdaSetup
+
+pmns_name=web # metric names differ from PMDA name
+daemon_opt=true # can install as daemon
+dso_opt=false
+pipe_opt=true # pipe IPC - YES
+socket_opt=false # socket IPC - NO
+socket_inet_def=2080 # default TCP port for Internet socket IPC
+check_delay=10 # give the PMDA a chance to set itself up
+
+# PMDA specific constants
+#
+configDir=$PCP_VAR_DIR/config/web
+
+# PMDA variables
+#
+tmp=`mktemp -d /tmp/pcp.XXXXXXXXX` || exit 1
+trap "rm -rf $tmp; exit" 0 1 2 3 15
+
+debugFlag=0
+do_debug=false
+
+configFile=""
+delay=15
+chkDelay=20
+maxserv=80
+
+
+# --- start functions ---
+#
+_parseDefaults()
+{
+ echo "Extracting options from current installation ..."
+ while getopts D:d:i:l:n:pS:t:u: c
+ do
+ case $c in
+ \?) echo "Warning: Unrecognized option in $PCP_PMCDCONF_PATH"
+ echo " Remove line for pmdaweblog in $PCP_PMCDCONF_PATH and re-run ./Install"
+ exit 2;;
+ D) debugFlag=$OPTARG;;
+ n) chkDelay=$OPTARG;;
+ t) delay=$OPTARG;;
+ S) maxserv=$OPTARG;;
+ *) # old or boring flags, silently ignore
+ ;;
+ esac
+ done
+ shift `expr $OPTIND - 1`
+ if [ $# -eq 1 ]
+ then
+ configFile=$1
+ elif [ $# -eq 0 ]
+ then
+ configFile=""
+ else
+ echo "Warning: unrecognized format for old specification in $PCP_PMCDCONF_PATH"
+ echo " Remove line for pmdaweblog in $PCP_PMCDCONF_PATH and re-run ./Install"
+ exit 2
+ fi
+}
+
+_defaultRegex()
+{
+ touch $1
+ echo '
+# Common regular expressions specifications for parsing access and error logs
+# Each regular expression specification should have a name (one word),
+# specify the order of regex parameters (method and size), and
+# a regular expression. Regular expressions for access logs require two
+# arguments to be set while errors logs require only a match.
+#
+# Set the online HTML Users and Administrators Guide, pmdaweblog(1) and
+# regexec(3) for more details.
+#
+
+# pattern for CERN, NCSA, Netscape, Apache etc Access Logs
+regex_posix CERN method,size ][ \\]+"([A-Za-z][-A-Za-z]+) [^"]*" [-0-9]+ ([-0-9]+)
+# pattern for CERN, NCSA, Netscape etc Error Logs
+regex_posix CERN_err - .
+# pattern for Proxy Server Extended Log Format
+regex_posix NS_PROXY 1,3,2,4 ][ ]+"([A-Za-z][-A-Za-z]+) [^"]*" ([-0-9]+) ([-0-9]+) ([-0-9]+)
+# pattern for Squid Cache logs
+regex_posix SQUID 4,3,2,1 [0-9]+\.[0-9]+[ ]+[0-9]+ [a-zA-Z0-9\.]+ ([_A-Z]+)\/([0-9]+) ([0-9]+) ([A-Z]+)
+# pattern for Netscape SOCKS Server Access logs
+regex_posix NS_SOCKS method,size (sockd)\[.*, ([0-9]+) bytes from .* \(http\)
+# pattern for Netscape SOCKS Server Error logs
+regex_posix NS_SOCKS_err - .
+# pattern for FTP through a Netscape SOCKS Server Access log
+regex_posix NS_FTP method,size (sockd)\[.*, ([0-9]+) bytes from .* \([0-9]+\)
+# pattern for FTP through a Netscape SOCKS Server Error logs
+regex_posix NS_FTP_err - .
+# pattern for FTP Server access logs (normally in SYSLOG)
+regex_posix SYSLOG_FTP method,size ftpd\[.*\]: ([gp][-A-Za-z]+)( )
+# pattern for FTP Server error logs (normally in SYSLOG)
+regex_posix SYSLOG_FTP_err - FTP LOGIN FAILED
+# pattern for WU_FTP Server access logs (normally in xferlog)
+regex_posix WU_FTP size,method :[0-9][0-9] [0-9]+ [0-9]+ .+ ([0-9]+) .+ [ba] .+ ([io]) [arg]
+# pattern for WU_FTP Server error logs (normally in SYSLOG/messages)
+regex_posix WU_FTP_err - failed login
+
+# Server specifications. The format of each specification is
+# "server" serverName on|off accessRegex accessFile errorRegex errorFile
+#
+# Set the online HTML Users and Administrators Guide and pmdaweblog(1)
+# for more details.
+#' >> $1
+}
+
+_parse_server()
+{
+ egrep "^server" | $PCP_AWK_PROG '
+ { i=index($2, ":");
+ if (i == 0) {
+ name = $2;
+ port = "";
+ }
+ else {
+ name = substr($2,1,i-1);
+ port = sprintf("Port %d", substr($2, i+1, length($2) - i));
+ }
+ printf("Server %s %s\n", name, port);
+ printf(" Access Log: %s (%s)\n", $5, $4);
+ printf(" Error Log: %s (%s)\n\n", $7, $6);
+ }'
+}
+
+_default_config ()
+{
+ rm -f $tmp/conf
+ touch $tmp/conf
+ _defaultRegex $tmp/conf
+ ./server.sh -q -l $tmp/conf
+ egrep "^server" $tmp/conf > /dev/null 2>&1
+ _st=$?
+ if [ $_st -eq 0 ]
+ then
+ ./pmdaweblog -C $tmp/conf >$tmp/out 2>&1
+ _st=$?
+ if [ $_st -eq 0 ] ; then
+ if [ -z "$configFile" ]
+ then
+ configFile=$configDir/$iam.conf
+ fi
+ rm -f $configFile
+ cp $tmp/conf $configFile
+ args="-D $debugFlag -t $delay -n $chkDelay -S $maxserv $configFile"
+ socket_opt=false
+ fi
+ fi
+ return $_st
+}
+
+#
+# --- end functions ---
+
+if $do_pmda
+then
+
+ [ ! -d $configDir ] && mkdir -p $configDir
+
+ if [ -n "$QUIET_INSTALL" ] ; then
+ _default_config
+ if [ $? -eq 0 ] ; then
+ pmdaInstall
+ exit $?
+ else
+ exit 1
+ fi
+ else
+ echo "----------------------------------------------------------------"
+ echo
+ echo "The default installation of the weblog PMDA will search for known"
+ echo "Web server configurations on this host and will setup the weblog"
+ echo "PMDA to monitor all associated Web server log files."
+ echo
+ echo "Otherwise, you will be prompted for the required information."
+ echo
+ $PCP_ECHO_PROG $PCP_ECHO_N "Do you want a default weblog PMDA installation [y] ""$PCP_ECHO_C"
+ read ans
+ echo
+ if [ "X$ans" = X -o "X$ans" = Xy -o "X$ans" = XY ]
+ then
+ _default_config
+ if [ $? -eq 0 ] ; then
+ pmdaInstall
+ exit $?
+ else
+ echo
+ echo "Unable to find any Web servers!"
+ echo "Reverting to detailed installation..."
+ fi
+ fi
+
+ echo "----------------------------------------------------------------"
+ echo
+ $PCP_ECHO_PROG $PCP_ECHO_N "Checking for a previous PMDA installation ...""$PCP_ECHO_C"
+
+ # weblogs -> weblog can be removed once all 1.0 betas are known to
+ # have gone away
+ ans=`$PCP_AWK_PROG < $PCP_PMCDCONF_PATH '
+ $1 == "'$iam'" {
+ printf "%s",$6
+ for (i=7;i<=NF;i++) printf " %s",$i
+ print ""
+ }'`
+ if [ -n "$ans" ]
+ then
+ echo " found"
+ _parseDefaults $ans
+ else
+ echo " appears to be a first-time install"
+ fi
+
+ if [ -n "$configFile" ]
+ then
+ if [ -f "$configFile" ]
+ then
+ if [ $PCP_PLATFORM = linux ] && \
+ egrep '^regex ' $configFile > /dev/null
+ then
+ echo "Warning: previous configuration file \"$configFile\""
+ echo " appears to be an incompatible version."
+ $PCP_ECHO_PROG $PCP_ECHO_N "Do you wish to automatically update the configuration file? [y] ""$PCP_ECHO_C"
+ read ans
+ if [ "X$ans" = X -o "$ans" = "y" -o "$ans" = "Y" ]
+ then
+ ./weblogconv.sh $configFile $tmp/conf
+ if ./pmdaweblog -C $tmp/conf > /dev/null 2>&1
+ then
+ cp $tmp/conf $configFile
+ else
+ echo "Warning: automatic conversion failed."
+ echo "You can either continue, and use the default configuration file or exit"
+ echo "this install procedure to manually update your existing configuration."
+ $PCP_ECHO_PROG $PCP_ECHO_N "Do you wish to continue with the default configuration? [n] ""$PCP_ECHO_C"
+ read ans
+ if [ "$ans" = "y" -o "$ans" = "Y" ]
+ then
+ configFile=""
+ else
+ exit 1
+ fi
+ fi
+ fi
+ else
+ echo "Using previous configuration file \"$configFile\""
+ fi
+ else
+ echo "Warning: previous configuration file \"$configFile\" no longer"
+ echo " exists, reverting to default"
+ configFile=""
+ fi
+ fi
+
+ if [ "X$configFile" = X -a -f $configDir/$iam.conf ]
+ then
+ configFile=$configDir/$iam.conf
+ echo "Using previous configuration file \"$configFile\""
+ fi
+
+ if [ "X$configFile" != X ]
+ then
+ if [ -f $configFile ]
+ then
+ echo "The inital configuration file contains the following Web server details:"
+ echo
+ cat $configFile | _parse_server | ${PAGER-more}
+ echo
+ echo "------------------------------------------------------------------------------"
+
+ if ./pmdaweblog -C $configFile >$tmp/out 2>&1
+ then
+ :
+ else
+ echo "Warning: parsing this configuration file produced the following errors,"
+ echo " and this file will be ignored."
+
+ cat $tmp/out
+ echo
+ if [ "X$configFile" = "X$tmp/default" ]
+ then
+ echo "Arrgh ... this is the default configuration, I cannot recover from here!"
+ exit 1
+ fi
+ configFile=""
+ fi
+ fi
+ fi
+
+ echo
+ echo "A configuration file can be automatically generated. This can"
+ echo "be used to compare or replace an existing configuration file."
+ echo
+
+ if [ "X$configFile" = X ]
+ then
+ $PCP_ECHO_PROG $PCP_ECHO_N "Do you want a configuration file to be automatically generated [y] ""$PCP_ECHO_C"
+ read ans
+ if [ "X$ans" = X ]
+ then
+ ans="y"
+ fi
+ else
+ $PCP_ECHO_PROG $PCP_ECHO_N "Do you want a configuration file to be automatically generated [n] ""$PCP_ECHO_C"
+ read ans
+ if [ "X$ans" = X ]
+ then
+ ans="n"
+ fi
+ fi
+
+ if [ "X$ans" = "Xy" -o "X$ans" = "XY" ]
+ then
+ echo
+ echo "Now scanning for Web servers ..."
+ echo
+
+ if [ ! -x ./server.sh ]
+ then
+ echo "Unable to scan for Web servers as ./server.sh is missing!"
+ else
+ rm -f $tmp/conf
+ touch $tmp/conf
+ _defaultRegex $tmp/conf
+ ./server.sh -l $tmp/conf
+ if egrep "^server" $tmp/conf > /dev/null 2>&1
+ then
+ echo
+ echo "This is a possible configuration file for your system:"
+ echo
+ cat $tmp/conf | _parse_server | ${PAGER-more}
+ echo
+ echo "------------------------------------------------------------------------------"
+ echo
+
+ if ./pmdaweblog -C $tmp/conf > /dev/null 2>&1
+ then
+ if [ "X$configFile" = X ]
+ then
+ $PCP_ECHO_PROG $PCP_ECHO_N "Would you like to use this configuration file [y] ""$PCP_ECHO_C"
+ read ans
+ if [ "X$ans" = "Xy" -o "X$ans" = "XY" -o "X$ans" = X ]
+ then
+ cp $tmp/conf $configDir/$iam.conf
+ configFile=$configDir/$iam.conf
+ fi
+ else
+ echo "Would you like to replace your existing configuration file with"
+ $PCP_ECHO_PROG $PCP_ECHO_N "the generated file [n] ""$PCP_ECHO_C"
+ read ans
+ if [ "X$ans" != "Xn" -a "X$and" != "XN" -a "X$ans" != X ]
+ then
+ cp $tmp/conf $configFile
+ fi
+ fi
+ else
+ echo "Automated configuration file generation is broken!"
+ if [ "X$configFile" = X ]
+ then
+ echo "Please consult the manual on how to create a configuration file."
+ echo "Installation failed."
+ exit 1
+ else
+ echo "Ignoring this file."
+ fi
+ fi
+ else
+ echo
+ echo "I could not find any Web servers."
+ fi
+ echo
+ fi
+ fi
+
+ echo "------------------------------------------------------------------------------"
+
+ echo
+ if [ "X$configFile" = X ]
+ then
+ $PCP_ECHO_PROG $PCP_ECHO_N "Do you want to specify some Web servers [n]: ""$PCP_ECHO_C"
+ serverAdded="false"
+ else
+ $PCP_ECHO_PROG $PCP_ECHO_N "Do you want to specify some more Web servers [n]: ""$PCP_ECHO_C"
+ serverAdded="true"
+ fi
+
+ read ans
+ while [ "X$ans" = "Xy" -o "X$ans" = "XY" ]
+ do
+ if [ "X$configFile" = X ]
+ then
+ if [ "X$configFile" = X -a -f $configDir/$iam.conf ]
+ then
+ echo "Replacing existing configuration file $configDir/$iam.conf"
+ rm -f $configDir/$iam.conf
+ else
+ echo "Creating configuration file $configDir/$iam.conf"
+ fi
+ _defaultRegex $configDir/$iam.conf
+ configFile="$configDir/$iam.conf"
+ fi
+
+ echo
+ serverName=`hostname`
+ $PCP_ECHO_PROG $PCP_ECHO_N "The name of the Web server [$serverName]: ""$PCP_ECHO_C"
+ read ans
+ if [ "X$ans" = X ]
+ then
+ serverName=`hostname`
+ else
+ serverName=$ans
+ fi
+
+ echo
+ accessPath=""
+ while [ "X$accessPath" = X ]
+ do
+ $PCP_ECHO_PROG $PCP_ECHO_N "The path to the access log:
+ ""$PCP_ECHO_C"
+ read accessPath
+ if [ "X$accessPath" != X ]
+ then
+ if [ -f $accessPath ]
+ then
+ :
+ else
+ echo "$accessPath does not exist or is not a regular file"
+ accessPath=""
+ fi
+ fi
+ done
+
+ echo
+ errorPath=""
+ while [ "X$errorPath" = X ]
+ do
+ $PCP_ECHO_PROG $PCP_ECHO_N "The path to the error log:
+ ""$PCP_ECHO_C"
+ read errorPath
+ if [ "X$errorPath" != X ]
+ then
+ if [ -f $errorPath ]
+ then
+ :
+ else
+ echo "$errorPath does not exist or is not a regular file"
+ errorPath=""
+ fi
+ fi
+ done
+
+ echo
+ echo "The configuration file contains these specifications:"
+ echo
+ ${PAGER-more} $configFile
+ echo
+ echo "Does the configuration file contain appropriate regular expressions"
+ $PCP_ECHO_PROG $PCP_ECHO_N "for the \"$serverName\" Web server [y]: ""$PCP_ECHO_C"
+ read ans
+ echo
+ if [ "X$ans" = "Xn" -o "X$ans" = "XN" ]
+ then
+ $PCP_ECHO_PROG $PCP_ECHO_N "Do you wish to quit the installation to add new regular expressions [y]: ""$PCP_ECHO_C"
+ read ans
+ if [ "$Xans" = "Xy" -o "X$ans" = "XY" -o "X$ans" = X ]
+ then
+ echo "Edit $configFile and then rerun this Install script."
+ exit 1
+ echo
+ echo "Skipping $serverName ..."
+ fi
+ else
+ accessRegex=""
+ while [ "X$accessRegex" = X ]
+ do
+ if egrep "^regex_posix CERN " $configFile > /dev/null 2>&1
+ then
+ $PCP_ECHO_PROG $PCP_ECHO_N "The regex for the access log [CERN]: ""$PCP_ECHO_C"
+ accessRegex="CERN"
+ else
+ $PCP_ECHO_PROG $PCP_ECHO_N "The regex for the access log: ""$PCP_ECHO_C"
+ accessRegex=""
+ fi
+ read ans
+ if [ "X$ans" != X ]
+ then
+ accessRegex=$ans
+ fi
+ if [ "X$accessRegex" != X ]
+ then
+ if egrep "^regex_posix $accessRegex " $configFile > /dev/null 2>&1
+ then
+ :
+ else
+ echo "Could not find $accessRegex in $configFile"
+ accessRegex=""
+ fi
+ fi
+ done
+
+ echo
+ errorRegex=""
+ while [ "X$errorRegex" = X ]
+ do
+ if egrep "^regex_posix CERN_err " $configFile > /dev/null 2>&1
+ then
+ $PCP_ECHO_PROG $PCP_ECHO_N "The regex for the error log [CERN_err]: ""$PCP_ECHO_C"
+ errorRegex="CERN_err"
+ else
+ $PCP_ECHO_PROG $PCP_ECHO_N "The regex for the error log: ""$PCP_ECHO_C"
+ errorRegex=""
+ fi
+ read ans
+ if [ "X$ans" != X ]
+ then
+ errorRegex=$ans
+ fi
+ if [ "X$errorRegex" != X ]
+ then
+ if egrep "^regex_posix $errorRegex " $configFile > /dev/null 2>&1
+ then
+ :
+ else
+ echo "Could not find $errorRegex in $configFile"
+ errorRegex=""
+ fi
+ fi
+ done
+
+ echo
+ echo "You have specified the following Web server:"
+ echo
+ server="server $serverName on $accessRegex $accessPath $errorRegex $errorPath"
+ echo "$server"
+ echo
+ $PCP_ECHO_PROG $PCP_ECHO_N "Is this correct [y]:
+ ""$PCP_ECHO_C"
+ read ans
+ if [ "X$ans" = "Xy" -o "X$ans" = "XY" -o "X$ans" = X ]
+ then
+ echo >> $configFile
+ echo "# User configured server called \"$serverName\"" >> $configFile
+ echo $server >> $configFile
+ serverAdded="true"
+ fi
+ fi
+
+ echo
+ $PCP_ECHO_PROG $PCP_ECHO_N "Do you wish to specify another Web Server [n]: ""$PCP_ECHO_C"
+ read ans
+ echo
+ done
+
+ if [ "$serverAdded" = "false" ]
+ then
+ rm -f $configFile
+ configFile=""
+ fi
+
+ if [ "X$configFile" = X ]
+ then
+ echo "Please consult the manual on how to create a configuration file."
+ echo "Installation failed as no servers were specified."
+ exit 1
+ fi
+
+ echo
+ echo "You may modify the configuration file by hand and add servers"
+ echo "that are not currently listed, change their names, etc."
+ echo
+ $PCP_ECHO_PROG $PCP_ECHO_N "Do you wish to exit and modify the configuration file [n] ""$PCP_ECHO_C"
+ read ans
+ if [ "X$ans" != "Xn" -a "X$ans" != "XN" -a "X$ans" != X ]
+ then
+ echo
+ echo "Edit $configFile and then rerun this Install script."
+ exit 1
+ fi
+
+ echo
+ echo "------------------------------------------------------------------------------"
+
+ echo
+ $PCP_ECHO_PROG $PCP_ECHO_N "The delay in seconds between forced reads of the log files [$delay] ""$PCP_ECHO_C"
+ read ans
+ if [ "X$ans" != X ]
+ then
+ delay=$ans
+ fi
+
+ echo
+ $PCP_ECHO_PROG $PCP_ECHO_N "Number of seconds of inactivity before checking for log rotation [$chkDelay] ""$PCP_ECHO_C"
+ read ans
+ if [ "X$ans" != X ]
+ then
+ chkDelay=$ans
+ fi
+
+ echo
+ $PCP_ECHO_PROG $PCP_ECHO_N "The maximum number of servers per agent process [$maxserv] ""$PCP_ECHO_C"
+ read ans
+ if [ "X$ans" != X ]
+ then
+ maxserv=$ans
+ fi
+
+ if [ "$do_debug" = true ]
+ then
+ echo
+ $PCP_ECHO_PROG $PCP_ECHO_N "the Debugging Flag (see pmdbg(1)) [$debugFlag] ""$PCP_ECHO_C"
+ read ans
+ if [ "X$ans" != X ]
+ then
+ debugFlag=$ans
+ fi
+ fi
+
+ args="-D $debugFlag -t $delay -n $chkDelay -S $maxserv $configFile"
+
+ echo
+ echo "------------------------------------------------------------------------------"
+ echo
+ fi
+fi
+
+pmdaInstall
+
+exit 0
+
diff --git a/src/pmdas/weblog/README b/src/pmdas/weblog/README
new file mode 100644
index 0000000..611a188
--- /dev/null
+++ b/src/pmdas/weblog/README
@@ -0,0 +1,205 @@
+Performance Co-Pilot Weblog PMDA for Monitoring of Web Server logs
+==================================================================
+
+This PMDA is capable of monitoring the activity of multiple Web servers,
+in terms of requests and bytes, in real time. The PMDA can also monitor
+proxy server, SOCKS server and ftpd logs.
+
+Site configuration is discussed in the online HTML documentation located
+at $PCP_DOC_DIR/pcpweb. This should be read before proceeding any further
+with installing this PMDA. The file $PCP_DOC_DIR/pcpweb/README contains
+instructions for installing this documentation.
+
+During the installation process, you may be prompted for several
+parameters which will affect the behavior of the weblog PMDA. These
+are discussed in the pmdaweblog(1) man page.
+
+
+Installation of the Weblog PMDA
+===============================
+
+1. Check that there is no clash with the Performance Metrics Domain
+ number defined in domain.h and the other PMDAs currently in use
+ (see $PCP_PMCDCONF_PATH). If there is, edit domain.h and choose
+ another domain number.
+
+2. Ensure that the web server control files can be correctly located as
+ follows.
+
+ Web Server Default Directory Environment Search for Config
+ Type Variable File(s) and/or Logs
+ Below the Default
+ Directory
+
+ Netscape /usr/ns-home $NSROOTPATH httpd-*/obj.conf
+ and httpd-*/magnus.conf
+ /var/netscape/suitespot https-*/obj.conf
+ https-*/magnus.conf
+ proxy-*/obj.conf
+ proxy-*/magnus.conf
+
+ Netscape /usr/ns-home $NSROOTPATH proxy-server/logs/sockd
+ Proxy
+
+ Netscape /var/ns-proxy $NSPROXYPATH logs/access
+ Proxy logs/errors
+ logs/sockd
+
+ Outbox /var/www/htdocs/outbox $OUTBOXPATH logs/access
+ logs/errors
+
+ NCSA /var/www $NCSAPATH server/logs/access_log
+ server/logs/error_log
+
+ Zeus /usr/local/zeus $ZEUSPATH server.ini
+ log/transfer
+ log/errors
+
+ Apache /usr/apache $APACHEPATH conf/httpd.conf
+ conf/srm.conf
+ log/access_log
+ log/error_log
+
+ Anon FTP /etc/passwd $PASSWDPATH [file, not dir] for ~ftp
+ /var/adm/SYSLOG $SYSLOGPATH [file, not dir] for
+ access and errors
+
+ To over-ride the Default Directory for a particular type of Web
+ server, set the corresponding Environment Variable to the absolute
+ pathname of the directory. As a special case $NSROOTPATH for the
+ non-proxy Netscape Web server can be set to a colon (:) separated
+ list of directory names to be searched (in the style of the $PATH
+ for /bin/sh).
+
+
+3. Then run the Install script (as root)
+
+ # cd $PCP_PMDAS_DIR/weblog
+ # ./Install
+
+4. The installation script will prompt if this is a collector and/or
+ monitor installation. Briefly:
+
+ o if there are Web servers on this host, then this is a collector host.
+
+ o if monitoring tools (pmchart(1), pmlogger(1) etc.) will be run on
+ this host, then this is a monitoring host.
+
+ Consult the HTML documentation for more details. A monitoring host
+ installation will install only the namespace and some application
+ configuration files.
+
+5. The next prompt will ask if this is a default installation. The
+ default installation will search for known Web server configurations
+ and install the PMDA to monitor any logs that are found. This is
+ appropriate for first time installations. The non-default
+ installation is described in points 6 to 8.
+
+6. The configuration file for the weblog PMDA must be found and
+ checked. The Install script will look in the likely places for an
+ existing file and prompt for confirmation. Otherwise, a
+ configuration file can be automatically generated by searching known
+ Web server configuration files and directories.
+
+7. The second stage of the Install script prompts for the pmdaweblog(1)
+ parameters. The default values should be adequate for an initial
+ installation.
+
+8. The final stage will install the agent and restart PMCD (the
+ Performance Metrics Collection Daemon). The Install script should
+ report that the Metrics are OK.
+
+
+De-installation
+===============
+
+Simply use (as root)
+
+ # cd $PCP_PMDAS_DIR/weblog
+ # ./Remove
+
+
+Changing the settings
+=====================
+
+The safest way to alter any settings that were entered in the Install
+script is to re-run the Install script. Changes to the weblog.conf file
+can be also be registered by running the Install script.
+
+To quickly test changes to the configuration files, the agent and pmcd
+can be restarted as follows:
+
+ To register any changes made to the weblog.conf file, the agent
+ must be killed and restarted:
+
+ # pmsignal -a -s KILL pmdaweblog
+ # pmsignal -a -s HUP pmcd
+
+ To register any changes to the $PCP_PMCDCONF_PATH file you must
+ restart PMCD:
+
+ # $PCP_RC_DIR/pcp start
+
+
+Troubleshooting
+===============
+
+0. If there is trouble locating the Web server access and error logs,
+ try running the server.sh script with diagnostics:
+
+ $ cd $PCP_PMDAS_DIR/weblog
+ $ ./server.sh -q -v </dev/null
+
+1. After installing or restarting the agent, the PMCD log file
+ ($PCP_LOG_DIR/pmcd/pmcd.log) and the PMDA log file
+ ($PCP_LOG_DIR/pmcd/weblog.log) should be checked for any warnings
+ or errors.
+
+2. If the Install script reports some warnings when checking the
+ metrics, the problem should be listed in one of the log files.
+
+3. If the PMDA is configured to look at the correct access logs, and
+ the Web server is demonstrably updating those access logs, but the
+ exported performance metrics are not being updated, then the problem
+ may be in the pattern matching. To diagnose this:
+
+ Find the corresponding "server" line in
+ $PCP_VAR_DIR/config/web/weblog.conf, e.g.
+
+ server ha2.melbourne.sgi.com:80 on \
+ CERN /usr/ns-home/httpd-ha2/logs/access \
+ CERN_err /usr/ns-home/httpd-ha2/logs/errors
+
+ the pattern is symbolicly named after the word "on" (CERN above) and
+ the path to the access log follows
+ (/usr/ns-home/httpd-ha2/logs/access above). These two are used as
+ the last two arguments to check_match below:
+
+ $ cd $PCP_PMDAS_DIR/weblog
+ $ ./check_match $PCP_VAR_DIR/config/web/weblog.conf \
+ CERN /usr/ns-home/httpd-ha2/logs/access
+
+ If things are working OK, expect to see lines like:
+
+ [1] match: method="GET" size="17198"
+ [2] match: method="GET" size="-"
+ [3] match: method="GET" size="27102"
+ [4] match: method="POST" size="4503"
+ [5] match: method="HEAD" size="-"
+
+ If this does not happen, you need to review the format of the lines
+ in the access logs and modify the pattern by reference to the
+ regcmp(3) man page.
+
+4. Additional information can be logged if there appears to be problems
+ with the monitoring of server log files. Running the Install script
+ with the -D flag will add a prompt for a debugging flag. This can be
+ a combination of bits given by pmdbg -l:
+
+ # pmdbg -l
+
+ The application flags will cause the PMDA to report additional
+ information in $PCP_LOG_DIR/pmcd/weblog.log. DBG_TRACE_APPL0 reports
+ the least information and DBG_TRACE_APPL2 may report too much if the
+ server is handling many requests.
+
diff --git a/src/pmdas/weblog/Remove b/src/pmdas/weblog/Remove
new file mode 100644
index 0000000..50beaa2
--- /dev/null
+++ b/src/pmdas/weblog/Remove
@@ -0,0 +1,43 @@
+#! /bin/sh
+#
+# Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+# Remove the weblog PMDA
+#
+
+# Get standard environment
+. $PCP_DIR/etc/pcp.env
+
+# Get the common procedures and variable assignments
+#
+. $PCP_SHARE_DIR/lib/pmdaproc.sh
+
+# The name of the PMDA
+#
+iam=weblog
+
+# Do it
+#
+#_setup
+pmdaSetup
+
+pmns_name=web # metric names differ from PMDA name
+
+#_remove
+pmdaRemove
+
+exit 0
diff --git a/src/pmdas/weblog/Web.Alarms.pmchart b/src/pmdas/weblog/Web.Alarms.pmchart
new file mode 100644
index 0000000..d346f80
--- /dev/null
+++ b/src/pmdas/weblog/Web.Alarms.pmchart
@@ -0,0 +1,22 @@
+#pmchart
+#
+# Web statistics (error rates)
+#
+# This file is installed by the script $PCP_PMDAS_DIR/weblog/Install
+#
+Version 2.0 host dynamic
+
+Chart Title "Web Alarms" Style stacking
+ Plot Color #-cycle Host * Metric web.allservers.errors
+ Plot Color #-cycle Host * Metric network.tcp.drops
+ Plot Color #-cycle Host * Metric network.tcp.conndrops
+ Plot Color #-cycle Host * Metric network.tcp.timeoutdrop
+ Plot Color #-cycle Host * Metric network.tcp.sndrexmitpack
+ Plot Color #-cycle Host * Metric network.tcp.rcvbadsum
+ Plot Color #-cycle Host * Metric network.tcp.rexmttimeo
+ Plot Color #-cycle Host * Metric network.mbuf.failed
+ Plot Color #-cycle Host * Metric network.mbuf.waited
+ Plot Color #-cycle Host * Metric swap.pagesout
+
+#
+# Created Thu Jul 2 10:48:36 1998
diff --git a/src/pmdas/weblog/Web.Allservers.pmchart b/src/pmdas/weblog/Web.Allservers.pmchart
new file mode 100755
index 0000000..4185e1b
--- /dev/null
+++ b/src/pmdas/weblog/Web.Allservers.pmchart
@@ -0,0 +1,90 @@
+#!/bin/sh
+
+. $PCP_DIR/etc/pcp.env
+
+tmp=`mktemp -d /var/tmp/pcp.XXXXXXXXX` || exit 1
+trap "rm -rf $tmp; exit" 0 1 2 3 15
+
+echo "/\"/s///g" >$tmp/sed
+
+pmprobe -I $* web.perserver.bytes.cached.total web.perserver.bytes.total > $tmp/pmprobe
+l1=`head -n 1 $tmp/pmprobe`
+l2=`tail -n 1 $tmp/pmprobe`
+
+num_caches=`echo $l1 | cut -f2 -d\ `
+num_servers=`echo $l2 | cut -f2 -d\ `
+if [ $num_servers -gt 0 ]
+then
+ caches=`echo $l1 | cut -f3- -d\ `
+ servers=`echo $l2 | cut -f3- -d\ `
+# hostname=`echo $servers | cut -f1 -d: | sed -f $tmp/sed`
+
+ if [ $num_caches -le 0 ]
+ then
+ # an old pmda - quietly handle all servers as if they were CERN - show only totals
+ caches="NeVeR_MaTcH"
+ num_caches=0
+ fi
+elif [ $num_servers -eq 0 ]
+then
+ $PCP_XCONFIRM_PROG -c -B OK -header "No Active Servers - cannot continue" \
+ -t "$message" \
+ -icon info > /dev/null
+ exit
+else
+ message=`pmerr $num_servers | cut -f5- -d\ `
+ $PCP_XCONFIRM_PROG -c -B OK -header "Fatal error - cannot continue" \
+ -t "$message" \
+ -icon error > /dev/null
+ exit
+fi
+
+#
+# if too many instances, turn off all legends
+#
+legendp=on
+if [ $num_servers -gt 6 ]
+then
+ legendp=off
+fi
+
+if [ $num_servers -gt 12 ]
+then
+ $PCP_XCONFIRM_PROG -c -B Cancel -b Continue -header \
+ "Too many charts" \
+ -t "There is 1 chart per server, more than can reasonably be displayed on the screen" \
+ -icon warning | grep Cancel >/dev/null
+if [ $? -eq 0 ]
+then
+ exit
+fi
+fi
+
+# chart preamble
+#
+cat > $tmp/base <<End-of-File
+#pmchart
+Version 2.0 host dynamic
+
+End-of-File
+
+if [ $num_caches -ne $num_servers ]
+then
+ echo Chart Title \"Total Requests serviced by all servers \" Style bars Legend off>> $tmp/base
+ echo Plot Color \#FF3030 Host \* Metric web.allservers.requests.total >> $tmp/base
+ echo Chart Title \"Total Bytes sent by all servers \" Style bars Legend off>> $tmp/base
+ echo Plot Color \#FF3030 Host \* Metric web.allservers.bytes.total >> $tmp/base
+fi
+if [ $num_caches -gt 0 ]
+then
+ echo Chart Title \"Total Requests serviced by caching servers \" Style stacking Legend $legendp >> $tmp/base
+ echo Plot Color \#FFFF30 Host \* Metric web.allservers.requests.client.total >> $tmp/base
+ echo Plot Color \#3030FF Host \* Metric web.allservers.requests.cached.total >> $tmp/base
+ echo Plot Color \#FF3030 Host \* Metric web.allservers.requests.uncached.total >> $tmp/base
+ echo Chart Title \"Total Bytes sent by caching servers \" Style stacking Legend $legendp >> $tmp/base
+ echo Plot Color \#3030FF Host \* Metric web.allservers.bytes.cached.total >> $tmp/base
+ echo Plot Color \#FF3030 Host \* Metric web.allservers.bytes.uncached.total >> $tmp/base
+fi
+
+cat $tmp/base
+rm -rf $tmp
diff --git a/src/pmdas/weblog/Web.Perserver.Bytes.pmchart b/src/pmdas/weblog/Web.Perserver.Bytes.pmchart
new file mode 100755
index 0000000..1f57a27
--- /dev/null
+++ b/src/pmdas/weblog/Web.Perserver.Bytes.pmchart
@@ -0,0 +1,90 @@
+#!/bin/sh
+
+. $PCP_DIR/etc/pcp.env
+
+tmp=`mktemp -d /var/tmp/pcp.XXXXXXXXX` || exit 1
+trap "rm -rf $tmp; exit" 0 1 2 3 15
+
+echo "/\"/s///g" >$tmp/sed
+
+pmprobe -I $* web.perserver.bytes.cached.total web.perserver.bytes.total > $tmp/pmprobe
+l1=`head -n 1 $tmp/pmprobe`
+l2=`tail -n 1 $tmp/pmprobe`
+
+num_caches=`echo $l1 | cut -f2 -d\ `
+num_servers=`echo $l2 | cut -f2 -d\ `
+if [ $num_servers -gt 0 ]
+then
+ caches=`echo $l1 | cut -f3- -d\ `
+ servers=`echo $l2 | cut -f3- -d\ `
+
+ if [ $num_caches -lt 0 ]
+ then
+ # an old pmda - quietly handle all servers as if they were CERN - show only totals
+ caches="NeVeR_MaTcH"
+ num_caches=0
+ fi
+elif [ $num_servers -eq 0 ]
+then
+ $PCP_XCONFIRM_PROG -c -B OK -header "No Active Servers - cannot continue" \
+ -t "$message" \
+ -icon info > /dev/null
+ exit
+else
+ message=`pmerr $num_servers | cut -f5- -d\ `
+ $PCP_XCONFIRM_PROG -c -B OK -header "Fatal error - cannot continue" \
+ -t "$message" \
+ -icon error > /dev/null
+ exit
+fi
+
+#
+# if too many instances, turn off all legends
+#
+legendp=on
+if [ $num_servers -gt 6 ]
+then
+ legendp=off
+fi
+
+if [ $num_servers -gt 12 ]
+then
+ $PCP_XCONFIRM_PROG -c -B Cancel -b Continue -header \
+ "Too many charts" \
+ -t "There is 1 chart per server, more than can reasonably be displayed on the screen" \
+ -icon warning | grep Cancel >/dev/null
+if [ $? -eq 0 ]
+then
+ exit
+fi
+fi
+
+# chart preamble
+#
+cat > $tmp/base <<End-of-File
+#pmchart
+Version 2.0 host dynamic
+
+End-of-File
+
+i=1
+while [ $i -le $num_servers ]
+do
+server=`echo $servers | cut -f$i -d\ `
+echo $caches | grep $server >/dev/null
+if [ $? -eq 0 ]
+then
+ j=`echo $server | sed -f $tmp/sed`
+ echo Chart Title \"Bytes sent by $j\" Style stacking Legend $legendp >> $tmp/base
+ echo Plot Color \#3030FF Host \* Metric web.perserver.bytes.cached.total Instance $j >> $tmp/base
+ echo Plot Color \#FF3030 Host \* Metric web.perserver.bytes.uncached.total Instance $j >> $tmp/base
+else
+ j=`echo $server | sed -f $tmp/sed`
+ echo Chart Title \"Total Bytes sent by $j\" Style bars Legend off>> $tmp/base
+ echo Plot Color \#FF3030 Host \* Metric web.perserver.bytes.total Instance $j >> $tmp/base
+fi
+i=`expr $i + 1`
+done
+
+cat $tmp/base
+rm -rf $tmp
diff --git a/src/pmdas/weblog/Web.Perserver.Requests.pmchart b/src/pmdas/weblog/Web.Perserver.Requests.pmchart
new file mode 100755
index 0000000..77ff366
--- /dev/null
+++ b/src/pmdas/weblog/Web.Perserver.Requests.pmchart
@@ -0,0 +1,91 @@
+#!/bin/sh
+
+. $PCP_DIR/etc/pcp.env
+
+tmp=`mktemp -d /var/tmp/pcp.XXXXXXXXX` || exit 1
+trap "rm -rf $tmp; exit" 0 1 2 3 15
+
+echo "/\"/s///g" >$tmp/sed
+
+pmprobe -I $* web.perserver.bytes.cached.total web.perserver.bytes.total > $tmp/pmprobe
+l1=`head -n 1 $tmp/pmprobe`
+l2=`tail -n 1 $tmp/pmprobe`
+
+num_caches=`echo $l1 | cut -f2 -d\ `
+num_servers=`echo $l2 | cut -f2 -d\ `
+if [ $num_servers -gt 0 ]
+then
+ caches=`echo $l1 | cut -f3- -d\ `
+ servers=`echo $l2 | cut -f3- -d\ `
+
+ if [ $num_caches -lt 0 ]
+ then
+ # an old pmda - quietly handle all servers as if they were CERN - show only totals
+ caches="NeVeR_MaTcH"
+ num_caches=0
+ fi
+elif [ $num_servers -eq 0 ]
+then
+ $PCP_XCONFIRM_PROG -c -B OK -header "No Active Servers - cannot continue" \
+ -t "$message" \
+ -icon info > /dev/null
+ exit
+else
+ message=`pmerr $num_servers | cut -f5- -d\ `
+ $PCP_XCONFIRM_PROG -c -B OK -header "Fatal error - cannot continue" \
+ -t "$message" \
+ -icon error > /dev/null
+ exit
+fi
+
+#
+# if too many instances, turn off all legends
+#
+legendp=on
+if [ $num_servers -gt 6 ]
+then
+ legendp=off
+fi
+
+if [ $num_servers -gt 12 ]
+then
+ $PCP_XCONFIRM_PROG -c -B Cancel -b Continue -header \
+ "Too many charts" \
+ -t "There is 1 chart per server, more than can reasonably be displayed on the screen" \
+ -icon warning | grep Cancel >/dev/null
+if [ $? -eq 0 ]
+then
+ exit
+fi
+fi
+
+# chart preamble
+#
+cat > $tmp/base <<End-of-File
+#pmchart
+Version 2.0 host dynamic
+
+End-of-File
+
+i=1
+while [ $i -le $num_servers ]
+do
+server=`echo $servers | cut -f$i -d\ `
+echo $caches | grep $server >/dev/null
+if [ $? -eq 0 ]
+then
+ j=`echo $server | sed -f $tmp/sed`
+ echo Chart Title \"Requests satisfied by $j\" Style stacking Legend $legendp >> $tmp/base
+ echo Plot Color \#FFFF30 Host \* Metric web.perserver.requests.client.total Instance $j >> $tmp/base
+ echo Plot Color \#3030FF Host \* Metric web.perserver.requests.cached.total Instance $j >> $tmp/base
+ echo Plot Color \#FF3030 Host \* Metric web.perserver.requests.uncached.total Instance $j >> $tmp/base
+else
+ j=`echo $server | sed -f $tmp/sed`
+ echo Chart Title \"Total Requests satisfied by $j\" Style bars Legend off>> $tmp/base
+ echo Plot Color \#FF3030 Host \* Metric web.perserver.requests.total Instance $j >> $tmp/base
+fi
+i=`expr $i + 1`
+done
+
+cat $tmp/base
+rm -rf $tmp
diff --git a/src/pmdas/weblog/Web.Requests.pmchart b/src/pmdas/weblog/Web.Requests.pmchart
new file mode 100644
index 0000000..7775fd5
--- /dev/null
+++ b/src/pmdas/weblog/Web.Requests.pmchart
@@ -0,0 +1,27 @@
+#pmchart
+#
+# Web statistics (request rates)
+#
+# This file is installed by the script $PCP_PMDAS_DIR/weblog/Install
+#
+Version 2.0 host dynamic
+
+Chart Title "Requests by HTTP method" Style stacking
+ Plot Color rgbi:1.0/1.0/0.0 Host * Metric web.allservers.requests.get
+ Plot Color rgbi:0.0/1.0/1.0 Host * Metric web.allservers.requests.post
+ Plot Color rgbi:1.0/0.0/1.0 Host * Metric web.allservers.requests.head
+ Plot Color rgbi:1.0/1.0/0.6 Host * Metric web.allservers.requests.other
+Chart Title "Requests by request size" Style stacking
+ Plot Color rgbi:1.0/0.8/0.6 Host * Metric web.allservers.requests.size.zero
+ Plot Color rgbi:0.6/1.0/0.6 Host * Metric web.allservers.requests.size.le3k
+ Plot Color rgbi:0.8/0.6/1.0 Host * Metric web.allservers.requests.size.le10k
+ Plot Color rgbi:1.0/0.65/0.3 Host * Metric web.allservers.requests.size.le30k
+ Plot Color rgbi:0.3/1.0/0.3 Host * Metric web.allservers.requests.size.le100k
+ Plot Color rgbi:0.65/0.3/1.0 Host * Metric web.allservers.requests.size.le300k
+ Plot Color rgbi:1.0/0.5/0.0 Host * Metric web.allservers.requests.size.le1m
+ Plot Color rgbi:0.0/1.0/0.0 Host * Metric web.allservers.requests.size.le3m
+ Plot Color rgbi:0.6/0.0/0.9 Host * Metric web.allservers.requests.size.gt3m
+ Plot Color rgbi:1.0/0.35/0.0 Host * Metric web.allservers.requests.size.unknown
+
+#
+# Created Thu Jul 2 10:48:19 1998
diff --git a/src/pmdas/weblog/Web.Volume.pmchart b/src/pmdas/weblog/Web.Volume.pmchart
new file mode 100644
index 0000000..569abd9
--- /dev/null
+++ b/src/pmdas/weblog/Web.Volume.pmchart
@@ -0,0 +1,25 @@
+#pmchart
+#
+# Web Statistics (data volume)
+#
+# This file is installed by the script $PCP_PMDAS_DIR/weblog/Install
+#
+Version 2.0 host dynamic
+
+Chart Title "Bytes sent by HTTP method" Style stacking
+ Plot Color rgbi:1.0/1.0/0.0 Host * Metric web.allservers.bytes.get
+ Plot Color rgbi:0.0/1.0/1.0 Host * Metric web.allservers.bytes.post
+ Plot Color rgbi:1.0/0.0/1.0 Host * Metric web.allservers.bytes.head
+ Plot Color rgbi:1.0/1.0/0.6 Host * Metric web.allservers.bytes.other
+Chart Title "Bytes sent by request size" Style stacking
+ Plot Color rgbi:0.6/1.0/0.6 Host * Metric web.allservers.bytes.size.le3k
+ Plot Color rgbi:0.8/0.6/1.0 Host * Metric web.allservers.bytes.size.le10k
+ Plot Color rgbi:1.0/0.65/0.3 Host * Metric web.allservers.bytes.size.le30k
+ Plot Color rgbi:0.3/1.0/0.3 Host * Metric web.allservers.bytes.size.le100k
+ Plot Color rgbi:0.65/0.3/1.0 Host * Metric web.allservers.bytes.size.le300k
+ Plot Color rgbi:1.0/0.5/0.0 Host * Metric web.allservers.bytes.size.le1m
+ Plot Color rgbi:0.0/1.0/0.0 Host * Metric web.allservers.bytes.size.le3m
+ Plot Color rgbi:0.6/0.0/0.9 Host * Metric web.allservers.bytes.size.gt3m
+
+#
+# Created Thu Jul 2 10:47:51 1998
diff --git a/src/pmdas/weblog/check_match.c b/src/pmdas/weblog/check_match.c
new file mode 100644
index 0000000..5166e75
--- /dev/null
+++ b/src/pmdas/weblog/check_match.c
@@ -0,0 +1,414 @@
+/*
+ * Copyright (c) 2000,2003 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+/*
+ * Uses the same regular expression logic as pmdaweblog, but extracted
+ * here so new patterns and access logs can be tested
+ *
+ * Usage: check_match configfile pat_name [input]
+ * configfile regex spec file as used by pmdaweblog
+ * pat_name use only this names regex from configfile
+ * input test input to try and match, defaults to stdin
+ */
+
+#include <ctype.h>
+#include <pmapi.h>
+#if defined(HAVE_REGEX_H)
+#include <regex.h>
+#endif
+#include <sys/types.h>
+
+int
+main(int argc, char *argv[])
+{
+ FILE *fc;
+ char buf[1024];
+ char *p;
+ char *q;
+#ifdef HAVE_REGEX
+ char *comp = NULL;
+ char sub0[1024];
+ char sub1[1024];
+ char sub2[1024];
+ char sub3[1024];
+#endif
+ int lno = 0;
+ int regex_posix = 0;
+ int cern_format = 0;
+ int common_extended_format = 0;
+ int squid_format = 0;
+ int methodpos = 1, c_statuspos = 2, sizepos = 2, s_statuspos = 2;
+ long client_cache_hits, proxy_cache_hits, remote_fetches;
+ double proxy_bytes, remote_bytes;
+#if (defined HAVE_REGEXEC) && (defined HAVE_REGCOMP)
+ regex_t re = {0};
+ regmatch_t pmatch[5];
+ size_t nmatch = 5;
+#endif
+
+
+ if (argc < 3 || argc > 4) {
+ fprintf(stderr, "Usage: check_match configfile pat_name [input]\n");
+ exit(1);
+ }
+
+ if ((fc = fopen(argv[1], "r")) == NULL) {
+ fprintf(stderr, "check_match: cannot open configfile \"%s\": %s\n", argv[1], osstrerror());
+ exit(1);
+ }
+
+ if (argc == 4) {
+ if (freopen(argv[3], "r", stdin) == NULL) {
+ fprintf(stderr, "check_match: cannot open input \"%s\": %s\n", argv[3], osstrerror());
+ exit(1);
+ }
+ }
+
+ while (fgets(buf, sizeof(buf), fc) != NULL) {
+ lno++;
+
+ if (strncmp(buf, "regex", 5) != 0) continue;
+ if (strncmp(buf, "regex_posix", 11) == 0) {
+ regex_posix = 1;
+ p = &buf[11];
+ }
+ else {
+ regex_posix = 0;
+ p = &buf[5];
+ }
+
+ while (*p && isspace((int)*p)) p++;
+ if (*p == '\0') continue;
+ q = p++;
+ while (*p && !isspace((int)*p)) p++;
+ if (*p == '\0') continue;
+ *p = '\0';
+
+ cern_format = squid_format = common_extended_format = 0;
+
+ if (strcmp(q, argv[2]) == 0) {
+ if(regex_posix) {
+
+ q = ++p;
+ while (*p && !isspace((int)*p)) p++;
+ if (*p == '\0') continue;
+ *p = '\0';
+ fprintf(stderr, "args are (%s)\n", q);
+ if(strncmp(q, "method,size", 11) == 0) {
+ cern_format = 1;
+ methodpos = 1;
+ sizepos = 2;
+ }
+ else if(strncmp(q, "size,method", 11) == 0) {
+ methodpos = 2;
+ sizepos = 1;
+ }
+ else {
+ char *str;
+ int pos;
+
+ pos = 1;
+ str=q;
+ do {
+ switch(str[0]) {
+ case '1':
+ methodpos = pos++;
+ break;
+ case '2':
+ sizepos = pos++;
+ break;
+ case '3':
+ c_statuspos = pos++;
+ break;
+ case '4':
+ s_statuspos = pos++;
+ break;
+ case '-':
+ methodpos = 1;
+ sizepos = 2;
+ str[0] = '\0';
+ break;
+ case ',':
+ case '\0':
+ break;
+ default:
+ fprintf(stderr,
+ "could figure out arg order params (%s)\n",
+ str);
+ exit(1);
+ }
+ } while ( *str++ );
+
+ if(c_statuspos > 0 && s_statuspos > 0) {
+ if(strcmp(argv[2], "SQUID") == 0)
+ squid_format = 1;
+ else
+ common_extended_format = 1;
+ } else
+ cern_format = 1;
+ }
+
+ fprintf(stderr, "cern: %d, cef: %d, squid: %d, MP: %d, SP: %d, CSP: %d, SSP: %d\n",
+ cern_format, common_extended_format, squid_format,
+ methodpos, sizepos, c_statuspos, s_statuspos);
+ }
+
+ q = ++p;
+ while (*p && *p != '\n') p++;
+ while (p >= q && isspace((int)*p)) p--;
+ p[1] = '\0';
+ if(regex_posix) {
+#ifdef HAVE_REGCOMP
+ fprintf(stderr, "%s[%d]: regex_posix: %s\n", argv[1], lno, q);
+ fclose(fc);
+ if(regcomp(&re, q, REG_EXTENDED) != 0 ) {
+ fprintf(stderr, "Error: bad regular expression\n");
+ exit(1);
+ }
+#else
+ fprintf(stderr, "%s[%d]: no support for POSIX regexp\n",
+ argv[1], lno);
+#endif
+ }
+ else {
+#ifdef HAVE_REGCMP
+ if(strcmp(argv[2], "CERN") == 0)
+ cern_format = 1;
+ else if (strcmp(argv[2], "NS_PROXY") == 0)
+ common_extended_format = 1;
+ else if (strcmp(argv[2], "SQUID") == 0)
+ squid_format = 1;
+
+ fprintf(stderr, "%s[%d]: regex: %s\n", argv[1], lno, q);
+ fclose(fc);
+ comp = regcmp(q, NULL);
+ if (comp == NULL) {
+ fprintf(stderr, "Error: bad regular expression\n");
+ exit(1);
+ }
+#else
+ fprintf(stderr, "%s[%d]: regcmp is not available\n",
+ argv[1], lno);
+#endif
+ }
+ break;
+ }
+ }
+
+ lno = 0;
+ remote_fetches = proxy_cache_hits = client_cache_hits = 0;
+ remote_bytes = proxy_bytes = 0.0;
+ while (fgets(buf, sizeof(buf), stdin) != NULL) {
+ lno++;
+ if(regex_posix) {
+#ifdef HAVE_REGEXEC
+ if(regexec(&re, buf, nmatch, pmatch, 0) == 0) {
+ buf[pmatch[methodpos].rm_eo] = '\0';
+ buf[pmatch[sizepos].rm_eo] = '\0';
+ if(common_extended_format || squid_format) {
+ buf[pmatch[c_statuspos].rm_eo] = '\0';
+ buf[pmatch[s_statuspos].rm_eo] = '\0';
+ }
+
+ if(common_extended_format) {
+ fprintf(stderr,"[%d] M: %s, S: %s, CS: %s, SS: %s\n",
+ lno,
+ &buf[pmatch[methodpos].rm_so],
+ &buf[pmatch[sizepos].rm_so],
+ &buf[pmatch[c_statuspos].rm_so],
+ &buf[pmatch[s_statuspos].rm_so]);
+ if(strcmp(&buf[pmatch[c_statuspos].rm_so], "200") == 0 &&
+ strcmp(&buf[pmatch[s_statuspos].rm_so], "200") == 0) {
+ fprintf(stderr,"\tREMOTE fetch of %.0f bytes\n",
+ atof(&buf[pmatch[sizepos].rm_so]));
+ remote_fetches++;
+ remote_bytes += atof(&buf[pmatch[sizepos].rm_so]);
+ }
+ if(strcmp(&buf[pmatch[c_statuspos].rm_so], "200") == 0 &&
+ (strcmp(&buf[pmatch[s_statuspos].rm_so], "304") == 0 ||
+ strcmp(&buf[pmatch[s_statuspos].rm_so], "-") == 0)) {
+ fprintf(stderr,"\tCACHE return of %.0f bytes\n",
+ atof(&buf[pmatch[sizepos].rm_so]));
+ proxy_cache_hits++;
+ proxy_bytes += atof(&buf[pmatch[sizepos].rm_so]);
+
+ }
+ if(strcmp(&buf[pmatch[c_statuspos].rm_so], "304") == 0 &&
+ (strcmp(&buf[pmatch[s_statuspos].rm_so], "304") == 0 ||
+ strcmp(&buf[pmatch[s_statuspos].rm_so], "-") == 0)) {
+ fprintf(stderr,"\tCLIENT hit of %.0f bytes\n",
+ atof(&buf[pmatch[sizepos].rm_so]));
+ client_cache_hits++;
+ }
+ } else if(squid_format) {
+ fprintf(stderr,"[%d] M: %s, S: %s, CS: %s, SS: %s\n",
+ lno,
+ &buf[pmatch[methodpos].rm_so],
+ &buf[pmatch[sizepos].rm_so],
+ &buf[pmatch[c_statuspos].rm_so],
+ &buf[pmatch[s_statuspos].rm_so]);
+ if(strcmp(&buf[pmatch[c_statuspos].rm_so], "200") == 0 &&
+ (strstr(&buf[pmatch[s_statuspos].rm_so],
+ "_MISS")!=NULL ||
+ strstr(&buf[pmatch[s_statuspos].rm_so],
+ "_CLIENT_REFRESH")!=NULL ||
+ strstr(&buf[pmatch[s_statuspos].rm_so],
+ "_SWAPFAIL")!=NULL)){
+ fprintf(stderr,"\tREMOTE fetch of %.0f bytes (code: %s, Squid result code: %s)\n",
+ atof(&buf[pmatch[sizepos].rm_so]),
+ &buf[pmatch[c_statuspos].rm_so], &buf[pmatch[s_statuspos].rm_so]);
+ remote_fetches++;
+ remote_bytes += atof(&buf[pmatch[sizepos].rm_so]);
+ }
+ if(strcmp(&buf[pmatch[c_statuspos].rm_so], "200") == 0 &&
+ strstr(&buf[pmatch[s_statuspos].rm_so], "_HIT") != NULL) {
+ fprintf(stderr,"\tCACHE return of %.0f bytes (code: %s, Squid result code: %s)\n",
+ atof(&buf[pmatch[sizepos].rm_so]),
+ &buf[pmatch[c_statuspos].rm_so], &buf[pmatch[s_statuspos].rm_so]);
+ proxy_cache_hits++;
+ proxy_bytes += atof(&buf[pmatch[sizepos].rm_so]);
+
+ }
+ if(strcmp(&buf[pmatch[c_statuspos].rm_so], "304") == 0 &&
+ strstr(&buf[pmatch[s_statuspos].rm_so], "_HIT") != NULL) {
+ fprintf(stderr,"\tCLIENT hit of %.0f bytes (code: %s, Squid result code: %s)\n",
+ atof(&buf[pmatch[sizepos].rm_so]),
+ &buf[pmatch[c_statuspos].rm_so], &buf[pmatch[s_statuspos].rm_so]);
+ client_cache_hits++;
+ }
+ } else {
+ fprintf(stderr, "[%d] match: method=\"%s\" size=\"%s\"\n", lno,
+ &buf[pmatch[methodpos].rm_so], &buf[pmatch[sizepos].rm_so]);
+ }
+ }
+ else
+ fprintf(stderr, "[%d] no match: %s\n", lno, buf);
+#else
+ fprintf(stderr, "[%d] - no regexec()\n", lno);
+#endif
+ }
+ else {
+#ifdef HAVE_REGEX
+ if (regex(comp, buf, sub0, sub1, sub2, sub3) != NULL) {
+ if(common_extended_format) {
+
+ fprintf(stderr,"[%d] M: %s, S: %s, CS: %s, SS: %s\n",
+ lno, sub0, sub1, sub2, sub3);
+
+ if(strcmp(sub2, "200") == 0 &&
+ strcmp(sub3, "200") == 0 ) {
+ fprintf(stderr,"\tREMOTE fetch of %s bytes\n", sub1);
+ remote_fetches++;
+ remote_bytes += atof(sub1);
+ }
+ if(strcmp(sub2, "200") == 0 &&
+ (strcmp(sub3, "304") == 0 || strcmp(sub3, "-") == 0)) {
+ fprintf(stderr,"\tCACHE return of %s bytes\n", sub1);
+ proxy_cache_hits++;
+ proxy_bytes += atof(sub1);
+ }
+ if(strcmp(sub2, "304") == 0 &&
+ (strcmp(sub3, "304") == 0 || strcmp(sub3, "-") == 0)) {
+ fprintf(stderr,"\tCLIENT hit of %s bytes\n", sub1);
+ client_cache_hits++;
+ }
+ } else if(squid_format) {
+
+ fprintf(stderr,"[%d] M: %s, S: %s, CS: %s, SS: %s\n",
+ lno, sub0, sub1, sub2, sub3);
+
+ if(strcmp(sub2, "200") == 0 &&
+ (strstr(sub3, "_MISS") != NULL ||
+ strstr(sub3, "_CLIENT_REFRESH")!= NULL ||
+ strstr(sub3, "_SWAPFAIL") != NULL)){
+
+ fprintf(stderr,"\tREMOTE fetch of %.0f bytes (code: %s, Squid result code: %s)\n",
+ atof(sub1),
+ sub2, sub3);
+
+ remote_fetches++;
+ remote_bytes += atof(sub1);
+ }
+ if(strcmp(sub2, "200") == 0 &&
+ strstr(sub3, "_HIT") != NULL) {
+
+ fprintf(stderr,"\tCACHE return of %.0f bytes (code: %s, Squid result code: %s)\n",
+ atof(sub1),
+ sub2, sub3);
+
+ proxy_cache_hits++;
+ proxy_bytes += atof(sub1);
+
+ }
+ if(strcmp(sub2, "304") == 0 &&
+ strstr(sub3, "_HIT") != NULL) {
+
+ fprintf(stderr,"\tCLIENT hit of %.0f bytes (code: %s, Squid result code: %s)\n",
+ atof(sub3),
+ sub2, sub3);
+
+ client_cache_hits++;
+ }
+ } else {
+ fprintf(stderr, "[%d] match: method=\"%s\" size=\"%s\"\n", lno,
+ sub0, sub1);
+ }
+ }
+ else
+ fprintf(stderr, "[%d] no match: %s\n", lno, buf);
+#else
+ fprintf(stderr, "[%d] - no regex()\n", lno);
+#endif
+ }
+ }
+
+ if(common_extended_format || squid_format) {
+ fprintf(stderr,"Proxy Cache Summary Report\n\n");
+
+ fprintf(stderr,
+ "# requests %ld\n# client cache hits %ld\n# cache hits %ld\n# remote fetches %ld\n",
+ (client_cache_hits + proxy_cache_hits + remote_fetches),
+ client_cache_hits, proxy_cache_hits, remote_fetches);
+ fprintf(stderr,
+ "\nTotal Mbytes %f bytes\nFrom proxy cache %f Mbytes\nFrom remote sites %f Mbytes\n\n",
+ (proxy_bytes + remote_bytes)/1000000.0,
+ proxy_bytes/1000000.0, remote_bytes/1000000.0);
+
+ fprintf(stderr,
+ "Client Cache %% hit rate: %.2f\n",
+ 100.0*(float)client_cache_hits/(float)(client_cache_hits + proxy_cache_hits + remote_fetches));
+ fprintf(stderr,
+ "Proxy Cache %% hit rate: %.2f\n",
+ 100.0*(float)proxy_cache_hits/(float)(client_cache_hits + proxy_cache_hits + remote_fetches));
+ fprintf(stderr,
+ "Local Cache %% hit rate: %.2f\n",
+ 100.0*(float)(client_cache_hits + proxy_cache_hits)/
+ (float)(client_cache_hits + proxy_cache_hits + remote_fetches));
+
+ fprintf(stderr,
+ "\nAverage fetch size: Proxy -> Client: %.2f Kb\n",
+ proxy_bytes/proxy_cache_hits/1000.0);
+ fprintf(stderr,
+ "Average fetch size: Remote -> Client : %.2f Kb\n",
+ remote_bytes/remote_fetches/1000.0);
+
+ fprintf(stderr,"\nClient Cache bandwidth reduction effectiveness: UNKNOWN\n");
+ fprintf(stderr,
+ "Proxy Cache bandwidth reduction effectiveness: %f%%\n",
+ 100.0*proxy_bytes/(proxy_bytes + remote_bytes));
+
+ }
+
+ exit(0);
+}
diff --git a/src/pmdas/weblog/help b/src/pmdas/weblog/help
new file mode 100644
index 0000000..3a523e6
--- /dev/null
+++ b/src/pmdas/weblog/help
@@ -0,0 +1,654 @@
+#
+#
+# Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+
+@ web.config.numservers number of servers in configuration file
+The number of Web servers specified in the configuration file.
+The log files for these Web servers may or may not be monitored,
+see web.perserver.watched and web.allservers.numwatched.
+
+@ web.config.catchup maximum time (secs) before Web server logs are probed
+The time in seconds after which monitored Web server logs will be
+examined, even if there have been no requests for performance metrics
+from those logs. The "catch up" process spreads the load and minimizes
+the latency at the first requests for metrics that have not been
+requested for a long time.
+
+This metric has the initial value of the -t delay option to
+pmdaweblog, and may be altered using pmStore(1).
+
+@ web.config.catchuptime time (secs) to perform catchup
+Accumulated elapsed time in which the Web logs PMDA has been performing
+the "catch up" process to examine all Web server logs.
+
+@ web.config.check time (secs) after which stationary logs will be re-opened
+Web server log files that are not changing are periodically closed and
+re-opened to detect possible log file rotation. This metric controls
+how often a stationary log file will be re-opened.
+
+This metric has the initial value of the -n idlesec option to
+pmdaweblog, and may be altered using pmStore(1).
+
+@ web.allservers.numwatched number of servers being monitored
+The number of Web servers that are being monitored, as opposed
+the number specified in the configuration file.
+
+See also web.config.numservers and web.perserver.watched.
+
+@ web.allservers.numalive number of watched servers that are alive
+The number of servers that are being watchedly watched that have both
+logs files.
+
+@ web.allservers.errors number of errors reported by all watched servers
+The number of errors reported by all watched servers.
+
+@ web.allservers.requests.total requests processed by all servers
+The total number of HTTP requests processed by all watched servers.
+
+@ web.allservers.bytes.total bytes sent by all servers
+The total number of bytes sent by all watched servers.
+
+@ web.allservers.requests.get GET requests handled by all watched servers
+The number of HTTP GET requests that were processed by all watched servers.
+
+@ web.allservers.bytes.get bytes sent in reply by all servers to GET requests
+The number of bytes that have been sent by all watched servers in reply
+to HTTP GET requests.
+
+@ web.allservers.requests.head HEAD requests handled by all watched servers
+The number of HTTP HEAD requests that were processed by all watched
+servers.
+
+@ web.allservers.bytes.head bytes sent in reply by all servers to HEAD requests
+The number of bytes that have been sent by all watched servers in reply
+to HTTP HEAD requests.
+
+@ web.allservers.requests.post POST requests handled by all watched servers
+The number of HTTP POST requests that were processed by all watched
+servers.
+
+@ web.allservers.bytes.post bytes sent in reply by all servers to POST requests
+The number of bytes that have been sent by all watched servers in reply
+to HTTP POST requests.
+
+@ web.allservers.requests.other other requests handled by all watch servers
+The number of HTTP requests, other than GET, HEAD and POST, that were
+processed by all watched servers.
+
+@ web.allservers.bytes.other bytes sent in reply by servers to other requests
+The number of bytes that have been sent by this server in reply to HTTP
+requests other than GET, HEAD or POST.
+
+@ web.allservers.requests.size.zero replies of 0 bytes sent by all servers
+The total number of HTTP requests that required a response of 0 bytes from
+all watched servers.
+
+@ web.allservers.bytes.size.zero total bytes sent in 0k replies
+The total number of bytes sent in replies of 0k by all watched servers.
+This metric is always zero and is provided for consistency only.
+
+@ web.allservers.requests.size.le3k replies of <= 3k sent by all servers
+The number of HTTP requests that required a response of less than or equal
+to 3k from all watched servers.
+
+@ web.allservers.bytes.size.le3k total bytes sent in <= 3k replies
+The total number of bytes sent in replies of less than or equal to 3k in
+size by all watched servers.
+
+@ web.allservers.requests.size.le10k replies of <= 10k sent by all servers
+The number of HTTP requests that required a response of less than or equal
+to 10k from all watched servers.
+
+@ web.allservers.bytes.size.le10k total bytes sent in <= 10k replies
+The total number of bytes sent in replies of less than or equal to 10k in
+size by all watched servers.
+
+@ web.allservers.requests.size.le30k replies of <= 30k sent by all servers
+The number of HTTP requests that required a response of less than or equal
+to 30k from all watched servers.
+
+@ web.allservers.bytes.size.le30k total bytes sent in <= 30k replies
+The total number of bytes sent in replies of less than or equal to 30k in
+size by all watched servers.
+
+@ web.allservers.requests.size.le100k replies of <= 100k sent by all servers
+The number of HTTP requests that required a response of less than or equal
+to 100k from all watched servers.
+
+@ web.allservers.bytes.size.le100k total bytes sent in <= 100k replies
+The total number of bytes sent in replies of less than or equal to 100k in
+size by all watched servers.
+
+@ web.allservers.requests.size.le300k replies of <= 300k sent by all servers
+The number of HTTP requests that required a response of less than or equal
+to 300k from all watched servers.
+
+@ web.allservers.bytes.size.le300k total bytes sent in <= 300k replies
+The total number of bytes sent in replies of less than or equal to 300k in
+size by all watched servers.
+
+@ web.allservers.requests.size.le1m replies of <= 1M sent by all servers
+The number of HTTP requests that required a response of less than or equal
+to 1M from all watched servers.
+
+@ web.allservers.bytes.size.le1m total bytes sent in <= 1M replies
+The total number of bytes sent in replies of less than or equal to 1M in
+size by all watched servers.
+
+@ web.allservers.requests.size.le3m replies of <= 3M sent by all servers
+The number of HTTP requests that required a response of less than or equal
+to 3M from all watched servers.
+
+@ web.allservers.bytes.size.le3m total bytes sent in <= 3M replies
+The total number of bytes sent in replies of less than or equal to 3M in
+size by all watched servers.
+
+@ web.allservers.requests.size.gt3m replies of > 3M sent by all servers
+The number of HTTP requests that required a response of greater than
+3M from all watched servers.
+
+@ web.allservers.bytes.size.gt3m total bytes sent > 3M replies
+The total number of bytes sent in replies of greater than 3M in size by
+all watched servers.
+
+@ web.allservers.requests.size.unknown replies of unknown size by all servers
+The number of HTTP requests that required a response of unknown size
+from all watched servers.
+
+@ web.allservers.requests.client.total requests satisfied by client caches for all cacheing servers
+The total number of HTTP GET/IMS requests that resulted in "Not Modified"
+responses from cache (and remote if checked). These are client cache hits.
+
+@ web.allservers.requests.cached.total requests satisfied by server caches for all cacheing servers
+The total number of HTTP GET/IMS requests that resulted in "Not Modified"
+responses from the remote site or were deemed cache hits via other
+mechanisms such as recency. These are server cache hits and result in
+data transferred from cache to client.
+
+@ web.allservers.requests.cached.size.zero replies of 0 bytes sent by all caches
+The number of HTTP GET cache hits that required a response of 0 bytes from
+all watched caches.
+
+@ web.allservers.requests.cached.size.le3k replies of <= 3k sent by all caches
+The number of HTTP GET cache hits that required a response of less than
+or equal to 3k from all watched caches.
+
+@ web.allservers.requests.cached.size.le10k replies of <= 10k sent by all caches
+The number of HTTP GET cache hits that required a response of less than
+or equal to 10k from all watched caches.
+
+@ web.allservers.requests.cached.size.le30k replies of <= 30k sent by all caches
+The number of HTTP GET cache hits that required a response of less than
+or equal to 30k from all watched caches.
+
+@ web.allservers.requests.cached.size.le100k replies of <= 100k sent by all caches
+The number of HTTP GET cache hits that required a response of less than
+or equal to 100k from all watched caches.
+
+@ web.allservers.requests.cached.size.le300k replies of <= 300k sent by all caches
+The number of HTTP GET cache hits that required a response of less than
+or equal to 300k from all watched caches.
+
+@ web.allservers.requests.cached.size.le1m replies of <= 1M sent by all caches
+The number of HTTP GET cache hits that required a response of less than
+or equal to 1M from all watched caches.
+
+@ web.allservers.requests.cached.size.le3m replies of <= 3M sent by all caches
+The number of HTTP GET cache hits that required a response of less than
+or equal to 3M from all watched caches.
+
+@ web.allservers.requests.cached.size.gt3m replies of > 3M sent by all caches
+The number of HTTP GET cache hits that required a response of greater than
+3M from all watched caches.
+
+@ web.allservers.requests.cached.size.unknown replies of unknown size by all caches
+The number of HTTP GET cache hits that required a response of unknown
+size from all watched caches.
+
+@ web.allservers.requests.uncached.total requests satisfied by remote server for all cacheing servers
+The total number of HTTP GET/IMS requests that resulted in a real data
+transfer from the remote server. These are either cache misses, or the
+remote file had been modified since the cache entry was made.
+
+@ web.allservers.requests.uncached.size.zero replies of 0 bytes sent by all caches
+The number of HTTP GET remote fetches that required a response of 0
+bytes from all watched caches.
+
+@ web.allservers.requests.uncached.size.le3k replies of <= 3k sent by all caches
+The number of HTTP GET remote fetches that required a response of less
+than or equal to 3k through all watched caches.
+
+@ web.allservers.requests.uncached.size.le10k replies of <= 10k sent by all caches
+The number of HTTP GET remote fetches that required a response of less
+than or equal to 10k through all watched caches.
+
+@ web.allservers.requests.uncached.size.le30k replies of <= 30k sent by all caches
+The number of HTTP GET remote fetches that required a response of less
+than or equal to 30k through all watched caches.
+
+@ web.allservers.requests.uncached.size.le100k replies of <= 100k sent by all caches
+The number of HTTP GET remote fetches that required a response of less
+than or equal to 100k through all watched caches.
+
+@ web.allservers.requests.uncached.size.le300k replies of <= 300k sent by all caches
+The number of HTTP GET remote fetches that required a response of less
+than or equal to 300k through all watched caches.
+
+@ web.allservers.requests.uncached.size.le1m replies of <= 1M sent by all caches
+The number of HTTP GET remote fetches that required a response of less
+than or equal to 1M through all watched caches.
+
+@ web.allservers.requests.uncached.size.le3m replies of <= 3M sent by all caches
+The number of HTTP GET remote fetches that required a response of less
+than or equal to 3M through all watched caches.
+
+@ web.allservers.requests.uncached.size.gt3m replies of > 3M sent by all caches
+The number of HTTP GET remote fetches that required a response of greater
+than 3M through all watched caches.
+
+@ web.allservers.requests.uncached.size.unknown replies of unknown size by all caches
+The number of HTTP GET requests that required a response of unknown size
+through all watched caches.
+
+@ web.allservers.bytes.cached.total bytes sent by caches as a result of cache hits for all cacheing servers
+The total number of bytes sent to client due to HTTP GET/IMS requests
+that resulted in "Not Modified"responses from the remote site or were
+deemed cache hits via other mechanisms such as recency.
+
+@ web.allservers.bytes.cached.size.zero total bytes sent in 0k replies
+The total number of bytes sent to client by cache hit replies of 0k
+by all watched caches. This metric is always zero and is provided for
+consistency only.
+
+@ web.allservers.bytes.cached.size.le3k total bytes sent in <= 3k replies
+The total number of bytes sent to client by cache hit replies of less
+than or equal to 3k in size by all watched caches.
+
+@ web.allservers.bytes.cached.size.le10k total bytes sent in <= 10k replies
+The total number of bytes sent to client by cache hit replies of less
+than or equal to 10k in size by all watched caches.
+
+@ web.allservers.bytes.cached.size.le30k total bytes sent in <= 30k replies
+The total number of bytes sent to client by cache hit replies of less
+than or equal to 30k in size by all watched caches.
+
+@ web.allservers.bytes.cached.size.le100k total bytes sent in <= 100k replies
+The total number of bytes sent to client by cache hit replies of less
+than or equal to 100k in size by all watched caches.
+
+@ web.allservers.bytes.cached.size.le300k total bytes sent in <= 300k replies
+The total number of bytes sent to client by cache hit replies of less
+than or equal to 300k in size by all watched caches.
+
+@ web.allservers.bytes.cached.size.le1m total bytes sent in <= 1M replies
+The total number of bytes sent to client by cache hit replies of less
+than or equal to 1M in size by all watched caches.
+
+@ web.allservers.bytes.cached.size.le3m total bytes sent in <= 3M replies
+The total number of bytes sent to client by cache hit replies of less
+than or equal to 3M in size by all watched caches.
+
+@ web.allservers.bytes.cached.size.gt3m total bytes sent > 3M replies
+The total number of bytes sent to client by cache hit replies of greater
+than 3M in size by all watched caches.
+
+@ web.allservers.bytes.uncached.total bytes sent by remote servers as a result of cache misses for all cacheing servers
+The total number of bytes sent to client from the remote server. These
+are either cache misses, or the remote file had been modified since
+the cache entry was made.
+
+@ web.allservers.bytes.uncached.size.zero total bytes sent in 0k replies
+The total number of bytes sent to client from the remote server of 0k
+by all watched caches. This metric is always zero and is provided for
+consistency only.
+
+@ web.allservers.bytes.uncached.size.le3k total bytes sent in <= 3k replies
+The total number of bytes sent to client from the remote server of less
+than or equal to 3k in size by all watched caches.
+
+@ web.allservers.bytes.uncached.size.le10k total bytes sent in <= 10k replies
+The total number of bytes sent to client from the remote server of less
+than or equal to 10k in size by all watched caches.
+
+@ web.allservers.bytes.uncached.size.le30k total bytes sent in <= 30k replies
+The total number of bytes sent to client from the remote server of less
+than or equal to 30k in size by all watched caches.
+
+@ web.allservers.bytes.uncached.size.le100k total bytes sent in <= 100k replies
+The total number of bytes sent to client from the remote server of less
+than or equal to 100k in size by all watched caches.
+
+@ web.allservers.bytes.uncached.size.le300k total bytes sent in <= 300k replies
+The total number of bytes sent to client from the remote server of less
+than or equal to 300k in size by all watched caches.
+
+@ web.allservers.bytes.uncached.size.le1m total bytes sent in <= 1M replies
+The total number of bytes sent to client from the remote server of less
+than or equal to 1M in size by all watched caches.
+
+@ web.allservers.bytes.uncached.size.le3m total bytes sent in <= 3M replies
+The total number of bytes sent to client from the remote server of less
+than or equal to 3M in size by all watched caches.
+
+@ web.allservers.bytes.uncached.size.gt3m total bytes sent > 3M replies
+The total number of bytes sent to client from the remote server of
+greater than 3M in size by all watched caches.
+
+@ web.perserver.watched flag set to 1 if monitoring this server
+A flag which is set to 1 if this server is being monitored.
+This metric may be altered using pmStore(1).
+
+@ web.perserver.numlogs number of readable log files for this server
+The number of log files that are readable for the server.
+
+@ web.perserver.errors number of logged errors by this server
+The number of errors (and other administrative messages) that have been
+logged in the error log by this server.
+
+@ web.perserver.requests.total requests processed by this server
+The number of HTTP requests processed by this server.
+
+@ web.perserver.bytes.total bytes sent by this server
+The number of bytes this server has sent.
+
+@ web.perserver.requests.get GET requests handled by server
+The number of HTTP GET requests that were processed by this server.
+
+@ web.perserver.bytes.get bytes sent in reply to GET requests
+The number of bytes that have been sent by this server in reply to HTTP
+GET requests.
+
+@ web.perserver.requests.head HEAD requests handled by server
+The number of HTTP HEAD requests that were processed by this server.
+
+@ web.perserver.bytes.head bytes sent in reply to HEAD requests
+The number of bytes that have been sent by this server in reply to HTTP
+HEAD requests.
+
+@ web.perserver.requests.post POST requests handled by server
+The number of HTTP POST requests that were processed by this server.
+
+@ web.perserver.bytes.post bytes sent in reply to POST requests
+The number of bytes that have been sent by this server in reply to HTTP
+POST requests.
+
+@ web.perserver.requests.other other requests handled by server
+The number of HTTP requests, other than GET, HEAD and POST, that were
+processed by this server.
+
+@ web.perserver.bytes.other bytes sent in reply to other requests
+The number of bytes that have been sent by this server in reply to HTTP
+requests other than GET, HEAD or POST.
+
+@ web.perserver.requests.size.zero requests requiring 0 bytes in reply
+The number of HTTP requests that required a response of 0 bytes from this
+server.
+
+@ web.perserver.bytes.size.zero total bytes sent in 0k replies.
+The total number of bytes sent in replies of 0k by this server. This metric
+is always 0 and is provided for consistency only.
+
+@ web.perserver.requests.size.le3k requests requiring <= 3k replies
+The number of HTTP requests that required a response of less than or equal
+to 3k from this server.
+
+@ web.perserver.bytes.size.le3k total bytes sent in <= 3k replies
+The total number of bytes sent in replies of less than or equal to 3k in
+size.
+
+@ web.perserver.requests.size.le10k requests requiring <= 10k replies
+The number of HTTP requests that required a response of less than or equal
+to 10k from this server.
+
+@ web.perserver.bytes.size.le10k total bytes sent in <= 10k replies
+The total number of bytes sent in replies of less than or equal to 10k in
+size.
+
+@ web.perserver.requests.size.le30k requests requiring <= 30k replies
+The number of HTTP requests that required a response of less than or equal
+to 30k from this server.
+
+@ web.perserver.bytes.size.le30k total bytes sent in <= 30k replies
+The total number of bytes sent in replies of less than or equal to 30k in
+size.
+
+@ web.perserver.requests.size.le100k requests requiring <= 100k replies
+The number of HTTP requests that required a response of less than or equal
+to 100k from this server.
+
+@ web.perserver.bytes.size.le100k total bytes sent in <= 100k replies
+The total number of bytes sent in replies of less than or equal to 100k in
+size.
+
+@ web.perserver.requests.size.le300k requests requiring <= 300k replies
+The number of HTTP requests that required a response of less than or equal
+to 300k from this server.
+
+@ web.perserver.bytes.size.le300k total bytes sent in <= 300k replies
+The total number of bytes sent in replies of less than or equal to 300k in
+size.
+
+@ web.perserver.requests.size.le1m requests requiring <= 1M replies
+The number of HTTP requests that required a response of less than or equal
+to 1M from this server.
+
+@ web.perserver.bytes.size.le1m total bytes sent in <= 1M replies
+The total number of bytes sent in replies of less than or equal to 1M in
+size.
+
+@ web.perserver.requests.size.le3m requests requiring <= 3M replies
+The number of HTTP requests that required a response of less than or equal
+to 3M from this server.
+
+@ web.perserver.bytes.size.le3m total bytes sent in <= 3M replies
+The total number of bytes sent in replies of less than or equal to 3M in
+size.
+
+@ web.perserver.requests.size.gt3m requests requiring > 3M replies
+The number of HTTP requests that required a response of greater than
+3M from this server.
+
+@ web.perserver.bytes.size.gt3m total bytes sent > 3M replies
+The total number of bytes sent in replies of greater than 3M in size.
+
+@ web.perserver.requests.size.unknown requests of unknown size
+The number of HTTP requests that required a response of unknown size from
+this server.
+
+@ web.perserver.logidletime seconds since log last modified
+The number of seconds since the access log for this server was modified.
+
+@ web.perserver.requests.client.total requests satisfied by client caches for this cache
+The total number of HTTP GET/IMS requests that resulted in "Not Modified"
+responses from cache (and remote if checked). These are client cache hits.
+
+@ web.perserver.requests.cached.total requests satisfied by server caches for this cache
+The total number of HTTP GET/IMS requests that resulted in "Not Modified"
+responses from the remote site or were deemed cache hits via other
+mechanisms such as recency. These are server cache hits and result in
+data transferred from cache to client.
+
+@ web.perserver.requests.cached.size.zero replies of 0 bytes sent by this cache
+The number of HTTP GET cache hits that required a response of 0 bytes from
+this cache.
+
+@ web.perserver.requests.cached.size.le3k replies of <= 3k sent by this cache
+The number of HTTP GET cache hits that required a response of less than
+or equal to 3k from this cache.
+
+@ web.perserver.requests.cached.size.le10k replies of <= 10k sent by this cache
+The number of HTTP GET cache hits that required a response of less than
+or equal to 10k from this cache.
+
+@ web.perserver.requests.cached.size.le30k replies of <= 30k sent by this cache
+The number of HTTP GET cache hits that required a response of less than
+or equal to 30k from this cache.
+
+@ web.perserver.requests.cached.size.le100k replies of <= 100k sent by this cache
+The number of HTTP GET cache hits that required a response of less than
+or equal to 100k from this cache.
+
+@ web.perserver.requests.cached.size.le300k replies of <= 300k sent by this cache
+The number of HTTP GET cache hits that required a response of less than
+or equal to 300k from this cache.
+
+@ web.perserver.requests.cached.size.le1m replies of <= 1M sent by this cache
+The number of HTTP GET cache hits that required a response of less than
+or equal to 1M from this cache.
+
+@ web.perserver.requests.cached.size.le3m replies of <= 3M sent by this cache
+The number of HTTP GET cache hits that required a response of less than
+or equal to 3M from this cache.
+
+@ web.perserver.requests.cached.size.gt3m replies of > 3M sent by this cache
+The number of HTTP GET cache hits that required a response of greater than
+3M from this cache.
+
+@ web.perserver.requests.cached.size.unknown replies of unknown size by this cache
+The number of HTTP GET cache hits that required a response of unknown
+size from this cache.
+
+@ web.perserver.requests.uncached.total requests satisfied by remote server for this cache
+The total number of HTTP GET/IMS requests that resulted in a real data
+transfer from the remote server. These are either cache misses, or the
+remote file had been modified since the cache entry was made.
+
+@ web.perserver.requests.uncached.size.zero replies of 0 bytes sent by this cache
+The number of HTTP GET remote fetches that required a response of 0
+bytes from this cache.
+
+@ web.perserver.requests.uncached.size.le3k replies of <= 3k sent by this cache
+The number of HTTP GET remote fetches that required a response of less
+than or equal to 3k through this cache.
+
+@ web.perserver.requests.uncached.size.le10k replies of <= 10k sent by this cache
+The number of HTTP GET remote fetches that required a response of less
+than or equal to 10k through this cache.
+
+@ web.perserver.requests.uncached.size.le30k replies of <= 30k sent by this cache
+The number of HTTP GET remote fetches that required a response of less
+than or equal to 30k through this cache.
+
+@ web.perserver.requests.uncached.size.le100k replies of <= 100k sent by this cache
+The number of HTTP GET remote fetches that required a response of less
+than or equal to 100k through this cache.
+
+@ web.perserver.requests.uncached.size.le300k replies of <= 300k sent by this cache
+The number of HTTP GET remote fetches that required a response of less
+than or equal to 300k through this cache.
+
+@ web.perserver.requests.uncached.size.le1m replies of <= 1M sent by this cache
+The number of HTTP GET remote fetches that required a response of less
+than or equal to 1M through this cache.
+
+@ web.perserver.requests.uncached.size.le3m replies of <= 3M sent by this cache
+The number of HTTP GET remote fetches that required a response of less
+than or equal to 3M through this cache.
+
+@ web.perserver.requests.uncached.size.gt3m replies of > 3M sent by this cache
+The number of HTTP GET remote fetches that required a response of greater
+than 3M through this cache.
+
+@ web.perserver.requests.uncached.size.unknown replies of unknown size by this cache
+The number of HTTP GET requests that required a response of unknown size
+through this cache.
+
+@ web.perserver.bytes.cached.total bytes sent by caches as a result of cache hits for this cache
+The total number of bytes sent to client due to HTTP GET/IMS requests
+that resulted in "Not Modified"responses from the remote site or were
+deemed cache hits via other mechanisms such as recency.
+
+@ web.perserver.bytes.cached.size.zero total bytes sent in 0k replies
+The total number of bytes sent to client by cache hit replies of 0k by
+this cache. This metric is always zero and is provided for consistency
+only.
+
+@ web.perserver.bytes.cached.size.le3k total bytes sent in <= 3k replies
+The total number of bytes sent to client by cache hit replies of less
+than or equal to 3k in size by this cache.
+
+@ web.perserver.bytes.cached.size.le10k total bytes sent in <= 10k replies
+The total number of bytes sent to client by cache hit replies of less
+than or equal to 10k in size by this cache.
+
+@ web.perserver.bytes.cached.size.le30k total bytes sent in <= 30k replies
+The total number of bytes sent to client by cache hit replies of less
+than or equal to 30k in size by this cache.
+
+@ web.perserver.bytes.cached.size.le100k total bytes sent in <= 100k replies
+The total number of bytes sent to client by cache hit replies of less
+than or equal to 100k in size by this cache.
+
+@ web.perserver.bytes.cached.size.le300k total bytes sent in <= 300k replies
+The total number of bytes sent to client by cache hit replies of less
+than or equal to 300k in size by this cache.
+
+@ web.perserver.bytes.cached.size.le1m total bytes sent in <= 1M replies
+The total number of bytes sent to client by cache hit replies of less
+than or equal to 1M in size by this cache.
+
+@ web.perserver.bytes.cached.size.le3m total bytes sent in <= 3M replies
+The total number of bytes sent to client by cache hit replies of less
+than or equal to 3M in size by this cache.
+
+@ web.perserver.bytes.cached.size.gt3m total bytes sent > 3M replies
+The total number of bytes sent to client by cache hit replies of greater
+than 3M in size by this cache.
+
+@ web.perserver.bytes.uncached.total bytes sent by remote servers as a result of cache misses for this cache
+The total number of bytes sent to client from the remote server. These
+are either cache misses, or the remote file had been modified since
+the cache entry was made.
+
+@ web.perserver.bytes.uncached.size.zero total bytes sent in 0k replies
+The total number of bytes sent to client from the remote server of 0k by
+this cache. This metric is always zero and is provided for consistency
+only.
+
+@ web.perserver.bytes.uncached.size.le3k total bytes sent in <= 3k replies
+The total number of bytes sent to client from the remote server of less
+than or equal to 3k in size by this cache.
+
+@ web.perserver.bytes.uncached.size.le10k total bytes sent in <= 10k replies
+The total number of bytes sent to client from the remote server of less
+than or equal to 10k in size by this cache.
+
+@ web.perserver.bytes.uncached.size.le30k total bytes sent in <= 30k replies
+The total number of bytes sent to client from the remote server of less
+than or equal to 30k in size by this cache.
+
+@ web.perserver.bytes.uncached.size.le100k total bytes sent in <= 100k replies
+The total number of bytes sent to client from the remote server of less
+than or equal to 100k in size by this cache.
+
+@ web.perserver.bytes.uncached.size.le300k total bytes sent in <= 300k replies
+The total number of bytes sent to client from the remote server of less
+than or equal to 300k in size by this cache.
+
+@ web.perserver.bytes.uncached.size.le1m total bytes sent in <= 1M replies
+The total number of bytes sent to client from the remote server of less
+than or equal to 1M in size by this cache.
+
+@ web.perserver.bytes.uncached.size.le3m total bytes sent in <= 3M replies
+The total number of bytes sent to client from the remote server of less
+than or equal to 3M in size by this cache.
+
+@ web.perserver.bytes.uncached.size.gt3m total bytes sent > 3M replies
+The total number of bytes sent to client from the remote server of
+greater than 3M in size by this cache.
+
diff --git a/src/pmdas/weblog/pmda.c b/src/pmdas/weblog/pmda.c
new file mode 100644
index 0000000..6c1967f
--- /dev/null
+++ b/src/pmdas/weblog/pmda.c
@@ -0,0 +1,1205 @@
+/*
+ * Web PMDA, based on generic driver for a daemon-based PMDA
+ *
+ * Copyright (c) 2012 Red Hat.
+ * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "weblog.h"
+#include "domain.h"
+#if defined(HAVE_REGEX_H)
+#include <regex.h>
+#endif
+#if defined(HAVE_SYS_WAIT_H)
+#include <sys/wait.h>
+#endif
+#if defined(HAVE_SCHED_H)
+#include <sched.h>
+#endif
+
+#ifdef IS_SOLARIS
+#define CLONE_VM 0x00000100
+#elif !defined(CLONE_VM)
+#define CLONE_VM 0x0
+#endif
+
+#ifndef HAVE_SPROC
+int sproc (void (*entry) (void *), int flags, void *arg);
+#endif
+
+/* path to the configuration file */
+static char *configFileName = (char*)0;
+
+/* line number of configuration file */
+static int line = 0;
+
+/* number of errors in configuration file */
+static int err = 0;
+
+/* configured for num of servers */
+__uint32_t wl_numServers = 0;
+
+/* number of active servers */
+__uint32_t wl_numActive = 0;
+
+/* check logs every 15 seconds by default */
+__uint32_t wl_refreshDelay = 15;
+
+/* re-open logs if unchanged in this number of seconds */
+__uint32_t wl_chkDelay = 20;
+
+/* max servers per sproc */
+__uint32_t wl_sprocThresh = 80;
+
+/* number of sprocs spawned */
+__uint32_t wl_numSprocs = 0;
+
+/* number of regex parsed */
+__uint32_t wl_numRegex = 0;
+
+/* list of web servers */
+WebServer *wl_servers = (WebServer*)0;
+
+/* list of regular expressions */
+WebRegex *wl_regexTable = (WebRegex*)0;
+
+/* instance table of web servers */
+pmdaInstid *wl_serverInst = (pmdaInstid*)0;
+
+/* list of sprocs spawned from the main process */
+WebSproc *wl_sproc;
+
+/* default name for log file */
+char *wl_logFile = "weblog.log";
+
+/* default path to help file */
+char wl_helpFile[MAXPATHLEN];
+
+/* default user name for PMDA */
+char *wl_username;
+
+/*
+ * Usage Information
+ */
+
+void
+usage(void)
+{
+ fprintf(stderr,
+ "Usage: %s [options] configfile\n\
+\n\
+Options\n\
+ -C check configuration and exit\n\
+ -d domain PMDA domain number\n\
+ -h helpfile get help text from helpfile rather than default path\n\
+ -i port expect PMCD to connect on given inet port (number or name)\n\
+ -l logfile redirect diagnostics and trace output (default weblog.log)\n\
+ -n idlesec number of seconds of weblog inactivity before checking for\n\
+ log rotation\n\
+ -p expect PMCD to supply stdin/stdout (pipe)\n\
+ -S num number of web servers per sproc\n\
+ -t delay maximum number of seconds between reading weblog files\n\
+ -u socket expect PMCD to connect on given unix domain socket\n\
+ -U username user account to run under (default \"pcp\")\n\
+ -6 port expect PMCD to connect on given ipv6 port (number or name)\n\
+\n\
+If none of the -i, -p or -u options are given, the configuration file is\n\
+checked and then %s terminates.\n", pmProgname, pmProgname);
+ exit(1);
+}
+
+void
+logmessage(int priority, const char *format, ...)
+{
+ va_list arglist;
+ char buffer[2048];
+ char *level;
+ char *p;
+ time_t now;
+
+ buffer[0] = '\0';
+ time(&now);
+
+ switch (priority) {
+ case LOG_EMERG :
+ level = "Emergency";
+ break;
+ case LOG_ALERT :
+ level = "Alert";
+ break;
+ case LOG_CRIT :
+ level = "Critical";
+ break;
+ case LOG_ERR :
+ level = "Error";
+ break;
+ case LOG_WARNING :
+ level = "Warning";
+ break;
+ case LOG_NOTICE :
+ level = "Notice";
+ break;
+ case LOG_INFO :
+ level = "Info";
+ break;
+ case LOG_DEBUG :
+ level = "Debug";
+ break;
+ default:
+ level = "???";
+ break;
+ }
+
+ va_start (arglist, format);
+ vsnprintf (buffer, sizeof(buffer), format, arglist);
+ for (p = buffer; *p; p++);
+ if (*(--p) == '\n') *p = '\0';
+ fprintf (stderr, "[%.19s] %s(%" FMT_PID ") %s: %s\n", ctime(&now), pmProgname, getpid(), level, buffer) ;
+ va_end (arglist) ;
+}
+
+/*
+ * Errors message during parsing of config file
+ */
+
+static void
+yyerror(char *s)
+{
+ fprintf(stderr, "[%s:%d] Error: %s\n", configFileName, line, s);
+ err++;
+}
+
+/*
+ * Warning message during parsing of config file
+ */
+
+static void
+yywarn(char *s)
+{
+ fprintf(stderr, "[%s:%d] Warning: %s\n", configFileName, line, s);
+}
+
+/*
+ * skip remaining characters on this line
+ */
+
+static void
+skip_to_eol(FILE *f)
+{
+ int c;
+
+ while ((c = fgetc(f)) != EOF) {
+ if (c == '\n')
+ return;
+ }
+ return;
+}
+
+/*
+ * Are we at the end of the line (sucks up spaces and tabs which may preceed
+ * EOL)
+ */
+
+static void
+check_to_eol(FILE *f)
+{
+ int c;
+ int i = 0;
+
+ while ((c = fgetc(f)) != EOF) {
+ if (c == '\n')
+ break;
+ if (c == ' ' || c == '\t')
+ continue;
+ i++;
+ }
+ if (i)
+ yywarn("additional words in line, ignored");
+
+ return;
+}
+
+/*
+ * Get a word. A word if any text until a whitespace
+ */
+
+static int
+getword(FILE *f, char *buf, int len)
+{
+ int c;
+ char *bend = &buf[len-1];
+
+ while ((c = fgetc(f)) != EOF) {
+ if (c == ' ' || c == '\t')
+ continue;
+ ungetc(c, f);
+ break;
+ }
+
+ while ((c = fgetc(f)) != EOF) {
+ if (c == ' ' || c == '\t')
+ break;
+ if (c == '\n') {
+ ungetc(c, f);
+ break;
+ }
+ if (buf < bend) {
+ *buf++ = c;
+ continue;
+ }
+ else {
+ yyerror("word too long, remainder of line ignored");
+ return -1;
+ }
+ }
+ *buf = '\0';
+
+ return c == EOF ? 0 : 1;
+}
+
+/*
+ * Get the next line from buffer
+ */
+
+static int
+get_to_eol(FILE *f, char *buf, int len)
+{
+ int c;
+ char *bend = &buf[len-1];
+
+ while ((c = fgetc(f)) != EOF) {
+ if (c == ' ' || c == '\t')
+ continue;
+ ungetc(c, f);
+ break;
+ }
+
+ while ((c = fgetc(f)) != EOF) {
+ if (c == '\n')
+ break;
+ if (buf < bend) {
+ *buf++ = c;
+ continue;
+ }
+ else {
+ yyerror("list of words too long, remainder of line ignored");
+ return -1;
+ }
+ }
+ *buf = '\0';
+ return c == EOF ? 0 : 1;
+}
+
+/*
+ * Replacement for pmdaMainLoop
+ * Has a select loop on pipe from PMCD, reads in PDUs and acts on them
+ * appropriately.
+ */
+
+static void
+receivePDUs(pmdaInterface *dispatch)
+{
+ int nfds = 0;
+ time_t interval = 0;
+ int sts = 0;
+ struct timeval timeout;
+ fd_set rfds;
+
+
+ FD_ZERO(&rfds);
+ nfds = fileno(stdin)+1;
+
+ for (;;) {
+
+ FD_SET(fileno(stdin), &rfds);
+ __pmtimevalNow(&timeout);
+ timeout.tv_usec = 0;
+ interval = (time_t)wl_refreshDelay - (timeout.tv_sec % (time_t)wl_refreshDelay);
+ timeout.tv_sec = interval;
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL1)
+ logmessage(LOG_DEBUG, "Select set for %d seconds\n",
+ interval);
+#endif
+
+ sts = select(nfds, &rfds, (fd_set*)0, (fd_set*)0, &timeout);
+ if (sts < 0) {
+ logmessage(LOG_ERR, "Error on fetch select: %s", netstrerror());
+ exit(1);
+ }
+
+ if (sts == 0) {
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL1)
+ logmessage(LOG_DEBUG, "Select timed out\n");
+#endif
+
+ refreshAll();
+ continue;
+ }
+
+ if (__pmdaMainPDU(dispatch) < 0){
+ exit(1);
+ }
+
+ if (interval == 0) {
+ refreshAll();
+ }
+
+ }
+}
+
+/*
+ * Catch an SPROC dying, report what we know, and exit
+ * -- when main exits, other sprocs will get SIGHUP and exit quietly
+ */
+static void
+onchld(int dummy)
+{
+ int done;
+ int waitStatus;
+ int sprocNum;
+
+ while ((done = waitpid(-1, &waitStatus, WNOHANG)) > 0) {
+ for (sprocNum = 1;
+ wl_sproc[sprocNum].pid != done && sprocNum <= wl_numSprocs;
+ sprocNum++);
+
+ if (sprocNum > wl_numSprocs)
+ {
+ logmessage(LOG_INFO,
+ "Unexpected child process (pid=%d) died!\n",
+ done);
+ continue;
+ }
+
+ if (WIFEXITED(waitStatus)) {
+
+ if (WEXITSTATUS(waitStatus) == 0)
+ logmessage(LOG_INFO,
+ "Sproc %d (pid=%d) exited normally\n",
+ sprocNum, done);
+ else
+ logmessage(LOG_INFO,
+ "Sproc %d (pid=%d) exited with status = %d\n",
+ sprocNum, done, WEXITSTATUS(waitStatus));
+ }
+ else if (WIFSIGNALED(waitStatus)) {
+
+#ifdef WCOREDUMP
+ if (WCOREDUMP(waitStatus))
+ logmessage(LOG_INFO,
+ "Sproc %d (pid=%d) received signal = %d and dumped core\n",
+ sprocNum, done, WTERMSIG(waitStatus));
+#endif
+ logmessage(LOG_INFO,
+ "Sproc %d (pid=%d) received signal = %d\n",
+ sprocNum, done, WTERMSIG(waitStatus));
+ }
+ else {
+ logmessage(LOG_INFO,
+ "Sproc %d (pid=%d) died, reason unknown\n",
+ sprocNum, done);
+ }
+
+ logmessage(LOG_INFO,
+ "Sproc %d managed servers %d to %d\n",
+ sprocNum,
+ wl_sproc[sprocNum].firstServer,
+ wl_sproc[sprocNum].lastServer);
+ }
+
+ logmessage(LOG_INFO, "Main process exiting\n");
+ exit(0);
+}
+
+/*
+ * Parse command line args and the configuration file. Also sets up and fires
+ * off the required sprocs
+ */
+
+int
+main(int argc, char **argv)
+{
+ WebServer *server = (WebServer *)0;
+ WebSproc *proc = (WebSproc *)0;
+
+ char *endnum = (char*)0;
+ char buf1[FILENAME_MAX];
+ char buf2[FILENAME_MAX];
+ char emess[120];
+ char *pstart, *pend;
+ char argsDone, argFound;
+ char *err_msg;
+
+ int i = 0;
+ int argCount = 0;
+ int checkOnly = 0;
+ int sts = 0;
+ int sep = __pmPathSeparator();
+ int n = 0;
+ int serverTableSize = 0;
+ int regexTableSize = 0;
+
+ FILE *configFile = (FILE*)0;
+ FILE *tmpFp = (FILE*)0;
+
+ pmdaInterface desc;
+ struct timeval delta;
+
+ struct {
+ int *argPos;
+ char *argString;
+ } regexargs[2];
+
+#ifdef PCP_DEBUG
+ struct timeval start;
+ struct timeval end;
+ double startTime;
+#endif
+
+ __pmSetProgname(argv[0]);
+ __pmGetUsername(&wl_username);
+
+#ifdef PCP_DEBUG
+ __pmtimevalNow(&start);
+#endif
+
+ wl_isDSO = 0;
+
+ snprintf(wl_helpFile, sizeof(wl_helpFile), "%s%c" "weblog" "%c" "help",
+ pmGetConfig("PCP_PMDAS_DIR"), sep, sep);
+ pmdaDaemon(&desc, PMDA_INTERFACE_2, pmProgname, WEBSERVER,
+ wl_logFile, wl_helpFile);
+
+ while ((n = pmdaGetOpt(argc, argv, "CD:d:h:i:l:n:pS:t:u:U:6:?",
+ &desc, &err)) != EOF) {
+ switch (n) {
+
+ case 'C':
+ checkOnly = 1;
+ break;
+
+ case 'S':
+ wl_sprocThresh = (int)strtol(optarg, &endnum, 10);
+ if (*endnum != '\0') {
+ fprintf(stderr, "%s: -S requires numeric argument\n",
+ pmProgname);
+ err++;
+ }
+ break;
+
+ case 'n':
+ if (pmParseInterval(optarg, &delta, &err_msg) < 0) {
+ (void)fprintf(stderr,
+ "%s: -n requires a time interval: %s\n",
+ err_msg, pmProgname);
+ free(err_msg);
+ err++;
+ }
+ else {
+ wl_chkDelay = delta.tv_sec;
+ }
+ break;
+
+ case 't':
+ if (pmParseInterval(optarg, &delta, &err_msg) < 0) {
+ (void)fprintf(stderr,
+ "%s: -t requires a time interval: %s\n",
+ err_msg, pmProgname);
+ free(err_msg);
+ err++;
+ }
+ else {
+ wl_refreshDelay = delta.tv_sec;
+ }
+ break;
+
+ case 'U':
+ wl_username = optarg;
+ break;
+
+ default:
+ fprintf(stderr, "%s: Unknown option \"-%c\"", pmProgname, (char)n);
+ err++;
+ break;
+ }
+ }
+
+ if (err || optind != argc-1) {
+ usage();
+ }
+
+ line = 0;
+ configFileName = argv[optind];
+ configFile = fopen(configFileName, "r");
+
+ if (configFile == (FILE*)0) {
+ fprintf(stderr, "Unable to open config file %s\n", configFileName);
+ usage();
+ }
+
+ if (checkOnly == 0) {
+ /*
+ * if doing more than just parsing, force errors from here
+ * on into the logfile
+ */
+ pmdaOpenLog(&desc);
+ __pmSetProcessIdentity(wl_username);
+ }
+
+ /*
+ * Parse the configuration file
+ */
+
+ /* These settings should be reflected below */
+ regexargs[0].argString = strdup("method");
+ regexargs[1].argString = strdup("size");
+
+ while(!feof(configFile)) {
+
+ sts = getword(configFile, buf1, sizeof(buf1));
+
+ if (sts == 0) {
+ /* End of File */
+ break;
+ }
+
+ line++;
+
+ if (sts < 0) {
+ /* error, reported in getword() */
+ skip_to_eol(configFile);
+ continue;
+ }
+
+ if (buf1[0] == '\0' || buf1[0] == '#') {
+ /* comment, or nothing in the line, next line please */
+ skip_to_eol(configFile);
+ continue;
+ }
+
+ if (strcasecmp(buf1, "regex_posix") == 0) {
+ /*
+ * Parse a regex specification
+ */
+
+ if (wl_numRegex == regexTableSize) {
+ regexTableSize += 2;
+ wl_regexTable = (WebRegex*)realloc(wl_regexTable,
+ regexTableSize * sizeof(WebRegex));
+ if (wl_regexTable == (WebRegex*)0) {
+ __pmNoMem("main.wl_regexInst",
+ (wl_numRegex + 1) * sizeof(WebRegex),
+ PM_FATAL_ERR);
+ }
+ }
+
+ sts = getword(configFile, buf1, sizeof(buf1));
+
+ if (sts <= 0 || buf1[0] == '\0') {
+ if (sts >= 0)
+ yyerror("unable to extract regex name");
+ skip_to_eol(configFile);
+ continue;
+ }
+
+ wl_regexTable[wl_numRegex].name = strdup(buf1);
+
+ if (wl_numRegex) {
+ for (n = 0; n < wl_numRegex; n++) {
+ if (strcmp(wl_regexTable[n].name,
+ wl_regexTable[wl_numRegex].name) == 0) {
+
+ snprintf(emess, sizeof(emess), "duplicate regex name (%s)",
+ wl_regexTable[wl_numRegex].name);
+ yyerror(emess);
+ break;
+ }
+ }
+ if (n < wl_numRegex) {
+ skip_to_eol(configFile);
+ continue;
+ }
+ }
+
+ sts = getword(configFile, buf1, sizeof(buf1));
+
+ if (sts <= 0 || buf1[0] == '\0') {
+ if (sts >= 0)
+ yyerror("unable to extract regex match parameters");
+ skip_to_eol(configFile);
+ continue;
+ }
+
+ regexargs[0].argPos = &(wl_regexTable[wl_numRegex].methodPos);
+ regexargs[1].argPos = &(wl_regexTable[wl_numRegex].sizePos);
+ wl_regexTable[wl_numRegex].methodPos = 0;
+ wl_regexTable[wl_numRegex].sizePos = 0;
+ wl_regexTable[wl_numRegex].sizePos = 0;
+ wl_regexTable[wl_numRegex].s_statusPos = 0;
+
+ pstart = buf1;
+ argCount = 0;
+ do {
+ argFound = 0;
+ argsDone = 1;
+ argCount++;
+ for(pend = pstart; *pend; pend++) {
+ if(*pend == ',') {
+ *pend = '\0';
+ argsDone = 0;
+ break;
+ }
+ }
+ for(i = 0; i < sizeof(regexargs) / sizeof(regexargs[0]); i++) {
+ if(strcmp(pstart, regexargs[i].argString) == 0) {
+ *regexargs[i].argPos = argCount;
+ argFound = 1;
+ break;
+ }
+ }
+ if(!argFound) {
+ /* not the old method,size style */
+ switch(pstart[0]) {
+ case '1':
+ wl_regexTable[wl_numRegex].methodPos = argCount;
+ argFound = 1;
+ break;
+ case '2':
+ wl_regexTable[wl_numRegex].sizePos = argCount;
+ argFound = 1;
+ break;
+ case '3':
+ wl_regexTable[wl_numRegex].c_statusPos = argCount;
+ argFound = 1;
+ break;
+ case '4':
+ wl_regexTable[wl_numRegex].s_statusPos = argCount;
+ argFound = 1;
+ break;
+ case '-':
+ wl_regexTable[wl_numRegex].methodPos = argCount++;
+ wl_regexTable[wl_numRegex].sizePos = argCount;
+ argFound = 1;
+ argsDone = 1;
+ break;
+ default:
+ break;
+ }
+ }
+ pstart = pend + 1;
+ } while(argsDone == 0 && argFound != 0);
+
+ if(argFound == 0) {
+ yyerror("invalid keyword in regex match parameters");
+ skip_to_eol(configFile);
+ continue;
+ }
+
+ sts = get_to_eol(configFile, buf1, sizeof(buf1));
+
+ if (sts <= 0 || buf1[0] == '\0') {
+ if (sts >= 0)
+ yyerror("unable to extract regex");
+ else
+ skip_to_eol(configFile);
+ continue;
+ }
+
+ wl_regexTable[wl_numRegex].regex = malloc(sizeof(*wl_regexTable[wl_numRegex].regex));
+ if(wl_regexTable[wl_numRegex].regex == NULL) {
+ __pmNoMem("main.wl_regex",
+ sizeof(*wl_regexTable[wl_numRegex].regex),
+ PM_FATAL_ERR);
+ }
+
+ if (regcomp(wl_regexTable[wl_numRegex].regex, buf1, REG_EXTENDED) != 0) {
+ yyerror("unable to compile regex");
+ continue;
+ }
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL0)
+ logmessage(LOG_DEBUG, "%d regex %s: %s\n",
+ wl_numRegex, wl_regexTable[wl_numRegex].name, buf1);
+#endif
+
+ wl_regexTable[wl_numRegex].posix_regexp = 1;
+ wl_numRegex++;
+ }
+#ifdef NON_POSIX_REGEX
+ else if (strcasecmp(buf1, "regex") == 0) {
+ /*
+ * Parse a regex specification
+ */
+
+ if (wl_numRegex == regexTableSize) {
+ regexTableSize += 2;
+ wl_regexTable = (WebRegex*)realloc(wl_regexTable,
+ regexTableSize * sizeof(WebRegex));
+ if (wl_regexTable == (WebRegex*)0) {
+ __pmNoMem("main.wl_regexInst",
+ (wl_numRegex + 1) * sizeof(WebRegex),
+ PM_FATAL_ERR);
+ }
+ }
+
+ sts = getword(configFile, buf1, sizeof(buf1));
+
+ if (sts <= 0 || buf1[0] == '\0') {
+ if (sts >= 0)
+ yyerror("unable to extract regex name");
+ skip_to_eol(configFile);
+ continue;
+ }
+
+ wl_regexTable[wl_numRegex].name = strdup(buf1);
+
+ if (wl_numRegex) {
+ for (n = 0; n < wl_numRegex; n++) {
+ if (strcmp(wl_regexTable[n].name,
+ wl_regexTable[wl_numRegex].name) == 0) {
+
+ snprintf(emess, sizeof(emess), "duplicate regex name (%s)",
+ wl_regexTable[wl_numRegex].name);
+ yyerror(emess);
+ break;
+ }
+ }
+ if (n < wl_numRegex) {
+ skip_to_eol(configFile);
+ continue;
+ }
+ }
+
+ sts = get_to_eol(configFile, buf1, sizeof(buf1));
+
+ if (sts <= 0 || buf1[0] == '\0') {
+ if (sts >= 0)
+ yyerror("unable to extract regex");
+ else
+ skip_to_eol(configFile);
+ continue;
+ }
+
+ if(strstr(buf1, "$2") != NULL && strstr(buf1, "$3") != NULL ) {
+ /*
+ * extended caching server format
+ *
+ * although these aren't used in the non-regex code, they
+ * are a good enough placeholder until server->counts.extendedp
+ * is set below
+ */
+ wl_regexTable[wl_numRegex].c_statusPos = 1;
+ wl_regexTable[wl_numRegex].s_statusPos = 1;
+
+ }
+ wl_regexTable[wl_numRegex].np_regex = regcmp(buf1, (char*)0);
+
+ if (wl_regexTable[wl_numRegex].np_regex == (char*)0) {
+ yyerror("unable to compile regex");
+ continue;
+ }
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL0)
+ logmessage(LOG_DEBUG, "%d NON POSIX regex %s: %s\n",
+ wl_numRegex, wl_regexTable[wl_numRegex].name, buf1);
+#endif
+
+ wl_regexTable[wl_numRegex].posix_regexp = 0;
+ wl_numRegex++;
+ }
+#endif
+ else if (strcasecmp(buf1, "server") == 0) {
+ /*
+ * Parse a server specification
+ */
+
+ if (wl_numServers == serverTableSize) {
+ serverTableSize += 4;
+ wl_serverInst = (pmdaInstid*)realloc(wl_serverInst,
+ serverTableSize * sizeof(pmdaInstid));
+ if (wl_serverInst == (pmdaInstid*)0) {
+ __pmNoMem("main.wl_serverInst",
+ (wl_numServers + 1) * sizeof(pmdaInstid),
+ PM_FATAL_ERR);
+ }
+
+ wl_servers = (WebServer*)realloc(wl_servers,
+ serverTableSize * sizeof(WebServer));
+ if (wl_servers == (WebServer*)0) {
+ __pmNoMem("main.wl_servers",
+ (wl_numServers + 1) * sizeof(WebServer),
+ PM_FATAL_ERR);
+ }
+ }
+
+ /* Get server name */
+
+ sts = getword(configFile, buf1, sizeof(buf1));
+
+ if (sts <= 0 || buf1[0] == '\0') {
+ if (sts >= 0)
+ yyerror("unable to extract server name");
+ skip_to_eol(configFile);
+ continue;
+ }
+
+ if (wl_numServers) {
+ for (n = 0; n < wl_numServers; n++) {
+ if (strcmp(buf1, wl_serverInst[n].i_name) == 0) {
+ snprintf(emess, sizeof(emess), "duplicate server name (%s)", buf1);
+ yyerror(emess);
+ break;
+ }
+ }
+ if (n < wl_numServers) {
+ skip_to_eol(configFile);
+ continue;
+ }
+ }
+
+ wl_serverInst[wl_numServers].i_name = strdup(buf1);
+ wl_serverInst[wl_numServers].i_inst = wl_numServers;
+
+ server = &(wl_servers[wl_numServers]);
+ memset(server, 0, sizeof(*server));
+ server->access.filePtr = -1;
+ server->error.filePtr = -1;
+
+ /* Get server active flag */
+
+ sts = getword(configFile, buf1, sizeof(buf1));
+
+ if (sts <= 0 || buf1[0] == '\0') {
+ if (sts >= 0)
+ yyerror("unable to extract active flag");
+ skip_to_eol(configFile);
+ continue;
+ }
+
+ if (strcasecmp(buf1, "on") == 0) {
+ server->counts.active = 1;
+ }
+ else if (strcasecmp(buf1, "off") == 0) {
+ server->counts.active = 0;
+ }
+ else {
+ yyerror("illegal active flag");
+ skip_to_eol(configFile);
+ continue;
+ }
+
+ /* Get access log regex and file name */
+
+
+ sts = getword(configFile, buf1, sizeof(buf1));
+
+ if (sts <= 0 || buf1[0] == '\0') {
+ if (sts >= 0)
+ yyerror("unable to extract access log regex");
+ skip_to_eol(configFile);
+ continue;
+ }
+
+ sts = getword(configFile, buf2, sizeof(buf2));
+
+ if (sts <= 0 || buf2[0] == '\0') {
+ if (sts >= 0)
+ yyerror("unable to extract access log name");
+ skip_to_eol(configFile);
+ continue;
+ }
+
+ for (n = 0; n < wl_numRegex; n++)
+ if (strcmp(buf1, wl_regexTable[n].name) == 0)
+ break;
+
+ if (n == wl_numRegex) {
+ snprintf(emess, sizeof(emess), "access log regex \"%s\" not defined", buf1);
+ yyerror(emess);
+ skip_to_eol(configFile);
+ continue;
+ } else if(wl_regexTable[n].c_statusPos > 0 &&
+ wl_regexTable[n].s_statusPos > 0) {
+ /* common extended format or one that uses the same codes */
+ server->counts.extendedp = 1;
+ if(strcmp(wl_regexTable[n].name, "SQUID") == 0) {
+ /*
+ * default squid format - uses text codes not numerics
+ * so it *has* to be a special case
+ */
+ server->counts.extendedp = 2;
+ }
+ }
+
+ server->access.format = n;
+ server->access.fileName = strdup(buf2);
+
+ if (server->counts.active) {
+ tmpFp = fopen(server->access.fileName, "r");
+ if (tmpFp == (FILE*)0) {
+ snprintf(emess, sizeof(emess), "cannot open access log \"%s\"", buf2);
+ yywarn(emess);
+ server->access.filePtr = -1;
+ }
+ else
+ fclose(tmpFp);
+ }
+
+ /* Get error log regex and file name */
+
+ sts = getword(configFile, buf1, sizeof(buf1));
+
+ if (sts <= 0 || buf1[0] == '\0') {
+ if (sts >= 0)
+ yyerror("unable to extract error log regex");
+ skip_to_eol(configFile);
+ continue;
+ }
+
+ sts = getword(configFile, buf2, sizeof(buf2));
+
+ if (sts <= 0 || buf2[0] == '\0') {
+ if (sts >= 0)
+ yyerror("unable to extract error log name");
+ skip_to_eol(configFile);
+ continue;
+ }
+
+ for (n = 0; n < wl_numRegex; n++)
+ if (strcmp(buf1, wl_regexTable[n].name) == 0)
+ break;
+
+ if (n == wl_numRegex) {
+ snprintf(emess, sizeof(emess), "error log regex \"%s\" not defined", buf1);
+ yyerror(emess);
+ skip_to_eol(configFile);
+ continue;
+ }
+
+ server->error.format = n;
+ server->error.fileName = strdup(buf2);
+
+ if (server->counts.active) {
+ tmpFp = fopen(server->error.fileName, "r");
+ if (tmpFp == (FILE*)0) {
+ snprintf(emess, sizeof(emess), "cannot open error log \"%s\"", buf2);
+ yywarn(emess);
+ server->error.filePtr = -1;
+ }
+ else
+ fclose(tmpFp);
+ }
+
+ check_to_eol(configFile);
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL0) {
+ logmessage(LOG_DEBUG, "%d Server %s, %d, %d, %s, %d, %s\n",
+ wl_numServers,
+ wl_serverInst[wl_numServers].i_name,
+ server->counts.active,
+ server->access.format,
+ server->access.fileName,
+ server->error.format,
+ server->error.fileName);
+ }
+#endif
+
+ if (server->counts.active)
+ wl_numActive++;
+
+ wl_numServers++;
+ }
+ else {
+ snprintf(emess, sizeof(emess), "illegal keyword \"%s\"", buf1);
+ yyerror(emess);
+ skip_to_eol(configFile);
+ continue;
+ }
+ }
+
+ if (wl_numServers == 0) {
+ yyerror("no servers were specified in the configuration file!");
+ }
+
+ fclose(configFile);
+
+ if (checkOnly || err) {
+ /* errors, or parse only, no PMCD communication option */
+ exit(err);
+ }
+
+ wl_indomTable[0].it_numinst = wl_numServers;
+ wl_indomTable[0].it_set = wl_serverInst;
+
+ web_init(&desc);
+ pmdaConnect(&desc);
+
+ /* catch any sprocs dying */
+
+ signal(SIGCHLD, onchld);
+
+ /* fire off all the sprocs that we need */
+
+ wl_numSprocs = (wl_numServers-1) / wl_sprocThresh;
+ wl_sproc = (WebSproc*)malloc((wl_numSprocs+1) * sizeof(WebSproc));
+ if (wl_sproc == NULL) {
+ logmessage(LOG_ERR,
+ "wl_numServers = %d, wl_sprocThresh = %d",
+ wl_numServers,
+ wl_sprocThresh);
+ __pmNoMem("main.wl_sproc",
+ (wl_numSprocs+1) * sizeof(WebSproc),
+ PM_FATAL_ERR);
+ }
+
+
+ for (n = 0; n <= wl_numSprocs; n++)
+ {
+ proc = &wl_sproc[n];
+ proc->pid = -1;
+ proc->methodStr = (char *)0;
+ proc->sizeStr = (char *)0;
+ proc->c_statusStr = (char *)0;
+ proc->s_statusStr = (char *)0;
+ proc->strLength = 0;
+ }
+
+ if (wl_numSprocs) {
+
+ for (n=1; n<=wl_numSprocs; n++) {
+ proc = &wl_sproc[n];
+
+ sts = pipe1(proc->inFD);
+ if (sts) {
+ logmessage(LOG_ERR,
+ "Cannot allocate fileDes 1 for sproc[%d]",
+ n);
+ exit(1);
+ }
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL2)
+ logmessage(LOG_DEBUG,
+ "Creating in pipe (in=%d, out=%d) for sproc %d\n",
+ proc->inFD[0],
+ proc->inFD[1],
+ n);
+#endif
+
+ sts = pipe1(proc->outFD);
+ if (sts) {
+ logmessage(LOG_ERR,
+ "Cannot allocate fileDes 2 for sproc[%d]",
+ n);
+ exit(1);
+ }
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL2)
+ logmessage(LOG_DEBUG,
+ "Creating out pipe (in=%d, out=%d) for sproc %d\n",
+ proc->outFD[0],
+ proc->outFD[1],
+ n);
+#endif
+
+ proc->firstServer = (n)*wl_sprocThresh;
+ if (n != wl_numSprocs)
+ proc->lastServer = proc->firstServer +
+ wl_sprocThresh - 1;
+ else
+ proc->lastServer = wl_numServers - 1;
+
+ logmessage(LOG_INFO,
+ "Creating sproc [%d] for servers %d to %d\n",
+ n, proc->firstServer, proc->lastServer);
+
+ proc->id = n;
+
+#ifndef HAVE_SPROC
+ proc->pid = sproc(sprocMain, CLONE_VM, (void*)(&proc->id));
+#else
+ proc->pid = sproc(sprocMain, PR_SADDR, (void*)(&proc->id));
+#endif
+
+ if (proc->pid < 0) {
+ logmessage(LOG_ERR, "main: error creating sproc %d: %s\n",
+ n, osstrerror());
+ exit(1);
+ }
+
+#ifdef PCP_DEBUG
+ if(pmDebug & DBG_TRACE_APPL0) {
+ logmessage(LOG_INFO,
+ "main: created sproc %d: pid %" FMT_PID "\n",
+ n,
+ proc->pid);
+ }
+#endif
+
+ /* close off unwanted pipes */
+
+ if(close(proc->inFD[0]) < 0) {
+ logmessage(LOG_WARNING,
+ "main: pipe close(fd=%d) failed: %s\n",
+ proc->inFD[0], osstrerror());
+ }
+ if(close(proc->outFD[1]) < 0) {
+ logmessage(LOG_WARNING,
+ "main: pipe close(fd=%d) failed: %s\n",
+ proc->outFD[1], osstrerror());
+ }
+ }
+ }
+
+ wl_sproc[0].firstServer = 0;
+ wl_sproc[0].lastServer = (wl_numServers <= wl_sprocThresh) ?
+ wl_numServers - 1 : wl_sprocThresh - 1;
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL0)
+ logmessage(LOG_DEBUG,
+ "Main process will monitor servers 0 to %d\n",
+ wl_sproc[0].lastServer);
+#endif
+
+ for (n=0; n <= wl_sproc[0].lastServer; n++) {
+ if (wl_servers[n].counts.active) {
+ openLogFile(&(wl_servers[n].access));
+ openLogFile(&(wl_servers[n].error));
+ }
+ }
+
+#ifdef PCP_DEBUG
+ __pmtimevalNow(&end);
+ startTime = (end.tv_sec - start.tv_sec) +
+ ((end.tv_usec - start.tv_usec) / 1000000.0);
+ if (pmDebug & DBG_TRACE_APPL0)
+ logmessage(LOG_DEBUG, "Agent started in %f seconds", startTime);
+#endif
+
+ receivePDUs(&desc);
+
+ logmessage(LOG_INFO, "Connection to PMCD closed by PMCD\n");
+ logmessage(LOG_INFO, "Last fetch took %d msec\n", wl_catchupTime);
+ logmessage(LOG_INFO, "Exiting...\n");
+
+ return 0;
+}
diff --git a/src/pmdas/weblog/pmns b/src/pmdas/weblog/pmns
new file mode 100644
index 0000000..fa2038d
--- /dev/null
+++ b/src/pmdas/weblog/pmns
@@ -0,0 +1,306 @@
+/*
+ * Web Performance Metric Domain (PMD) Identifiers
+ *
+ * Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Cluster numbers are used by agent to indicate:
+ *
+ * 0 - Does not require any servers to be updated
+ * 1 - Requires all servers to be updated
+ * 2 - Requires only this server to be updated
+ *
+ * Changes to this file must also be carried into the help file and weblog.c
+ * (especially the meta table, web_fetch and web_store).
+ *
+ */
+
+web {
+ config
+ allservers
+ perserver
+}
+
+web.config {
+ numservers WEBSERVER:0:0 /* in the PMDA configuration file */
+ catchup WEBSERVER:0:1 /* maximum catch-up period (secs) */
+ catchuptime WEBSERVER:0:2 /* time spent in catchup (msecs) */
+ check WEBSERVER:0:3 /* inactivity period (secs), before
+ trying to re-open files */
+}
+
+web.allservers {
+ numwatched WEBSERVER:0:4 /* number to be watched */
+ numalive WEBSERVER:0:5 /* number of the watched servers
+ that are apparently alive */
+ requests
+ bytes
+ errors WEBSERVER:1:6
+}
+
+web.allservers.requests {
+ total WEBSERVER:1:7
+ get WEBSERVER:1:8
+ head WEBSERVER:1:9
+ post WEBSERVER:1:10
+ other WEBSERVER:1:11
+ size
+ client
+ cached
+ uncached
+}
+
+web.allservers.bytes {
+ total WEBSERVER:1:12
+ get WEBSERVER:1:13
+ head WEBSERVER:1:14
+ post WEBSERVER:1:15
+ other WEBSERVER:1:16
+ size
+ cached
+ uncached
+}
+
+web.allservers.requests.size {
+ zero WEBSERVER:1:17
+ le3k WEBSERVER:1:18
+ le10k WEBSERVER:1:19
+ le30k WEBSERVER:1:20
+ le100k WEBSERVER:1:21
+ le300k WEBSERVER:1:22
+ le1m WEBSERVER:1:23
+ le3m WEBSERVER:1:24
+ gt3m WEBSERVER:1:25
+ unknown WEBSERVER:1:66
+}
+
+web.allservers.bytes.size {
+ zero WEBSERVER:1:26
+ le3k WEBSERVER:1:27
+ le10k WEBSERVER:1:28
+ le30k WEBSERVER:1:29
+ le100k WEBSERVER:1:30
+ le300k WEBSERVER:1:31
+ le1m WEBSERVER:1:32
+ le3m WEBSERVER:1:33
+ gt3m WEBSERVER:1:34
+}
+
+web.allservers.requests.client {
+ total WEBSERVER:3:1
+}
+
+web.allservers.requests.cached {
+ total WEBSERVER:3:11
+ size
+}
+
+web.allservers.requests.cached.size {
+ zero WEBSERVER:3:12
+ le3k WEBSERVER:3:13
+ le10k WEBSERVER:3:14
+ le30k WEBSERVER:3:15
+ le100k WEBSERVER:3:16
+ le300k WEBSERVER:3:17
+ le1m WEBSERVER:3:18
+ le3m WEBSERVER:3:19
+ gt3m WEBSERVER:3:20
+ unknown WEBSERVER:3:21
+}
+
+web.allservers.requests.uncached {
+ total WEBSERVER:3:31
+ size
+}
+
+web.allservers.requests.uncached.size {
+ zero WEBSERVER:3:32
+ le3k WEBSERVER:3:33
+ le10k WEBSERVER:3:34
+ le30k WEBSERVER:3:35
+ le100k WEBSERVER:3:36
+ le300k WEBSERVER:3:37
+ le1m WEBSERVER:3:38
+ le3m WEBSERVER:3:39
+ gt3m WEBSERVER:3:40
+ unknown WEBSERVER:3:41
+}
+
+web.allservers.bytes.cached {
+ total WEBSERVER:3:51
+ size
+}
+
+web.allservers.bytes.cached.size {
+ zero WEBSERVER:3:52
+ le3k WEBSERVER:3:53
+ le10k WEBSERVER:3:54
+ le30k WEBSERVER:3:55
+ le100k WEBSERVER:3:56
+ le300k WEBSERVER:3:57
+ le1m WEBSERVER:3:58
+ le3m WEBSERVER:3:59
+ gt3m WEBSERVER:3:60
+}
+
+web.allservers.bytes.uncached {
+ total WEBSERVER:3:71
+ size
+}
+
+web.allservers.bytes.uncached.size {
+ zero WEBSERVER:3:72
+ le3k WEBSERVER:3:73
+ le10k WEBSERVER:3:74
+ le30k WEBSERVER:3:75
+ le100k WEBSERVER:3:76
+ le300k WEBSERVER:3:77
+ le1m WEBSERVER:3:78
+ le3m WEBSERVER:3:79
+ gt3m WEBSERVER:3:80
+}
+
+web.perserver {
+ watched WEBSERVER:0:35 /* is this server being watched? */
+ numlogs WEBSERVER:2:36 /* number of logs I can read */
+ requests
+ bytes
+ errors WEBSERVER:2:37
+ logidletime WEBSERVER:2:68
+}
+
+web.perserver.requests {
+ total WEBSERVER:2:38 /* per server */
+ get WEBSERVER:2:39
+ head WEBSERVER:2:40
+ post WEBSERVER:2:41
+ other WEBSERVER:2:42
+ size
+ client
+ cached
+ uncached
+}
+
+web.perserver.bytes {
+ total WEBSERVER:2:43 /* per server */
+ get WEBSERVER:2:44
+ head WEBSERVER:2:45
+ post WEBSERVER:2:46
+ other WEBSERVER:2:47
+ size
+ cached
+ uncached
+}
+
+web.perserver.requests.size {
+ zero WEBSERVER:2:48
+ le3k WEBSERVER:2:49
+ le10k WEBSERVER:2:50
+ le30k WEBSERVER:2:51
+ le100k WEBSERVER:2:52
+ le300k WEBSERVER:2:53
+ le1m WEBSERVER:2:54
+ le3m WEBSERVER:2:55
+ gt3m WEBSERVER:2:56
+ unknown WEBSERVER:2:67
+}
+
+web.perserver.bytes.size {
+ zero WEBSERVER:2:57
+ le3k WEBSERVER:2:58
+ le10k WEBSERVER:2:59
+ le30k WEBSERVER:2:60
+ le100k WEBSERVER:2:61
+ le300k WEBSERVER:2:62
+ le1m WEBSERVER:2:63
+ le3m WEBSERVER:2:64
+ gt3m WEBSERVER:2:65
+}
+
+web.perserver.requests.client {
+ total WEBSERVER:4:1
+}
+
+web.perserver.requests.cached {
+ total WEBSERVER:4:11
+ size
+}
+
+web.perserver.requests.cached.size {
+ zero WEBSERVER:4:12
+ le3k WEBSERVER:4:13
+ le10k WEBSERVER:4:14
+ le30k WEBSERVER:4:15
+ le100k WEBSERVER:4:16
+ le300k WEBSERVER:4:17
+ le1m WEBSERVER:4:18
+ le3m WEBSERVER:4:19
+ gt3m WEBSERVER:4:20
+ unknown WEBSERVER:4:21
+}
+
+web.perserver.requests.uncached {
+ total WEBSERVER:4:31
+ size
+}
+
+web.perserver.requests.uncached.size {
+ zero WEBSERVER:4:32
+ le3k WEBSERVER:4:33
+ le10k WEBSERVER:4:34
+ le30k WEBSERVER:4:35
+ le100k WEBSERVER:4:36
+ le300k WEBSERVER:4:37
+ le1m WEBSERVER:4:38
+ le3m WEBSERVER:4:39
+ gt3m WEBSERVER:4:40
+ unknown WEBSERVER:4:41
+}
+
+web.perserver.bytes.cached {
+ total WEBSERVER:4:51
+ size
+}
+
+web.perserver.bytes.cached.size {
+ zero WEBSERVER:4:52
+ le3k WEBSERVER:4:53
+ le10k WEBSERVER:4:54
+ le30k WEBSERVER:4:55
+ le100k WEBSERVER:4:56
+ le300k WEBSERVER:4:57
+ le1m WEBSERVER:4:58
+ le3m WEBSERVER:4:59
+ gt3m WEBSERVER:4:60
+}
+
+web.perserver.bytes.uncached {
+ total WEBSERVER:4:71
+ size
+}
+
+web.perserver.bytes.uncached.size {
+ zero WEBSERVER:4:72
+ le3k WEBSERVER:4:73
+ le10k WEBSERVER:4:74
+ le30k WEBSERVER:4:75
+ le100k WEBSERVER:4:76
+ le300k WEBSERVER:4:77
+ le1m WEBSERVER:4:78
+ le3m WEBSERVER:4:79
+ gt3m WEBSERVER:4:80
+}
+
diff --git a/src/pmdas/weblog/root b/src/pmdas/weblog/root
new file mode 100644
index 0000000..de85ad7
--- /dev/null
+++ b/src/pmdas/weblog/root
@@ -0,0 +1,10 @@
+/*
+ * fake "root" for validating the local PMNS subtree
+ */
+
+#include <stdpmid>
+
+root { web }
+
+#include "pmns"
+
diff --git a/src/pmdas/weblog/server.sh b/src/pmdas/weblog/server.sh
new file mode 100755
index 0000000..fc63dfa
--- /dev/null
+++ b/src/pmdas/weblog/server.sh
@@ -0,0 +1,1228 @@
+#! /bin/sh
+#
+# Copyright (c) 2000-2001,2003 Silicon Graphics, Inc. All Rights Reserved.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+
+# Get standard environment
+. $PCP_DIR/etc/pcp.env
+
+# Setup some default paths
+_logdir=/var/log
+_msgfil=messages
+
+#
+# Every supported server defines 10 variables which are used by addServer()
+# and installFiles() to create a server specification for the weblog PMDA
+# and a URL for the webping PMDA, respectively.
+#
+# access The full path to the access log
+# accessRegex The regex for the access log
+# errors The full path to the error log
+# errorRegex The regex for the error log
+# serverPath The server path
+# serverDesc A desciption of the type of server
+# serverName The name for the server (must be unique)
+# serverPort Port the server is bound to
+# docs The full path to the document root
+# "$noDocs" - indicates there is no document root
+# http The URL for the server
+# files How to put the HTML files into the doc root
+# "link" - create a soft link
+# "copy" - copy the files
+# "skip" - do not create URLs for this server
+#
+
+do_logs=false
+do_files=false
+do_auto=false
+do_verbose=false
+debug=false
+noDocs="???"
+unknownDocs=""
+docsDir="$PCP_DOC_DIR/pcpweb/"
+link="pcpweb"
+file1="index.html"
+file2="planning.html"
+file3="tasks.html"
+pfx=" "
+skipping="${pfx}skipping..."
+tmp=`mktemp -d /tmp/pcp.XXXXXXXXX` || exit 1
+trap "rm -rf $tmp; exit" 0 1 2 3 15
+
+# Duplicate entry check file
+#
+rm -f $tmp/dup
+touch $tmp/dup
+
+# pv 816562 - try to work around $PCP_DOC_DIR confusion
+[ ! -x $docsDir -a -x /usr/pcp/doc/pcpweb/ ] && docsDir=/usr/pcp/doc/pcpweb/
+
+LOCALHOSTNAME=`hostname`
+
+# web server attribute names (global)
+#
+ATTRLIST="serverPort serverName docs access errors"
+
+# look for netscape stuff here
+#
+NSROOTPATH="${NSROOTPATH-/usr/ns-home:/var/netscape/suitespot:/var/netscape/fasttrack}"
+
+# the Netscape server types we know how to handle
+#
+NSTYPE="httpd https proxy"
+
+# look for old outbox
+#
+OUTBOXPATH="${OUTBOXPATH-/var/mc-httpd}"
+
+# look for old Netscape Proxy Servers here
+#
+NSPROXYPATH="${NSPROXYPATH-/var/ns-proxy}"
+
+# look for NCSA servers here
+#
+NCSAPATH="${NCSAPATH-/var/www}"
+
+# look for Zeus servers here
+#
+ZEUSPATH="${ZEUSPATH-/usr/local/zeus}"
+
+# look for Squid Object caches here
+#
+SQUIDPATH="${SQUIDPATH-/usr/local/squid}"
+
+# look for Apache servers here
+#
+APACHEPATH="${APACHEPATH-/etc/apache2:/etc/httpd}"
+
+# look for anonymous ftp here
+#
+FTPPATH="${FTPPATH:-$_logdir}"
+
+# look for password file here (to determine ~ftp)
+#
+PASSWDPATH="${PASSWDPATH-/etc/passwd}"
+
+# look for SYSLOG here
+#
+SYSLOGPATH="${SYSLOGPATH:-$_logdir/$_msgfil}"
+
+# look for xferlog here (for wu_ftp)
+# XFERLOG is default for wu_ftp
+XFERLOG="${XFERLOG:-$_logdir/xferlog}"
+# WUFTPLOG is used in sgi freeware wu_ftp
+WUFTPLOG="${WUFTPLOG-$_logdir/wu-ftpd.log}"
+
+_getLogFiles()
+{
+ $PCP_ECHO_PROG $PCP_ECHO_N "Full path to access log [$access] ""$PCP_ECHO_C"
+ read ans
+ if [ -n "$ans" ]
+ then
+ access="$ans"
+ if [ ! -f "$access" ]
+ then
+ echo "Warning: $access does not exist at this time."
+ fi
+ fi
+
+ $PCP_ECHO_PROG $PCP_ECHO_N "Full path to error log [$errors] ""$PCP_ECHO_C"
+ read ans
+ if [ -n "$ans" ]
+ then
+ errors="$ans"
+ if [ ! -f "$errors" ]
+ then
+ echo "Warning: $errors does not exist at this time."
+ fi
+ fi
+}
+
+# _addServer_check
+# 1: servername
+# 2: other args for log file
+# 3: server description
+_addServer_check()
+{
+ if grep "$1" $tmp/dup > /dev/null 2>&1
+ then
+ echo "${pfx}Error: already found a server with the name \"$1\""
+ if $do_auto
+ then
+ echo "$skipping"
+ else
+ $PCP_ECHO_PROG $PCP_ECHO_N "New name for server (or return to skip this server): ""$PCP_ECHO_C"
+ read ans
+ if [ -n "$ans" ]
+ then
+ if grep "$ans" $tmp/dup > /dev/null 2>&1
+ then
+ echo "${pfx}Error: new server name already exists"
+ echo "$skipping"
+ else
+ echo >> $logFile
+ echo "# $3." >> $logFile
+ echo "server $ans $2" >> $logFile
+ echo "$1" >> $tmp/dup
+ fi
+ else
+ echo "$skipping"
+ fi
+ fi
+ else
+ echo >> $logFile
+ echo "# $3." >> $logFile
+ echo "server $1 $2" >> $logFile
+ echo "$1" >> $tmp/dup
+ fi
+}
+
+_addServer()
+{
+ echo "Found $serverDesc at $serverPath"
+ if [ \( -f "$access" -o -c "$access" \) -a \( -f "$errors" -o -c "$errors" \) ]
+ then
+ found="true"
+ if [ -z "$serverPort" ]
+ then
+ echo "${pfx}identified as $serverName"
+ _addServer_check "$serverName" "on $accessRegex $access $errorRegex $errors" "$serverDesc"
+ else
+ echo "${pfx}identified as $serverName:$serverPort"
+ _addServer_check "$serverName:$serverPort" "on $accessRegex $access $errorRegex $errors" "$serverDesc"
+ fi
+ echo
+ else
+ echo "${pfx}Error: log files are not in the expected place:"
+ echo "${pfx} $access"
+ echo "${pfx} $errors"
+ if $do_auto
+ then
+ echo "$skipping"
+ else
+ echo
+ echo "Do you want to specify an alternate location for the log files"
+ $PCP_ECHO_PROG $PCP_ECHO_N "(otherwise this server will be ignored) [y] ""$PCP_ECHO_C"
+ read ans
+ if [ -z "$ans" -o "$ans" = "y" -o "$ans" = "Y" ]
+ then
+ _getLogFiles
+ if [ -z "$serverPort" ]
+ then
+ _addServer_check "$serverName" "on $accessRegex $access $errorRegex $errors" "$serverDesc"
+ else
+ _addServer_check "$serverName:$serverPort" "on $accessRegex $access $errorRegex $errors" "$serverDesc"
+ fi
+ else
+ echo "$skipping"
+ fi
+ fi
+ echo
+ fi
+}
+
+_installFiles()
+{
+
+ echo
+ echo "Found $serverDesc at $serverPath"
+ if [ "$docs" != "$noDocs" ]
+ then
+ if [ "$docs" = "$unknownDocs" ]
+ then
+ echo "${pfx}Error: unable to determine document root"
+ if $do_auto
+ then
+ docs=$unknownDocs
+ echo "$skipping"
+ else
+ echo
+ $PCP_ECHO_PROG $PCP_ECHO_N "Path to document root (return to skip HTML link for this server): ""$PCP_ECHO_C"
+ read ans
+ if [ -n "$ans" ]
+ then
+ if [ -d "$ans" ]
+ then
+ docs="$ans"
+ else
+ echo "\"$ans\" is not a directory."
+ echo "No link to HTML files will be created for this server."
+ fi
+ fi
+ fi
+ elif [ ! -d "$docs" ]
+ then
+ echo "${pfx}Error: document root cannot be found at:"
+ echo "${pfx} $docs"
+ if $do_auto
+ then
+ docs=$unknownDocs
+ echo "$skipping"
+ else
+ echo
+ echo "Path to document root (return to skip HTML link for this server)"
+ $PCP_ECHO_PROG $PCP_ECHO_N "$docs: ""$PCP_ECHO_C"
+ read ans
+ if [ -n "$ans" ]
+ then
+ if [ -d $ans ]
+ then
+ docs=$ans
+ else
+ echo "${pfx}Error: \"$ans\" is not a directory."
+ docs=$unknownDocs
+ echo "$skipping"
+ fi
+ else
+ docs=$unknownDocs
+ fi
+ fi
+ else
+ echo "${pfx}document root found at:"
+ echo "${pfx}$docs"
+ fi
+
+ if [ "$docs" != "$unknownDocs" ]
+ then
+ if [ ! -f $docs/$link/$file1 -o ! -f $docs/$link/$file2 -o ! -f $docs/$link/$file3 ]
+ then
+ if [ "$files" = "link" ]
+ then
+ $PCP_ECHO_PROG $PCP_ECHO_N "Do you want a link to some sample HTML files created in this directory [y] ""$PCP_ECHO_C"
+ elif [ "$files" = "copy" ]
+ then
+ $PCP_ECHO_PROG $PCP_ECHO_N "Do you want some sample HTML files installed in this directory [y] ""$PCP_ECHO_C"
+ fi
+
+ read ans
+ if [ -z "$ans" -o "$ans" = "y" -o "$ans" = "Y" ]
+ then
+ if [ "$files" = "link" ]
+ then
+ [ -L $docs/$link ] && rm -f $docs/$link
+ if [ -f $docs/$link ]
+ then
+ echo "${pfx}Error: $docs/$link already exists."
+ echo "$skipping"
+ else
+ ln -s $docsDir $docs/$link
+ fi
+ elif [ "$files" = "copy" ]
+ then
+ if [ ! -f $docs/$link -o -d $docs/$link ]
+ then
+ cp $docsDir/$file1 $docs/$link/$file1
+ cp $docsDir/$file2 $docs/$link/$file2
+ cp $docsDir/$file3 $docs/$link/$file3
+ else
+ echo "${pfx}Error: $docs/$link is not a directory."
+ echo "$skipping"
+ fi
+ fi
+
+ if [ -z "$http" ]
+ then
+ echo "$http/$link/$file1" >> $logFile
+ echo "$http/$link/$file2" >> $logFile
+ echo "$http/$link/$file3" >> $logFile
+ fi
+ fi
+ else
+ echo "${pfx}Note: the link to the sample HTML files already exists."
+ if [ -n "$http" ]
+ then
+ echo "$http/$link/$file1" >> $logFile
+ echo "$http/$link/$file2" >> $logFile
+ echo "$http/$link/$file3" >> $logFile
+ fi
+ fi
+ else
+ if [ "$docs" != "$unknownDocs" ]
+ then
+ echo "$skipping"
+ fi
+ fi
+ else
+ echo "${pfx}Error: no document root, cannot install files."
+ echo "$skipping"
+ fi
+ echo
+}
+
+_switchAction()
+{
+ if $do_verbose
+ then
+ echo "------------------------------------------------------------"
+ echo "access = $access"
+ echo "accessRegex = $accessRegex"
+ echo "errors = $errors"
+ echo "errorRegex = $errorRegex"
+ echo "serverPath = $serverPath"
+ echo "serverDesc = $serverDesc"
+ echo "serverName = $serverName"
+ echo "serverPort = $serverPort"
+ echo "docs = $docs"
+ echo "http = $http"
+ echo "files = $files"
+ echo "------------------------------------------------------------"
+ echo
+ fi
+
+ if $do_logs
+ then
+ _addServer
+ else
+ _installFiles
+ fi
+}
+
+_scan_config()
+{
+ serverPort=
+ serverName=
+ errors=
+ access=
+ docs=
+
+ eval `cat $* 2>/dev/null | $PCP_AWK_PROG '
+NF == 2 && tolower($1) == "port" { print "serverPort=" $2; next }
+NF == 2 && tolower($1) == "errorlog" { print "errors=" $2; next }
+NF == 2 && tolower($1) == "servername" { print "serverName=" $2; next }
+tolower($1) == "init" { for (i=1; i<=NF; i++) {
+ if (match($i, "^access=")) print $i
+ if (match($i, "^global=")) printf "access=%s ",substr($i,8,length($i)-7)
+ }
+ next
+ }
+tolower($0) ~ /fn="document-root"/ || tolower($0) ~ /fn=document-root/ {
+ for (i=1; i<=NF; i++) {
+ if (match($i, "^root="))
+ printf "docs=%s ",substr($i,6,length($i)-5)
+ }
+ next
+ }'`
+}
+
+_netscape_extract()
+{
+ here=`pwd`
+ echo >$tmp/ns
+ for root in `echo "$NSROOTPATH" | sed -e 's/:/ /g'`
+ do
+ for type in $NSTYPE
+ do
+ for dir in $root/$type-*
+ do
+ [ -L "$dir" ] && continue
+ if [ -d "$dir" ]
+ then
+ cd $dir
+ check=`pwd`
+ cd $here
+ match=`grep "^$check " $tmp/ns`
+ if [ ! -z "$match" ]
+ then
+ echo "$match $dir" | $PCP_AWK_PROG '
+ { if ($1 == $2)
+ printf "The server at %s appears to be a link to %s which is already monitored as %s\n", $3, $2, $1
+ else if ($1 == $3) {
+ printf "The server at %s was already detected,\n", $1
+ printf "using the link %s. ", $2
+ }
+ else {
+ printf "The server at %s was already detected,\n", $1
+ printf "using the link %s. The link %s,\n", $2, $3
+ printf "which is also to this server, will be ignored.\n"
+ }
+ }'
+ echo "$skipping"
+ continue
+ fi
+ echo "$check $dir" >>$tmp/ns
+ access=
+ errors=
+ docs=
+ serverName=
+ serverPort=
+
+ if [ ! -f $dir/config/obj.conf ]
+ then
+ echo "Found Netscape $type Server at $dir"
+ echo "${pfx}Error: unable to find configuration file:"
+ echo "${pfx} $dir/config/obj.conf"
+ echo "$skipping"
+ echo
+ continue
+ elif [ ! -f $dir/config/magnus.conf ]
+ then
+ echo "Found Netscape $type Server at $dir"
+ echo "${pfx}Error: unable to find configuration file:"
+ echo "${pfx} $dir/config/magnus.conf"
+ echo "$skipping"
+ echo
+ continue
+ fi
+
+ _scan_config $dir/config/obj.conf $dir/config/magnus.conf
+
+ # fix server name as Netscape often adds a trailing '.'
+ serverName=`echo $serverName | sed -e 's/\.$//'`
+
+ if [ -z "$serverName" -o -z "$serverPort" ]
+ then
+ echo "Found Netscape $type Server at $dir"
+ echo "${pfx}Error: unable to determine server name or port from:"
+ echo "${pfx} $dir/config/magnus.conf"
+ echo "$skipping"
+ echo
+ continue
+ fi
+
+ if [ -z "$access" ]
+ then
+ access=$dir/logs/access
+ echo "Found Netscape $type Server at $dir"
+ echo "${pfx}Warning: unable to determine access log name, assuming:"
+ echo "${pfx} $access"
+ echo
+ fi
+
+ if [ -z "$errors" ]
+ then
+ errors=$dir/logs/errors
+ echo "Found Netscape $type Server at $dir"
+ echo "${pfx}Warning: unable to determine error log name, assuming:"
+ echo "${pfx} $errors"
+ echo
+ fi
+
+ #
+ # figure out if this is a caching server or not
+ #
+ if [ -f $access ]
+ then
+ num_lines=`wc -l $access | $PCP_AWK_PROG '{print $1}'`
+ if [ $num_lines -gt 1 ]
+ then
+ num_fields=`tail -n 1 $access | cut -f3 -d\" | wc -w`
+ if [ $num_fields -eq 11 ]
+ then
+ accessRegex="NS_PROXY"
+ else
+ accessRegex="CERN"
+ fi
+ else
+ accessRegex="CERN"
+ fi
+ fi
+
+ errorRegex="CERN_err"
+ serverPath="$dir"
+ serverDesc="Netscape $type Server"
+ http="GET http://$serverName:$serverPort"
+ files="link"
+
+ _switchAction
+ fi
+ done
+ done
+ done
+}
+
+_zeus_extract()
+{
+ if [ -d $ZEUSPATH ]
+ then
+ if [ -f $ZEUSPATH/server.ini ]
+ then
+ rm -f $tmp/zeus
+ touch $tmp/zeus
+ $PCP_AWK_PROG < $ZEUSPATH/server.ini -v hostname=$LOCALHOSTNAME -v out=$tmp/zeus -v ini=$ZEUSPATH/server.ini -F'=' '
+BEGIN { mode = 0;
+ port = 0;
+ name = "";
+ access = "???";
+ errors = "???";
+ docs = "???";
+ host = hostname;
+ }
+
+/^port/ { if (mode == 0)
+ port=$2;
+ next
+ }
+$1 ~ /\[Admin/ { mode = 1; next }
+$1 ~ /\[Server/ { if (mode == 2) {
+ printf("%s %s %s %d %s %s\n", name, access, errors, port, host, docs) > out;
+ name=""; access="???"; errors="???"; docs="???";
+ host = hostname
+ }
+ else
+ mode = 2;
+
+ i = match($1, " .*]");
+ if (i == 0) {
+ mode = 1
+ }
+ else {
+ name = substr($1, RSTART+1, RLENGTH-2);
+ }
+ next
+ }
+/^logdir/ { if (mode == 2) {
+ access = sprintf("%s/transfer", $2);
+ errors = sprintf("%s/errors", $2);
+ }
+ next
+ }
+/^docroot/ { if (mode == 2)
+ docs = $2;
+ next
+ }
+/^ipname/ { if (mode == 2)
+ host = $2;
+ next
+ }
+END { if (mode == 2)
+ printf("%s %s %s %d %s %s\n", name, access, errors, port, host, docs) > out;
+ }'
+
+ if [ -f $tmp/zeus -a -s $tmp/zeus ]
+ then
+ accessRegex=CERN
+ errorRegex=CERN_err
+ serverPath=$ZEUSPATH
+ files="link"
+ lines=`wc -l $tmp/zeus | $PCP_AWK_PROG '{ print $1 }'`
+ count=1
+ while [ $count -le $lines ]
+ do
+ eval `$PCP_AWK_PROG < $tmp/zeus -v line=$count '
+NR == line { printf("serverName=%s\naccess=%s\nerrors=%s\nserverPort=%d\nhttp=%s\ndocs=%s\n", $1, $2, $3, $4, $5, $6); exit }'`
+
+ serverDesc="Zeus Server $serverName"
+ serverName="zeus-$serverName"
+ http="GET http://$http:$serverPort"
+
+ if [ "$access" = "???" ]
+ then
+ access=$ZEUSPATH/log/transfer
+ echo "Found $serverDesc at $serverPath"
+ echo "${pfx}Warning: unable to determine access log name, assuming:"
+ echo "${pfx} $access"
+ echo
+ fi
+ if [ "$errors" = "???" ]
+ then
+ errors=$ZEUSPATH/log/errors
+ echo "Found $serverDesc at $serverPath"
+ echo "${pfx}Warning: unable to determine error log name, assuming:"
+ echo "${pfx} $errors"
+ echo
+ fi
+ if [ "$docs" = "???" ]
+ then
+ docs=$ZEUSPATH/docroot
+ echo "Found $serverDesc at $serverPath"
+ echo "${pfx}Warning: unable to determine document root, assuming:"
+ echo "${pfx} $docs"
+ echo
+ fi
+
+ _switchAction
+ count=`expr $count + 1`
+ done
+ else
+ echo "Found Zeus Server/s at $ZEUSPATH"
+ echo "${pfx}Error: could not detect any servers in configuration file:"
+ echo "${pfx} $ZEUSPATH/server.ini"
+ echo "$skipping"
+ fi
+
+ else
+ echo "Found Zeus Server at $ZEUSPATH"
+ echo "${pfx}Error: unable to find configuration file:"
+ echo "${pfx} $ZEUSPATH/server.ini"
+ echo "$skipping"
+ fi
+ fi
+}
+
+_squid_extract()
+{
+ if [ -d $SQUIDPATH ]
+ then
+ if [ -f $SQUIDPATH/etc/squid.conf ]
+ then
+ rm -f $tmp/squid
+ touch $tmp/squid
+ $PCP_AWK_PROG < $SQUIDPATH/etc/squid.conf -v hostname=${LOCALHOSTNAME} -v out=$tmp/squid '
+BEGIN { port = 3128;
+ name = hostname;
+ access = "/usr/local/squid/logs/access.log";
+ errors = "/dev/null";
+ host = hostname;
+ }
+
+$1 == "emulate_httpd_log" { if ( $2 == "on" )
+ mode = 1;
+ }
+$1 == "cache_access_log" { access = $2;
+ }
+$1 == "http_port" { port = $2;
+ }
+$1 == "visible_hostname" { name = $2;
+ }
+END { if (mode == 0)
+ printf("SQUID %s %s %s %d %s\n", name, access, errors, port, host) > out;
+ else
+ printf("CERN %s %s %s %d %s\n", name, access, errors, port, host) > out;
+ }'
+
+ if [ -f $tmp/squid -a -s $tmp/squid ]
+ then
+ grep CERN $tmp/squid >/dev/null
+ if [ $? -eq 0 ]
+ then
+ accessRegex=CERN
+ else
+ accessRegex=SQUID
+ fi
+ errorRegex=CERN_err
+ serverPath=$SQUIDPATH
+ files="skip"
+ eval `$PCP_AWK_PROG < $tmp/squid '
+{ printf("serverName=%s\naccess=%s\nerrors=%s\nserverPort=%d\nhttp=%s\n", $2, $3, $4, $5, $6); exit }'`
+
+ serverDesc="Squid Server $serverName"
+ serverName="squid-$serverName"
+ http="GET http://$http:$serverPort"
+ docs=$noDocs
+
+ if [ "$access" = "???" ]
+ then
+ access=$SQUIDPATH/log/transfer
+ echo "Found $serverDesc at $serverPath"
+ echo "${pfx}Warning: unable to determine access log name, assuming:"
+ echo "${pfx} $access"
+ echo
+ fi
+ if [ "$errors" = "???" ]
+ then
+ errors=$SQUIDPATH/log/errors
+ echo "Found $serverDesc at $serverPath"
+ echo "${pfx}Warning: unable to determine error log name, assuming:"
+ echo "${pfx} $errors"
+ echo
+ fi
+
+ _switchAction
+ else
+ echo "Found Squid Server/s at $SQUIDPATH"
+ echo "${pfx}Error: could not detect any servers in configuration file:"
+ echo "${pfx} $SQUIDPATH/squid.conf"
+ echo "$skipping"
+ fi
+
+ else
+ echo "Found Squid Server at $SQUIDPATH"
+ echo "${pfx}Error: unable to find configuration file:"
+ echo "${pfx} $SQUIDPATH/squid.conf"
+ echo "$skipping"
+ fi
+ fi
+}
+
+_apache_extract()
+{
+ for apchroot in `echo "$APACHEPATH" | sed -e 's/:/ /g'`
+ do
+ $debug && echo "_apache_extract: apachroot=$apchroot"
+ if [ -d "$apchroot/sites-available" ]
+ then
+ config="$apchroot/sites-available/"
+ elif [ -d "$apchroot/vhosts.d" ]
+ then
+ config="$apchroot/vhosts.d/"
+ elif [ -d "$apchroot/conf" ]
+ then
+ config="$apchroot/conf/"
+ elif [ -f "$apchroot/httpd.conf" ]
+ then
+ config="$apchroot/httpd.conf"
+ else
+ continue
+ fi
+
+ for config in `echo ${config}*`
+ do
+ $debug && echo "_apache_extract: config=$config"
+ [ -f "$config" ] || continue
+
+ cat $config \
+ | sed -e's/#.*//' -e'/^$/d' \
+ | $PCP_AWK_PROG -v def=`hostname` '
+ BEGIN {
+ curnam=def;
+ names[def] = curnam;
+ ports[def] = 80;
+ }
+ $1 == "<VirtualHost" {
+ sub(">", "", $2);
+ n = split ($2, nm, ":");
+ if ( n == 1 ) {
+ curnam=$2;
+ port=ports[def];
+ } else {
+ if ( length (nm[1]) && nm[1] != "*" ) {
+ curnam = nm[1];
+ } else {
+ curnam = def;
+ }
+ if ( length (nm[2]) ) {
+ port = nm[2];
+ } else {
+ port = ports[def];
+ }
+ }
+ cn=sprintf("%s:%d", curnam, port);
+ names[cn] = curnam;
+ ports[cn] = port;
+ curnam = cn;
+ }
+ $1 == "ServerName" { names[curnam] = $2; }
+ $1 == "Port" { ports[curnam] = $2; }
+ $1 == "</VirtualHost>" { curnam=def; }
+ $1 == "ErrorLog" {
+ path = $2
+ sub (/\$\{APACHE_LOG_DIR\}/, "/var/log/apache2", path)
+ if ( match (path, "/") != 1 ) {
+ erlog[curnam] = sprintf ("%s/%s", "'$apchroot'", path);
+ } else {
+ erlog[curnam] = path;
+ }
+ }
+ $1 == "DocumentRoot" {
+ path = $2
+ sub (/\$\{APACHE_LOG_DIR\}/, "/var/log/apache2", path)
+ if ( match (path, "/") != 1 ) {
+ docs[curnam] = sprintf ("%s/%s", "'$apchroot'", path);
+ } else {
+ docs[curnam] = path;
+ }
+ }
+ $1 == "TransferLog" {
+ path = $2
+ sub (/\$\{APACHE_LOG_DIR\}/, "/var/log/apache2", path)
+ if ( match (path, "/") != 1 ) {
+ tlog[curnam] = sprintf ("%s/%s", "'$apchroot'", path);
+ } else {
+ tlog[curnam] = path;
+ }
+ }
+ $1 == "CustomLog" && ($3 == "common" || $3 == "combined") {
+ path = $2
+ sub (/\$\{APACHE_LOG_DIR\}/, "/var/log/apache2", path)
+ if ( match (path, "/") != 1 ) {
+ tlog[curnam] = sprintf ("%s/%s", "'$apchroot'", path);
+ } else {
+ tlog[curnam] = path;
+ }
+ }
+ END {
+ for ( n in names ) {
+ print names[n], ports[n], tlog[n], erlog[n], docs[n];
+ }
+ }'\
+ | while read serverName serverPort access errors docs ; do
+ $debug && echo "_apache_extract: serverName=$serverName serverPort=$serverPort access=$access errors=$errors docs=$docs"
+
+ accessRegex=CERN
+ errorRegex=CERN_err
+ serverPath="$apchroot"
+ serverDesc="Apache Server"
+ files="copy"
+
+ _switchAction
+ done
+ done
+ done
+}
+
+while [ $# -gt 0 ]
+do
+ case $1
+ in
+
+ -d) # debug
+ debug=true
+ ;;
+
+ -f) # install dummy HTML files in server document root
+ do_files=true
+ if [ $# -gt 1 ]
+ then
+ shift
+ logFile=$1
+ else
+ echo "-f requires the name of log file"
+ exit 1
+ fi
+ ;;
+
+ -l) # generate pmdaweblog configuration file
+ do_logs=true
+ if [ $# -gt 1 ]
+ then
+ shift
+ logFile=$1
+ else
+ echo "-l requires the name of log file"
+ exit 1
+ fi
+ ;;
+
+ -q) # do not prompt for misconfigured servers
+ do_auto=true
+ ;;
+
+ -v) # verbose
+ do_verbose=true
+ ;;
+
+ *) # USAGE
+ echo "Usage: server.sh [-dqv] [-f logFile] [-l logFile]"
+ exit 1
+ ;;
+ esac
+ shift
+done
+
+if [ "$do_logs" = "true" -a "$do_files" = "true" ]
+then
+ echo "May only perform one of the two options at any one time"
+ exit 1
+fi
+
+if $do_files
+then
+ if [ ! -f $docsDir/$file1 -o ! -f $docsDir/$file2 -o ! -f $docsDir/$file3 ]
+ then
+ echo "Some or all of the sample HTML files ($file1, $file2, $file3)"
+ echo "are missing. Cannot continue!"
+ exit 1
+ fi
+fi
+
+_netscape_extract
+
+# Another common place for Netscape servers
+
+if [ -d $OUTBOXPATH ]
+then
+ access=$OUTBOXPATH/logs/access
+ accessRegex="CERN"
+ errors=$OUTBOXPATH/logs/errors
+ errorRegex="CERN_err"
+ serverPath=$OUTBOXPATH
+ serverDesc="Outbox Server"
+ serverName="outbox-$LOCALHOSTNAME"
+ serverPort=
+ docs="$OUTBOXPATH/html"
+ http="GET http://$LOCALHOSTNAME"
+ files="link"
+ _switchAction
+fi
+
+# Netscape Proxy Server
+
+if [ -d $NSPROXYPATH/logs ]
+then
+ access=$NSPROXYPATH/logs/access
+ accessRegex="CERN"
+ errors=$NSPROXYPATH/logs/errors
+ errorRegex="CERN_err"
+ serverPath=$NSPROXYPATH
+ serverDesc="Old Netscape proxy Server"
+ serverName="proxy-$LOCALHOSTNAME"
+ serverPort=
+ docs=$noDocs
+ http=""
+ files="skip"
+ _switchAction
+fi
+
+# Netscape SOCKS Proxy Server
+
+if [ -f $NSROOTPATH/proxy-server/logs/sockd ]
+then
+ access=$NSROOTPATH/proxy-server/logs/sockd
+ accessRegex="NS_SOCKS"
+ errors=/dev/null
+ errorRegex="NS_SOCKS_err"
+ serverPath=$NSROOTPATH/proxy-server
+ serverDesc="Netscape SOCKS Proxy Server"
+ serverName="socks-$LOCALHOSTNAME"
+ serverPort=
+ docs=$noDocs
+ http=""
+ files="skip"
+ _switchAction
+
+ if [ "$do_logs" = "true" ]
+ then
+ echo
+ $PCP_ECHO_PROG $PCP_ECHO_N "Would you like to log SOCKS ftp transactions [y] ""$PCP_ECHO_C"
+ read ans
+ if [ -z "$ans" -o "$ans" = "y" -o "$ans" = "Y" ]
+ then
+ access=$NSROOTPATH/proxy-server/logs/sockd
+ accessRegex="NS_FTP"
+ errors=/dev/null
+ errorRegex="NS_FTP_err"
+ serverPath=$NSROOTPATH/proxy-server
+ serverDesc="FTP through Netscape SOCKS Server"
+ serverName="ftp-socks-$LOCALHOSTNAME"
+ serverPort=
+ docs=$noDocs
+ http=""
+ files="skip"
+ _switchAction
+ fi
+ fi
+fi
+
+if [ -f $NSPROXYPATH/logs/sockd ]
+then
+ access=$NSPROXYPATH/logs/sockd
+ accessRegex="NS_SOCKS"
+ errors=/dev/null
+ errorRegex="NS_SOCKS_err"
+ serverPath=$NSPROXYPATH
+ serverDesc="Netscape SOCKS Proxy Server"
+ serverName="socks-$LOCALHOSTNAME"
+ serverPort=
+ docs=$noDocs
+ http=""
+ files="skip"
+ _switchAction
+
+ if [ "$do_logs" = "true" ]
+ then
+ echo
+ $PCP_ECHO_PROG $PCP_ECHO_N "Would you like to log SOCKS ftp transactions [y] ""$PCP_ECHO_C"
+ read ans
+ if [ -z "$ans" -o "$ans" = "y" -o "$ans" = "Y" ]
+ then
+ access=$NSPROXYPATH/logs/sockd
+ accessRegex="NS_FTP"
+ errors=/dev/null
+ errorRegex="NS_FTP_err"
+ serverPath=$NSPROXYPATH
+ serverDesc="FTP through Netscape SOCKS Server"
+ serverName="ftp-socks-$LOCALHOSTNAME"
+ serverPort=
+ docs=$noDocs
+ http=""
+ files="skip"
+ _switchAction
+ fi
+ fi
+fi
+
+# NCSA (or derived) Server
+
+if [ -d $NCSAPATH/server ]
+then
+ access=$NCSAPATH/server/logs/access_log
+ accessRegex="CERN"
+ errors=$NCSAPATH/server/logs/error_log
+ errorRegex="CERN_err"
+ serverPath=$NCSAPATH/server
+ serverDesc="NCSA (or derived) Server"
+ serverName="ncsa-$LOCALHOSTNAME"
+ serverPort=
+ docs="$NCSAPATH/htdocs"
+ http="GET http://$LOCALHOSTNAME"
+ files="link"
+ _switchAction
+fi
+
+# Zeus Server
+
+_zeus_extract
+
+# Squid Server
+
+_squid_extract
+
+# Apache Server
+
+_apache_extract
+
+# Oracle Webserver
+
+if [ -n "$ORACLE_HOME" ]
+then
+ if [ -d $ORACLE_HOME/ows ]
+ then
+ serverPath=$ORACLE_HOME/ows
+ for i in `ls $serverPath/log/sv*.log*`
+ do
+ serverPort=`basename $i | sed 's/sv//' | sed 's/\.log//'`
+ access=$i
+ accessRegex="CERN"
+ errors="$serverPath/ows/log/sv$serverPort.err"
+ errorRegex="CERN_err"
+ serverDesc="Oracle Webserver"
+ serverName="ows-$serverPort"
+ docs="$serverPath/doc"
+ http="GET http://${LOCALHOSTNAME}:$serverPort"
+ files="link"
+ _switchAction
+ done
+ fi
+fi
+
+# Harvest Cache
+
+if [ -n "$HARVEST_HOME" ]
+then
+ serverPath=$HARVEST_HOME
+ serverPort=80
+ access=$serverPath/cache.access.log
+ accessRegex="CERN"
+ errors="$serverPath/cache.log"
+ errorRegex="CERN_err"
+ serverDesc="Harvest Cache"
+ serverName="harvest-cache"
+ docs="$noDocs"
+ http=""
+ files="skip"
+ _switchAction
+elif [ -d /usr/local/harvest ]
+then
+ serverPath=/usr/local/harvest
+ serverPort=80
+ access=$serverPath/cache.access.log
+ accessRegex="CERN"
+ errors="$serverPath/cache.log"
+ errorRegex="CERN_err"
+ serverDesc="Harvest Cache"
+ serverName="harvest-cache"
+ docs="$noDocs"
+ http=""
+ files="skip"
+ _switchAction
+fi
+
+# FTP
+if [ -n "$QUIET_INSTALL" ]; then
+ ans=y
+else
+ echo
+ if [ "$do_logs" = "true" ]
+ then
+ $PCP_ECHO_PROG $PCP_ECHO_N "Do you also want to monitor ftp transactions [y] ""$PCP_ECHO_C"
+ else
+ $PCP_ECHO_PROG $PCP_ECHO_N "Would you like the sample HTML files installed for anonymous ftp [y] ""$PCP_ECHO_C"
+ fi
+ read ans
+fi
+
+if [ -z "$ans" -o "$ans" = "y" -o "$ans" = "Y" ]
+then
+ echo
+ if [ -f $PASSWDPATH ]
+ then
+ if [ -n "$QUIET_INSTALL" ] ; then
+ ans=y
+ else
+ $PCP_ECHO_PROG $PCP_ECHO_N "Do you want to monitor wu_ftp [n] ""$PCP_ECHO_C"
+ read ans
+ echo
+ fi
+ if [ "$ans" = "y" -o "$ans" = "Y" ]
+ then
+ wulog="$WUFTPLOG"
+ if [ -f "$WUFTPLOG" ]
+ then
+ wulog="$WUFTPLOG"
+ elif [ -f "$XFERLOG" ]
+ then
+ wulog="$XFERLOG"
+ else
+ if $do_auto
+ then
+ echo "${pfx}Error: log files are not in the expected place:"
+ echo "$pfx $XFERLOG"
+ echo "$pfx or $WUFTPLOG"
+ echo "$skipping"
+ wulog=""
+ fi
+ fi
+
+ access="$wulog"
+ accessRegex="WU_FTP"
+ errors="$SYSLOGPATH"
+ errorRegex="WU_FTP_err"
+ serverDesc="WU_FTP Server"
+ serverName="wu_ftp"
+ serverPath=$FTPPATH
+ serverPort=
+ else
+ access=$SYSLOGPATH
+ accessRegex="SYSLOG_FTP"
+ errors=$SYSLOGPATH
+ errorRegex="SYSLOG_FTP_err"
+ serverDesc="FTP Server"
+ serverName="ftpd"
+ serverPath=$FTPPATH
+ serverPort=
+ fi
+
+ if [ ! -z "$access" ]
+ then
+ docs=""
+ docs=`$PCP_AWK_PROG -F: '$1 == "ftp" { print $6 "/pub"; exit }' < ${PASSWDPATH}`
+ if [ -z "$docs" ]
+ then
+ echo "Found FTP Server at $FTPPATH"
+ echo "${pfx}Error: user ftp is not listed in the password file:"
+ echo "${pfx} $PASSWDPATH"
+ echo "$skipping"
+ else
+ http="GET ftp://$LOCALHOSTNAME/pub"
+ files="copy"
+ _switchAction
+ fi
+ fi
+ else
+ echo "Found FTP Server at $FTPPATH"
+ echo "${pfx}Error: unable to find password file:"
+ echo "${pfx} $PASSWDPATH"
+ echo "$skipping"
+ fi
+fi
+
+if $do_logs
+then
+ :
+else
+ [ -f "$logFile" ] && sort -u $logFile -o $logFile
+fi
diff --git a/src/pmdas/weblog/sproc.c b/src/pmdas/weblog/sproc.c
new file mode 100644
index 0000000..e9fdc7d
--- /dev/null
+++ b/src/pmdas/weblog/sproc.c
@@ -0,0 +1,39 @@
+/*
+ * Web PMDA, based on generic driver for a daemon-based PMDA
+ *
+ * Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "weblog.h"
+#if defined(HAVE_PTHREAD_H)
+#include <pthread.h>
+#endif
+#if defined(HAVE_SCHED_H)
+#include <sched.h>
+#endif
+
+#if defined(HAVE_PTHREAD_H)
+static pthread_t sproc_thread;
+
+int sproc (void (*entry) (void *), int flags, void *arg)
+{
+ int retval;
+
+ retval = pthread_create(&sproc_thread, NULL, (void (*))entry, NULL);
+ return retval;
+}
+#endif
diff --git a/src/pmdas/weblog/weblog.c b/src/pmdas/weblog/weblog.c
new file mode 100644
index 0000000..570d104
--- /dev/null
+++ b/src/pmdas/weblog/weblog.c
@@ -0,0 +1,3132 @@
+/*
+ * Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "weblog.h"
+#include "domain.h"
+#include <ctype.h>
+#include <sys/stat.h>
+#if defined(HAVE_SYS_RESOURCE_H)
+#include <sys/resource.h>
+#endif
+#if defined(HAVE_SYS_PRCTL_H)
+#include <sys/prctl.h>
+#endif
+#if defined(HAVE_SYS_WAIT_H)
+#include <sys/wait.h>
+#endif
+
+/*
+ * Types of metrics, used by fetch to more efficiently calculate metrics
+ */
+
+enum MetaType {
+ wl_globalPtr, wl_offset32, wl_offset64, wl_totalAggregate,
+ wl_serverAggregate, wl_requestMethod, wl_bytesMethod,
+ wl_requestSize, wl_requestCachedSize, wl_requestUncachedSize,
+ wl_bytesSize, wl_bytesCachedSize, wl_bytesUncachedSize,
+ wl_watched, wl_numAlive, wl_nosupport, wl_numMetaTypes
+};
+
+/*
+ * Return code of checkLogFile()
+ */
+
+enum LogFileCode {
+ wl_ok, wl_opened, wl_reopened, wl_closed, wl_unableToOpen, wl_unableToStat,
+ wl_irregularFile, wl_dormant
+};
+
+static WebCount dummyCount;
+
+/*
+ * Instance domain table
+ * This is completed when parsing the config file
+ */
+
+pmdaIndom wl_indomTable[] =
+{
+#define WEBLOG_INDOM 0
+ { WEBLOG_INDOM, 0, 0 }
+};
+
+/*
+ * Metric specific data to help identify each metric during a fetch
+ *
+ * MG: Note: must be in the same order as wl_metric table below.
+ *
+ */
+
+typedef struct {
+ int m_type;
+ __psint_t m_offset;
+} WebMetric;
+
+WebMetric wl_metricInfo[] =
+{
+/* config.numservers */
+ { wl_globalPtr, (__psint_t)&wl_numServers },
+/* config.catchup */
+ { wl_globalPtr, (__psint_t)&wl_refreshDelay },
+/* config.catchuptime */
+ { wl_globalPtr, (__psint_t)&wl_catchupTime },
+/* config.check */
+ { wl_globalPtr, (__psint_t)&wl_chkDelay },
+/* allserves.numwatched */
+ { wl_globalPtr, (__psint_t)&wl_numActive },
+/* allserves.numalive */
+ { wl_numAlive, (__psint_t)0 },
+/* allservers.errors */
+ { wl_totalAggregate, (__psint_t)0 },
+/* allservers.requests.total */
+ { wl_totalAggregate, (__psint_t)1 },
+/* allservers.requests.get */
+ { wl_requestMethod, (__psint_t)wl_httpGet },
+/* allservers.requests.head */
+ { wl_requestMethod, (__psint_t)wl_httpHead },
+/* allservers.requests.post */
+ { wl_requestMethod, (__psint_t)wl_httpPost },
+/* allservers.requests.other */
+ { wl_requestMethod, (__psint_t)wl_httpOther },
+/* allservers.bytes.total */
+ { wl_totalAggregate, (__psint_t)2 },
+/* allservers.bytes.get */
+ { wl_bytesMethod, (__psint_t)wl_httpGet },
+/* allservers.bytes.head */
+ { wl_bytesMethod, (__psint_t)wl_httpHead },
+/* allservers.bytes.post */
+ { wl_bytesMethod, (__psint_t)wl_httpPost },
+/* allservers.bytes.other */
+ { wl_bytesMethod, (__psint_t)wl_httpOther },
+/* allservers.requests.size.zero */
+ { wl_requestSize, (__psint_t)wl_zero },
+/* allservers.requests.size.le3k */
+ { wl_requestSize, (__psint_t)wl_le3k },
+/* allservers.requests.size.le10k */
+ { wl_requestSize, (__psint_t)wl_le10k },
+/* allservers.requests.size.le30k */
+ { wl_requestSize, (__psint_t)wl_le30k },
+/* allservers.requests.size.le100k */
+ { wl_requestSize, (__psint_t)wl_le100k },
+/* allservers.requests.size.le300k */
+ { wl_requestSize, (__psint_t)wl_le300k },
+/* allservers.requests.size.le1m */
+ { wl_requestSize, (__psint_t)wl_le1m },
+/* allservers.requests.size.le3m */
+ { wl_requestSize, (__psint_t)wl_le3m },
+/* allservers.requests.size.gt3m */
+ { wl_requestSize, (__psint_t)wl_gt3m },
+/* allservers.requests.size.unknown */
+ { wl_requestSize, (__psint_t)wl_unknownSize },
+/* allservers.requests.client.total */
+ { wl_totalAggregate, (__psint_t)3 },
+/* allservers.requests.cached.total */
+ { wl_totalAggregate, (__psint_t)4 },
+/* allservers.requests.cached.size.zero */
+ { wl_requestCachedSize, (__psint_t)wl_zero },
+/* allservers.requests.cached.size.le3k */
+ { wl_requestCachedSize, (__psint_t)wl_le3k },
+/* allservers.requests.cached.size.le10k */
+ { wl_requestCachedSize, (__psint_t)wl_le10k },
+/* allservers.requests.cached.size.le30k */
+ { wl_requestCachedSize, (__psint_t)wl_le30k },
+/* allservers.requests.cached.size.le100k */
+ { wl_requestCachedSize, (__psint_t)wl_le100k },
+/* allservers.requests.cached.size.le300k */
+ { wl_requestCachedSize, (__psint_t)wl_le300k },
+/* allservers.requests.cached.size.le1m */
+ { wl_requestCachedSize, (__psint_t)wl_le1m },
+/* allservers.requests.cached.size.le3m */
+ { wl_requestCachedSize, (__psint_t)wl_le3m },
+/* allservers.requests.cached.size.gt3m */
+ { wl_requestCachedSize, (__psint_t)wl_gt3m },
+/* allservers.requests.cached.size.unknown */
+ { wl_requestCachedSize, (__psint_t)wl_unknownSize },
+/* allservers.requests.uncached.total */
+ { wl_totalAggregate, (__psint_t)5 },
+/* allservers.requests.uncached.size.zero */
+ { wl_requestUncachedSize, (__psint_t)wl_zero },
+/* allservers.requests.uncached.size.le3k */
+ { wl_requestUncachedSize, (__psint_t)wl_le3k },
+/* allservers.requests.uncached.size.le10k */
+ { wl_requestUncachedSize, (__psint_t)wl_le10k },
+/* allservers.requests.uncached.size.le30k */
+ { wl_requestUncachedSize, (__psint_t)wl_le30k },
+/* allservers.requests.uncached.size.le100k */
+ { wl_requestUncachedSize, (__psint_t)wl_le100k },
+/* allservers.requests.uncached.size.le300k */
+ { wl_requestUncachedSize, (__psint_t)wl_le300k },
+/* allservers.requests.uncached.size.le1m */
+ { wl_requestUncachedSize, (__psint_t)wl_le1m },
+/* allservers.requests.uncached.size.le3m */
+ { wl_requestUncachedSize, (__psint_t)wl_le3m },
+/* allservers.requests.uncached.size.gt3m */
+ { wl_requestUncachedSize, (__psint_t)wl_gt3m },
+/* allservers.requests.uncached.size.unknown */
+ { wl_requestUncachedSize, (__psint_t)wl_unknownSize },
+/* allservers.bytes.size.zero */
+ { wl_bytesSize, (__psint_t)wl_zero },
+/* allservers.bytes.size.le3k */
+ { wl_bytesSize, (__psint_t)wl_le3k },
+/* allservers.bytes.size.le10k */
+ { wl_bytesSize, (__psint_t)wl_le10k },
+/* allservers.bytes.size.le30k */
+ { wl_bytesSize, (__psint_t)wl_le30k },
+/* allservers.bytes.size.le100k */
+ { wl_bytesSize, (__psint_t)wl_le100k },
+/* allservers.bytes.size.le300k */
+ { wl_bytesSize, (__psint_t)wl_le300k },
+/* allservers.bytes.size.le1m */
+ { wl_bytesSize, (__psint_t)wl_le1m },
+/* allservers.bytes.size.le3m */
+ { wl_bytesSize, (__psint_t)wl_le3m },
+/* allservers.bytes.size.gt3m */
+ { wl_bytesSize, (__psint_t)wl_gt3m },
+/* allservers.bytes.cached.total */
+ { wl_totalAggregate, (__psint_t)6 },
+/* allservers.bytes.cached.size.zero */
+ { wl_bytesCachedSize, (__psint_t)wl_zero },
+/* allservers.bytes.cached.size.le3k */
+ { wl_bytesCachedSize, (__psint_t)wl_le3k },
+/* allservers.bytes.cached.size.le10k */
+ { wl_bytesCachedSize, (__psint_t)wl_le10k },
+/* allservers.bytes.cached.size.le30k */
+ { wl_bytesCachedSize, (__psint_t)wl_le30k },
+/* allservers.bytes.cached.size.le100k */
+ { wl_bytesCachedSize, (__psint_t)wl_le100k },
+/* allservers.bytes.cached.size.le300k */
+ { wl_bytesCachedSize, (__psint_t)wl_le300k },
+/* allservers.bytes.cached.size.le1m */
+ { wl_bytesCachedSize, (__psint_t)wl_le1m },
+/* allservers.bytes.cached.size.le3m */
+ { wl_bytesCachedSize, (__psint_t)wl_le3m },
+/* allservers.bytes.cached.size.gt3m */
+ { wl_bytesCachedSize, (__psint_t)wl_gt3m },
+/* allservers.bytes.uncached.total */
+ { wl_totalAggregate, (__psint_t)7 },
+/* allservers.bytes.uncached.size.zero */
+ { wl_bytesUncachedSize, (__psint_t)wl_zero },
+/* allservers.bytes.uncached.size.le3k */
+ { wl_bytesUncachedSize, (__psint_t)wl_le3k },
+/* allservers.bytes.uncached.size.le10k */
+ { wl_bytesUncachedSize, (__psint_t)wl_le10k },
+/* allservers.bytes.uncached.size.le30k */
+ { wl_bytesUncachedSize, (__psint_t)wl_le30k },
+/* allservers.bytes.uncached.size.le100k */
+ { wl_bytesUncachedSize, (__psint_t)wl_le100k },
+/* allservers.bytes.uncached.size.le300k */
+ { wl_bytesUncachedSize, (__psint_t)wl_le300k },
+/* allservers.bytes.uncached.size.le1m */
+ { wl_bytesUncachedSize, (__psint_t)wl_le1m },
+/* allservers.bytes.uncached.size.le3m */
+ { wl_bytesUncachedSize, (__psint_t)wl_le3m },
+/* allservers.bytes.uncached.size.gt3m */
+ { wl_bytesUncachedSize, (__psint_t)wl_gt3m },
+/* perserver.watched */
+ { wl_watched, (__psint_t)&dummyCount.active },
+/* perserver.numlogs */
+ { wl_offset32, (__psint_t)&dummyCount.numLogs },
+/* perserver.errors */
+ { wl_offset32, (__psint_t)&dummyCount.errors },
+/* perserver.requests.total */
+ { wl_serverAggregate, (__psint_t)0 },
+/* perserver.requests.get */
+ { wl_requestMethod, (__psint_t)wl_httpGet },
+/* perserver.requests.head */
+ { wl_requestMethod, (__psint_t)wl_httpHead },
+/* perserver.requests.post */
+ { wl_requestMethod, (__psint_t)wl_httpPost },
+/* perserver.requests.other */
+ { wl_requestMethod, (__psint_t)wl_httpOther },
+/* perserver.bytes.total */
+ { wl_serverAggregate, (__psint_t)1 },
+/* perserver.bytes.get */
+ { wl_bytesMethod, (__psint_t)wl_httpGet },
+/* perserver.bytes.head */
+ { wl_bytesMethod, (__psint_t)wl_httpHead },
+/* perserver.bytes.post */
+ { wl_bytesMethod, (__psint_t)wl_httpPost },
+/* perserver.bytes.other */
+ { wl_bytesMethod, (__psint_t)wl_httpOther },
+/* perserver.requests.size.zero */
+ { wl_requestSize, (__psint_t)wl_zero },
+/* perserver.requests.size.le3k */
+ { wl_requestSize, (__psint_t)wl_le3k },
+/* perserver.requests.size.le10k */
+ { wl_requestSize, (__psint_t)wl_le10k },
+/* perserver.requests.size.le30k */
+ { wl_requestSize, (__psint_t)wl_le30k },
+/* perserver.requests.size.le100k */
+ { wl_requestSize, (__psint_t)wl_le100k },
+/* perserver.requests.size.le300k */
+ { wl_requestSize, (__psint_t)wl_le300k },
+/* perserver.requests.size.le1m */
+ { wl_requestSize, (__psint_t)wl_le1m },
+/* perserver.requests.size.le3m */
+ { wl_requestSize, (__psint_t)wl_le3m },
+/* perserver.requests.size.gt3m */
+ { wl_requestSize, (__psint_t)wl_gt3m },
+/* perserver.requests.size.unknown */
+ { wl_requestSize, (__psint_t)wl_unknownSize },
+/* perserver.requests.client.total */
+ { wl_serverAggregate, (__psint_t)2 },
+/* perserver.requests.cached.total */
+ { wl_serverAggregate, (__psint_t)3 },
+/* perserver.requests.cached.size.zero */
+ { wl_requestCachedSize, (__psint_t)wl_zero },
+/* perserver.requests.cached.size.le3k */
+ { wl_requestCachedSize, (__psint_t)wl_le3k },
+/* perserver.requests.cached.size.le10k */
+ { wl_requestCachedSize, (__psint_t)wl_le10k },
+/* perserver.requests.cached.size.le30k */
+ { wl_requestCachedSize, (__psint_t)wl_le30k },
+/* perserver.requests.cached.size.le100k */
+ { wl_requestCachedSize, (__psint_t)wl_le100k },
+/* perserver.requests.cached.size.le300k */
+ { wl_requestCachedSize, (__psint_t)wl_le300k },
+/* perserver.requests.cached.size.le1m */
+ { wl_requestCachedSize, (__psint_t)wl_le1m },
+/* perserver.requests.cached.size.le3m */
+ { wl_requestCachedSize, (__psint_t)wl_le3m },
+/* perserver.requests.cached.size.gt3m */
+ { wl_requestCachedSize, (__psint_t)wl_gt3m },
+/* perserver.requests.cached.size.unknown */
+ { wl_requestCachedSize, (__psint_t)wl_unknownSize },
+/* perserver.requests.uncached.total */
+ { wl_serverAggregate, (__psint_t)4 },
+/* perserver.requests.uncached.size.zero */
+ { wl_requestUncachedSize, (__psint_t)wl_zero },
+/* perserver.requests.uncached.size.le3k */
+ { wl_requestUncachedSize, (__psint_t)wl_le3k },
+/* perserver.requests.uncached.size.le10k */
+ { wl_requestUncachedSize, (__psint_t)wl_le10k },
+/* perserver.requests.uncached.size.le30k */
+ { wl_requestUncachedSize, (__psint_t)wl_le30k },
+/* perserver.requests.uncached.size.le100k */
+ { wl_requestUncachedSize, (__psint_t)wl_le100k },
+/* perserver.requests.uncached.size.le300k */
+ { wl_requestUncachedSize, (__psint_t)wl_le300k },
+/* perserver.requests.uncached.size.le1m */
+ { wl_requestUncachedSize, (__psint_t)wl_le1m },
+/* perserver.requests.uncached.size.le3m */
+ { wl_requestUncachedSize, (__psint_t)wl_le3m },
+/* perserver.requests.uncached.size.gt3m */
+ { wl_requestUncachedSize, (__psint_t)wl_gt3m },
+/* perserver.requests.uncached.size.unknown */
+ { wl_requestUncachedSize, (__psint_t)wl_unknownSize },
+/* perserver.bytes.size.zero */
+ { wl_bytesSize, (__psint_t)wl_zero },
+/* perserver.bytes.size.le3k */
+ { wl_bytesSize, (__psint_t)wl_le3k },
+/* perserver.bytes.size.le10k */
+ { wl_bytesSize, (__psint_t)wl_le10k },
+/* perserver.bytes.size.le30k */
+ { wl_bytesSize, (__psint_t)wl_le30k },
+/* perserver.bytes.size.le100k */
+ { wl_bytesSize, (__psint_t)wl_le100k },
+/* perserver.bytes.size.le300k */
+ { wl_bytesSize, (__psint_t)wl_le300k },
+/* perserver.bytes.size.le1m */
+ { wl_bytesSize, (__psint_t)wl_le1m },
+/* perserver.bytes.size.le3m */
+ { wl_bytesSize, (__psint_t)wl_le3m },
+/* perserver.bytes.size.gt3m */
+ { wl_bytesSize, (__psint_t)wl_gt3m },
+/* perserver.bytes.cached.total */
+ { wl_serverAggregate, (__psint_t)5 },
+/* perserver.bytes.cached.size.zero */
+ { wl_bytesCachedSize, (__psint_t)wl_zero },
+/* perserver.bytes.cached.size.le3k */
+ { wl_bytesCachedSize, (__psint_t)wl_le3k },
+/* perserver.bytes.cached.size.le10k */
+ { wl_bytesCachedSize, (__psint_t)wl_le10k },
+/* perserver.bytes.cached.size.le30k */
+ { wl_bytesCachedSize, (__psint_t)wl_le30k },
+/* perserver.bytes.cached.size.le100k */
+ { wl_bytesCachedSize, (__psint_t)wl_le100k },
+/* perserver.bytes.cached.size.le300k */
+ { wl_bytesCachedSize, (__psint_t)wl_le300k },
+/* perserver.bytes.cached.size.le1m */
+ { wl_bytesCachedSize, (__psint_t)wl_le1m },
+/* perserver.bytes.cached.size.le3m */
+ { wl_bytesCachedSize, (__psint_t)wl_le3m },
+/* perserver.bytes.cached.size.gt3m */
+ { wl_bytesCachedSize, (__psint_t)wl_gt3m },
+/* perserver.bytes.uncached.total */
+ { wl_serverAggregate, (__psint_t)6 },
+/* perserver.bytes.uncached.size.zero */
+ { wl_bytesUncachedSize, (__psint_t)wl_zero },
+/* perserver.bytes.uncached.size.le3k */
+ { wl_bytesUncachedSize, (__psint_t)wl_le3k },
+/* perserver.bytes.uncached.size.le10k */
+ { wl_bytesUncachedSize, (__psint_t)wl_le10k },
+/* perserver.bytes.uncached.size.le30k */
+ { wl_bytesUncachedSize, (__psint_t)wl_le30k },
+/* perserver.bytes.uncached.size.le100k */
+ { wl_bytesUncachedSize, (__psint_t)wl_le100k },
+/* perserver.bytes.uncached.size.le300k */
+ { wl_bytesUncachedSize, (__psint_t)wl_le300k },
+/* perserver.bytes.uncached.size.le1m */
+ { wl_bytesUncachedSize, (__psint_t)wl_le1m },
+/* perserver.bytes.uncached.size.le3m */
+ { wl_bytesUncachedSize, (__psint_t)wl_le3m },
+/* perserver.bytes.uncached.size.gt3m */
+ { wl_bytesUncachedSize, (__psint_t)wl_gt3m },
+/* perserver.logidletime */
+ { wl_offset32, (__psint_t)&dummyCount.modTime },
+};
+
+/*
+ * all metrics supported in this PMDA - one table entry for each
+ */
+
+static pmdaMetric wl_metrics[] = {
+
+/*
+ * web.config
+ */
+
+/* config.numservers */
+{ (void *)0,
+ { PMDA_PMID(0,0), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, 0) } },
+
+/* config.catchup */
+{ (void *)0,
+ { PMDA_PMID(0,1), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE,
+ PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_SEC, 0) } },
+
+/* config.catchuptime */
+{ (void *)0,
+ { PMDA_PMID(0,2), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE,
+ PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_SEC, 0) } },
+
+/* config.check */
+{ (void *)0,
+ { PMDA_PMID(0,3), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE,
+ PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_SEC, 0) } },
+
+/*
+ * web.allservers
+ */
+
+/* allserves.numwatched */
+{ (void *)0,
+ { PMDA_PMID(0,4), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, 0) } },
+
+/* allserves.numalive */
+{ (void *)0,
+ { PMDA_PMID(0,5), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, 0) } },
+
+/* allservers.errors */
+{ (void *)0,
+ { PMDA_PMID(1,6), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* allservers.requests.total */
+{ (void *)0,
+ { PMDA_PMID(1,7), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* allservers.requests.get */
+{ (void *)0,
+ { PMDA_PMID(1,8), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* allservers.requests.head */
+{ (void *)0,
+ { PMDA_PMID(1,9), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* allservers.requests.post */
+{ (void *)0,
+ { PMDA_PMID(1,10), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* allservers.requests.other */
+{ (void *)0,
+ { PMDA_PMID(1,11), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* allservers.bytes.total */
+{ (void *)0,
+ { PMDA_PMID(1,12), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } },
+
+/* allservers.bytes.get */
+{ (void *)0,
+ { PMDA_PMID(1,13), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } },
+
+/* allservers.bytes.head */
+{ (void *)0,
+ { PMDA_PMID(1,14), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } },
+
+/* allservers.bytes.post */
+{ (void *)0,
+ { PMDA_PMID(1,15), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } },
+
+/* allservers.bytes.other */
+{ (void *)0,
+ { PMDA_PMID(1,16), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } },
+
+/* allservers.requests.size.zero */
+{ (void *)0,
+ { PMDA_PMID(1,17), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* allservers.requests.size.le3k */
+{ (void *)0,
+ { PMDA_PMID(1,18), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* allservers.requests.size.le10k */
+{ (void *)0,
+ { PMDA_PMID(1,19), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* allservers.requests.size.le30k */
+{ (void *)0,
+ { PMDA_PMID(1,20), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* allservers.requests.size.le100k */
+{ (void *)0,
+ { PMDA_PMID(1,21), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* allservers.requests.size.le300k */
+{ (void *)0,
+ { PMDA_PMID(1,22), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* allservers.requests.size.le1m */
+{ (void *)0,
+ { PMDA_PMID(1,23), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* allservers.requests.size.le3m */
+{ (void *)0,
+ { PMDA_PMID(1,24), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* allservers.requests.size.gt3m */
+{ (void *)0,
+ { PMDA_PMID(1,25), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* allservers.requests.size.unknown */
+{ (void *)0,
+ { PMDA_PMID(1,66), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* allservers.requests.client.total */
+{ (void *)0,
+ { PMDA_PMID(3,1), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* allservers.requests.cached.total */
+{ (void *)0,
+ { PMDA_PMID(3,11), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* allservers.requests.cached.size.zero */
+{ (void *)0,
+ { PMDA_PMID(3,12), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* allservers.requests.cached.size.le3k */
+{ (void *)0,
+ { PMDA_PMID(3,13), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* allservers.requests.cached.size.le10k */
+{ (void *)0,
+ { PMDA_PMID(3,14), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* allservers.requests.cached.size.le30k */
+{ (void *)0,
+ { PMDA_PMID(3,15), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* allservers.requests.cached.size.le100k */
+{ (void *)0,
+ { PMDA_PMID(3,16), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* allservers.requests.cached.size.le300k */
+{ (void *)0,
+ { PMDA_PMID(3,17), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* allservers.requests.cached.size.le1m */
+{ (void *)0,
+ { PMDA_PMID(3,18), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* allservers.requests.cached.size.le3m */
+{ (void *)0,
+ { PMDA_PMID(3,19), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* allservers.requests.cached.size.gt3m */
+{ (void *)0,
+ { PMDA_PMID(3,20), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* allservers.requests.cached.size.unknown */
+{ (void *)0,
+ { PMDA_PMID(3,21), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* allservers.requests.uncached.total */
+{ (void *)0,
+ { PMDA_PMID(3,31), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* allservers.requests.uncached.size.zero */
+{ (void *)0,
+ { PMDA_PMID(3,32), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* allservers.requests.uncached.size.le3k */
+{ (void *)0,
+ { PMDA_PMID(3,33), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* allservers.requests.uncached.size.le10k */
+{ (void *)0,
+ { PMDA_PMID(3,34), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* allservers.requests.uncached.size.le30k */
+{ (void *)0,
+ { PMDA_PMID(3,35), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* allservers.requests.uncached.size.le100k */
+{ (void *)0,
+ { PMDA_PMID(3,36), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* allservers.requests.uncached.size.le300k */
+{ (void *)0,
+ { PMDA_PMID(3,37), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* allservers.requests.uncached.size.le1m */
+{ (void *)0,
+ { PMDA_PMID(3,38), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* allservers.requests.uncached.size.le3m */
+{ (void *)0,
+ { PMDA_PMID(3,39), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* allservers.requests.uncached.size.gt3m */
+{ (void *)0,
+ { PMDA_PMID(3,40), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* allservers.requests.uncached.size.unknown */
+{ (void *)0,
+ { PMDA_PMID(3,41), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* allservers.bytes.size.zero */
+{ (void *)0,
+ { PMDA_PMID(1,26), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } },
+
+/* allservers.bytes.size.le3k */
+{ (void *)0,
+ { PMDA_PMID(1,27), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } },
+
+/* allservers.bytes.size.le10k */
+{ (void *)0,
+ { PMDA_PMID(1,28), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } },
+
+/* allservers.bytes.size.le30k */
+{ (void *)0,
+ { PMDA_PMID(1,29), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } },
+
+/* allservers.bytes.size.le100k */
+{ (void *)0,
+ { PMDA_PMID(1,30), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } },
+
+/* allservers.bytes.size.le300k */
+{ (void *)0,
+ { PMDA_PMID(1,31), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } },
+
+/* allservers.bytes.size.le1m */
+{ (void *)0,
+ { PMDA_PMID(1,32), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } },
+
+/* allservers.bytes.size.le3m */
+{ (void *)0,
+ { PMDA_PMID(1,33), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } },
+
+/* allservers.bytes.size.gt3m */
+{ (void *)0,
+ { PMDA_PMID(1,34), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } },
+
+/* allservers.bytes.cached.total */
+{ (void *)0,
+ { PMDA_PMID(3,51), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } },
+
+/* allservers.bytes.cached.size.zero */
+{ (void *)0,
+ { PMDA_PMID(3,52), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } },
+
+/* allservers.bytes.cached.size.le3k */
+{ (void *)0,
+ { PMDA_PMID(3,53), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } },
+
+/* allservers.bytes.cached.size.le10k */
+{ (void *)0,
+ { PMDA_PMID(3,54), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } },
+
+/* allservers.bytes.cached.size.le30k */
+{ (void *)0,
+ { PMDA_PMID(3,55), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } },
+
+/* allservers.bytes.cached.size.le100k */
+{ (void *)0,
+ { PMDA_PMID(3,56), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } },
+
+/* allservers.bytes.cached.size.le300k */
+{ (void *)0,
+ { PMDA_PMID(3,57), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } },
+
+/* allservers.bytes.cached.size.le1m */
+{ (void *)0,
+ { PMDA_PMID(3,58), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } },
+
+/* allservers.bytes.cached.size.le3m */
+{ (void *)0,
+ { PMDA_PMID(3,59), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } },
+
+/* allservers.bytes.cached.size.gt3m */
+{ (void *)0,
+ { PMDA_PMID(3,60), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } },
+
+/* allservers.bytes.uncached.total */
+{ (void *)0,
+ { PMDA_PMID(3,71), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } },
+
+/* allservers.bytes.uncached.size.zero */
+{ (void *)0,
+ { PMDA_PMID(3,72), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } },
+
+/* allservers.bytes.uncached.size.le3k */
+{ (void *)0,
+ { PMDA_PMID(3,73), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } },
+
+/* allservers.bytes.uncached.size.le10k */
+{ (void *)0,
+ { PMDA_PMID(3,74), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } },
+
+/* allservers.bytes.uncached.size.le30k */
+{ (void *)0,
+ { PMDA_PMID(3,75), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } },
+
+/* allservers.bytes.uncached.size.le100k */
+{ (void *)0,
+ { PMDA_PMID(3,76), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } },
+
+/* allservers.bytes.uncached.size.le300k */
+{ (void *)0,
+ { PMDA_PMID(3,77), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } },
+
+/* allservers.bytes.uncached.size.le1m */
+{ (void *)0,
+ { PMDA_PMID(3,78), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } },
+
+/* allservers.bytes.uncached.size.le3m */
+{ (void *)0,
+ { PMDA_PMID(3,79), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } },
+
+/* allservers.bytes.uncached.size.gt3m */
+{ (void *)0,
+ { PMDA_PMID(3,80), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } },
+
+/*
+ * web.perserver
+ */
+
+/* perserver.watched */
+{ (void *)0,
+ { PMDA_PMID(0,35), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_DISCRETE,
+ PMDA_PMUNITS(0, 0, 0, 0, 0, 0) } },
+
+/* perserver.numlogs */
+{ (void *)0,
+ { PMDA_PMID(2,36), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_DISCRETE,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* perserver.errors */
+{ (void *)0,
+ { PMDA_PMID(2,37), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* perserver.requests.total */
+{ (void *)0,
+ { PMDA_PMID(2,38), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* perserver.requests.get */
+{ (void *)0,
+ { PMDA_PMID(2,39), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* perserver.requests.head */
+{ (void *)0,
+ { PMDA_PMID(2,40), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* perserver.requests.post */
+{ (void *)0,
+ { PMDA_PMID(2,41), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* perserver.requests.other */
+{ (void *)0,
+ { PMDA_PMID(2,42), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* perserver.bytes.total */
+{ (void *)0,
+ { PMDA_PMID(2,43), PM_TYPE_U64, WEBLOG_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } },
+
+/* perserver.bytes.get */
+{ (void *)0,
+ { PMDA_PMID(2,44), PM_TYPE_U64, WEBLOG_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } },
+
+/* perserver.bytes.head */
+{ (void *)0,
+ { PMDA_PMID(2,45), PM_TYPE_U64, WEBLOG_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } },
+
+/* perserver.bytes.post */
+{ (void *)0,
+ { PMDA_PMID(2,46), PM_TYPE_U64, WEBLOG_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } },
+
+/* perserver.bytes.other */
+{ (void *)0,
+ { PMDA_PMID(2,47), PM_TYPE_U64, WEBLOG_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } },
+
+/* perserver.requests.size.zero */
+{ (void *)0,
+ { PMDA_PMID(2,48), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* perserver.requests.size.le3k */
+{ (void *)0,
+ { PMDA_PMID(2,49), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* perserver.requests.size.le10k */
+{ (void *)0,
+ { PMDA_PMID(2,50), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* perserver.requests.size.le30k */
+{ (void *)0,
+ { PMDA_PMID(2,51), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* perserver.requests.size.le100k */
+{ (void *)0,
+ { PMDA_PMID(2,52), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* perserver.requests.size.le300k */
+{ (void *)0,
+ { PMDA_PMID(2,53), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* perserver.requests.size.le1m */
+{ (void *)0,
+ { PMDA_PMID(2,54), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* perserver.requests.size.le3m */
+{ (void *)0,
+ { PMDA_PMID(2,55), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* perserver.requests.size.gt3m */
+{ (void *)0,
+ { PMDA_PMID(2,56), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* perserver.requests.size.unknown */
+{ (void *)0,
+ { PMDA_PMID(2,67), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* perserver.requests.client.total */
+{ (void *)0,
+ { PMDA_PMID(4,1), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* perserver.requests.cached.total */
+{ (void *)0,
+ { PMDA_PMID(4,11), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* perserver.requests.cached.size.zero */
+{ (void *)0,
+ { PMDA_PMID(4,12), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* perserver.requests.cached.size.le3k */
+{ (void *)0,
+ { PMDA_PMID(4,13), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* perserver.requests.cached.size.le10k */
+{ (void *)0,
+ { PMDA_PMID(4,14), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* perserver.requests.cached.size.le30k */
+{ (void *)0,
+ { PMDA_PMID(4,15), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* perserver.requests.cached.size.le100k */
+{ (void *)0,
+ { PMDA_PMID(4,16), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* perserver.requests.cached.size.le300k */
+{ (void *)0,
+ { PMDA_PMID(4,17), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* perserver.requests.cached.size.le1m */
+{ (void *)0,
+ { PMDA_PMID(4,18), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* perserver.requests.cached.size.le3m */
+{ (void *)0,
+ { PMDA_PMID(4,19), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* perserver.requests.cached.size.gt3m */
+{ (void *)0,
+ { PMDA_PMID(4,20), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* perserver.requests.cached.size.unknown */
+{ (void *)0,
+ { PMDA_PMID(4,21), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* perserver.requests.uncached.total */
+{ (void *)0,
+ { PMDA_PMID(4,31), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* perserver.requests.uncached.size.zero */
+{ (void *)0,
+ { PMDA_PMID(4,32), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* perserver.requests.uncached.size.le3k */
+{ (void *)0,
+ { PMDA_PMID(4,33), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* perserver.requests.uncached.size.le10k */
+{ (void *)0,
+ { PMDA_PMID(4,34), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* perserver.requests.uncached.size.le30k */
+{ (void *)0,
+ { PMDA_PMID(4,35), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* perserver.requests.uncached.size.le100k */
+{ (void *)0,
+ { PMDA_PMID(4,36), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* perserver.requests.uncached.size.le300k */
+{ (void *)0,
+ { PMDA_PMID(4,37), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* perserver.requests.uncached.size.le1m */
+{ (void *)0,
+ { PMDA_PMID(4,38), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* perserver.requests.uncached.size.le3m */
+{ (void *)0,
+ { PMDA_PMID(4,39), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* perserver.requests.uncached.size.gt3m */
+{ (void *)0,
+ { PMDA_PMID(4,40), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* perserver.requests.uncached.size.unknown */
+{ (void *)0,
+ { PMDA_PMID(4,41), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } },
+
+/* perserver.bytes.size.zero */
+{ (void *)0,
+ { PMDA_PMID(2,57), PM_TYPE_U64, WEBLOG_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } },
+
+/* perserver.bytes.size.le3k */
+{ (void *)0,
+ { PMDA_PMID(2,58), PM_TYPE_U64, WEBLOG_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } },
+
+/* perserver.bytes.size.le10k */
+{ (void *)0,
+ { PMDA_PMID(2,59), PM_TYPE_U64, WEBLOG_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } },
+
+/* perserver.bytes.size.le30k */
+{ (void *)0,
+ { PMDA_PMID(2,60), PM_TYPE_U64, WEBLOG_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } },
+
+/* perserver.bytes.size.le100k */
+{ (void *)0,
+ { PMDA_PMID(2,61), PM_TYPE_U64, WEBLOG_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } },
+
+/* perserver.bytes.size.le300k */
+{ (void *)0,
+ { PMDA_PMID(2,62), PM_TYPE_U64, WEBLOG_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } },
+
+/* perserver.bytes.size.le1m */
+{ (void *)0,
+ { PMDA_PMID(2,63), PM_TYPE_U64, WEBLOG_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } },
+
+/* perserver.bytes.size.le3m */
+{ (void *)0,
+ { PMDA_PMID(2,64), PM_TYPE_U64, WEBLOG_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } },
+
+/* perserver.bytes.size.gt3m */
+{ (void *)0,
+ { PMDA_PMID(2,65), PM_TYPE_U64, WEBLOG_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } },
+
+/* perserver.bytes.cached.total */
+{ (void *)0,
+ { PMDA_PMID(4,51), PM_TYPE_U64, WEBLOG_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } },
+
+/* perserver.bytes.cached.size.zero */
+{ (void *)0,
+ { PMDA_PMID(4,52), PM_TYPE_U64, WEBLOG_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } },
+
+/* perserver.bytes.cached.size.le3k */
+{ (void *)0,
+ { PMDA_PMID(4,53), PM_TYPE_U64, WEBLOG_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } },
+
+/* perserver.bytes.cached.size.le10k */
+{ (void *)0,
+ { PMDA_PMID(4,54), PM_TYPE_U64, WEBLOG_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } },
+
+/* perserver.bytes.cached.size.le30k */
+{ (void *)0,
+ { PMDA_PMID(4,55), PM_TYPE_U64, WEBLOG_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } },
+
+/* perserver.bytes.cached.size.le100k */
+{ (void *)0,
+ { PMDA_PMID(4,56), PM_TYPE_U64, WEBLOG_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } },
+
+/* perserver.bytes.cached.size.le300k */
+{ (void *)0,
+ { PMDA_PMID(4,57), PM_TYPE_U64, WEBLOG_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } },
+
+/* perserver.bytes.cached.size.le1m */
+{ (void *)0,
+ { PMDA_PMID(4,58), PM_TYPE_U64, WEBLOG_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } },
+
+/* perserver.bytes.cached.size.le3m */
+{ (void *)0,
+ { PMDA_PMID(4,59), PM_TYPE_U64, WEBLOG_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } },
+
+/* perserver.bytes.cached.size.gt3m */
+{ (void *)0,
+ { PMDA_PMID(4,60), PM_TYPE_U64, WEBLOG_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } },
+
+/* perserver.bytes.uncached.total */
+{ (void *)0,
+ { PMDA_PMID(4,71), PM_TYPE_U64, WEBLOG_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } },
+
+/* perserver.bytes.uncached.size.zero */
+{ (void *)0,
+ { PMDA_PMID(4,72), PM_TYPE_U64, WEBLOG_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } },
+
+/* perserver.bytes.uncached.size.le3k */
+{ (void *)0,
+ { PMDA_PMID(4,73), PM_TYPE_U64, WEBLOG_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } },
+
+/* perserver.bytes.uncached.size.le10k */
+{ (void *)0,
+ { PMDA_PMID(4,74), PM_TYPE_U64, WEBLOG_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } },
+
+/* perserver.bytes.uncached.size.le30k */
+{ (void *)0,
+ { PMDA_PMID(4,75), PM_TYPE_U64, WEBLOG_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } },
+
+/* perserver.bytes.uncached.size.le100k */
+{ (void *)0,
+ { PMDA_PMID(4,76), PM_TYPE_U64, WEBLOG_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } },
+
+/* perserver.bytes.uncached.size.le300k */
+{ (void *)0,
+ { PMDA_PMID(4,77), PM_TYPE_U64, WEBLOG_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } },
+
+/* perserver.bytes.uncached.size.le1m */
+{ (void *)0,
+ { PMDA_PMID(4,78), PM_TYPE_U64, WEBLOG_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } },
+
+/* perserver.bytes.uncached.size.le3m */
+{ (void *)0,
+ { PMDA_PMID(4,79), PM_TYPE_U64, WEBLOG_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } },
+
+/* perserver.bytes.uncached.size.gt3m */
+{ (void *)0,
+ { PMDA_PMID(4,80), PM_TYPE_U64, WEBLOG_INDOM, PM_SEM_COUNTER,
+ PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } },
+/*
+ * Added in PCPWEB 1.1.1
+ */
+
+/* perserver.logidletime */
+{ (void *)0,
+ { PMDA_PMID(2,68), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_DISCRETE,
+ PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_SEC, 0) } },
+
+};
+
+/* number of metrics */
+static int numMetrics = (sizeof(wl_metrics)/sizeof(wl_metrics[0]));
+
+/* number of instance domains */
+static int numIndoms = sizeof(wl_indomTable)/sizeof(wl_indomTable[0]);
+
+/* mask to get the cluster from a PMID */
+static int _clusterMask = (1<<22) - (1<<10);
+
+/* refresh all logs if wl_updateAll != 0 */
+int wl_updateAll = 0;
+
+/* time in milliseconds to update all the logs */
+__uint32_t wl_catchupTime = 0;
+
+/* time log refresh was started */
+time_t wl_timeOfRefresh = 0;
+
+/* flag to indicate DSO or Daemon */
+int wl_isDSO = 0;
+
+/* request size categories */
+long wl_sizes[] = {
+ 0, 3*1024, 10*1024, 30*1024, 100*1024, 300*1024, 1024*1024, 3*1024*1024, 0
+};
+
+#define BUFFER_LEN 2048
+
+static pmdaExt *extp; /* set in web_init() */
+
+#ifdef HAVE_SIGHUP
+/*
+ * Signal handler for an sproc receiving TERM (probably from parent)
+ */
+static void
+onhup(int s)
+{
+ _exit(s != SIGHUP);
+}
+#endif
+
+/*
+ * Replacement for fgets using the FileInfo structure
+ */
+
+int
+wl_gets(FileInfo *fip, char **line)
+{
+ char *p;
+ int nch;
+ int sts;
+
+ if (fip->filePtr < 0) {
+ return -1;
+ }
+
+ p = fip->bp;
+
+more:
+ while (p < fip->bend) {
+ if (*p == '\n') {
+ /* newline, we are done */
+ *p++ = '\0';
+ *line = fip->bp;
+ fip->bp = p;
+ return p - *line;
+ }
+ p++;
+ }
+
+ /* out the end of the buffer, and no newline */
+ nch = fip->bend - fip->bp;
+ if (nch == FIBUFSIZE) {
+ /* buffer full, and no newline! ... truncate and return */
+ fip->buf[FIBUFSIZE-1] = '\n';
+ p = &fip->buf[FIBUFSIZE-1];
+ goto more;
+ }
+ if (nch)
+ /* shuffle partial line to start of buffer */
+ memcpy(fip->buf, fip->bp, nch);
+ fip->bp = fip->buf;
+ fip->bend = &fip->buf[nch];
+
+ /* refill */
+ sts = read(fip->filePtr, fip->bend, FIBUFSIZE-nch);
+ if (sts <= 0) {
+ /* no more, either terminate last line, or really return status */
+ if (nch) {
+ *fip->bend = '\n';
+ sts = 1;
+ }
+ else {
+ return sts;
+ }
+ }
+ p = fip->bend;
+ fip->bend = &fip->bend[sts];
+ goto more;
+}
+
+/*
+ * Open a log file and seek to the end
+ */
+
+int
+openLogFile(FileInfo *theFile)
+{
+ int diff = theFile->filePtr;
+ char *line = (char *)0;
+
+ theFile->filePtr = open(theFile->fileName, O_RDONLY);
+
+ if (theFile->filePtr == -1) {
+ if (theFile->filePtr != diff) {
+ logmessage(LOG_ERR, "openLogFile: open %s: %s\n",
+ theFile->fileName, osstrerror());
+ }
+ return -1;
+ }
+
+ if (fstat(theFile->filePtr, &(theFile->fileStat)) < 0) {
+ logmessage(LOG_ERR, "openLogFile: stat for %s: %s\n",
+ theFile->fileName, osstrerror());
+ wl_close(theFile->filePtr);
+ return -1;
+ }
+
+ logmessage(LOG_INFO, "%s opened (fd=%d, inode=%d)\n",
+ theFile->fileName,
+ theFile->filePtr,
+ theFile->fileStat.st_ino);
+
+ /* throw away last line in file */
+ if (theFile->fileStat.st_size != 0) {
+ lseek(theFile->filePtr, -2L, SEEK_END);
+ wl_gets(theFile, &line);
+ }
+
+ if (fstat(theFile->filePtr, &(theFile->fileStat)) < 0) {
+ logmessage(LOG_ERR, "openLogFile: update stat for %s: %s\n",
+ theFile->fileName, osstrerror());
+ wl_close(theFile->filePtr);
+ return -1;
+ }
+
+/*
+* Check and warn if a log file has not been modified in the last 24 hours,
+* as this may indicate something is wrong with the PMDA's configuration,
+* or the Web server's configuration
+*/
+
+ diff = time((time_t*)0) - theFile->fileStat.st_mtime;
+ if (diff > DORMANT_WARN) {
+ logmessage(LOG_WARNING,
+ "log file %s has not been modified for at least %d days",
+ theFile->fileName,
+ diff / DORMANT_WARN);
+ }
+
+ return 0;
+}
+
+/*
+ * Check the log file is still the correct log file.
+ *
+ * If the file has not been modified in wl_chkDelay seconds, then reopen
+ * the file and compare the inodes.
+ * Otherwise the current inode and size of the file are checked.
+ *
+ * Returns a LogFileCode indicating the status of the log file.
+ */
+
+static int
+checkLogFile(FileInfo *theFile,
+ struct stat *tmpStat)
+{
+ int tmpFd = -1;
+ int result = wl_ok;
+
+/*
+ * File is closed, if enough time has elasped since last attempt, try to
+ * open it
+ */
+
+ if (theFile->filePtr < 0)
+ {
+ if (wl_timeOfRefresh - theFile->lastActive > wl_chkDelay)
+ {
+ theFile->lastActive = wl_timeOfRefresh;
+ if (openLogFile(theFile) < 0)
+ result = wl_unableToOpen;
+ else
+ result = wl_opened;
+ }
+ else
+ result = wl_closed;
+ }
+
+/* Get the file stat info on the open file */
+
+ if (theFile->filePtr >= 0) {
+ if (fstat(theFile->filePtr, tmpStat) < 0) {
+ logmessage(LOG_ERR, "checkLogFile: stat on open %s: %s\n",
+ theFile->fileName, osstrerror());
+ wl_close(theFile->filePtr);
+ result = wl_unableToStat;
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL0) {
+ logmessage(LOG_DEBUG,
+ "checkLogFile: could not stat %s\n",
+ theFile->fileName);
+ }
+#endif
+
+ }
+ }
+
+/*
+ * Check that we are dealing with a regular file. If is a character
+ * device or directory etc just ignore it.
+ */
+
+ if (result == wl_ok && !(theFile->fileStat.st_mode & S_IFREG)) {
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL2)
+ logmessage(LOG_DEBUG,
+ "%s is not a regular file. Skipping...\n",
+ theFile->fileName);
+#endif
+
+ result = wl_irregularFile;
+ }
+
+/*
+ * Check that the size hasn't gotten any smaller e.g. from ftruncate(2)
+ */
+
+ if (result == wl_ok && tmpStat->st_size < theFile->fileStat.st_size) {
+
+ logmessage(LOG_WARNING,
+ "%s stat - inode %d, size %d -> %d\n",
+ theFile->fileName,
+ theFile->fileStat.st_ino,
+ theFile->fileStat.st_size,
+ tmpStat->st_size);
+
+ result = wl_reopened;
+ }
+
+/*
+ * File was already open, check to see if it hasn't been modified, and
+ * that the last time we checked it was > wl_chkDelay ago.
+ */
+
+ if (result == wl_ok &&
+ tmpStat->st_mtime == theFile->fileStat.st_mtime &&
+ wl_timeOfRefresh - theFile->lastActive > wl_chkDelay) {
+
+ tmpFd = open(theFile->fileName, O_RDONLY);
+
+ if (tmpFd < 0) {
+ logmessage(LOG_ERR,
+ "checkLogFile: 2nd open to %s: %s\n",
+ theFile->fileName,
+ osstrerror());
+ wl_close(theFile->filePtr);
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL0) {
+ logmessage(LOG_DEBUG,
+ "checkLogFile: could not check %s\n",
+ theFile->fileName);
+ }
+#endif
+
+ }
+ else if (fstat(tmpFd, tmpStat) < 0) {
+ logmessage(LOG_ERR,
+ "checkLogFile: stat on inactive %s: %s\n",
+ theFile->fileName,
+ osstrerror());
+ wl_close(theFile->filePtr);
+ result = wl_unableToStat;
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL0) {
+ logmessage(LOG_DEBUG,
+ "checkLogFile: could not stat inactive %s\n",
+ theFile->fileName);
+ }
+#endif
+
+ }
+ else if (tmpStat->st_ino != theFile->fileStat.st_ino) {
+
+ logmessage(LOG_WARNING,
+ "%s inactive - inode %d -> %d\n",
+ theFile->fileName,
+ theFile->fileStat.st_ino,
+ tmpStat->st_ino);
+
+ result = wl_reopened;
+ }
+ else
+ theFile->lastActive = wl_timeOfRefresh;
+
+
+ if (tmpFd >= 0)
+ close(tmpFd);
+ }
+
+
+/*
+ * File needs to be reopened due to change in inode, smaller size, or lack
+ * of activity
+ */
+
+ if (result == wl_reopened) {
+
+ theFile->lastActive = wl_timeOfRefresh;
+
+ wl_close(theFile->filePtr);
+
+ if (openLogFile(theFile) < 0) {
+
+ logmessage(LOG_WARNING,
+ "checkLogFile: unable to reopen %s\n",
+ theFile->fileName);
+ result = wl_unableToOpen;
+ }
+
+/* update the stat information using new file desc */
+
+ else if (fstat(theFile->filePtr, tmpStat) < 0) {
+ logmessage(LOG_ERR,
+ "checkLogFile - stat on reopened %s: %s\n",
+ theFile->fileName,
+ osstrerror());
+ wl_close(theFile->filePtr);
+ result = wl_unableToStat;
+ }
+ }
+
+/* if the size has increased in the logs, then change the lastActive time */
+
+ if (result == wl_ok && tmpStat->st_mtime > theFile->fileStat.st_mtime) {
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL1)
+ logmessage(LOG_DEBUG, "%s grew %d bytes\n",
+ theFile->fileName,
+ tmpStat->st_size - theFile->fileStat.st_size);
+#endif
+ theFile->lastActive = wl_timeOfRefresh;
+ }
+
+ return result;
+}
+
+/*
+ * Main function for sprocs. Contains an infinite loop selecting on the pipe from the
+ * main process. Anything on the pipe indicates a refresh is required.
+ */
+
+void
+sprocMain(void *sprocNum)
+{
+ int mySprocNum = *((int*)sprocNum);
+ int i = 0;
+ int sts = 0;
+ WebSproc *sprocData = &wl_sproc[mySprocNum];
+ WebServer *server = (WebServer*)0;
+
+ /* Pause a sec' so the output log doesn't get mucked up */
+ sleep(1);
+
+#ifdef HAVE_SIGHUP
+ /* SIGHUP when the parent dies */
+ signal(SIGHUP, onhup);
+#endif
+
+#ifdef HAVE_PRCTL
+#ifdef HAVE_PR_TERMCHILD
+ prctl(PR_TERMCHILD);
+#elif HAVE_PR_SET_PDEATHSIG
+ prctl(PR_SET_PDEATHSIG, SIGHUP);
+#endif
+#endif
+
+/* close channel to pmcd */
+ if (__pmSocketIPC(extp->e_infd))
+ __pmCloseSocket(extp->e_infd);
+ else if (close(extp->e_infd) < 0) {
+ logmessage(LOG_ERR, "sprocMain: pmcd ch. close(fd=%d) failed: %s\n",
+ extp->e_infd, osstrerror());
+ }
+ if (__pmSocketIPC(extp->e_outfd))
+ __pmCloseSocket(extp->e_outfd);
+ else if (close(extp->e_outfd) < 0) {
+ logmessage(LOG_ERR, "sprocMain: pmcd ch. close(fd=%d) failed: %s\n",
+ extp->e_outfd, osstrerror());
+ }
+
+/* close pipes to main process which are not to be used */
+
+ if(close(sprocData->inFD[1]) < 0) {
+ logmessage(LOG_ERR, "sprocMain[%d]: pipe close(fd=%d) failed: %s\n",
+ mySprocNum, sprocData->inFD[1], osstrerror());
+ }
+ if(close(sprocData->outFD[0]) < 0) {
+ logmessage(LOG_ERR, "sprocMain[%d]: pipe close(fd=%d) failed: %s\n",
+ mySprocNum, sprocData->outFD[0], osstrerror());
+ }
+
+/* open up all file descriptors */
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL2)
+ logmessage(LOG_DEBUG, "Sproc %d started for servers %d to %d\n",
+ mySprocNum,
+ sprocData->firstServer,
+ sprocData->lastServer);
+#endif
+
+ for (i=sprocData->firstServer; i<=sprocData->lastServer; i++)
+ {
+ server = &wl_servers[i];
+ if (server->counts.active) {
+ openLogFile(&(server->access));
+ openLogFile(&(server->error));
+ }
+ }
+
+/* wait for message from pmda to probe files */
+
+ for (;;) {
+ sts = read(sprocData->inFD[0], &i, sizeof(i));
+ if (sts <= 0) {
+ logmessage(LOG_ERR, "Sproc[%d] read(fd=%d) failed: %s\n",
+ mySprocNum, sprocData->inFD[0], osstrerror());
+ exit(1);
+ }
+ refresh(sprocData);
+ sts = write(sprocData->outFD[1], &i, sizeof(i));
+ if (sts <= 0) {
+ logmessage(LOG_ERR, "Sproc[%d] write(fd=%d) failed: %s\n",
+ sprocData->outFD[1], mySprocNum, osstrerror());
+ exit(1);
+ }
+ }
+}
+
+/*
+ * Refresh all the server log files that this process monitors.
+ * Any entries are parsed, categorised and added to the appropriate metrics.
+ */
+
+void
+refresh(WebSproc* proc)
+{
+ struct stat tmpStat;
+
+ WebServer *server = (WebServer *)0;
+ WebCount *count = (WebCount *)0;
+ FileInfo *accessFile = (FileInfo *)0;
+ FileInfo *errorFile = (FileInfo *)0;
+
+ char *line = (char *)0;
+ char *end = (char *)0;
+ int httpMethod = 0;
+ long size = 0;
+ int sizeIndex = 0;
+ int newLength = 0;
+ int i = 0;
+ int sts = 0;
+ int result = wl_ok;
+ int ok = 0;
+ time_t currentTime;
+ size_t nmatch = 5;
+ regmatch_t pmatch[5];
+
+
+ currentTime = time((time_t*)0);
+
+/* iterate through each flagged server */
+
+ for (i=proc->firstServer; i<=proc->lastServer; i++) {
+
+ server = &(wl_servers[i]);
+ accessFile = &(server->access);
+ errorFile = &(server->error);
+
+ if ((server->update || wl_updateAll) && server->counts.active) {
+
+ server->counts.numLogs = 0;
+
+/* check access log still exists */
+
+ result = checkLogFile(accessFile, &tmpStat);
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL2)
+ logmessage(LOG_DEBUG,
+ "checkLogFile returned %d for server %d (access)\n",
+ result,
+ i);
+#endif
+
+/* scan access log */
+
+ if (result == wl_ok || result == wl_reopened ||
+ result == wl_opened) {
+
+ server->counts.numLogs++;
+ server->counts.modTime = (__uint32_t)(currentTime -
+ tmpStat.st_mtime);
+
+ while (accessFile->fileStat.st_size < tmpStat.st_size) {
+
+ sts = wl_gets(accessFile, &line);
+ if (sts <= 0) {
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL0)
+ logmessage(LOG_DEBUG,
+ "Short read of %s by %d bytes\n",
+ accessFile->fileName,
+ tmpStat.st_size - accessFile->fileStat.st_size);
+#endif
+
+ if (sts == 0) {
+ logmessage(LOG_WARNING,
+ "refresh %s: unexpected eof\n",
+ accessFile->fileName);
+ }
+ else {
+ logmessage(LOG_ERR, "refresh %s: %s\n",
+ accessFile->fileName, osstrerror());
+ }
+
+ wl_close(accessFile->filePtr);
+ accessFile->lastActive -= wl_chkDelay;
+ break;
+ }
+
+ accessFile->fileStat.st_size += sts;
+
+ if (proc->strLength == 0 || proc->strLength <= sts)
+ newLength = sts > 255 ? ((sts / 256) + 1) * 256 : 256;
+ else
+ newLength = proc->strLength;
+
+ if (newLength > proc->strLength)
+ {
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL2) {
+ logmessage(LOG_DEBUG,
+ "Resizing strings from %d to %d bytes\n",
+ proc->strLength,
+ newLength);
+ }
+#endif
+ proc->methodStr = (char*)realloc(proc->methodStr,
+ newLength * sizeof(char));
+ proc->sizeStr = (char*)realloc(proc->sizeStr,
+ newLength * sizeof(char));
+ proc->c_statusStr = (char*)realloc(proc->c_statusStr,
+ newLength * sizeof(char));
+ proc->s_statusStr = (char*)realloc(proc->s_statusStr,
+ newLength * sizeof(char));
+ proc->strLength = newLength;
+ }
+
+ if (proc->methodStr == (char *)0 ||
+ proc->sizeStr == (char *)0 ||
+ proc->c_statusStr == (char *)0 ||
+ proc->s_statusStr == (char *)0 ) {
+ logmessage(LOG_ERR,
+ "Unable to allocate %d bytes to strings",
+ newLength);
+ proc->strLength = 0;
+ if (proc->methodStr != (char *)0)
+ free(proc->methodStr);
+ if (proc->sizeStr != (char *)0)
+ free(proc->sizeStr);
+ if (proc->c_statusStr != (char *)0)
+ free(proc->c_statusStr);
+ if (proc->s_statusStr != (char *)0)
+ free(proc->s_statusStr);
+
+ break;
+ }
+
+ ok = 0;
+
+ if (wl_regexTable[accessFile->format].posix_regexp) {
+ if (regexec(wl_regexTable[accessFile->format].regex,
+ line, nmatch, pmatch, 0) == 0) {
+
+ if(pmatch[1].rm_so < 0 || pmatch[2].rm_so < 0) {
+ logmessage(LOG_ERR,
+ "failed to match method and size: %s\n",
+ line);
+ continue;
+ }
+
+ if(server->counts.extendedp) {
+ if(pmatch[3].rm_so < 0 || pmatch[4].rm_so < 0) {
+ logmessage(LOG_ERR,
+ "failed to match status codes: %s\n",
+ line);
+ continue;
+ }
+ }
+
+ line[pmatch[wl_regexTable[accessFile->format].methodPos].rm_eo] = '\0';
+ strncpy(proc->methodStr, &line[pmatch[wl_regexTable[accessFile->format].methodPos].rm_so],
+ (pmatch[wl_regexTable[accessFile->format].methodPos].rm_eo -
+ pmatch[wl_regexTable[accessFile->format].methodPos].rm_so) + 1);
+
+ line[pmatch[wl_regexTable[accessFile->format].sizePos].rm_eo] = '\0';
+ strncpy(proc->sizeStr, &line[pmatch[wl_regexTable[accessFile->format].sizePos].rm_so],
+ (pmatch[wl_regexTable[accessFile->format].sizePos].rm_eo -
+ pmatch[wl_regexTable[accessFile->format].sizePos].rm_so) + 1);
+
+ if(server->counts.extendedp) {
+ line[pmatch[wl_regexTable[accessFile->format].c_statusPos].rm_eo] = '\0';
+ strncpy(proc->c_statusStr, &line[pmatch[wl_regexTable[accessFile->format].c_statusPos].rm_so],
+ (pmatch[wl_regexTable[accessFile->format].c_statusPos].rm_eo -
+ pmatch[wl_regexTable[accessFile->format].c_statusPos].rm_so) + 1);
+
+ line[pmatch[wl_regexTable[accessFile->format].s_statusPos].rm_eo] = '\0';
+ strncpy(proc->s_statusStr, &line[pmatch[wl_regexTable[accessFile->format].s_statusPos].rm_so],
+ (pmatch[wl_regexTable[accessFile->format].s_statusPos].rm_eo -
+ pmatch[wl_regexTable[accessFile->format].s_statusPos].rm_so) + 1);
+ } else {
+ proc->c_statusStr[0] = '\0';
+ proc->s_statusStr[0] = '\0';
+ }
+ ok = 1;
+ }
+#ifdef PCP_DEBUG
+ else if (pmDebug & DBG_TRACE_APPL2)
+ logmessage(LOG_DEBUG, "Regex failed on %s\n", line);
+#endif
+ }
+#ifdef NON_POSIX_REGEX
+ else if (regex(wl_regexTable[accessFile->format].np_regex,
+ line, proc->methodStr, proc->sizeStr, proc->c_statusStr, proc->s_statusStr) != NULL) {
+ ok = 1;
+ }
+#ifdef PCP_DEBUG
+ else if (pmDebug & DBG_TRACE_APPL2)
+ logmessage(LOG_DEBUG, "Regex failed on %s\n", line);
+#endif
+#endif
+ if ( ok ) {
+
+ for (line = proc->methodStr; *line; line++)
+ *line = toupper((int)*line);
+
+ httpMethod = wl_httpOther;
+ switch(proc->methodStr[0]) {
+ case 'G':
+ if(strcmp(proc->methodStr, "GET") == 0) {
+ httpMethod = wl_httpGet;
+ }
+ break;
+ case 'O':
+ if(strcmp(proc->methodStr, "O") == 0) {
+ httpMethod = wl_httpGet;
+ }
+ break;
+ case 'H':
+ if(strcmp(proc->methodStr, "HEAD") == 0) {
+ httpMethod = wl_httpHead;
+ }
+ break;
+ case 'P':
+ if(strcmp(proc->methodStr, "POST") == 0 ||
+ strcmp(proc->methodStr, "PUT") == 0) {
+ httpMethod = wl_httpPost;
+ }
+ break;
+ case 'I':
+ if(strcmp(proc->methodStr, "I") == 0) {
+ httpMethod = wl_httpPost;
+ }
+ break;
+ }
+
+ if (strcmp(proc->sizeStr, "-") == 0 ||
+ strcmp(proc->sizeStr, " ") == 0) {
+ size = 0;
+ sizeIndex = wl_unknownSize;
+ }
+ else {
+ size = strtol(proc->sizeStr, &end, 10);
+ if (*end != '\0') {
+ logmessage(LOG_ERR, "Bad size (%s) @ %s",
+ proc->sizeStr,
+ line);
+ continue;
+ }
+
+ for (sizeIndex = 0;
+ sizeIndex < wl_gt3m && size > wl_sizes[sizeIndex];
+ sizeIndex++);
+ }
+
+ count = &(server->counts);
+ count->methodReq[httpMethod]++;
+ count->methodBytes[httpMethod] += size;
+
+ count->sizeReq[sizeIndex]++;
+ count->sizeBytes[sizeIndex] += size;
+
+ count->sumReq++;
+ count->sumBytes += size;
+
+ if(server->counts.extendedp == 1) {
+ /* common extended format */
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL2) {
+ logmessage(LOG_DEBUG,
+ "Access: Server=%d, line=%s [CEF]\n M: %s S: %s CS: %s, SS: %s",
+ i,
+ line,
+ proc->methodStr,
+ proc->sizeStr,
+ proc->c_statusStr,
+ proc->s_statusStr);
+ }
+#endif
+
+ /*
+ * requested page is not in client/browser cache, nor in the
+ * server's cache so it has been fetched from the remote server
+ */
+ if(strcmp(proc->c_statusStr, "200") == 0 &&
+ strcmp(proc->s_statusStr, "200") == 0) {
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL2) {
+ logmessage(LOG_DEBUG,
+ "Access: Server=%d, REMOTE fetch: of %.0f bytes\n",
+ i,
+ atof(proc->sizeStr));
+ }
+#endif
+ /*
+ * now bucket the size
+ */
+ if (strcmp(proc->sizeStr, "-") == 0 ||
+ strcmp(proc->sizeStr, " ") == 0) {
+ size = 0;
+ sizeIndex = wl_unknownSize;
+ }
+ else {
+ size = strtol(proc->sizeStr, &end, 10);
+ if (*end != '\0') {
+ logmessage(LOG_ERR, "Bad size (%s) @ %s",
+ proc->sizeStr,
+ line);
+ continue;
+ }
+
+ for (sizeIndex = 0;
+ sizeIndex < wl_gt3m && size > wl_sizes[sizeIndex];
+ sizeIndex++);
+ }
+ count->uncached_sumReq++;
+ count->uncached_sumBytes += size;
+ count->uncached_sizeReq[sizeIndex]++;
+ count->uncached_sizeBytes[sizeIndex] += size;
+
+ }
+
+ /*
+ * requested page is not in client/browser cache, but is in the
+ * server's cache so it is just returned to the client (a cache hit)
+ */
+ if(strcmp(proc->c_statusStr, "200") == 0 &&
+ (strcmp(proc->s_statusStr, "304") == 0 ||
+ strcmp(proc->s_statusStr, "-") == 0)) {
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL2) {
+ logmessage(LOG_DEBUG,
+ "Access: Server=%d, CACHE return: of %.0f bytes\n",
+ i,
+ atof(proc->sizeStr));
+ }
+#endif
+ /*
+ * now bucket the size
+ */
+ if (strcmp(proc->sizeStr, "-") == 0 ||
+ strcmp(proc->sizeStr, " ") == 0) {
+ size = 0;
+ sizeIndex = wl_unknownSize;
+ }
+ else {
+ size = strtol(proc->sizeStr, &end, 10);
+ if (*end != '\0') {
+ logmessage(LOG_ERR, "Bad size (%s) @ %s",
+ proc->sizeStr,
+ line);
+ continue;
+ }
+
+ for (sizeIndex = 0;
+ sizeIndex < wl_gt3m && size > wl_sizes[sizeIndex];
+ sizeIndex++);
+ }
+ count->cached_sumReq++;
+ count->cached_sumBytes += size;
+ count->cached_sizeReq[sizeIndex]++;
+ count->cached_sizeBytes[sizeIndex] += size;
+
+ }
+
+ /*
+ * requested page is in client/browser cache
+ */
+ if(strcmp(proc->c_statusStr, "304") == 0 &&
+ (strcmp(proc->s_statusStr, "304") == 0 ||
+ strcmp(proc->s_statusStr, "-") == 0)) {
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL2) {
+ logmessage(LOG_DEBUG,
+ "Access: Server=%d, CLIENT hit\n",
+ i);
+ }
+#endif
+ count->client_sumReq++;
+ }
+ } else if(server->counts.extendedp == 2) {
+ /* default squid format */
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL2) {
+ logmessage(LOG_DEBUG,
+ "Access: Server=%d, line=%s [squid]\n M: %s S: %s CS: %s, SS: %s",
+ i,
+ line,
+ proc->methodStr,
+ proc->sizeStr,
+ proc->c_statusStr,
+ proc->s_statusStr);
+ }
+#endif
+
+ /*
+ * requested page is not in client/browser cache, nor in the
+ * server's cache so it has been fetched from the remote server
+ */
+ if(strcmp(proc->c_statusStr, "200") == 0 &&
+ (strstr(proc->s_statusStr, "_MISS") != NULL ||
+ strstr(proc->s_statusStr, "_CLIENT_REFRESH") != NULL ||
+ strstr(proc->s_statusStr, "_SWAPFAIL") != NULL)) {
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL2) {
+ logmessage(LOG_DEBUG,
+ "Access: Server=%d, REMOTE fetch: of %.0f bytes\n",
+ i,
+ atof(proc->sizeStr));
+ }
+#endif
+ /*
+ * now bucket the size
+ */
+ if (strcmp(proc->sizeStr, "-") == 0 ||
+ strcmp(proc->sizeStr, " ") == 0) {
+ size = 0;
+ sizeIndex = wl_unknownSize;
+ }
+ else {
+ size = strtol(proc->sizeStr, &end, 10);
+ if (*end != '\0') {
+ logmessage(LOG_ERR, "Bad size (%s) @ %s",
+ proc->sizeStr,
+ line);
+ continue;
+ }
+
+ for (sizeIndex = 0;
+ sizeIndex < wl_gt3m && size > wl_sizes[sizeIndex];
+ sizeIndex++);
+ }
+ count->uncached_sumReq++;
+ count->uncached_sumBytes += size;
+ count->uncached_sizeReq[sizeIndex]++;
+ count->uncached_sizeBytes[sizeIndex] += size;
+
+ }
+
+ /*
+ * requested page is not in client/browser cache, but is in the
+ * server's cache so it is just returned to the client (a cache hit)
+ */
+ if(strcmp(proc->c_statusStr, "200") == 0 &&
+ strstr(proc->s_statusStr, "_HIT") != NULL) {
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL2) {
+ logmessage(LOG_DEBUG,
+ "Access: Server=%d, CACHE return: of %.0f bytes\n",
+ i,
+ atof(proc->sizeStr));
+ }
+#endif
+ /*
+ * now bucket the size
+ */
+ if (strcmp(proc->sizeStr, "-") == 0 ||
+ strcmp(proc->sizeStr, " ") == 0) {
+ size = 0;
+ sizeIndex = wl_unknownSize;
+ }
+ else {
+ size = strtol(proc->sizeStr, &end, 10);
+ if (*end != '\0') {
+ logmessage(LOG_ERR, "Bad size (%s) @ %s",
+ proc->sizeStr,
+ line);
+ continue;
+ }
+
+ for (sizeIndex = 0;
+ sizeIndex < wl_gt3m && size > wl_sizes[sizeIndex];
+ sizeIndex++);
+ }
+ count->cached_sumReq++;
+ count->cached_sumBytes += size;
+ count->cached_sizeReq[sizeIndex]++;
+ count->cached_sizeBytes[sizeIndex] += size;
+ }
+
+ /*
+ * requested page is in client/browser cache
+ */
+ if(strcmp(proc->c_statusStr, "304") == 0) {
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL2) {
+ logmessage(LOG_DEBUG,
+ "Access: Server=%d, CLIENT hit\n",
+ i);
+ }
+#endif
+ count->client_sumReq++;
+ }
+ }
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL2) {
+ logmessage(LOG_DEBUG,
+ "Access: Server=%d, line=%s\n method=%s [%d], size=%s=%d [%d]\n",
+ i,
+ line,
+ proc->methodStr,
+ httpMethod,
+ proc->sizeStr,
+ size,
+ sizeIndex);
+ }
+#endif
+
+ }
+ }
+ accessFile->fileStat = tmpStat;
+ }
+
+ result = checkLogFile(errorFile, &tmpStat);
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL2)
+ logmessage(LOG_DEBUG,
+ "checkLogFile returned %d for server %d (error)\n",
+ result,
+ i);
+#endif
+
+ /* scan error log */
+
+ if (result == wl_ok || result == wl_reopened ||
+ result == wl_opened) {
+
+ server->counts.numLogs++;
+
+ while (errorFile->fileStat.st_size < tmpStat.st_size) {
+ sts = wl_gets(errorFile, &line);
+ if (sts <= 0) {
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL0)
+ logmessage(LOG_DEBUG, "%s was %d bytes short\n",
+ errorFile->fileName,
+ tmpStat.st_size -
+ errorFile->fileStat.st_size);
+#endif
+
+ if (sts < 0) {
+ logmessage(LOG_ERR, "refresh %s: %s\n",
+ errorFile->fileName, osstrerror());
+ }
+ else {
+ logmessage(LOG_WARNING,
+ "refresh %s: unexpected eof\n",
+ errorFile->fileName);
+ }
+
+ wl_close(errorFile->filePtr);
+ errorFile->lastActive -= wl_chkDelay;
+ break;
+ }
+
+ errorFile->fileStat.st_size += sts;
+
+ if(wl_regexTable[errorFile->format].posix_regexp) {
+ if (regexec(wl_regexTable[errorFile->format].regex,
+ line, nmatch, pmatch, 0) == 0) {
+ server->counts.errors++;
+ }
+#ifdef NON_POSIX_REGEX
+ } else {
+ if (regex(wl_regexTable[errorFile->format].np_regex,
+ line, proc->methodStr, proc->sizeStr) != NULL) {
+ server->counts.errors++;
+ }
+#endif
+ }
+ }
+ errorFile->fileStat = tmpStat;
+ }
+ }
+
+ /* check to see if a server is inactive but has a file open. It may
+ have just been deactivated */
+
+ else if ((server->update || wl_updateAll) && !server->counts.active) {
+
+ if (accessFile->filePtr >= 0) {
+
+ logmessage(LOG_WARNING,
+ "Closing inactive server %d access file: %s\n",
+ i,
+ accessFile->fileName);
+
+ wl_close(accessFile->filePtr);
+ }
+
+ if (errorFile->filePtr >= 0) {
+
+ logmessage(LOG_WARNING,
+ "Closing inactive server %d error file: %s\n",
+ i,
+ errorFile->fileName);
+
+ wl_close(errorFile->filePtr);
+ }
+ }
+ }
+}
+
+/*
+ * Initialise the indom and meta tables
+ * Check that we can do direct mapping.
+ */
+
+/*
+ * Mark servers that are required in the latest profile.
+ */
+static int
+web_profile(__pmProfile *prof, pmdaExt *ext)
+{
+ pmdaIndom *idp = wl_indomTable;
+ int j;
+
+ ext->e_prof = prof;
+ for (j = 0; j < idp->it_numinst; j++) {
+ if (__pmInProfile(idp->it_indom, prof, idp->it_set[j].i_inst))
+ wl_servers[j].update = 1;
+ else
+ wl_servers[j].update = 0;
+ }
+
+ return 0;
+}
+
+/*
+ * Probe servers for log file changes.
+ * Only those servers that are marked will be requsted. Therefore, if an sproc does
+ * not have any marked servers, it will not be signalled.
+ * NOTE: The main process completes its refresh before signalling the other sprocs.
+ */
+
+void
+probe(void)
+{
+ int i = 0;
+ int j = 0;
+ int sts = 0;
+ int dummy = 1;
+ int sprocsUsed = 0;
+ int nfds = 0;
+ fd_set rfds;
+ fd_set tmprfds;
+ int thisFD;
+ WebSproc *sprocData = (WebSproc*)0;
+ struct timeval theTime;
+
+ __pmtimevalNow(&theTime);
+
+ wl_timeOfRefresh = theTime.tv_sec;
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL1)
+ logmessage(LOG_DEBUG, "Starting probe at %d\n", wl_timeOfRefresh);
+#endif
+
+ FD_ZERO(&rfds);
+
+/*
+ * Determine which sprocs have servers that must be refreshed.
+ * Add those sprocs pipes to the file descriptor list.
+ */
+
+ for (i=1; i<=wl_numSprocs; i++) {
+ sprocData = &wl_sproc[i];
+
+ if (!wl_updateAll) {
+ for (j=sprocData->firstServer; j<=sprocData->lastServer; j++)
+ if (wl_servers[j].update)
+ break;
+ }
+ else {
+ for (j=sprocData->firstServer; j<=sprocData->lastServer; j++)
+ if (wl_servers[j].counts.active)
+ break;
+ }
+
+ if (j > sprocData->lastServer) {
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL2)
+ logmessage(LOG_DEBUG, "Skipping sproc %d\n", i);
+#endif
+ continue;
+ }
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL1)
+ logmessage(LOG_DEBUG,
+ "Told sproc %d to probe for at least server %d\n",
+ i,
+ j);
+#endif
+
+ sprocsUsed++;
+ thisFD = sprocData->outFD[0];
+ sts = write(sprocData->inFD[1], &dummy, sizeof(dummy));
+ if (sts < 0) {
+ logmessage(LOG_ERR, "Error on fetch write(fd=%d): %s",
+ sprocData->inFD[1], osstrerror());
+ exit(1);
+ }
+
+ FD_SET(thisFD, &rfds);
+ nfds = nfds < (thisFD + 1) ? thisFD + 1 : nfds;
+ }
+
+/*
+ * Check that we have to update the main process servers
+ */
+
+ sprocData = &wl_sproc[0];
+ if (!wl_updateAll) {
+ for (j=sprocData->firstServer; j<=sprocData->lastServer; j++)
+ if (wl_servers[j].update)
+ break;
+ }
+ else {
+ for (j=sprocData->firstServer; j<=sprocData->lastServer; j++)
+ if (wl_servers[j].counts.active)
+ break;
+ }
+
+ if (j <= sprocData->lastServer) {
+ refresh(&wl_sproc[0]);
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL2)
+ logmessage(LOG_DEBUG, "Done probe for 0 to %d\n",
+ sprocData->lastServer);
+#endif
+ }
+#ifdef PCP_DEBUG
+ else if (pmDebug & DBG_TRACE_APPL2)
+ logmessage(LOG_DEBUG, "Skipping refresh of main process\n");
+#endif
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL2) {
+ logmessage(LOG_DEBUG, "Waiting for reply from %d out of %d sprocs\n",
+ sprocsUsed,
+ wl_numSprocs);
+ }
+#endif
+
+/*
+ * Wait for all sprocs to reply
+ * Note: This could get into a hard select loop if an sproc losses it
+ */
+
+ for (i=0; i<sprocsUsed;) {
+ memcpy(&tmprfds, &rfds, sizeof(tmprfds));
+ sts = select(nfds, &tmprfds, (fd_set*)0, (fd_set*)0,
+ (struct timeval*)0);
+ if (sts < 0) {
+ logmessage(LOG_ERR, "Error on fetch select: %s", netstrerror());
+ exit(1);
+ }
+ else if (sts == 0)
+ continue;
+
+ i += sts;
+ for (j=1; j<=wl_numSprocs; j++) {
+ sprocData = &wl_sproc[j];
+ thisFD = sprocData->outFD[0];
+
+ if (FD_ISSET(thisFD, &tmprfds)) {
+ FD_CLR(sprocData->outFD[0], &rfds);
+ sts = read(thisFD, &dummy, sizeof(dummy));
+ if (sts < 0) {
+ logmessage(LOG_ERR, "Error on fetch read: %s",
+ osstrerror());
+ exit(1);
+ }
+ }
+ }
+ }
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL1)
+ logmessage(LOG_DEBUG, "Finished probe\n");
+#endif
+}
+
+/*
+ * Refresh all servers
+ * Usually called if no fetches have been received after a set time
+ */
+
+void
+refreshAll(void)
+{
+ struct timeval before;
+ struct timeval after;
+
+ wl_updateAll = 1;
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL1) {
+ logmessage(LOG_DEBUG, "Starting a refreshAll\n");
+ }
+#endif
+
+ __pmtimevalNow(&before);
+ probe();
+
+ __pmtimevalNow(&after);
+ wl_catchupTime = (after.tv_sec - before.tv_sec) * 1000;
+ wl_catchupTime += (after.tv_usec - before.tv_usec) / 1000;
+
+ wl_updateAll = 0;
+
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL1)
+ logmessage(LOG_DEBUG, "Probed all logs, took %d msec\n",
+ wl_catchupTime);
+#endif
+
+}
+
+/*
+ * Build a pmResult table of the requested metrics
+ */
+
+static int
+web_fetch(int numpmid, pmID pmidlist[], pmResult **resp, pmdaExt *ext)
+{
+ int i; /* over pmidlist[] */
+ int j; /* over vset->vlist[] */
+ int s; /* over server */
+ int sts;
+ int need;
+ int inst;
+ int numval;
+ static pmResult *res = (pmResult *)0;
+ static int maxnpmids = 0;
+ pmValueSet *vset = (pmValueSet *)0;
+ pmDesc *dp = (pmDesc *)0;
+ __pmID_int *pmidp;
+ pmAtomValue atom;
+ int haveValue = 0;
+ int type;
+ __psint_t m_offset = 0; /* initialize to pander to gcc */
+ int m_type = 0; /* initialize to pander to gcc */
+ int cluster;
+ __uint32_t tmp32;
+ __uint64_t tmp64;
+
+/* determine if the total aggregates are required, which forces a refresh
+ of all servers, and if a probe is require at all */
+
+ j = 0;
+ for (i = 0; i < numpmid; i++) {
+ pmidp = (__pmID_int *)&pmidlist[i];
+ if (pmidp->cluster == 1)
+ break;
+ else
+ j += pmidp->cluster;
+ }
+
+ if (i < numpmid) {
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL1)
+ logmessage(LOG_DEBUG, "web_fetch: refreshAll\n");
+#endif
+ refreshAll();
+ }
+ else if (j) {
+#ifdef PCP_DEBUG
+ if (pmDebug & DBG_TRACE_APPL1)
+ logmessage(LOG_DEBUG, "web_fetch: probe\n");
+#endif
+ probe();
+ }
+#ifdef PCP_DEBUG
+ else if (pmDebug & DBG_TRACE_APPL1)
+ logmessage(LOG_DEBUG, "web_fetch: no probes required\n");
+#endif
+
+
+ if (numpmid > maxnpmids) {
+ if (res != (pmResult *)0)
+ free(res);
+
+/* (numpmid - 1) because there's room for one valueSet in a pmResult */
+
+ need = sizeof(pmResult) + (numpmid - 1) * sizeof(pmValueSet *);
+ if ((res = (pmResult *) malloc(need)) == (pmResult *)0)
+ return -oserror();
+ maxnpmids = numpmid;
+ }
+
+ res->timestamp.tv_sec = 0;
+ res->timestamp.tv_usec = 0;
+ res->numpmid = numpmid;
+
+/*
+ * Get each corresponding metric from the meta table.
+ * Check that the metric has the correct cluster
+ */
+
+ for (i = 0; i < numpmid; i++) {
+
+ pmidp = (__pmID_int*)&pmidlist[i];
+ dp = (pmDesc *)0;
+
+ if (ext->e_direct) {
+
+ if (pmidp->item < numMetrics &&
+ pmidlist[i] == wl_metrics[pmidp->item].m_desc.pmid) {
+
+ dp = &wl_metrics[pmidp->item].m_desc;
+ m_offset = wl_metricInfo[pmidp->item].m_offset;
+ m_type = wl_metricInfo[pmidp->item].m_type;
+ }
+ }
+ else {
+ for (j = 0; j<numMetrics; j++) {
+ if (wl_metrics[j].m_desc.pmid == pmidlist[i]) {
+
+ dp = &wl_metrics[j].m_desc;
+ m_offset = wl_metricInfo[j].m_offset;
+ m_type = wl_metricInfo[j].m_type;
+ break;
+ }
+ }
+ }
+
+/*
+ * count the number of instances in profile
+ */
+
+ if (dp == (pmDesc *)0)
+ numval = PM_ERR_PMID;
+ else {
+ if (dp->indom != PM_INDOM_NULL) {
+ numval = 0;
+ __pmdaStartInst(dp->indom, ext);
+ while(__pmdaNextInst(&inst, ext)) {
+ numval++;
+ }
+ }
+ else {
+ numval = 1;
+ }
+ }
+
+
+ /* Must use individual malloc()s because of pmFreeResult() */
+
+ if (numval >= 1)
+ res->vset[i] = vset = (pmValueSet *)malloc(sizeof(pmValueSet) +
+ (numval - 1)*sizeof(pmValue));
+ else
+ res->vset[i] = vset = (pmValueSet*)malloc(sizeof(pmValueSet) -
+ sizeof(pmValue));
+
+ if (vset == (pmValueSet *)0) {
+ if (i) {
+ res->numpmid = i;
+ __pmFreeResultValues(res);
+ }
+ return -oserror();
+ }
+
+ vset->pmid = pmidlist[i];
+ vset->numval = numval;
+ vset->valfmt = PM_VAL_INSITU;
+ if (vset->numval <= 0)
+ continue;
+
+ if (dp->indom == PM_INDOM_NULL)
+ inst = PM_IN_NULL;
+ else {
+ __pmdaStartInst(dp->indom, ext);
+ __pmdaNextInst(&inst, ext);
+ }
+
+ type = dp->type;
+ pmidp = (__pmID_int *)&pmidlist[i];
+ j = 0;
+
+ do {
+ if (j == numval) {
+
+ /* more instances than expected! */
+
+ numval++;
+ res->vset[i] = vset = (pmValueSet *)realloc(vset,
+ sizeof(pmValueSet) + (numval - 1)*sizeof(pmValue));
+ if (vset == (pmValueSet *)0) {
+ if (i) {
+ res->numpmid = i;
+ __pmFreeResultValues(res);
+ }
+ return -oserror();
+ }
+ }
+
+ vset->vlist[j].inst = inst;
+
+ cluster = (dp->pmid & _clusterMask) >> 10;
+ haveValue = 1;
+
+ switch(m_type) {
+ case wl_globalPtr:
+ atom.ul = *(__uint32_t *)(m_offset);
+ break;
+
+ case wl_offset32:
+ if (wl_servers[inst].counts.active)
+ atom.ul = *((__uint32_t *)(((__psint_t)(&(wl_servers[inst].counts))) + m_offset));
+ else
+ haveValue = 0;
+ break;
+
+ case wl_offset64:
+ if (wl_servers[inst].counts.active)
+ atom.ull = *((__uint64_t *)(((__psint_t)(&(wl_servers[inst].counts))) + m_offset));
+ else
+ haveValue = 0;
+ break;
+
+ case wl_totalAggregate:
+
+ if (wl_numActive == 0)
+ haveValue = 0;
+ else {
+ switch(m_offset) {
+ case 0:
+ /* errors */
+ tmp32 = 0;
+ for (s = 0; s < wl_numServers; s++) {
+ if (wl_servers[s].counts.active) {
+ tmp32 += wl_servers[s].counts.errors;
+ }
+ }
+ atom.ul = tmp32;
+ break;
+ case 1:
+ /* requests */
+ tmp32 = 0;
+ for (s = 0; s < wl_numServers; s++) {
+ if (wl_servers[s].counts.active) {
+ tmp32 += wl_servers[s].counts.sumReq;
+ }
+ }
+ atom.ul = tmp32;
+ break;
+ case 2:
+ /* bytes */
+ tmp64 = 0;
+ for (s = 0; s < wl_numServers; s++) {
+ if (wl_servers[s].counts.active) {
+ tmp64 += wl_servers[s].counts.sumBytes;
+ }
+ }
+ atom.ull = tmp64;
+ break;
+ case 3:
+ /* client hit requests */
+ tmp32 = haveValue = 0;
+ for (s = 0; s < wl_numServers; s++) {
+ if (wl_servers[s].counts.active &&
+ wl_servers[s].counts.extendedp) {
+ haveValue = 1;
+ tmp32 += wl_servers[s].counts.client_sumReq;
+ }
+ }
+ atom.ul = tmp32;
+ break;
+ case 4:
+ /* cached hit requests */
+ tmp32 = haveValue = 0;
+ for (s = 0; s < wl_numServers; s++) {
+ if (wl_servers[s].counts.active &&
+ wl_servers[s].counts.extendedp) {
+ haveValue = 1;
+ tmp32 += wl_servers[s].counts.cached_sumReq;
+ }
+ }
+ atom.ul = tmp32;
+ break;
+ case 5:
+ /* cached hit requests */
+ tmp32 = haveValue = 0;
+ for (s = 0; s < wl_numServers; s++) {
+ if (wl_servers[s].counts.active &&
+ wl_servers[s].counts.extendedp) {
+ haveValue = 1;
+ tmp32 += wl_servers[s].counts.uncached_sumReq;
+ }
+ }
+ atom.ul = tmp32;
+ break;
+ case 6:
+ /* cached hit bytes */
+ tmp64 = haveValue = 0;
+ for (s = 0; s < wl_numServers; s++) {
+ if (wl_servers[s].counts.active &&
+ wl_servers[s].counts.extendedp) {
+ haveValue = 1;
+ tmp64 += wl_servers[s].counts.cached_sumBytes;
+ }
+ }
+ atom.ull = tmp64;
+ break;
+ case 7:
+ /* uncached bytes */
+ tmp64 = haveValue = 0;
+ for (s = 0; s < wl_numServers; s++) {
+ if (wl_servers[s].counts.active &&
+ wl_servers[s].counts.extendedp) {
+ haveValue = 1;
+ tmp64 += wl_servers[s].counts.uncached_sumBytes;
+ }
+ }
+ atom.ull = tmp64;
+ break;
+ default:
+ break;
+ }
+
+ }
+ break;
+
+ case wl_serverAggregate:
+
+ if (wl_servers[inst].counts.active == 0)
+ haveValue = 0;
+ else switch(m_offset) {
+ case 0:
+ /* requests */
+ atom.ul = wl_servers[inst].counts.sumReq;
+ break;
+ case 1:
+ /* bytes */
+ atom.ull = wl_servers[inst].counts.sumBytes;
+ break;
+ case 2:
+ /* client hit requests */
+ if( wl_servers[inst].counts.extendedp ) {
+ atom.ul = wl_servers[inst].counts.client_sumReq;
+ } else
+ haveValue = 0;
+ break;
+ case 3:
+ /* cache hit requests */
+ if( wl_servers[inst].counts.extendedp ) {
+ atom.ul = wl_servers[inst].counts.cached_sumReq;
+ } else
+ haveValue = 0;
+ break;
+ case 4:
+ /* uncached requests */
+ if( wl_servers[inst].counts.extendedp ) {
+ atom.ul = wl_servers[inst].counts.uncached_sumReq;
+ } else
+ haveValue = 0;
+ break;
+ case 5:
+ /* cached bytes */
+ if( wl_servers[inst].counts.extendedp ) {
+ atom.ull = wl_servers[inst].counts.cached_sumBytes;
+ } else
+ haveValue = 0;
+ break;
+ case 6:
+ /* uncached bytes */
+ if( wl_servers[inst].counts.extendedp ) {
+ atom.ull = wl_servers[inst].counts.uncached_sumBytes;
+ } else
+ haveValue = 0;
+ default:
+ break;
+ }
+ break;
+
+ case wl_requestMethod:
+
+ if (cluster == 1) { /* all servers */
+ if (wl_numActive == 0)
+ haveValue = 0;
+ else {
+ tmp32 = 0;
+ for (s = 0; s < wl_numServers; s++)
+ if (wl_servers[s].counts.active)
+ tmp32 += wl_servers[s].counts.methodReq[m_offset];
+ atom.ul = tmp32;
+ }
+ }
+ else if (wl_servers[inst].counts.active)
+ atom.ul = wl_servers[inst].counts.methodReq[m_offset];
+ else
+ haveValue = 0;
+
+ break;
+
+ case wl_bytesMethod:
+ if (cluster == 1) { /* all servers */
+ if (wl_numActive == 0)
+ haveValue = 0;
+ else {
+ tmp64 = 0;
+ for (s = 0; s < wl_numServers; s++)
+ if (wl_servers[s].counts.active)
+ tmp64 += wl_servers[s].counts.methodBytes[m_offset];
+ atom.ull = tmp64;
+ }
+ }
+ else if (wl_servers[inst].counts.active)
+ atom.ull = wl_servers[inst].counts.methodBytes[m_offset];
+ else
+ haveValue = 0;
+ break;
+
+ case wl_requestSize:
+ if (cluster == 1) { /* all servers */
+ if (wl_numActive == 0)
+ haveValue = 0;
+ else {
+ tmp32 = 0;
+ for (s = 0; s < wl_numServers; s++)
+ if (wl_servers[s].counts.active)
+ tmp32 += wl_servers[s].counts.sizeReq[m_offset];
+ atom.ul = tmp32;
+ }
+ }
+ else if (wl_servers[inst].counts.active)
+ atom.ul = wl_servers[inst].counts.sizeReq[m_offset];
+ else
+ haveValue = 0;
+ break;
+
+ case wl_bytesSize:
+ if (cluster == 1) { /* all servers */
+ if (wl_numActive == 0)
+ haveValue = 0;
+ else {
+ tmp64 = 0;
+ for (s = 0; s < wl_numServers; s++)
+ if (wl_servers[s].counts.active)
+ tmp64 += wl_servers[s].counts.sizeBytes[m_offset];
+ atom.ull = tmp64;
+ }
+ }
+ else if (wl_servers[inst].counts.active)
+ atom.ull = wl_servers[inst].counts.sizeBytes[m_offset];
+ else
+ haveValue = 0;
+ break;
+
+ case wl_requestCachedSize:
+ haveValue = 0;
+ if (cluster == 3) { /* all servers */
+ tmp32 = 0;
+ for (s = 0; s < wl_numServers; s++)
+ if (wl_servers[s].counts.active &&
+ wl_servers[s].counts.extendedp) {
+ haveValue = 1;
+ tmp32 += wl_servers[s].counts.cached_sizeReq[m_offset];
+ }
+ atom.ul = tmp32;
+ }
+ else if (wl_servers[inst].counts.active &&
+ wl_servers[inst].counts.extendedp) {
+ haveValue = 1;
+ atom.ul = wl_servers[inst].counts.cached_sizeReq[m_offset];
+ }
+ break;
+
+ case wl_bytesCachedSize:
+ haveValue = 0;
+ if (cluster == 3) { /* all servers */
+ tmp64 = 0;
+ for (s = 0; s < wl_numServers; s++) {
+ if (wl_servers[s].counts.active &&
+ wl_servers[s].counts.extendedp) {
+ haveValue = 1;
+ tmp64 += wl_servers[s].counts.cached_sizeBytes[m_offset];
+ }
+ }
+ atom.ull = tmp64;
+ }
+ else if (wl_servers[inst].counts.active &&
+ wl_servers[inst].counts.extendedp) {
+ haveValue = 1;
+ atom.ull = wl_servers[inst].counts.cached_sizeBytes[m_offset];
+ }
+ break;
+
+ case wl_requestUncachedSize:
+ haveValue = 0;
+ if (cluster == 3) { /* all servers */
+ tmp32 = 0;
+ for (s = 0; s < wl_numServers; s++) {
+ if (wl_servers[s].counts.active &&
+ wl_servers[s].counts.extendedp ) {
+ haveValue = 1;
+ tmp32 += wl_servers[s].counts.uncached_sizeReq[m_offset];
+ }
+ }
+ atom.ul = tmp32;
+ }
+ else if (wl_servers[inst].counts.active &&
+ wl_servers[inst].counts.extendedp) {
+ haveValue = 1;
+ atom.ul = wl_servers[inst].counts.uncached_sizeReq[m_offset];
+ }
+ break;
+
+ case wl_bytesUncachedSize:
+ haveValue = 0;
+ if (cluster == 3) { /* all servers */
+ tmp64 = 0;
+ for (s = 0; s < wl_numServers; s++) {
+ if (wl_servers[s].counts.active &&
+ wl_servers[s].counts.extendedp) {
+ haveValue = 1;
+ tmp64 += wl_servers[s].counts.uncached_sizeBytes[m_offset];
+ }
+ }
+ atom.ull = tmp64;
+ }
+ else if (wl_servers[inst].counts.active &&
+ wl_servers[inst].counts.extendedp) {
+ haveValue = 1;
+ atom.ull = wl_servers[inst].counts.uncached_sizeBytes[m_offset];
+ }
+ break;
+
+ case wl_watched:
+ atom.ul = *((__uint32_t *)(((__psint_t)(&(wl_servers[inst].counts))) + m_offset));
+ break;
+ case wl_numAlive:
+ tmp32 = 0;
+ for (s = 0; s < wl_numServers; s++) {
+ if (wl_servers[s].counts.active)
+ tmp32 += wl_servers[s].counts.numLogs > 0 ?1:0;
+ }
+ atom.ul = tmp32;
+ break;
+
+ case wl_nosupport:
+ haveValue = 0;
+ break;
+
+ default:
+ logmessage(LOG_CRIT,
+ "Illegal Meta Type (%d) for metric %d\n",
+ m_type,
+ pmidp->item);
+ exit(1);
+ }
+
+ if (haveValue) {
+ sts = __pmStuffValue(&atom, &vset->vlist[j], type);
+ if (sts < 0) {
+ __pmFreeResultValues(res);
+ return sts;
+ }
+
+ vset->valfmt = sts;
+ j++; /* next element in vlist[] for next instance */
+ }
+
+ } while (dp->indom != PM_INDOM_NULL && __pmdaNextInst(&inst, ext));
+
+ vset->numval = j;
+ }
+ *resp = res;
+ return 0;
+}
+
+/*
+ * Store into one of three metrics:
+ * web.activity.config.catchup, web.activity.config.check and web.activity.server.watched
+ */
+
+static int
+web_store(pmResult *result, pmdaExt *ext)
+{
+ int i;
+ int j;
+ pmValueSet *vsp;
+ int sts = 0;
+ __pmID_int *pmidp;
+ WebServer *server = (WebServer*)0;
+
+ for (i = 0; i < result->numpmid; i++) {
+ vsp = result->vset[i];
+ pmidp = (__pmID_int *)&vsp->pmid;
+ if (pmidp->cluster == 0) {
+ if (pmidp->item == 1) { /* web.activity.config.catchup */
+ int val = vsp->vlist[0].value.lval;
+ if (val < 0) {
+ sts = PM_ERR_SIGN;
+ val = 20;
+ }
+ wl_refreshDelay = val;
+ }
+ else if (pmidp->item == 3) {/* web.activity.config.check */
+ int val = vsp->vlist[0].value.lval;
+ if (val < 0) {
+ sts = PM_ERR_SIGN;
+ val = 20;
+ }
+ wl_chkDelay = val;
+ }
+ else if (pmidp->item == 35) {/* web.activity.server.watched */
+ for (j = 0; j < vsp->numval; j++) {
+ int val = vsp->vlist[j].value.lval;
+ if (val < 0) {
+ sts = PM_ERR_SIGN;
+ val = 1;
+ }
+
+ server = &wl_servers[vsp->vlist[j].inst];
+ if (val > 0 && server->counts.active == 0) {
+ wl_numActive++;
+ server->counts.active = 1;
+ }
+ else if (val == 0 && server->counts.active > 0){
+ wl_numActive--;
+ server->counts.active = 0;
+ }
+ }
+ }
+ else {
+ sts = PM_ERR_PMID;
+ break;
+ }
+ }
+ else {
+ /* not one of the metrics we are willing to change */
+ sts = PM_ERR_PMID;
+ break;
+ }
+ }
+ return sts;
+}
+
+/*
+ * Initialise the callback table, and open the help text.
+ * This also calls the routine that to initialise the indom and meta tables.
+ */
+
+void
+web_init(pmdaInterface *dp)
+{
+ int m;
+ int type;
+
+ extp = dp->version.two.ext;
+
+ if (wl_isDSO)
+ pmdaDSO(dp, PMDA_INTERFACE_2, "weblog DSO", wl_helpFile);
+
+ if (dp->status != 0)
+ return;
+
+ dp->version.two.profile = web_profile;
+ dp->version.two.fetch = web_fetch;
+ dp->version.two.store = web_store;
+
+ if (numMetrics != (sizeof(wl_metricInfo)/sizeof(wl_metricInfo[0]))) {
+ logmessage(LOG_CRIT,
+ "Metric and Metric Info tables are not the same size\n");
+ dp->status = -1;
+ return;
+ }
+
+ pmdaInit(dp, wl_indomTable, numIndoms, wl_metrics, numMetrics);
+
+ for (m = 0; m < numMetrics; m++) {
+ type = wl_metricInfo[m].m_type;
+ if (type == wl_offset32 || type == wl_offset64 ||
+ type == wl_watched) {
+ wl_metricInfo[m].m_offset -= (__psint_t)&dummyCount;
+ }
+ }
+
+ return;
+}
+
diff --git a/src/pmdas/weblog/weblog.h b/src/pmdas/weblog/weblog.h
new file mode 100644
index 0000000..a2c99dd
--- /dev/null
+++ b/src/pmdas/weblog/weblog.h
@@ -0,0 +1,140 @@
+
+/*
+ * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _WEBLOG_H
+#define _WEBLOG_H
+
+#include "pmapi.h"
+#include "impl.h"
+#include "pmda.h"
+#include <regex.h>
+#include <sys/stat.h>
+
+enum HTTP_Methods {
+ wl_httpGet, wl_httpHead, wl_httpPost, wl_httpOther, wl_numMethods
+};
+
+enum HistSizes {
+ wl_zero, wl_le3k, wl_le10k, wl_le30k, wl_le100k, wl_le300k, wl_le1m,
+ wl_le3m, wl_gt3m, wl_unknownSize, wl_numSizes
+};
+
+#define FIBUFSIZE 16*1024
+#define DORMANT_WARN 86400
+
+typedef struct {
+ char* fileName;
+ int filePtr;
+ struct stat fileStat;
+ char buf[FIBUFSIZE];
+ char *bp;
+ char *bend;
+ u_int format; /* index into regex for parsing file */
+ time_t lastActive; /* time in sec when last active */
+} FileInfo;
+
+typedef struct {
+ __uint32_t methodReq[wl_numMethods];
+ __uint64_t methodBytes[wl_numMethods];
+ __uint32_t sizeReq[wl_numSizes];
+ __uint64_t sizeBytes[wl_numSizes];
+ __uint32_t cached_sizeReq[wl_numSizes];
+ __uint64_t cached_sizeBytes[wl_numSizes];
+ __uint32_t uncached_sizeReq[wl_numSizes];
+ __uint64_t uncached_sizeBytes[wl_numSizes];
+ __uint32_t sumReq;
+ __uint32_t client_sumReq;
+ __uint32_t cached_sumReq;
+ __uint32_t uncached_sumReq;
+ __uint64_t sumBytes;
+ __uint64_t cached_sumBytes;
+ __uint64_t uncached_sumBytes;
+ __uint32_t errors;
+ __uint32_t active;
+ __uint32_t numLogs;
+ __uint32_t modTime;
+ __uint32_t extendedp;
+} WebCount;
+
+typedef struct {
+ int update; /* flag for updating this server */
+ WebCount counts;
+ FileInfo access;
+ FileInfo error;
+} WebServer;
+
+typedef struct {
+ int id;
+ pid_t pid;
+ int firstServer;
+ int lastServer;
+ int inFD[2];
+ int outFD[2];
+ char *methodStr;
+ char *sizeStr;
+ char *c_statusStr;
+ char *s_statusStr;
+ int strLength;
+} WebSproc;
+
+typedef struct {
+ char* name;
+#ifdef NON_POSIX_REGEX
+ char *np_regex;
+#endif
+ regex_t* regex;
+ int methodPos;
+ int sizePos;
+ int c_statusPos;
+ int s_statusPos;
+ int posix_regexp;
+} WebRegex;
+
+extern WebServer *wl_servers;
+extern WebSproc *wl_sproc;
+extern WebRegex *wl_regexTable;
+extern pmdaInstid *wl_serverInst;
+extern pmdaIndom wl_indomTable[];
+
+extern __uint32_t wl_numServers;
+extern __uint32_t wl_numActive;
+extern __uint32_t wl_refreshDelay;
+extern __uint32_t wl_chkDelay;
+extern __uint32_t wl_sprocThresh;
+extern __uint32_t wl_numSprocs;
+extern __uint32_t wl_catchupTime;
+extern __uint32_t wl_numRegex;
+
+extern int wl_updateAll;
+extern time_t wl_timeOfProbe;
+extern char *wl_logFile;
+extern char wl_helpFile[];
+extern int wl_isDSO;
+
+int openLogFile(FileInfo*);
+void probe(void);
+void refresh(WebSproc*);
+void refreshAll(void);
+void sprocMain(void*);
+void web_init(pmdaInterface*);
+void logmessage(int, const char *, ...);
+
+#define wl_close(fd) do { if (fd >= 0) close(fd); fd = -1; } while (0)
+
+#endif /* _WEBLOG_H */
diff --git a/src/pmdas/weblog/weblogconv.sh b/src/pmdas/weblog/weblogconv.sh
new file mode 100755
index 0000000..d62d2d2
--- /dev/null
+++ b/src/pmdas/weblog/weblogconv.sh
@@ -0,0 +1,62 @@
+#! /bin/sh
+#
+# Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+
+#
+# weblogconv: convert weblog.conf files to posix regex
+#
+
+# only needed on Linux
+
+progname=$0
+
+if [ $# -gt 0 -a "$1" = "-?" ]; then
+ echo "Usage: $progname infile [outfile]"
+ exit 0
+fi
+
+if [ $# -gt 2 ]; then
+ echo "$progname: Too many arguments."
+ exit 1
+fi
+
+if [ $# -lt 1 ] ; then
+ infile=""
+else
+ infile=$1
+fi
+
+if [ $# -lt 2 ]; then
+ outfile=""
+else
+ outfile="> $2"
+fi
+
+if [ -n "$infile" -a ! -r "$infile" ]; then
+ echo "$progname: cannot read $infile"
+ exit 1
+fi
+
+sed \
+ -e '/)\$[01]/!s/^regex[ \t][ \t]*\([^ \t][^ \t]*\)[ \t][ \t]*/regex_posix \1 - /' \
+ -e 's/^regex[ \t][ \t]*\([^ \t][^ \t]*\)[ \t][ \t]*\(.*$0.*$1.*\)/regex_posix \1 method,size \2/' \
+ -e 's/^regex[ \t][ \t]*\([^ \t][^ \t]*\)[ \t][ \t]*\(.*$1.*$0.*\)/regex_posix \1 size,method \2/' \
+ -e 's/)$0/)/g' \
+ -e 's/)$1/)/g' $infile | eval cat $outfile
+
+exit 0