diff options
Diffstat (limited to 'src/pmsnap')
-rw-r--r-- | src/pmsnap/GNUmakefile | 29 | ||||
-rw-r--r-- | src/pmsnap/Snap | 30 | ||||
-rw-r--r-- | src/pmsnap/control | 71 | ||||
-rw-r--r-- | src/pmsnap/crontab.IN | 6 | ||||
-rwxr-xr-x | src/pmsnap/pmsnap.sh | 457 | ||||
-rw-r--r-- | src/pmsnap/summary.html | 34 |
6 files changed, 627 insertions, 0 deletions
diff --git a/src/pmsnap/GNUmakefile b/src/pmsnap/GNUmakefile new file mode 100644 index 0000000..df7c270 --- /dev/null +++ b/src/pmsnap/GNUmakefile @@ -0,0 +1,29 @@ +TOPDIR = ../.. +include $(TOPDIR)/src/include/builddefs + +SCRIPTS = pmsnap.sh +CONFIGS = crontab.IN Snap control +HTMLDOC = summary.html +LSRCFILES = $(SCRIPTS) $(CONFIGS) $(HTMLDOC) +LDIRT = crontab + +default: crontab + +crontab : crontab.IN + $(SED) -e '/\# .*/b' -e 's;PCP_BINADM_DIR;$(PCP_BINADM_DIR);g' < $< > $@ + +include $(BUILDRULES) + +install: default +ifeq "$(ENABLE_QT)" "true" + $(INSTALL) -m 755 -d $(PCP_BINADM_DIR) + $(INSTALL) -m 755 pmsnap.sh $(PCP_BINADM_DIR)/pmsnap + $(INSTALL) -m 755 -d $(PCP_VAR_DIR)/config/pmsnap + $(INSTALL) -m 644 Snap crontab summary.html $(PCP_VAR_DIR)/config/pmsnap + $(INSTALL) -m 755 -d `dirname $(PCP_PMSNAPCONTROL_PATH)` + $(INSTALL) -m 644 control $(PCP_PMSNAPCONTROL_PATH) +endif + +default_pcp: default + +install_pcp: install diff --git a/src/pmsnap/Snap b/src/pmsnap/Snap new file mode 100644 index 0000000..8f49a80 --- /dev/null +++ b/src/pmsnap/Snap @@ -0,0 +1,30 @@ +#kmchart +Version 1 + +Chart Title "CPU Utilization" Style utilization + Plot Color #2d2de2 Metric kernel.all.cpu.user + Plot Color #e71717 Metric kernel.all.cpu.sys + Plot Color rgbi:0.8/0.8/0.0 Metric kernel.all.cpu.intr + Optional-Plot Color rgbi:0.4/0.9/0.4 Metric kernel.all.cpu.nice + Optional-Plot Color rgbi:0.0/0.8/0.8 Metric kernel.all.cpu.wait.total + Plot Color #16e116 Metric kernel.all.cpu.idle + +Chart Title "Average Load" Style plot + Plot Metric kernel.all.load Instance 1 minute + Plot Metric kernel.all.load Instance 5 minute + Plot Metric kernel.all.load Instance 15 minute + Plot Color black Metric hinv.ncpu + +Chart Title "Disk Activity" Style stacking + Plot Color yellow Metric disk.all.read + Plot Color violet Metric disk.all.write + +Chart Title "Network Interface Activity" Style stacking + Plot Metric network.interface.in.bytes Not-Matching ^lo|^sl|^ppp|^sit + Plot Metric network.interface.out.bytes Not-Matching ^lo|^sl|^ppp|^sit + +Chart Title "TCP Network Failures" Style stacking + Plot Metric network.tcp.attemptfails Not-Matching ^lo|^sl|^ppp|^sit + Plot Metric network.tcp.retranssegs Not-Matching ^lo|^sl|^ppp|^sit + Plot Metric network.tcp.inerrs Not-Matching ^lo|^sl|^ppp|^sit + Plot Metric network.tcp.outrsts Not-Matching ^lo|^sl|^ppp|^sit diff --git a/src/pmsnap/control b/src/pmsnap/control new file mode 100644 index 0000000..54440b5 --- /dev/null +++ b/src/pmsnap/control @@ -0,0 +1,71 @@ +# +# Configuration file for pmsnap(1) +# +# This file controls the output of pmsnap. +# See the manual page for pmsnap(1) for full details. +# +# Although not mandatory, it is strongly advised that you follow +# the instructions described in the manual page for pmlogger_daily(1) +# before proceeding with the instructions described in pmsnap(1). +# +# Each line below (which is not a comment) has 4 columns, with +# the following meaning .. +# +# (1) Name : name of the output file. This is typically +# in the local Web content directory hierarchy. +# +# (2) Folio : use the named PCP archive, OR use the archives +# in the named PCP archive folio. This is usually +# in PCP_LOG_DIR/pmlogger/HOSTNAME, but may be the path of an +# archive on an NFS/CIFS mounted filesystem if logging is done +# on a remote host. Note that pmlogger_daily(1) automatically +# creates the folio PCP_LOG_DIR/pmlogger/LOCALHOSTNAME/Latest. +# +# (3) Config : the pmchart "view" to use. If not found in the +# local directory (relative to the -o flag), pmsnap +# will also search the directories $PCP_VAR_DIR/config/pmsnap, +# $PCP_VAR_DIR/config/pmchart, and $PCP_VAR_DIR/config/pmchart. +# +# (4) Arguments : passed to pmchart, see pmchart(1). Note that $commonargs +# will be prepended to the argument list (see the assignment to +# $commonargs below). Do NOT include any of the following +# arguments: -o -c -a +# +# Notes : the string LOCALHOSTNAME in this file will be substituted +# by the name of the local host by pmsnap at run-time. +# If pmlogger is logging Snap metrics on the local host, +# the example below should work virtually out of the box, +# provided you want the output images in /var/www/htdocs/snapshots. +# You will of course need to publish an html page that shows +# the generated gif images - you can use the example provided +# in the file $PCP_VAR_DIR/config/pmsnap/Snap.html. +# +# : lines beginning with $ are assumed to be assignments to +# environment variables in the style of sh(1), and all text +# following the $ will be eval'ed by the script reading +# this control file, and the corresponding variable +# exported into the environment. +# +# Recommended pmchart arguments : +# -g 650x600 (raw image size, Width x Height) +# -t 1min (update interval, i.e. time between ticks on the X-Axis) +# -v 30 (number of visible points) +# -O -0 (show end of archive, backwards by (-vh) * (-t) seconds) +# -A 10min (aligned to start at the nearest 10 minutes) +# -W (generated image has a white background, not transparent) +# + +# === Variable Assignments === +# +# DO NOT REMOVE OR EDIT THE FOLLOWING LINE +$version=1.0 + +# Common pmchart Arguments. Edit as required. +$commonargs='' + +# +# === pmsnap Control Specifications === +# +# Name (Output Image) Folio|Archive Config Arguments +/var/www/pcp/LOCALHOSTNAME.1hour.summary LOCALHOSTNAME/Latest Snap -O-0 -A 10min -t 2min -v 30 +/var/www/pcp/LOCALHOSTNAME.12hour.summary LOCALHOSTNAME/Latest Snap -O-0 -A 1hour -t 30min -v 30 diff --git a/src/pmsnap/crontab.IN b/src/pmsnap/crontab.IN new file mode 100644 index 0000000..32427b0 --- /dev/null +++ b/src/pmsnap/crontab.IN @@ -0,0 +1,6 @@ +# +# Standard Performance Co-Pilot pmsnap crontab entry for a PCP site +# with one or more pmlogger instances running +# +# every 30 minutes, generate snapshot images +30,0 * * * * PCP_BIN_DIR/pmsnap # -d DISPLAY diff --git a/src/pmsnap/pmsnap.sh b/src/pmsnap/pmsnap.sh new file mode 100755 index 0000000..87434a5 --- /dev/null +++ b/src/pmsnap/pmsnap.sh @@ -0,0 +1,457 @@ +#!/bin/sh +# +# Copyright (c) 2008 Aconex. All Rights Reserved. +# Copyright (c) 1995-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. +# +# 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, USA +# + +. $PCP_DIR/etc/pcp.env + +tmp=`mktemp -d /tmp/pcp.XXXXXXXXX` || exit 1 +trap "rm -rf $tmp; exit 0" 0 1 2 3 15 +prog=`basename $0` + +LOCALHOST=`pmhostname` +CONFIGDIR=$PCP_VAR_DIR/config/pmsnap +CONTROL=$CONFIGDIR/control +[ -z "$PCP_PMSNAPCONTROL_PATH" ] || CONTROL="$PCP_PMSNAPCONTROL_PATH" + +_usage() +{ + cat << EOF +Usage: $prog [-dNV] [-C dir] [-c regex] [-f format] [-n regex] [-o dir] + -C alternate directory for control file(s) + -c matches the Config field in the pmsnap control file + -f output image format (default png) + -N show me, but do not execute commands + -n matches the Name field in the pmsnap control file + -o default directory for output images (default ".") + -V verbose trace of actions (for debugging) + -- pass all following options directly to pmchart + +If no patterns are given then all lines in the pmsnap control file + $CONTROL +will be processed. If any patterns are given then only lines which +match all patterns will be processed. + +Patterns are full regular expressions, see egrep(1) and may require +appropriate quotes to avoid shell meta character expansion. +EOF + exit 1 +} + +_fixpath() +{ + echo $1 $2 |\ + $PCP_AWK_PROG '{ + if (substr($2, 1, 1) == "/") + print $2 + else + printf "%s/%s\n", $1, $2 + }' +} + +_warning() +{ + echo + echo "$prog: $CONTROL[$line]:" + echo "$*" | fmt \ +| sed -e '1{ +s/^/Warning: / +n +}' -e 's/^/ /' +} + +_error() +{ + echo + echo "$prog: $CONTROL[$line]:" + echo "$*" | fmt \ +| sed -e '1{ +s/^/Error: / +n +}' -e 's/^/ /' +} + +_debug() +{ + echo + echo "$prog: $CONTROL[$line]:" + echo "$*" | fmt \ +| sed -e '1{ +s/^/Debug: / +n +}' -e 's/^/ /' +} + +serverId() +{ + id=42 + while [ -f /tmp/.X$id-lock ]; do + id=`expr $id + 1` + done + echo $id +} + +startXvfb() +{ + [ -x /usr/bin/Xvfb ] || return + + geom="2048x2048" + args="-nolisten tcp -screen 0 ${geom}x8" + server=`serverId` + cookie=`mcookie` + XAUTHORITY=$tmp/xauth xauth add ":$server" . "$cookie" >/dev/null 2>&1 + XAUTHORITY=$tmp/xauth /usr/bin/Xvfb ":$server" $args >/dev/null 2>&1 & + pid=$? + pmsleep 0.2 + kill -0 $pid 2>/dev/null || return + export XAUTHORITY=$tmp/xauth + export DISPLAY=":$server" + echo $pid +} + +stopXvfb() +{ + pid="$1" + [ -z "$pid" -o "$pid" -le 0 ] && return + kill $pid +} + +line=0 +archives="" +configs='.*' +names='.*' +dir="." +format="png" +verbose=false +passthru=false +version="1.0" + +# option parsing +# +SHOWME=false +PMLC="echo flush | pmlc >/dev/null 2>&1" +while getopts a:C:c:f:Nn:o:V-? c +do + case $c + in + C) CONFIGDIR="$OPTARG" + ;; + c) configs="$OPTARG" + ;; + f) format="$OPTARG" + ;; + o) dir="$OPTARG" + ;; + N) SHOWME=true + PMLC="echo '+ echo flush | pmlc'" + ;; + n) names="$OPTARG" + ;; + V) verbose=true + ;; + -) passthru=true + ;; + ?) _usage + ;; + esac + [ $passthru = true ] && break +done + +if [ $passthru = false ] +then + shift `expr $OPTIND - 1` + [ $# -ne 0 ] && _usage +fi +commonargs="$commonargs $@" + +CONTROL=$CONFIGDIR/control +if [ ! -f "$CONTROL" ] +then + echo "$prog: Error: cannot find control file \"$CONTROL\"" + exit 1 +fi + +if [ ! -d "$dir" ] +then + echo "$prog: Error: directory \"$dir\" does not exist" + exit 1 +fi +cd $dir +dir=`pwd` +$SHOWME && echo "+ cd $dir" + +$SHOWME || xvfb=`startXvfb` + +# escape / in patterns so $PCP_AWK_PROG is not confused +# +names=`echo "$names" | sed -e 's;/;\\\\/;g'` +configs=`echo "$configs" | sed -e 's;/;\\\\/;g'` + +sed -e 's/LOCALHOSTNAME/'$LOCALHOST'/g' < $CONTROL \ +| $PCP_AWK_PROG ' +/^\#/ || /^\$/ || NF < 4 { + print + next +} +{ + if ($1 ~ /'$names'/ && $3 ~ /'$configs'/) { + printf "%s %s %s '\''", $1, $2, $3 + for (i=4; i<= NF; i++) + printf "%s ", $i + printf "'\''\n" + } +}' \ +| while read aname afolio aview args +do + line=`expr $line + 1` + case "$aname" + in + \#*|'') # comment or empty + continue + ;; + + \$*) # in-line variable assignment + $SHOWME && echo "# $aname $afolio $aview $args" + cmd=`echo "$aname $afolio $aview $args" \ + | sed -n \ + -e "/='/s/\(='[^']*'\).*/\1/" \ + -e '/="/s/\(="[^"]*"\).*/\1/' \ + -e '/=[^"'"'"']/s/[;&<>|].*$//' \ + -e '/^\\$[A-Za-z][A-Za-z0-9_]*=/{ +s/^\\$// +s/^\([A-Za-z][A-Za-z0-9_]*\)=/export \1; \1=/p +}'` + if [ -z "$cmd" ] + then + # in-line command, not a variable assignment + _warning "in-line command is not a variable assignment, line ignored" + else + case "$cmd" + in + 'export PATH;'*) + _warning "cannot change \$PATH, line ignored" + ;; + 'export IFS;'*) + _warning "cannot change \$IFS, line ignored" + ;; + *) + $SHOWME && echo "+ $cmd" + eval $cmd + ;; + esac + fi + continue + ;; + esac + + if [ -z "$afolio" -o -z "$aview" -o -z "$args" ] + then + _error "insufficient fields in control file record" + continue + fi + + # strip first and last single quote added by awk prior to read + # + args=`echo $args | sed -e "s/^'//" -e "s/'$//"` + + name=`_fixpath $dir $aname` + if [ -d $PCP_LOG_DIR/pmlogger ]; then + folio=`_fixpath $PCP_LOG_DIR/pmlogger $afolio` + fi + view=`_fixpath $dir $aview` + + # make sure output directory exists + # + outdir=`dirname $name` + if [ ! -d $outdir ] + then + if $SHOWME + then + echo "+ mkdir -p $outdir" + else + mkdir -p $outdir + if [ ! -d $outdir ] + then + _error "cannot create directory \"$outdir\" for output file" + else + $verbose && _debug "created image output directory \"$outdir\"" + fi + fi + fi + + if $SHOWME + then + : + else + if [ ! -w $outdir ] + then + _error "cannot write in directory \"$outdir\" to create output file" + exit 1 + fi + fi + + if $verbose + then + echo + _debug "name=\"$name\"" + _debug "folio=\"$folio\"" + _debug "view=\"$view\"" + _debug "args=\"$args\"" + _debug "commonargs=\"$commonargs\"" + fi + + if [ ! -f "$view" ] + then + if [ ! -f $CONFIGDIR/$aview ] + then + if [ ! -f $PCP_VAR_DIR/config/pmchart/$aview ] + then + if [ ! -f $PCP_VAR_DIR/config/kmchart/$aview ] + then + _warning "could not find \"$view\", \"$CONFIGDIR/$aview\", \"$PCP_VAR_DIR/config/pmchart/$aview, or \"$PCP_VAR_DIR/config/kmchart/$aview\"" + continue + else + view=$PCP_VAR_DIR/config/kmchart/$aview + fi + else + view=$PCP_VAR_DIR/config/pmchart/$aview + fi + else + view=$CONFIGDIR/$aview + fi + fi + + if [ ! -f $folio ] + then + # oops, no folio + _error "cannot find archive folio \"$folio\"" + echo "Skipping entry from control file ..." + continue + fi + + f=$folio + $SHOWME && echo "+ pmafm $f selection" + pmafm "$f" selection >$tmp/out 2>&1 + + if [ $? -ne 0 ] + then + if [ ! -f $folio.meta ] + then + _warning "\"$folio\" is neither a PCP folio nor a PCP archive" + ls -l $folio + continue + else + contents=$folio + fi + else + contents=`sed -n -e '/Archive:/s///gp' <$tmp/out` + if [ -z "$contents" ] + then + _warning "cannot determine archive name from PCP folio \"$folio\"" + continue + fi + fi + + arch="" + + for c in $contents + do + if [ -f $c.meta ] + then + host=`pminfo -f -a $c pmcd.pmlogger.host \ + | sed -e 's/"//g' -e 's/\[//g' \ + | $PCP_AWK_PROG '$1=="inst" {print $6; exit}'` + + port=`pminfo -f -a $c pmcd.pmlogger.port \ + | sed -e 's/"//g' -e 's/\[//g' \ + | $PCP_AWK_PROG '$1=="inst" {print $6; exit}'` + + if [ ! -z "$host" -a ! -z "$port" ] + then + echo "$host $port" >> $tmp/flush + else + if $verbose + then + _warning "could not extract host and pmlogger control port from archive \"$c\" ... this archive may not be flushed" + fi + fi + + if [ -z "$arch" ] + then + arch=$c + else + arch=$arch","$c + fi + else + _warning "cannot find or open archive \"$c\"" + fi + done + + if [ -z "$arch" ] + then + _warning "no archives could be found for \"$contents\"" + continue + fi + + sort -u $tmp/flush | while read host port + do + eval $PMLC -h $host -p $port + done + + if $SHOWME + then + echo "+ pmchart -c $view -o $name.$format -a $arch $commonargs $args" + else + eval pmchart -c "$view" -o "$tmp/name.$format" -a "$arch" $commonargs $args > $tmp/err 2>&1 + sts=$? + + if [ $sts -eq 0 -a -f $tmp/name.$format ] + then + # success, update the image + mv $tmp/name.$format $name.$format + $verbose && _debug "created \"$name.$format\"" + if [ -s "$tmp/err" ] + then + _warning "the output image \"$name.$format\" was created but there were warning messages from pmchart, as follows:" + cat $tmp/err + echo "-------------" + fi + elif grep 'too short to satisfy the requested starting alignment' $tmp/err >/dev/null + then + # archive's duration is too short for chart configuration ... + # silently ignore this one, as we'll probably succeed next time + # or soon thereafter + if $verbose + then + _debug "archive \"$arch\" too short for pmchart args \"$args\"" + fi + else + # failed, remove the image and report the error + _warning "the output image \"$name.$format\" was not created. There were error messages from pmchart, as follows:" + cat $tmp/err + echo "-------------" + rm -f $name.$format + fi + fi + + rm -f $tmp/err +done + +$SHOWME || stopXvfb "$xvfb" + +exit $status diff --git a/src/pmsnap/summary.html b/src/pmsnap/summary.html new file mode 100644 index 0000000..f33a72b --- /dev/null +++ b/src/pmsnap/summary.html @@ -0,0 +1,34 @@ +<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"> +<HTML VERSION="2.0"> +<! +<! To customize this file, globally change MYHOST with the name of the host +<! you want to monitor. You may also want to change the auto-refresh rate +<! to something other than every five minutes (300 seconds, below). +<! +<HEAD> +<META HTTP-EQUIV="Refresh" CONTENT="300"> +<META HTTP-EQUIV="Pragma" CONTENT="no-cache"> +<META HTTP-EQUIV="Expires" CONTENT="-1"> +<TITLE>PCP Summary Snapshot for MYHOST</TITLE> +</HEAD> +<BODY BGCOLOR="#bfbfbf"> +<META http-equiv=refresh content=300> +<H2>System Performance Summary</H2> +<HR> +<CENTER> +<H3 ALIGN="CENTER"><FONT SIZE="3">One Hour Activity for MYHOST</FONT></H3> +<P ALIGN="CENTER"><IMG SRC="MYHOST.1hour.summary.gif"></P> +</CENTER> +<HR> +<CENTER> +<H3 ALIGN="CENTER"><FONT SIZE="3">Twelve Hour Activity for MYHOST</FONT></H3> +<P ALIGN="CENTER"><IMG SRC="MYHOST.12hour.summary.gif"></P> +</CENTER> +<HR> +<P>Images produced by <A HREF="http://oss.sgi.com/projects/pcp/">Performance Co-Pilot Charts</A></P> +</BODY> +<HEAD> +<META HTTP-EQUIV="Pragma" CONTENT="no-cache"> +<META HTTP-EQUIV="Expires" CONTENT="-1"> +</HEAD> +</HTML> |