4 PROGRAM_NAME="$(basename $0)"
5 PROGRAM_NAME="${PROGRAM_NAME/.plugin}"
7 # if you need to run parallel charts.d processes
8 # just link this files with a different name
9 # in the same directory, with a .plugin suffix
10 # netdata will start multiple of them
11 # each will have a different config file
13 echo >&2 "$PROGRAM_NAME: started from '$PROGRAM_FILE' with options: $*"
15 if [ $(( ${BASH_VERSINFO[0]} )) -lt 4 ]
18 echo >&2 "$PROGRAM_NAME: ERROR"
19 echo >&2 "BASH version 4 or later is required."
20 echo >&2 "You are running version: ${BASH_VERSION}"
21 echo >&2 "Please upgrade."
26 # check a few commands
31 echo >&2 "$PROGRAM_NAME: ERROR: Command '$1' is not found in the system path."
37 require_cmd date || exit 1
38 require_cmd sed || exit 1
39 require_cmd basename || exit 1
40 require_cmd dirname || exit 1
41 require_cmd cat || exit 1
42 require_cmd grep || exit 1
43 require_cmd mktemp || exit 1
45 # -----------------------------------------------------------------------------
47 # netdata exposes a few environment variables for us
49 pause_method="sleep" # use either "suspend" or "sleep"
50 # DO NOT USE SUSPEND - LINUX WILL SUSPEND NETDATA TOO
51 # THE WHOLE PROCESS GROUP - NOT JUST THE SHELL
53 pluginsd="${NETDATA_PLUGINS_DIR}"
54 [ -z "$pluginsd" ] && pluginsd="$( dirname $PROGRAM_FILE )"
56 confd="${NETDATA_CONFIG_DIR-/etc/netdata}"
57 chartsd="$pluginsd/../charts.d"
59 myconfig="$confd/$PROGRAM_NAME.conf"
61 minimum_update_frequency="${NETDATA_UPDATE_EVERY-1}"
62 update_every=${minimum_update_frequency} # this will be overwritten by the command line
64 # work around for non BASH shells
65 charts_create="_create"
66 charts_update="_update"
70 # when making iterations, charts.d can loop more frequently
71 # to prevent plugins missing iterations.
72 # this is a percentage relative to update_every to align its
74 # The minimum is 10%, the maximum 100%.
75 # So, if update_every is 1 second and time_divisor is 50,
76 # charts.d will iterate every 500ms.
77 # Charts will be called to collect data only if the time
78 # passes since the last time the collected data is equal or
79 # above their update_every.
82 # number of seconds to run without restart
83 # after this time, charts.d.plugin will exit
84 # netdata will restart it
87 # check if the charts.d plugins are using global variables
89 # It does not currently support BASH v4 arrays, so it is
93 # -----------------------------------------------------------------------------
101 if [ "$1" = "check" ]
108 if [ "$1" = "debug" -o "$1" = "all" ]
115 if [ -f "$chartsd/$1.chart.sh" ]
118 chart_only="$( echo $1.chart.sh | sed "s/\.chart\.sh$//g" )"
123 if [ -f "$chartsd/$1" ]
126 chart_only="$( echo $1 | sed "s/\.chart\.sh$//g" )"
138 [ $update_every -lt $minimum_update_frequency ] && update_every=$minimum_update_frequency
142 echo >&2 "Cannot understand parameter $1. Aborting."
148 # -----------------------------------------------------------------------------
149 # load my configuration
151 if [ -f "$myconfig" ]
156 echo >&2 "$PROGRAM_NAME: cannot load $myconfig"
160 time_divisor=$((time_divisor))
161 [ $time_divisor -lt 10 ] && time_divisor=10
162 [ $time_divisor -gt 100 ] && time_divisor=100
165 if [ "$pause_method" = "suspend" ]
167 # enable bash job control
168 # this is required for suspend to work
172 # -----------------------------------------------------------------------------
175 # netdata passes the requested update frequency as the first argument
176 update_every=$(( update_every + 1 - 1)) # makes sure it is a number
177 test $update_every -eq 0 && update_every=1 # if it is zero, make it 1
179 # check the charts.d directory
180 if [ ! -d "$chartsd" ]
182 echo >&2 "$PROGRAM_NAME: cannot find charts directory '$chartsd'"
187 # -----------------------------------------------------------------------------
190 # default sleep function
192 [ "$1" = "tellwork" ] && shift
198 now_ms="$(date +'%s')000"
201 # if found and included, this file overwrites loopsleepms()
202 # and current_time_ms() with a high resolution timer function
203 # for precise looping.
204 . "$pluginsd/loopsleepms.sh.inc"
207 # -----------------------------------------------------------------------------
212 tr -c "[A-Z][a-z][0-9]" "_" |\
213 sed -e "s|^_\+||g" -e "s|_\+$||g" -e "s|_\+|_|g" |\
218 # -----------------------------------------------------------------------------
219 # charts check functions
223 [ $? -ne 0 ] && echo >&2 "$PROGRAM_NAME: Cannot cd to $chartsd" && return 1
225 ls *.chart.sh | sed "s/\.chart\.sh$//g"
228 all_enabled_charts() {
231 # find all enabled charts
233 for chart in $( all_charts )
235 eval "enabled=\$$chart"
236 if [ "$enabled" = "yes" ]
238 [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: '$chart' is enabled."
239 local charts="$charts $chart"
241 echo >&2 "$PROGRAM_NAME: '$chart' is NOT enabled. Add a line with $chart=yes in $myconfig to enable it."
248 # check the enabled charts
249 local check="$( cat "$chartsd/$chart.chart.sh" | sed "s/^ \+//g" | grep "^$chart$charts_check()" )"
252 echo >&2 "$PROGRAM_NAME: chart '$chart' does not seem to have a $chart$charts_check() function. Disabling it."
256 local create="$( cat "$chartsd/$chart.chart.sh" | sed "s/^ \+//g" | grep "^$chart$charts_create()" )"
259 echo >&2 "$PROGRAM_NAME: chart '$chart' does not seem to have a $chart$charts_create() function. Disabling it."
263 local update="$( cat "$chartsd/$chart.chart.sh" | sed "s/^ \+//g" | grep "^$chart$charts_update()" )"
266 echo >&2 "$PROGRAM_NAME: chart '$chart' does not seem to have a $chart$charts_update() function. Disabling it."
271 #if [ -f "$confd/$chart.conf" ]
273 # if [ ! -z "$( cat "$confd/$chart.conf" | sed "s/^ \+//g" | grep -v "^$" | grep -v "^#" | grep -v "^$chart$charts_undescore" )" ]
275 # echo >&2 "$PROGRAM_NAME: chart's $chart config $confd/$chart.conf should only have lines starting with $chart$charts_undescore . Disabling it."
280 if [ $dryrunner -eq 1 ]
282 "$pluginsd/charts.d.dryrun-helper.sh" "$chart" "$chartsd/$chart.chart.sh" "$confd/$chart.conf" >/dev/null
285 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."
290 local charts2="$charts2 $chart"
294 [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: enabled charts: $charts2"
298 # -----------------------------------------------------------------------------
301 suffix_update_every="_update_every"
303 for chart in $( all_enabled_charts )
305 [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: loading chart: '$chartsd/$chart.chart.sh'"
306 . "$chartsd/$chart.chart.sh"
308 if [ -f "$confd/$chart.conf" ]
310 [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: loading chart options: '$confd/$chart.conf'"
311 . "$confd/$chart.conf"
314 eval "dt=\$$chart$suffix_update_every"
315 dt=$(( dt + 1 - 1 )) # make sure it is a number
316 if [ $dt -lt $update_every ]
318 eval "$chart$suffix_update_every=$update_every"
324 [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: '$chart' activated"
325 active_charts="$active_charts $chart"
327 echo >&2 "$PROGRAM_NAME: chart '$chart' check() function reports failure."
330 [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: activated charts: $active_charts"
333 # -----------------------------------------------------------------------------
336 # enable work time reporting
338 test $debug -eq 1 && debug_time=tellwork
340 # if we only need a specific chart, remove all the others
341 if [ ! -z "${chart_only}" ]
343 [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: requested to run only for: '${chart_only}'"
345 for chart in $active_charts
347 if [ "$chart" = "$chart_only" ]
349 check_charts="$chart"
353 active_charts="$check_charts"
355 [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: activated charts: $active_charts"
357 # stop if we just need a pre-check
360 echo >&2 "CHECK RESULT"
361 echo >&2 "Will run the charts: $active_charts"
365 # -----------------------------------------------------------------------------
371 if [ ! -z "$TMP_DIR" -a -d "$TMP_DIR" ]
373 [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: cleaning up temporary directory $TMP_DIR ..."
378 trap chartsd_cleanup EXIT
379 trap chartsd_cleanup SIGHUP
380 trap chartsd_cleanup INT
384 TMP_DIR="$( mktemp -d /var/run/netdata-${PROGRAM_NAME}-XXXXXXXXXX )"
386 TMP_DIR="$( mktemp -d /tmp/.netdata-${PROGRAM_NAME}-XXXXXXXXXX )"
389 cd "$TMP_DIR" || exit 1
391 # -----------------------------------------------------------------------------
395 for chart in $active_charts
397 [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: Calling '$chart$charts_create()'..."
401 run_charts="$run_charts $chart"
402 [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: '$chart' has initialized."
404 echo >&2 "$PROGRAM_NAME: chart '$chart' function '$chart$charts_create()' reports failure."
407 [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: run_charts='$run_charts'"
410 # -----------------------------------------------------------------------------
413 if [ -z "$run_charts" ]
415 echo >&2 "$PROGRAM_NAME: No charts to collect data from."
420 declare -A charts_last_update=() charts_min_dt=()
422 local exit_after=$((restart_timeout / update_every)) \
424 chart now_charts=() next_charts=($run_charts)
426 # return the current time in ms in $now_ms
429 for chart in $run_charts
431 eval "charts_min_dt[$chart]=\$$chart$suffix_update_every"
432 test -z "${charts_min_dt[$chart]}" && charts_min_dt[$charts]=$update_every
433 charts_last_update[$chart]=$((now_ms - (charts_min_dt[$chart] * 1000) ))
440 now_charts=("${next_charts[@]}")
443 for chart in "${now_charts[@]}"
445 # return the current time in ms in $now_ms
448 dt=$(( (now_ms - charts_last_update[$chart]) * 1000 ))
449 if [ $dt -ge $(( charts_min_dt[$chart] * 1000000 )) ]
451 charts_last_update[$chart]=$now_ms
453 # the first call should not give a duration
454 # so that netdata calibrates to current time
457 $chart$charts_update $dt
460 next_charts+=($chart)
462 echo >&2 "$PROGRAM_NAME: chart '$chart' update() function reports failure. Disabling it."
465 next_charts+=($chart)
469 if [ "$pause_method" = "suspend" ]
471 echo "STOPPING_WAKE_ME_UP_PLEASE"
472 suspend || ( echo >&2 "$PROGRAM_NAME: suspend returned error $?, falling back to sleep."; loopsleepms $debug_time $update_every $time_divisor)
474 # wait the time you are required to
475 loopsleepms $debug_time $update_every $time_divisor
478 test $c -gt $exit_after && exit 0