]> arthur.barton.de Git - netdata.git/blob - plugins.d/charts.d.plugin
fixed charts.d.plugin to get directories from netdata server; netdata now exports...
[netdata.git] / plugins.d / charts.d.plugin
1 #!/bin/bash
2
3 PROGRAM_FILE="$0"
4 PROGRAM_NAME="charts.d"
5 echo >&2 "$PROGRAM_NAME: started from '$PROGRAM_FILE' with options: $*"
6
7 if [ $(( ${BASH_VERSINFO[0]} )) -lt 4 ]
8 then
9         echo >&2 
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."
14         echo >&2 
15         exit 1
16 fi
17
18 # check a few commands
19 require_cmd() {
20         which "$1" >/dev/null
21         if [ $? -ne 0 ]
22                 then
23                 echo >&2 "$PROGRAM_NAME: ERROR: Command '$1' is not found in the system path."
24                 return 1
25         fi
26         return 0
27 }
28
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
36
37 # -----------------------------------------------------------------------------
38 # insternal defaults
39 # netdata exposes a few environment variables for us
40
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
44
45 pluginsd="${NETDATA_PLUGINS_DIR}"
46 [ -z "$pluginsd" ] && pluginsd="$( dirname $PROGRAM_FILE )"
47
48 confd="${NETDATA_CONFIG_DIR-/etc/netdata}"
49 chartsd="$pluginsd/../charts.d"
50 myconfig="$confd/charts.d.conf"
51
52 minimum_update_frequency="${NETDATA_UPDATE_EVERY-1}"
53 update_every=${minimum_update_frequency}        # this will be overwritten by the command line
54
55 # work around for non BASH shells
56 charts_create="_create"
57 charts_update="_update"
58 charts_check="_check"
59 charts_undescore="_"
60
61 # -----------------------------------------------------------------------------
62 # parse parameters
63
64 debug=0
65 check=0
66 chart_only=
67 while [ ! -z "$1" ]
68 do
69         if [ "$1" = "check" ]
70         then
71                 check=1
72                 shift
73                 continue
74         fi
75
76         if [ "$1" = "debug" -o "$1" = "all" ]
77         then
78                 debug=1
79                 shift
80                 continue
81         fi
82
83         if [ -f "$chartsd/$1.chart.sh" ]
84         then
85                 debug=1
86                 chart_only="$( echo $1.chart.sh | sed "s/\.chart\.sh$//g" )"
87                 shift
88                 continue
89         fi
90
91         if [ -f "$chartsd/$1" ]
92         then
93                 debug=1
94                 chart_only="$( echo $1 | sed "s/\.chart\.sh$//g" )"
95                 shift
96                 continue
97         fi
98
99         # number check
100         n="$1"
101         x=$(( n ))
102         if [ "$x" = "$n" ]
103         then
104                 shift
105                 update_every=$x
106                 continue
107         fi
108
109         echo >&2 "Cannot understand parameter $1. Aborting."
110         echo "DISABLE"
111         exit 1
112 done
113
114
115 # -----------------------------------------------------------------------------
116 # load my configuration
117
118 if [ -f "$myconfig" ]
119         then
120         . "$myconfig"
121         if [ $? -ne 0 ]
122         then
123                 echo >&2 "$PROGRAM_NAME: cannot load $myconfig"
124                 echo "DISABLE"
125                 exit 1
126         fi
127 fi
128
129 if [ "$pause_method" = "suspend" ]
130 then
131         # enable bash job control
132         # this is required for suspend to work
133         set -m
134 fi
135
136 # -----------------------------------------------------------------------------
137 # internal checks
138
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
142
143 # check the charts.d directory
144 if [ ! -d "$chartsd" ]
145         then
146         echo >&2 "$PROGRAM_NAME: cannot find charts directory '$chartsd'"
147         echo "DISABLE"
148 fi
149
150
151 # -----------------------------------------------------------------------------
152 # loop control
153
154 # default sleep function
155 loopsleepms() {
156         sleep $1
157 }
158
159 now_ms=
160 current_time_ms() {
161         now_ms="$(date +'%s')000"
162 }
163
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"
168
169
170 # -----------------------------------------------------------------------------
171 # charts check functions
172
173 all_charts() {
174         cd "$chartsd"
175         [ $? -ne 0 ] && echo >&2 "$PROGRAM_NAME: Cannot cd to $chartsd" && return 1
176
177         ls *.chart.sh | sed "s/\.chart\.sh$//g"
178 }
179
180 all_enabled_charts() {
181         local charts=
182
183         # find all enabled charts
184
185         for chart in $( all_charts )
186         do
187                 eval "enabled=\$$chart"
188                 if [ "$enabled" = "yes" ]
189                 then
190                         [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: '$chart' is enabled."
191                         local charts="$charts $chart"
192                 else
193                         echo >&2 "$PROGRAM_NAME: '$chart' is NOT enabled. Add a line with $chart=yes in $myconfig to enable it."
194                 fi
195         done
196
197         local charts2=
198         for chart in $charts
199         do
200                 # check the enabled charts
201                 local check="$( cat "$chartsd/$chart.chart.sh" | sed "s/^ \+//g" | grep "^$chart$charts_check()" )"
202                 if [ -z "$check" ]
203                 then
204                         echo >&2 "$PROGRAM_NAME: chart '$chart' does not seem to have a $chart$charts_check() function. Disabling it."
205                         continue
206                 fi
207
208                 local create="$( cat "$chartsd/$chart.chart.sh" | sed "s/^ \+//g" | grep "^$chart$charts_create()" )"
209                 if [ -z "$create" ]
210                 then
211                         echo >&2 "$PROGRAM_NAME: chart '$chart' does not seem to have a $chart$charts_create() function. Disabling it."
212                         continue
213                 fi
214
215                 local update="$( cat "$chartsd/$chart.chart.sh" | sed "s/^ \+//g" | grep "^$chart$charts_update()" )"
216                 if [ -z "$update" ]
217                 then
218                         echo >&2 "$PROGRAM_NAME: chart '$chart' does not seem to have a $chart$charts_update() function. Disabling it."
219                         continue
220                 fi
221
222                 # check its config
223                 #if [ -f "$confd/$chart.conf" ]
224                 #then
225                 #       if [ ! -z "$( cat "$confd/$chart.conf" | sed "s/^ \+//g" | grep -v "^$" | grep -v "^#" | grep -v "^$chart$charts_undescore" )" ]
226                 #       then
227                 #               echo >&2 "$PROGRAM_NAME: chart's $chart config $confd/$chart.conf should only have lines starting with $chart$charts_undescore . Disabling it."
228                 #               continue
229                 #       fi
230                 #fi
231
232                 "$pluginsd/charts.d.dryrun-helper.sh" "$chart" "$chartsd/$chart.chart.sh" "$confd/$chart.conf" >/dev/null
233                 if [ $? -ne 0 ]
234                 then
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."
236                         continue
237                 fi
238
239                 local charts2="$charts2 $chart"
240         done
241
242         echo $charts2
243         [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: enabled charts: $charts2"
244 }
245
246
247 # -----------------------------------------------------------------------------
248 # load the charts
249
250 suffix_update_every="_update_every"
251 active_charts=
252 for chart in $( all_enabled_charts )
253 do
254         [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: loading chart: '$chartsd/$chart.chart.sh'"
255         . "$chartsd/$chart.chart.sh"
256
257         if [ -f "$confd/$chart.conf" ]
258         then
259                 [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: loading chart options: '$confd/$chart.conf'"
260                 . "$confd/$chart.conf"
261         fi
262
263         eval "dt=\$$chart$suffix_update_every"
264         dt=$(( dt + 1 - 1 )) # make sure it is a number
265         if [ $dt -lt $update_every ]
266         then
267                 eval "$chart$suffix_update_every=$update_every"
268         fi
269
270         $chart$charts_check
271         if [ $? -eq 0 ]
272         then
273                 [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: '$chart' activated"
274                 active_charts="$active_charts $chart"
275         else
276                 echo >&2 "$PROGRAM_NAME: chart '$chart' check() function reports failure."
277         fi
278 done
279 [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: activated charts: $active_charts"
280
281
282 # -----------------------------------------------------------------------------
283 # check overwrites
284
285 # enable work time reporting
286 debug_time=
287 test $debug -eq 1 && debug_time=tellwork
288
289 # if we only need a specific chart, remove all the others
290 if [ ! -z "${chart_only}" ]
291 then
292         [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: requested to run only for: '${chart_only}'"
293         check_charts=
294         for chart in $active_charts
295         do
296                 if [ "$chart" = "$chart_only" ]
297                 then
298                         check_charts="$chart"
299                         break
300                 fi
301         done
302         active_charts="$check_charts"
303 fi
304 [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: activated charts: $active_charts"
305
306 # stop if we just need a pre-check
307 if [ $check -eq 1 ]
308 then
309         echo >&2 "CHECK RESULT"
310         echo >&2 "Will run the charts: $active_charts"
311         exit 0
312 fi
313
314 # -----------------------------------------------------------------------------
315 # create temp dir
316
317 TMP_DIR=
318 chartsd_cleanup() {
319         cd /tmp
320         if [ ! -z "$TMP_DIR" -a -d "$TMP_DIR" ]
321         then
322                 [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: cleaning up temporary directory $TMP_DIR ..."
323                 rm -rf "$TMP_DIR"
324         fi
325         exit 0
326 }
327 trap chartsd_cleanup EXIT
328 trap chartsd_cleanup SIGHUP
329 trap chartsd_cleanup INT
330
331 if [ $UID = "0" ]
332 then
333         TMP_DIR="$( mktemp -d /var/run/netdata-charts.d-XXXXXXXXXX )"
334 else
335         TMP_DIR="$( mktemp -d /tmp/.netdata-charts.d-XXXXXXXXXX )"
336 fi
337
338 cd "$TMP_DIR" || exit 1
339
340 # -----------------------------------------------------------------------------
341 # library functions
342
343 fixid() {
344         echo "$*" |\
345                 tr -c "[A-Z][a-z][0-9]" "_" |\
346                 sed -e "s|^_\+||g" -e "s|_\+$||g" -e "s|_\+|_|g" |\
347                 tr "[A-Z]" "[a-z]"
348 }
349
350
351 # -----------------------------------------------------------------------------
352 # create charts
353
354 run_charts=
355 for chart in $active_charts
356 do
357         [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: Calling '$chart$charts_create()'..."
358         $chart$charts_create
359         if [ $? -eq 0 ]
360         then
361                 run_charts="$run_charts $chart"
362                 [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: '$chart' has initialized."
363         else
364                 echo >&2 "$PROGRAM_NAME: chart '$chart' function '$chart$charts_create()' reports failure."
365         fi
366 done
367 [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: run_charts='$run_charts'"
368
369
370 # -----------------------------------------------------------------------------
371 # update dimensions
372
373 declare -A charts_last_update=() charts_min_dt=()
374 global_update() {
375         local exit_after=$((3600 / update_every)) \
376                 c=0 dt \
377                 chart now_charts=() next_charts=($run_charts)
378
379         # return the current time in ms in $now_ms
380         current_time_ms
381
382         for chart in $run_charts
383         do
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) ))
387         done
388
389         # the main loop
390         while [ 1 ]
391         do
392                 c=$((c + 1))
393                 now_charts=("${next_charts[@]}")
394                 next_charts=()
395
396                 for chart in "${now_charts[@]}"
397                 do
398                         # return the current time in ms in $now_ms
399                         current_time_ms
400
401                         dt=$(( (now_ms - charts_last_update[$chart]) * 1000 ))
402                         if [ $dt -ge $(( charts_min_dt[$chart] * 1000000 )) ]
403                         then
404                                 charts_last_update[$chart]=$now_ms
405
406                                 # the first call should not give a duration
407                                 # so that netdata calibrates to current time
408                                 test $c -eq 1 && dt=
409
410                                 $chart$charts_update $dt
411                                 if [ $? -eq 0 ]
412                                 then
413                                         next_charts+=($chart)
414                                 else
415                                         echo >&2 "$PROGRAM_NAME: chart '$chart' update() function reports failure. Disabling it."
416                                 fi
417                         else
418                                 next_charts+=($chart)
419                         fi
420                 done
421
422                 if [ "$pause_method" = "suspend" ]
423                 then
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 )
426                 else
427                         # wait the time you are required to
428                         loopsleepms $debug_time $update_every
429                 fi
430
431                 test $c -gt $exit_after && exit 0
432         done
433 }
434
435 global_update