structured main routines. implement file reporter

This commit is contained in:
Patrick Stadler 2015-03-08 20:37:56 +01:00
parent c54c9d73b7
commit 9858beb329
12 changed files with 213 additions and 138 deletions

View File

@ -1,14 +1,12 @@
## TODO
- [] README
- [] option parsing
- [] allow multiple reporters
- [] implement log reporter
- [] better docs, including reporters (--docs)
- [] config file support
- [] config file auto-generation
- [] disk_io metric
- [] load custom metrics
- [] async metrics
- [] extended metric labels?
- [] same metric multiple times (e.g. disk_usage for multiple devices)
- README
- option parsing
- allow multiple reporters
- better docs, including reporters (--docs)
- config file support
- config file auto-generation
- load custom metrics
- async metrics
- extended metric labels?
- same metric multiple times (e.g. disk_usage for multiple devices)

108
lib/main.sh Normal file
View File

@ -0,0 +1,108 @@
# load utils
for util in ./lib/utils/*.sh; do source $util; done
# init
__METRICS=()
__TEMP_DIR=$(make_temp_dir)
# load reporter
main_load () {
source ./reporters/${REPORTER}.sh
copy_function init __r_${REPORTER}_init
copy_function report __r_${REPORTER}_report
copy_function terminate __r_${REPORTER}_terminate
copy_function docs __r_${REPORTER}_docs
unset -f init report terminate docs
# load metrics
for file in ./metrics/*.sh; do
filename=$(basename $file)
metric=${filename%.*}
# soruce file and copy functions
source $file
copy_function init __m_${metric}_init
copy_function collect __m_${metric}_collect
copy_function terminate __m_${metric}_terminate
copy_function docs __m_${metric}_docs
unset -f init collect terminate docs
# register metric
__METRICS+=($metric)
done
}
main_init () {
# init reporter
if is_function __r_${REPORTER}_init; then
__r_${REPORTER}_init
fi
# init metrics
for metric in ${__METRICS[@]}; do
if ! is_function __m_${metric}_init; then
continue
fi
__m_${metric}_init
done
}
main_docs () {
echo "Available metrics:"
for metric in ${__METRICS[@]}; do
if ! is_function __m_${metric}_docs; then
continue
fi
echo "[$metric]"
__m_${metric}_docs
echo
done
}
main_collect () {
# used by metrics to return results
report () {
local _r_result
if [ -z $2 ]; then
_r_label=$metric
_r_result="$1"
else
_r_label="$metric.$1"
_r_result="$2"
fi
if is_number $_r_result; then
__r_${REPORTER}_report $_r_label $_r_result
fi
}
# collect metrics
while true; do
for metric in ${__METRICS[@]}; do
if ! is_function __m_${metric}_collect; then
continue
fi
__m_${metric}_collect
done
sleep $INTERVAL
done
}
main_terminate () {
# terminate metrics
for metric in ${__METRICS[@]}; do
if ! is_function __m_${metric}_terminate; then
continue
fi
__m_${metric}_terminate
done
# terminate reporter
if is_function __r_${REPORTER}_terminate; then
__r_${REPORTER}_terminate
fi
}

7
lib/utils/helpers.sh Normal file
View File

@ -0,0 +1,7 @@
is_number () {
[ ! -z "$1" ] && printf '%f' "$1" &>/dev/null
}
iso_date () {
date -u +"%Y-%m-%dT%H:%M:%SZ"
}

View File

@ -14,11 +14,13 @@ is_linux () { [ $OS_TYPE == 'solaris' ]; }
is_bsd () { [ $OS_TYPE == 'bsd']; }
is_unknown () { [ $OS_TYPE == 'unknown' ]; }
make_temp_dir () {
if is_osx; then
# http://unix.stackexchange.com/a/84980/50905
if is_osx; then
make_temp_dir () {
mktemp -d -t 'sysmetrics'
else
}
else
make_temp_dir () {
mktemp -d
fi
}
}
fi

View File

@ -1,12 +1,17 @@
#!/bin/sh
if [ -z $DISK_IO_MOUNTPOINT ]; then
if is_osx; then
DISK_IO_MOUNTPOINT="disk0"
else
DISK_IO_MOUNTPOINT="/dev/vda"
init () {
if [ -z $DISK_IO_MOUNTPOINT ]; then
if is_osx; then
DISK_IO_MOUNTPOINT="disk0"
else
DISK_IO_MOUNTPOINT="/dev/vda"
fi
fi
fi
readonly __disk_io_fifo=$__TEMP_DIR/disk_io
mkfifo $__disk_io_fifo
__disk_io_bgproc &
}
if is_osx; then
__disk_io_bgproc () {
@ -20,19 +25,14 @@ else
}
fi
__disk_io_fifo=$__TEMP_DIR/disk_io
init () {
__disk_io_bgproc &
mkfifo $__disk_io_fifo
}
collect () {
report $(cat $__disk_io_fifo)
}
terminate () {
rm $__disk_io_fifo
if [ ! -z $__disk_io_fifo ] && [ -f $__disk_io_fifo ]; then
rm $__disk_io_fifo
fi
}
docs () {

View File

@ -1,12 +1,14 @@
#!/bin/sh
if [ -z $DISK_USAGE_MOUNTPOINT ]; then
if is_osx; then
DISK_USAGE_MOUNTPOINT="/dev/disk1"
else
DISK_USAGE_MOUNTPOINT="/dev/vda"
init () {
if [ -z $DISK_USAGE_MOUNTPOINT ]; then
if is_osx; then
DISK_USAGE_MOUNTPOINT="/dev/disk1"
else
DISK_USAGE_MOUNTPOINT="/dev/vda"
fi
fi
fi
}
collect () {
report $(df | awk -v disk_regexp="^$DISK_USAGE_MOUNTPOINT" \

View File

@ -1,7 +1,9 @@
#!/bin/sh
if is_osx; then
declare -r __memory_os_memsize=$(sysctl -n hw.memsize)
init () {
readonly __memory_os_memsize=$(sysctl -n hw.memsize)
}
collect () {
report $(vm_stat | awk -v total_memory=$__memory_os_memsize \

View File

@ -1,19 +1,14 @@
#!/bin/sh
if [ -z $NETWORK_IO_INTERFACE ]; then
if is_osx; then
NETWORK_IO_INTERFACE="en0"
else
NETWORK_IO_INTERFACE="eth0"
init () {
if [ -z $NETWORK_IO_INTERFACE ]; then
if is_osx; then
NETWORK_IO_INTERFACE="en0"
else
NETWORK_IO_INTERFACE="eth0"
fi
fi
fi
declare -r __network_io_divisor=$[$INTERVAL * 1024]
__network_io_sample=(0 0)
__network_io_calc_kBps() {
echo $1 $2 | awk -v divisor=$__network_io_divisor \
'{printf "%.2f", ($1 - $2) / divisor}'
readonly __network_io_divisor=$[$INTERVAL * 1024]
}
if is_osx; then
@ -28,9 +23,14 @@ else
}
fi
__network_io_calc_kBps() {
echo $1 $2 | awk -v divisor=$__network_io_divisor \
'{printf "%.2f", ($1 - $2) / divisor}'
}
collect () {
local sample=( $(__network_io_collect) )
if [ ${__network_io_sample[0]} -ne 0 ]; then
if [ ! -z $__network_io_sample ]; then
report "in" $(__network_io_calc_kBps ${sample[0]} ${__network_io_sample[0]})
report "out" $(__network_io_calc_kBps ${sample[1]} ${__network_io_sample[1]})
fi

9
metrics/ping.sh Normal file
View File

@ -0,0 +1,9 @@
#!/bin/sh
collect () {
report 1
}
docs () {
echo "Send a simple ping in form of an integer '1'."
}

24
reporters/file.sh Normal file
View File

@ -0,0 +1,24 @@
#!/bin/sh
report () {
local METRIC=$1
local VALUE=$2
local DATE=$(iso_date)
echo $DATE $METRIC: $VALUE >> $FILE_LOCATION
}
init () {
if [ -z $FILE_LOCATION ]; then
echo "Missing configuration: \$FILE_LOCATION"
return 1
fi
if [ ! -f $FILE_LOCATION ]; then
touch $FILE_LOCATION
fi
}
docs () {
echo "Write to a file or named pipe."
echo "\$FILE_LOCATION=$FILE_LOCATION"
}

View File

@ -3,7 +3,7 @@
report () {
METRIC=$1
VALUE=$2
curl -d "stat=$METRIC&ezkey=$API_KEY&value=$VALUE" http://api.stathat.com/ez
curl -d "stat=$METRIC&ezkey=$STATHAT_API_KEY&value=$VALUE" http://api.stathat.com/ez
}
docs () {

View File

@ -2,93 +2,16 @@
# config
INTERVAL=1
REPORTER=stdout
# load utils
for util in ./lib/utils/*.sh; do source $util; done
# init
__METRICS=()
__TEMP_DIR=$(make_temp_dir)
REPORTER=file
# register trap
trap '
for metric in ${__METRICS[@]}; do
if ! is_function __m_${metric}_terminate; then
continue
fi
__m_${metric}_terminate
done
main_terminate
trap - SIGTERM && kill -- -$$ SIGINT SIGTERM EXIT
' SIGINT SIGTERM EXIT
# load reporter
source ./reporters/${REPORTER}.sh
copy_function init __r_${REPORTER}_init
copy_function report __r_${REPORTER}_report
copy_function terminate __r_${REPORTER}_terminate
copy_function docs __r_${REPORTER}_docs
unset -f init report terminate docs
# load metrics
for file in ./metrics/*.sh; do
filename=$(basename $file)
metric=${filename%.*}
# soruce file and copy functions
source $file
copy_function init __m_${metric}_init
copy_function collect __m_${metric}_collect
copy_function terminate __m_${metric}_terminate
copy_function docs __m_${metric}_docs
unset -f init collect terminate docs
# register metric
__METRICS+=($metric)
done
# init metrics
for metric in ${__METRICS[@]}; do
if ! is_function __m_${metric}_init; then
continue
fi
__m_${metric}_init
done
# print docs for metrics
echo "Available metrics:"
for metric in ${__METRICS[@]}; do
if ! is_function __m_${metric}_docs; then
continue
fi
echo "[$metric]"
__m_${metric}_docs
echo
done
report () {
local result
if [ -z $2 ]; then
label=$metric
result="$1"
else
label="$metric.$1"
result="$2"
fi
__r_${REPORTER}_report $label $result
}
# collect metrics
while true; do
for metric in ${__METRICS[@]}; do
if ! is_function __m_${metric}_collect; then
continue
fi
__m_${metric}_collect
done
sleep $INTERVAL
done
# load and start main routine
source ./lib/main.sh
main_load
main_init
main_collect