4 PROGRAM_NAME="charts.d"
5 echo >&2 "$PROGRAM_NAME: started from '$PROGRAM_FILE' with options: $*"
7 if [ $(( ${BASH_VERSINFO[0]} )) -lt 4 ]
10 echo >&2 "$PROGRAM_NAME: ERROR"
11 echo >&2 "BASH version 4 or later is required."
12 echo >&2 "You are running version: ${BASH_VERSION}"
13 echo >&2 "Please upgrade."
18 # check a few commands
23 echo >&2 "$PROGRAM_NAME: ERROR: Command '$1' is not found in the system path."
29 require_cmd date || exit 1
30 require_cmd sed || exit 1
31 require_cmd basename || exit 1
32 require_cmd dirname || exit 1
33 require_cmd cat || exit 1
34 require_cmd grep || exit 1
35 require_cmd mktemp || exit 1
37 # -----------------------------------------------------------------------------
39 # netdata exposes a few environment variables for us
41 pause_method="sleep" # use either "suspend" or "sleep"
42 # DO NOT USE SUSPEND - LINUX WILL SUSPEND NETDATA TOO
43 # THE WHOLE PROCESS GROUP - NOT JUST THE SHELL
45 pluginsd="${NETDATA_PLUGINS_DIR}"
46 [ -z "$pluginsd" ] && pluginsd="$( dirname $PROGRAM_FILE )"
48 confd="${NETDATA_CONFIG_DIR-/etc/netdata}"
49 chartsd="$pluginsd/../charts.d"
50 myconfig="$confd/charts.d.conf"
52 minimum_update_frequency="${NETDATA_UPDATE_EVERY-1}"
53 update_every=${minimum_update_frequency} # this will be overwritten by the command line
55 # work around for non BASH shells
56 charts_create="_create"
57 charts_update="_update"
61 # -----------------------------------------------------------------------------
76 if [ "$1" = "debug" -o "$1" = "all" ]
83 if [ -f "$chartsd/$1.chart.sh" ]
86 chart_only="$( echo $1.chart.sh | sed "s/\.chart\.sh$//g" )"
91 if [ -f "$chartsd/$1" ]
94 chart_only="$( echo $1 | sed "s/\.chart\.sh$//g" )"
109 echo >&2 "Cannot understand parameter $1. Aborting."
115 # -----------------------------------------------------------------------------
116 # load my configuration
118 if [ -f "$myconfig" ]
123 echo >&2 "$PROGRAM_NAME: cannot load $myconfig"
129 if [ "$pause_method" = "suspend" ]
131 # enable bash job control
132 # this is required for suspend to work
136 # -----------------------------------------------------------------------------
139 # netdata passes the requested update frequency as the first argument
140 update_every=$(( update_every + 1 - 1)) # makes sure it is a number
141 test $update_every -eq 0 && update_every=1 # if it is zero, make it 1
143 # check the charts.d directory
144 if [ ! -d "$chartsd" ]
146 echo >&2 "$PROGRAM_NAME: cannot find charts directory '$chartsd'"
151 # -----------------------------------------------------------------------------
154 # default sleep function
161 now_ms="$(date +'%s')000"
164 # if found and included, this file overwrites loopsleepms()
165 # and current_time_ms() with a high resolution timer function
166 # for precise looping.
167 . "$pluginsd/loopsleepms.sh.inc"
170 # -----------------------------------------------------------------------------
171 # charts check functions
175 [ $? -ne 0 ] && echo >&2 "$PROGRAM_NAME: Cannot cd to $chartsd" && return 1
177 ls *.chart.sh | sed "s/\.chart\.sh$//g"
180 all_enabled_charts() {
183 # find all enabled charts
185 for chart in $( all_charts )
187 eval "enabled=\$$chart"
188 if [ "$enabled" = "yes" ]
190 [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: '$chart' is enabled."
191 local charts="$charts $chart"
193 echo >&2 "$PROGRAM_NAME: '$chart' is NOT enabled. Add a line with $chart=yes in $myconfig to enable it."
200 # check the enabled charts
201 local check="$( cat "$chartsd/$chart.chart.sh" | sed "s/^ \+//g" | grep "^$chart$charts_check()" )"
204 echo >&2 "$PROGRAM_NAME: chart '$chart' does not seem to have a $chart$charts_check() function. Disabling it."
208 local create="$( cat "$chartsd/$chart.chart.sh" | sed "s/^ \+//g" | grep "^$chart$charts_create()" )"
211 echo >&2 "$PROGRAM_NAME: chart '$chart' does not seem to have a $chart$charts_create() function. Disabling it."
215 local update="$( cat "$chartsd/$chart.chart.sh" | sed "s/^ \+//g" | grep "^$chart$charts_update()" )"
218 echo >&2 "$PROGRAM_NAME: chart '$chart' does not seem to have a $chart$charts_update() function. Disabling it."
223 #if [ -f "$confd/$chart.conf" ]
225 # if [ ! -z "$( cat "$confd/$chart.conf" | sed "s/^ \+//g" | grep -v "^$" | grep -v "^#" | grep -v "^$chart$charts_undescore" )" ]
227 # echo >&2 "$PROGRAM_NAME: chart's $chart config $confd/$chart.conf should only have lines starting with $chart$charts_undescore . Disabling it."
232 "$pluginsd/charts.d.dryrun-helper.sh" "$chart" "$chartsd/$chart.chart.sh" "$confd/$chart.conf" >/dev/null
235 echo >&2 "$PROGRAM_NAME: chart's $chart did not pass the dry run check. This means it uses global variables not starting with $chart. Disabling it."
239 local charts2="$charts2 $chart"
243 [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: enabled charts: $charts2"
247 # -----------------------------------------------------------------------------
250 suffix_update_every="_update_every"
252 for chart in $( all_enabled_charts )
254 [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: loading chart: '$chartsd/$chart.chart.sh'"
255 . "$chartsd/$chart.chart.sh"
257 if [ -f "$confd/$chart.conf" ]
259 [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: loading chart options: '$confd/$chart.conf'"
260 . "$confd/$chart.conf"
263 eval "dt=\$$chart$suffix_update_every"
264 dt=$(( dt + 1 - 1 )) # make sure it is a number
265 if [ $dt -lt $update_every ]
267 eval "$chart$suffix_update_every=$update_every"
273 [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: '$chart' activated"
274 active_charts="$active_charts $chart"
276 echo >&2 "$PROGRAM_NAME: chart '$chart' check() function reports failure."
279 [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: activated charts: $active_charts"
282 # -----------------------------------------------------------------------------
285 # enable work time reporting
287 test $debug -eq 1 && debug_time=tellwork
289 # if we only need a specific chart, remove all the others
290 if [ ! -z "${chart_only}" ]
292 [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: requested to run only for: '${chart_only}'"
294 for chart in $active_charts
296 if [ "$chart" = "$chart_only" ]
298 check_charts="$chart"
302 active_charts="$check_charts"
304 [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: activated charts: $active_charts"
306 # stop if we just need a pre-check
309 echo >&2 "CHECK RESULT"
310 echo >&2 "Will run the charts: $active_charts"
314 # -----------------------------------------------------------------------------
320 if [ ! -z "$TMP_DIR" -a -d "$TMP_DIR" ]
322 [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: cleaning up temporary directory $TMP_DIR ..."
327 trap chartsd_cleanup EXIT
328 trap chartsd_cleanup SIGHUP
329 trap chartsd_cleanup INT
333 TMP_DIR="$( mktemp -d /var/run/netdata-charts.d-XXXXXXXXXX )"
335 TMP_DIR="$( mktemp -d /tmp/.netdata-charts.d-XXXXXXXXXX )"
338 cd "$TMP_DIR" || exit 1
340 # -----------------------------------------------------------------------------
345 tr -c "[A-Z][a-z][0-9]" "_" |\
346 sed -e "s|^_\+||g" -e "s|_\+$||g" -e "s|_\+|_|g" |\
351 # -----------------------------------------------------------------------------
355 for chart in $active_charts
357 [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: Calling '$chart$charts_create()'..."
361 run_charts="$run_charts $chart"
362 [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: '$chart' has initialized."
364 echo >&2 "$PROGRAM_NAME: chart '$chart' function '$chart$charts_create()' reports failure."
367 [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: run_charts='$run_charts'"
370 # -----------------------------------------------------------------------------
373 declare -A charts_last_update=() charts_min_dt=()
375 local exit_after=$((3600 / update_every)) \
377 chart now_charts=() next_charts=($run_charts)
379 # return the current time in ms in $now_ms
382 for chart in $run_charts
384 eval "charts_min_dt[$chart]=\$$chart$suffix_update_every"
385 test -z "${charts_min_dt[$chart]}" && charts_min_dt[$charts]=$update_every
386 charts_last_update[$chart]=$((now_ms - (charts_min_dt[$chart] * 1000) ))
393 now_charts=("${next_charts[@]}")
396 for chart in "${now_charts[@]}"
398 # return the current time in ms in $now_ms
401 dt=$(( (now_ms - charts_last_update[$chart]) * 1000 ))
402 if [ $dt -ge $(( charts_min_dt[$chart] * 1000000 )) ]
404 charts_last_update[$chart]=$now_ms
406 # the first call should not give a duration
407 # so that netdata calibrates to current time
410 $chart$charts_update $dt
413 next_charts+=($chart)
415 echo >&2 "$PROGRAM_NAME: chart '$chart' update() function reports failure. Disabling it."
418 next_charts+=($chart)
422 if [ "$pause_method" = "suspend" ]
424 echo "STOPPING_WAKE_ME_UP_PLEASE"
425 suspend || ( echo >&2 "$PROGRAM_NAME: suspend returned error $?, falling back to sleep."; loopsleepms $debug_time $update_every )
427 # wait the time you are required to
428 loopsleepms $debug_time $update_every
431 test $c -gt $exit_after && exit 0