fully working config handling. support for multiple metrics of the same type. implement signal trapping

This commit is contained in:
Patrick Stadler 2015-03-21 16:50:35 +01:00
parent f06e238b85
commit e0a528859f
6 changed files with 88 additions and 79 deletions

View File

@ -7,7 +7,7 @@ metrics.sh is a lightweight metrics collection and fowarding utility implemented
``` ```
$ ./metrics.sh --help $ ./metrics.sh --help
Usage: ./metrics.sh [-d] [-h] [-v] [-m metrics] [-r reporter] [-i interval] Usage: ./metrics.sh [-d] [-h] [-v] [-c] [-m] [-r] [-i]
Options: Options:
@ -54,8 +54,7 @@ TODO: how to write custom reporters
## TODO ## TODO
- README - README
- config file support - config file docs
- config file auto-generation - config file auto-generation
- load custom/contrib metrics and reporters - load custom/contrib metrics and reporters
- same metric multiple times? (e.g. disk_usage for multiple devices)
- allow multiple reporters? - allow multiple reporters?

View File

@ -28,9 +28,6 @@ main_load () {
# register metric # register metric
__AVAILABLE_METRICS=$(trim "$__AVAILABLE_METRICS $metric") __AVAILABLE_METRICS=$(trim "$__AVAILABLE_METRICS $metric")
done done
load_metric_with_prefix __m_${metric}_ $file
} }
main_init () { main_init () {
@ -41,12 +38,6 @@ main_init () {
# create temp dir # create temp dir
TEMP_DIR=$(make_temp_dir) TEMP_DIR=$(make_temp_dir)
# register trap
trap '
main_terminate
trap - TERM && kill -- -$$ INT TERM EXIT
' INT TERM EXIT
# check if reporter exists # check if reporter exists
if ! in_array $__REPORTER "$__AVAILABLE_REPORTERS"; then if ! in_array $__REPORTER "$__AVAILABLE_REPORTERS"; then
echo "Error: reporter '$__REPORTER' is not available" echo "Error: reporter '$__REPORTER' is not available"
@ -63,78 +54,96 @@ main_init () {
done done
# init reporter # init reporter
if is_function __r_${__REPORTER}_config; then
__r_${__REPORTER}_config
fi
if is_function __r_${__REPORTER}_init; then if is_function __r_${__REPORTER}_init; then
__r_${__REPORTER}_init __r_${__REPORTER}_init
fi fi
# init metrics
for metric in $__METRICS; do
local metric_name=$(get_name $metric)
local metric_alias=$(get_alias $metric)
load_metric_with_prefix __m_${metric_alias}_ ./metrics/${metric_name}.sh
if ! is_function __m_${metric_alias}_init; then
continue
fi
__m_${metric_alias}_init
done
} }
main_collect () { main_collect () {
# used by metrics to return results # register trap
report () { trap '
local _r_label _r_result trap "" 13
if [ -z $2 ]; then trap - INT TERM EXIT
_r_label=$metric echo Exit signal received.
_r_result="$1" kill -13 -$$
else ' 13 INT TERM EXIT
_r_label="$metric.$1"
_r_result="$2"
fi
if is_number $_r_result; then
__r_${__REPORTER}_report $_r_label $_r_result
fi
}
# collect metrics # collect metrics
for metric in $__METRICS; do for metric in $__METRICS; do
metric=$(get_alias $metric) # run in subshell to isolate scope
if ! is_function __m_${metric}_collect; then (
continue local metric_name=$(get_name $metric)
fi local metric_alias=$(get_alias $metric)
# used by metrics to return results
report () {
local _r_label _r_result
if [ -z $2 ]; then
_r_label=$metric_alias
_r_result="$1"
else
_r_label="$metric_alias.$1"
_r_result="$2"
fi
if is_number $_r_result; then
__r_${__REPORTER}_report $_r_label $_r_result
fi
}
# fork # init metric
(while true; do if is_function __m_${metric_alias}_config; then
__m_${metric}_collect __m_${metric_alias}_config
sleep $INTERVAL fi
done) &
load_metric_with_prefix __m_${metric_alias}_ ./metrics/${metric_name}.sh
if is_function __m_${metric_alias}_init; then
__m_${metric_alias}_init
fi
if ! is_function __m_${metric_alias}_collect; then
continue
fi
# collect metrics
trap "
if is_function __m_${metric_alias}_terminate; then
verbose 'Stopping metric ${metric_alias}'
__m_${metric_alias}_terminate
fi
exit 0
" 13
while true; do
__m_${metric_alias}_collect
sleep $INTERVAL
done
) &
done done
# run forever # wait until interrupted
sleep 2147483647 # `sleep infinity` is not portable wait
# then wait again for processes to end
wait
main_terminate
} }
main_terminate () { main_terminate () {
# terminate metrics
for metric in $__METRICS; do
metric=$(get_alias $metric)
if ! is_function __m_${metric}_terminate; then
continue
fi
__m_${metric}_terminate
done
# terminate reporter # terminate reporter
if is_function __r_${__REPORTER}_terminate; then if is_function __r_${__REPORTER}_terminate; then
verbose "Stopping reporter ${__REPORTER}"
__r_${__REPORTER}_terminate __r_${__REPORTER}_terminate
fi fi
verbose -n "Cleaning up..."
# delete temporary directory # delete temporary directory
if [ -d $TEMP_DIR ]; then if [ -d $TEMP_DIR ]; then
rmdir $TEMP_DIR rmdir $TEMP_DIR
fi fi
verbose "done"
} }
main_docs () { main_docs () {

View File

@ -24,7 +24,6 @@ parse_config () {
local _group local _group
local _name local _name
local _alias
local _body local _body
end_section () { end_section () {
@ -34,20 +33,16 @@ parse_config () {
local fn_name local fn_name
if [ "$_group" = "reporter" ]; then if [ "$_group" = "reporter" ]; then
__CFG_REPORTERS=$(trim "${__CFG_REPORTERS} ${_name}:${_alias}") __CFG_REPORTERS=$(trim "${__CFG_REPORTERS} ${_name}")
fn_name="__r_" fn_name="__r_"
elif [ "$_group" = "metric" ]; then elif [ "$_group" = "metric" ]; then
__CFG_METRICS=$(trim "${__CFG_METRICS} ${_name}:${_alias}") __CFG_METRICS=$(trim "${__CFG_METRICS} ${_name}")
fn_name="__m_" fn_name="__m_"
else else
fn_name="global" fn_name="main"
fi fi
if [ -n "$_alias" ]; then fn_name=${fn_name}$(get_alias $_name)
fn_name="${fn_name}${_alias}"
elif [ -n "$_name" ]; then
fn_name="${fn_name}${_name}"
fi
if [ -z "$_body" ]; then if [ -z "$_body" ]; then
return return
@ -68,7 +63,7 @@ parse_config () {
local _section=$(echo $line | grep '^\[.*' | sed 's/\[\(.*\)\]/\1/') local _section=$(echo $line | grep '^\[.*' | sed 's/\[\(.*\)\]/\1/')
if [ -n "$_section" ]; then if [ -n "$_section" ]; then
end_section end_section
unset _group _name _alias _body unset _group _name _body
_group=$(echo $_section | awk '{ print $1 }') _group=$(echo $_section | awk '{ print $1 }')
@ -78,13 +73,11 @@ parse_config () {
fi fi
if [ "$_group" = "metrics.sh" ]; then if [ "$_group" = "metrics.sh" ]; then
_group="global" _group="main"
continue continue
fi fi
_section=$(echo $_section | awk '{ print $2 }') _name=$(echo $_section | awk '{ print $2 }')
_name=$(echo $_section | awk 'BEGIN { FS=":" } { print $1 }')
_alias=$(echo $_section | awk 'BEGIN { FS=":" } { print $2 }')
continue continue
fi fi

View File

@ -16,4 +16,11 @@ in_array () {
trim () { trim () {
echo $1 | sed -e 's/^[[:space:]]*//g' -e 's/[[:space:]]*\$//g' echo $1 | sed -e 's/^[[:space:]]*//g' -e 's/[[:space:]]*\$//g'
}
unique_id () {
RESTORE_LC_ALL=$LC_ALL
LC_ALL=C
echo __u_$(cat /dev/urandom | tr -dc 'A-Za-z0-9' | head -c 10)
LC_ALL=$RESTORE_LC_ALL
} }

View File

@ -12,7 +12,7 @@ LANG=en_US.UTF-8
LANGUAGE=en_US.UTF-8 LANGUAGE=en_US.UTF-8
usage () { usage () {
echo " Usage: $0 [-d] [-h] [-v] [-m metrics] [-r reporter] [-i interval]" echo " Usage: $0 [-d] [-h] [-v] [-c] [-m] [-r] [-i]"
} }
help () { help () {
@ -82,10 +82,11 @@ done
# run # run
. ./lib/main.sh . ./lib/main.sh
if [ $opt_verbose = "true" ]; then if [ $opt_verbose = true ]; then
verbose_on verbose_on
verbose "Started in verbose mode" verbose "Started in verbose mode"
fi fi
verbose "PID: $$"
verbose "OS detected: $OS_TYPE" verbose "OS detected: $OS_TYPE"
main_load main_load
@ -105,8 +106,8 @@ if [ -n "$CONFIG_FILE" ]; then
exit 1 exit 1
fi fi
if is_function global_config; then if is_function main_config; then
global_config main_config
fi fi
configured_reporters=$(get_configured_reporters) configured_reporters=$(get_configured_reporters)

View File

@ -8,7 +8,7 @@ init () {
DISK_IO_MOUNTPOINT="/dev/vda" DISK_IO_MOUNTPOINT="/dev/vda"
fi fi
fi fi
readonly __disk_io_fifo=$TEMP_DIR/disk_io readonly __disk_io_fifo=$TEMP_DIR/$(unique_id)
mkfifo $__disk_io_fifo mkfifo $__disk_io_fifo
__disk_io_bgproc & __disk_io_bgproc &
} }