@cryptotaxi247 / netdata-1 / commits / c50ec4efe

converted tabs for C, JS, BASH to 4 spaces

Costa Tsaousis committed Aug 13, 2016 at 22:08 UTC c50ec4efef94710302a2da98b78d8a2bfc567c35
68 files changed +22674 -22674
netdata-installer.sh
+698 -698
@@ -26,18 +26,18 @@ printf "\n" >>netdata-installer.log
26 service="$(which service 2>/dev/null || command -v service 2>/dev/null)"
27 systemctl="$(which systemctl 2>/dev/null || command -v systemctl 2>/dev/null)"
28 service() {
29 - local cmd="${1}" action="${2}"
30 -
31 - if [ ! -z "${service}" ]
32 - then
33 - run "${service}" "${cmd}" "${action}"
34 - return $?
35 - elif [ ! -z "${systemctl}" ]
36 - then
37 - run "${systemctl}" "${action}" "${cmd}"
38 - return $?
39 - fi
40 - return 1
29 + local cmd="${1}" action="${2}"
30 +
31 + if [ ! -z "${service}" ]
32 + then
33 + run "${service}" "${cmd}" "${action}"
34 + return $?
35 + elif [ ! -z "${systemctl}" ]
36 + then
37 + run "${systemctl}" "${action}" "${cmd}"
38 + return $?
39 + fi
40 + return 1
41 }
42
43 ME="$0"
@@ -47,353 +47,353 @@ NETDATA_PREFIX=
47 LIBS_ARE_HERE=0
48
49 usage() {
50 - cat <<-USAGE
50 + cat <<-USAGE
51
52 - ${ME} <installer options>
52 + ${ME} <installer options>
53
54 - Valid <installer options> are:
54 + Valid <installer options> are:
55
56 - --install /PATH/TO/INSTALL
56 + --install /PATH/TO/INSTALL
57
58 - If your give: --install /opt
59 - netdata will be installed in /opt/netdata
58 + If your give: --install /opt
59 + netdata will be installed in /opt/netdata
60
61 - --dont-start-it
61 + --dont-start-it
62
63 - Do not (re)start netdata.
64 - Just install it.
63 + Do not (re)start netdata.
64 + Just install it.
65
66 - --dont-wait
66 + --dont-wait
67
68 - Do not wait for the user to press ENTER.
69 - Start immediately building it.
68 + Do not wait for the user to press ENTER.
69 + Start immediately building it.
70
71 - --zlib-is-really-here
72 - --libs-are-really-here
71 + --zlib-is-really-here
72 + --libs-are-really-here
73
74 - If you get errors about missing zlib,
75 - or libuuid but you know it is available,
76 - you have a broken pkg-config.
77 - Use this option to allow it continue
78 - without checking pkg-config.
74 + If you get errors about missing zlib,
75 + or libuuid but you know it is available,
76 + you have a broken pkg-config.
77 + Use this option to allow it continue
78 + without checking pkg-config.
79
80 - Netdata will by default be compiled with gcc optimization -O3
81 - If you need to pass different CFLAGS, use something like this:
80 + Netdata will by default be compiled with gcc optimization -O3
81 + If you need to pass different CFLAGS, use something like this:
82
83 - CFLAGS="<gcc options>" ${ME} <installer options>
83 + CFLAGS="<gcc options>" ${ME} <installer options>
84
85 - For the installer to complete successfully, you will need
86 - these packages installed:
85 + For the installer to complete successfully, you will need
86 + these packages installed:
87
88 - gcc make autoconf automake pkg-config zlib1g-dev (or zlib-devel)
89 - uuid-dev (or libuuid-devel)
88 + gcc make autoconf automake pkg-config zlib1g-dev (or zlib-devel)
89 + uuid-dev (or libuuid-devel)
90
91 - For the plugins, you will at least need:
91 + For the plugins, you will at least need:
92
93 - curl nodejs
93 + curl nodejs
94
95 USAGE
96 }
97
98 md5sum="$(which md5sum 2>/dev/null || command -v md5sum 2>/dev/null)"
99 get_git_config_signatures() {
100 - local x s file md5
101 -
102 - [ ! -d "conf.d" ] && echo >&2 "Wrong directory." && return 1
103 - [ -z "${md5sum}" -o ! -x "${md5sum}" ] && echo >&2 "No md5sum command." && return 1
104 -
105 - echo >configs.signatures.tmp
106 -
107 - for x in $(find conf.d -name \*.conf)
108 - do
109 - x="${x/conf.d\//}"
110 - echo "${x}"
111 - for c in $(git log --follow "conf.d/${x}" | grep ^commit | cut -d ' ' -f 2)
112 - do
113 - git checkout ${c} "conf.d/${x}" || continue
114 - s="$(cat "conf.d/${x}" | md5sum | cut -d ' ' -f 1)"
115 - echo >>configs.signatures.tmp "${x}:${s}"
116 - echo " ${s}"
117 - done
118 - git checkout HEAD "conf.d/${x}" || break
119 - done
120 -
121 - cat configs.signatures.tmp |\
122 - grep -v "^$" |\
123 - sort -u |\
124 - {
125 - echo "declare -A configs_signatures=("
126 - IFS=":"
127 - while read file md5
128 - do
129 - echo " ['${md5}']='${file}'"
130 - done
131 - echo ")"
132 - } >configs.signatures
133 -
134 - rm configs.signatures.tmp
135 -
136 - return 0
100 + local x s file md5
101 +
102 + [ ! -d "conf.d" ] && echo >&2 "Wrong directory." && return 1
103 + [ -z "${md5sum}" -o ! -x "${md5sum}" ] && echo >&2 "No md5sum command." && return 1
104 +
105 + echo >configs.signatures.tmp
106 +
107 + for x in $(find conf.d -name \*.conf)
108 + do
109 + x="${x/conf.d\//}"
110 + echo "${x}"
111 + for c in $(git log --follow "conf.d/${x}" | grep ^commit | cut -d ' ' -f 2)
112 + do
113 + git checkout ${c} "conf.d/${x}" || continue
114 + s="$(cat "conf.d/${x}" | md5sum | cut -d ' ' -f 1)"
115 + echo >>configs.signatures.tmp "${x}:${s}"
116 + echo " ${s}"
117 + done
118 + git checkout HEAD "conf.d/${x}" || break
119 + done
120 +
121 + cat configs.signatures.tmp |\
122 + grep -v "^$" |\
123 + sort -u |\
124 + {
125 + echo "declare -A configs_signatures=("
126 + IFS=":"
127 + while read file md5
128 + do
129 + echo " ['${md5}']='${file}'"
130 + done
131 + echo ")"
132 + } >configs.signatures
133 +
134 + rm configs.signatures.tmp
135 +
136 + return 0
137 }
138
139
140 while [ ! -z "${1}" ]
141 do
142 - if [ "$1" = "--install" ]
143 - then
144 - NETDATA_PREFIX="${2}/netdata"
145 - shift 2
146 - elif [ "$1" = "--zlib-is-really-here" -o "$1" = "--libs-are-really-here" ]
147 - then
148 - LIBS_ARE_HERE=1
149 - shift 1
150 - elif [ "$1" = "--dont-start-it" ]
151 - then
152 - DONOTSTART=1
153 - shift 1
154 - elif [ "$1" = "--dont-wait" ]
155 - then
156 - DONOTWAIT=1
157 - shift 1
158 - elif [ "$1" = "--help" -o "$1" = "-h" ]
159 - then
160 - usage
161 - exit 1
162 - elif [ "$1" = "get_git_config_signatures" ]
163 - then
164 - get_git_config_signatures && exit 0
165 - exit 1
166 - else
167 - echo >&2
168 - echo >&2 "ERROR:"
169 - echo >&2 "I cannot understand option '$1'."
170 - usage
171 - exit 1
172 - fi
142 + if [ "$1" = "--install" ]
143 + then
144 + NETDATA_PREFIX="${2}/netdata"
145 + shift 2
146 + elif [ "$1" = "--zlib-is-really-here" -o "$1" = "--libs-are-really-here" ]
147 + then
148 + LIBS_ARE_HERE=1
149 + shift 1
150 + elif [ "$1" = "--dont-start-it" ]
151 + then
152 + DONOTSTART=1
153 + shift 1
154 + elif [ "$1" = "--dont-wait" ]
155 + then
156 + DONOTWAIT=1
157 + shift 1
158 + elif [ "$1" = "--help" -o "$1" = "-h" ]
159 + then
160 + usage
161 + exit 1
162 + elif [ "$1" = "get_git_config_signatures" ]
163 + then
164 + get_git_config_signatures && exit 0
165 + exit 1
166 + else
167 + echo >&2
168 + echo >&2 "ERROR:"
169 + echo >&2 "I cannot understand option '$1'."
170 + usage
171 + exit 1
172 + fi
173 done
174
175 cat <<-BANNER
176
177 - Welcome to netdata!
178 - Nice to see you are giving it a try!
177 + Welcome to netdata!
178 + Nice to see you are giving it a try!
179
180 - You are about to build and install netdata to your system.
180 + You are about to build and install netdata to your system.
181
182 - It will be installed at these locations:
182 + It will be installed at these locations:
183
184 - - the daemon at ${NETDATA_PREFIX}/usr/sbin/netdata
185 - - config files at ${NETDATA_PREFIX}/etc/netdata
186 - - web files at ${NETDATA_PREFIX}/usr/share/netdata
187 - - plugins at ${NETDATA_PREFIX}/usr/libexec/netdata
188 - - cache files at ${NETDATA_PREFIX}/var/cache/netdata
189 - - db files at ${NETDATA_PREFIX}/var/lib/netdata
190 - - log files at ${NETDATA_PREFIX}/var/log/netdata
191 - - pid file at ${NETDATA_PREFIX}/var/run
184 + - the daemon at ${NETDATA_PREFIX}/usr/sbin/netdata
185 + - config files at ${NETDATA_PREFIX}/etc/netdata
186 + - web files at ${NETDATA_PREFIX}/usr/share/netdata
187 + - plugins at ${NETDATA_PREFIX}/usr/libexec/netdata
188 + - cache files at ${NETDATA_PREFIX}/var/cache/netdata
189 + - db files at ${NETDATA_PREFIX}/var/lib/netdata
190 + - log files at ${NETDATA_PREFIX}/var/log/netdata
191 + - pid file at ${NETDATA_PREFIX}/var/run
192
193 - This installer allows you to change the installation path.
194 - Press Control-C and run the same command with --help for help.
193 + This installer allows you to change the installation path.
194 + Press Control-C and run the same command with --help for help.
195
196 BANNER
197
198 if [ "${UID}" -ne 0 ]
199 - then
200 - if [ -z "${NETDATA_PREFIX}" ]
201 - then
202 - cat <<-NONROOTNOPREFIX
199 + then
200 + if [ -z "${NETDATA_PREFIX}" ]
201 + then
202 + cat <<-NONROOTNOPREFIX
203
204 - Sorry! This will fail!
204 + Sorry! This will fail!
205
206 - You are attempting to install netdata as non-root, but you plan to install it
207 - in system paths.
206 + You are attempting to install netdata as non-root, but you plan to install it
207 + in system paths.
208
209 - Please set an installation prefix, like this:
209 + Please set an installation prefix, like this:
210
211 - $0 ${@} --install /tmp
211 + $0 ${@} --install /tmp
212
213 - or, run the installer as root:
213 + or, run the installer as root:
214
215 - sudo $0 ${@}
215 + sudo $0 ${@}
216
217 - We suggest to install it as root, or certain data collectors will not be able
218 - to work. Netdata drops root privileges when running. So, if you plan to keep
219 - it, install it as root to get the full functionality.
217 + We suggest to install it as root, or certain data collectors will not be able
218 + to work. Netdata drops root privileges when running. So, if you plan to keep
219 + it, install it as root to get the full functionality.
220
221 NONROOTNOPREFIX
222 - exit 1
222 + exit 1
223
224 - else
225 - cat <<-NONROOT
224 + else
225 + cat <<-NONROOT
226
227 - IMPORTANT:
228 - You are about to install netdata as a non-root user.
229 - Netdata will work, but a few data collection modules that
230 - require root access will fail.
227 + IMPORTANT:
228 + You are about to install netdata as a non-root user.
229 + Netdata will work, but a few data collection modules that
230 + require root access will fail.
231
232 - If you installing permanently on your system, run the
233 - installer like this:
232 + If you installing permanently on your system, run the
233 + installer like this:
234
235 - sudo $0 ${@}
235 + sudo $0 ${@}
236
237 NONROOT
238 - fi
238 + fi
239 fi
240
241 have_autotools=
242 if [ "$(type autoreconf 2> /dev/null)" ]
243 then
244 - autoconf_maj_min() {
245 - local maj min IFS=.-
246 -
247 - maj=$1
248 - min=$2
249 -
250 - set -- $(autoreconf -V | sed -ne '1s/.* \([^ ]*\)$/\1/p')
251 - eval $maj=\$1 $min=\$2
252 - }
253 - autoconf_maj_min AMAJ AMIN
254 -
255 - if [ "$AMAJ" -gt 2 ]
256 - then
257 - have_autotools=Y
258 - elif [ "$AMAJ" -eq 2 -a "$AMIN" -ge 60 ]
259 - then
260 - have_autotools=Y
261 - else
262 - echo "Found autotools $AMAJ.$AMIN"
263 - fi
244 + autoconf_maj_min() {
245 + local maj min IFS=.-
246 +
247 + maj=$1
248 + min=$2
249 +
250 + set -- $(autoreconf -V | sed -ne '1s/.* \([^ ]*\)$/\1/p')
251 + eval $maj=\$1 $min=\$2
252 + }
253 + autoconf_maj_min AMAJ AMIN
254 +
255 + if [ "$AMAJ" -gt 2 ]
256 + then
257 + have_autotools=Y
258 + elif [ "$AMAJ" -eq 2 -a "$AMIN" -ge 60 ]
259 + then
260 + have_autotools=Y
261 + else
262 + echo "Found autotools $AMAJ.$AMIN"
263 + fi
264 else
265 - echo "No autotools found"
265 + echo "No autotools found"
266 fi
267
268 if [ ! "$have_autotools" ]
269 then
270 - if [ -f configure ]
271 - then
272 - echo "Will skip autoreconf step"
273 - else
274 - cat <<-"EOF"
270 + if [ -f configure ]
271 + then
272 + echo "Will skip autoreconf step"
273 + else
274 + cat <<-"EOF"
275
276 - -------------------------------------------------------------------------------
277 - autotools 2.60 or later is required
276 + -------------------------------------------------------------------------------
277 + autotools 2.60 or later is required
278
279 - Sorry, you do not seem to have autotools 2.60 or later, which is
280 - required to build from the git sources of netdata.
279 + Sorry, you do not seem to have autotools 2.60 or later, which is
280 + required to build from the git sources of netdata.
281
282 - You can either install a suitable version of autotools and automake
283 - or download a netdata package which does not have these dependencies.
282 + You can either install a suitable version of autotools and automake
283 + or download a netdata package which does not have these dependencies.
284
285 - Source packages where autotools have already been run are available
286 - here:
287 - https://firehol.org/download/netdata/
285 + Source packages where autotools have already been run are available
286 + here:
287 + https://firehol.org/download/netdata/
288
289 - The unsigned/master folder tracks the head of the git tree and released
290 - packages are also available.
289 + The unsigned/master folder tracks the head of the git tree and released
290 + packages are also available.
291 EOF
292 - exit 1
293 - fi
292 + exit 1
293 + fi
294 fi
295
296 if [ ${DONOTWAIT} -eq 0 ]
297 - then
298 - if [ ! -z "${NETDATA_PREFIX}" ]
299 - then
300 - read -p "Press ENTER to build and install netdata to '${NETDATA_PREFIX}' > "
301 - else
302 - read -p "Press ENTER to build and install netdata to your system > "
303 - fi
297 + then
298 + if [ ! -z "${NETDATA_PREFIX}" ]
299 + then
300 + read -p "Press ENTER to build and install netdata to '${NETDATA_PREFIX}' > "
301 + else
302 + read -p "Press ENTER to build and install netdata to your system > "
303 + fi
304 fi
305
306 build_error() {
307 - cat <<-EOF
307 + cat <<-EOF
308
309 - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
309 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
310
311 - Sorry! NetData failed to build...
311 + Sorry! NetData failed to build...
312
313 - You many need to check these:
313 + You many need to check these:
314
315 - 1. The package uuid-dev (or libuuid-devel) has to be installed.
315 + 1. The package uuid-dev (or libuuid-devel) has to be installed.
316
317 - If your system cannot find libuuid, although it is installed
318 - run me with the option: --libs-are-really-here
317 + If your system cannot find libuuid, although it is installed
318 + run me with the option: --libs-are-really-here
319
320 - 2. The package zlib1g-dev (or zlib-devel) has to be installed.
320 + 2. The package zlib1g-dev (or zlib-devel) has to be installed.
321
322 - If your system cannot find zlib, although it is installed
323 - run me with the option: --libs-are-really-here
322 + If your system cannot find zlib, although it is installed
323 + run me with the option: --libs-are-really-here
324
325 - 3. You need basic build tools installed, like:
325 + 3. You need basic build tools installed, like:
326
327 - gcc make autoconf automake pkg-config
327 + gcc make autoconf automake pkg-config
328
329 - Autoconf version 2.60 or higher is required.
329 + Autoconf version 2.60 or higher is required.
330
331 - If you still cannot get it to build, ask for help at github:
331 + If you still cannot get it to build, ask for help at github:
332
333 - https://github.com/firehol/netdata/issues
333 + https://github.com/firehol/netdata/issues
334
335
336 EOF
337 - trap - EXIT
338 - exit 1
337 + trap - EXIT
338 + exit 1
339 }
340
341 run() {
342 - printf >>netdata-installer.log "# "
343 - printf >>netdata-installer.log "%q " "${@}"
344 - printf >>netdata-installer.log " ... "
345 -
346 - printf >&2 "\n"
347 - printf >&2 ":-----------------------------------------------------------------------------\n"
348 - printf >&2 "Running command:\n"
349 - printf >&2 "\n"
350 - printf >&2 "%q " "${@}"
351 - printf >&2 "\n"
352 -
353 - "${@}"
354 -
355 - local ret=$?
356 - if [ ${ret} -ne 0 ]
357 - then
358 - printf >>netdata-installer.log "FAILED!\n"
359 - else
360 - printf >>netdata-installer.log "OK\n"
361 - fi
362 -
363 - return ${ret}
342 + printf >>netdata-installer.log "# "
343 + printf >>netdata-installer.log "%q " "${@}"
344 + printf >>netdata-installer.log " ... "
345 +
346 + printf >&2 "\n"
347 + printf >&2 ":-----------------------------------------------------------------------------\n"
348 + printf >&2 "Running command:\n"
349 + printf >&2 "\n"
350 + printf >&2 "%q " "${@}"
351 + printf >&2 "\n"
352 +
353 + "${@}"
354 +
355 + local ret=$?
356 + if [ ${ret} -ne 0 ]
357 + then
358 + printf >>netdata-installer.log "FAILED!\n"
359 + else
360 + printf >>netdata-installer.log "OK\n"
361 + fi
362 +
363 + return ${ret}
364 }
365
366 if [ ${LIBS_ARE_HERE} -eq 1 ]
367 - then
368 - shift
369 - echo >&2 "ok, assuming libs are really installed."
370 - export ZLIB_CFLAGS=" "
371 - export ZLIB_LIBS="-lz"
372 - export UUID_CFLAGS=" "
373 - export UUID_LIBS="-luuid"
367 + then
368 + shift
369 + echo >&2 "ok, assuming libs are really installed."
370 + export ZLIB_CFLAGS=" "
371 + export ZLIB_LIBS="-lz"
372 + export UUID_CFLAGS=" "
373 + export UUID_LIBS="-luuid"
374 fi
375
376 trap build_error EXIT
377
378 if [ "$have_autotools" ]
379 then
380 - run ./autogen.sh || exit 1
380 + run ./autogen.sh || exit 1
381 fi
382
383 run ./configure \
384 - --prefix="${NETDATA_PREFIX}/usr" \
385 - --sysconfdir="${NETDATA_PREFIX}/etc" \
386 - --localstatedir="${NETDATA_PREFIX}/var" \
387 - --with-zlib --with-math --with-user=netdata \
388 - CFLAGS="${CFLAGS}" || exit 1
384 + --prefix="${NETDATA_PREFIX}/usr" \
385 + --sysconfdir="${NETDATA_PREFIX}/etc" \
386 + --localstatedir="${NETDATA_PREFIX}/var" \
387 + --with-zlib --with-math --with-user=netdata \
388 + CFLAGS="${CFLAGS}" || exit 1
389
390 # remove the build_error hook
391 trap - EXIT
392
393 if [ -f src/netdata ]
394 - then
395 - echo >&2 "Cleaning a possibly old compilation ..."
396 - run make clean
394 + then
395 + echo >&2 "Cleaning a possibly old compilation ..."
396 + run make clean
397 fi
398
399 echo >&2 "Compiling netdata ..."
@@ -401,101 +401,101 @@ run make || exit 1
401
402 if [ "${BASH_VERSINFO[0]}" -ge "4" ]
403 then
404 - declare -A configs_signatures=()
405 - if [ -f "configs.signatures" ]
406 - then
407 - source "configs.signatures" || echo >&2 "ERROR: Failed to load configs.signatures !"
408 - fi
404 + declare -A configs_signatures=()
405 + if [ -f "configs.signatures" ]
406 + then
407 + source "configs.signatures" || echo >&2 "ERROR: Failed to load configs.signatures !"
408 + fi
409 fi
410
411 # migrate existing configuration files
412 # for node.d and charts.d
413 if [ -d "${NETDATA_PREFIX}/etc/netdata" ]
414 - then
415 - # the configuration directory exists
416 -
417 - if [ ! -d "${NETDATA_PREFIX}/etc/netdata/charts.d" ]
418 - then
419 - run mkdir "${NETDATA_PREFIX}/etc/netdata/charts.d"
420 - fi
421 -
422 - # move the charts.d config files
423 - for x in apache ap cpu_apps cpufreq example exim hddtemp load_average mem_apps mysql nginx nut opensips phpfpm postfix sensors squid tomcat
424 - do
425 - for y in "" ".old" ".orig"
426 - do
427 - if [ -f "${NETDATA_PREFIX}/etc/netdata/${x}.conf${y}" -a ! -f "${NETDATA_PREFIX}/etc/netdata/charts.d/${x}.conf${y}" ]
428 - then
429 - run mv -f "${NETDATA_PREFIX}/etc/netdata/${x}.conf${y}" "${NETDATA_PREFIX}/etc/netdata/charts.d/${x}.conf${y}"
430 - fi
431 - done
432 - done
433 -
434 - if [ ! -d "${NETDATA_PREFIX}/etc/netdata/node.d" ]
435 - then
436 - run mkdir "${NETDATA_PREFIX}/etc/netdata/node.d"
437 - fi
438 -
439 - # move the node.d config files
440 - for x in named sma_webbox snmp
441 - do
442 - for y in "" ".old" ".orig"
443 - do
444 - if [ -f "${NETDATA_PREFIX}/etc/netdata/${x}.conf${y}" -a ! -f "${NETDATA_PREFIX}/etc/netdata/node.d/${x}.conf${y}" ]
445 - then
446 - run mv -f "${NETDATA_PREFIX}/etc/netdata/${x}.conf${y}" "${NETDATA_PREFIX}/etc/netdata/node.d/${x}.conf${y}"
447 - fi
448 - done
449 - done
414 + then
415 + # the configuration directory exists
416 +
417 + if [ ! -d "${NETDATA_PREFIX}/etc/netdata/charts.d" ]
418 + then
419 + run mkdir "${NETDATA_PREFIX}/etc/netdata/charts.d"
420 + fi
421 +
422 + # move the charts.d config files
423 + for x in apache ap cpu_apps cpufreq example exim hddtemp load_average mem_apps mysql nginx nut opensips phpfpm postfix sensors squid tomcat
424 + do
425 + for y in "" ".old" ".orig"
426 + do
427 + if [ -f "${NETDATA_PREFIX}/etc/netdata/${x}.conf${y}" -a ! -f "${NETDATA_PREFIX}/etc/netdata/charts.d/${x}.conf${y}" ]
428 + then
429 + run mv -f "${NETDATA_PREFIX}/etc/netdata/${x}.conf${y}" "${NETDATA_PREFIX}/etc/netdata/charts.d/${x}.conf${y}"
430 + fi
431 + done
432 + done
433 +
434 + if [ ! -d "${NETDATA_PREFIX}/etc/netdata/node.d" ]
435 + then
436 + run mkdir "${NETDATA_PREFIX}/etc/netdata/node.d"
437 + fi
438 +
439 + # move the node.d config files
440 + for x in named sma_webbox snmp
441 + do
442 + for y in "" ".old" ".orig"
443 + do
444 + if [ -f "${NETDATA_PREFIX}/etc/netdata/${x}.conf${y}" -a ! -f "${NETDATA_PREFIX}/etc/netdata/node.d/${x}.conf${y}" ]
445 + then
446 + run mv -f "${NETDATA_PREFIX}/etc/netdata/${x}.conf${y}" "${NETDATA_PREFIX}/etc/netdata/node.d/${x}.conf${y}"
447 + fi
448 + done
449 + done
450 fi
451
452 # backup user configurations
453 installer_backup_suffix="${PID}.${RANDOM}"
454 for x in $(find "${NETDATA_PREFIX}/etc/netdata/" -name '*.conf' -type f)
455 do
456 - if [ -f "${x}" ]
457 - then
458 - # make a backup of the configuration file
459 - cp -p "${x}" "${x}.old"
460 -
461 - if [ -z "${md5sum}" -o ! -x "${md5sum}" ]
462 - then
463 - # we don't have md5sum - keep it
464 - cp -p "${x}" "${x}.installer_backup.${installer_backup_suffix}"
465 - else
466 - # find it relative filename
467 - f="${x/*\/etc\/netdata\//}"
468 -
469 - # find its checksum
470 - md5="$(cat "${x}" | ${md5sum} | cut -d ' ' -f 1)"
471 -
472 - # copy the original
473 - if [ -f "conf.d/${f}" ]
474 - then
475 - cp "conf.d/${f}" "${x}.orig"
476 - fi
477 -
478 - if [ "${BASH_VERSINFO[0]}" -ge "4" ]
479 - then
480 - if [ "${configs_signatures[${md5}]}" = "${f}" ]
481 - then
482 - # it is a stock version - don't keep it
483 - echo >&2 "File '${x}' is stock version."
484 - else
485 - # edited by user - keep it
486 - echo >&2 "File '${x}' has been edited by user."
487 - cp -p "${x}" "${x}.installer_backup.${installer_backup_suffix}"
488 - fi
489 - else
490 - echo >&2 "File '${x}' cannot be check for custom edits."
491 - cp -p "${x}" "${x}.installer_backup.${installer_backup_suffix}"
492 - fi
493 - fi
494 -
495 - elif [ -f "${x}.installer_backup.${installer_backup_suffix}" ]
496 - then
497 - rm -f "${x}.installer_backup.${installer_backup_suffix}"
498 - fi
456 + if [ -f "${x}" ]
457 + then
458 + # make a backup of the configuration file
459 + cp -p "${x}" "${x}.old"
460 +
461 + if [ -z "${md5sum}" -o ! -x "${md5sum}" ]
462 + then
463 + # we don't have md5sum - keep it
464 + cp -p "${x}" "${x}.installer_backup.${installer_backup_suffix}"
465 + else
466 + # find it relative filename
467 + f="${x/*\/etc\/netdata\//}"
468 +
469 + # find its checksum
470 + md5="$(cat "${x}" | ${md5sum} | cut -d ' ' -f 1)"
471 +
472 + # copy the original
473 + if [ -f "conf.d/${f}" ]
474 + then
475 + cp "conf.d/${f}" "${x}.orig"
476 + fi
477 +
478 + if [ "${BASH_VERSINFO[0]}" -ge "4" ]
479 + then
480 + if [ "${configs_signatures[${md5}]}" = "${f}" ]
481 + then
482 + # it is a stock version - don't keep it
483 + echo >&2 "File '${x}' is stock version."
484 + else
485 + # edited by user - keep it
486 + echo >&2 "File '${x}' has been edited by user."
487 + cp -p "${x}" "${x}.installer_backup.${installer_backup_suffix}"
488 + fi
489 + else
490 + echo >&2 "File '${x}' cannot be check for custom edits."
491 + cp -p "${x}" "${x}.installer_backup.${installer_backup_suffix}"
492 + fi
493 + fi
494 +
495 + elif [ -f "${x}.installer_backup.${installer_backup_suffix}" ]
496 + then
497 + rm -f "${x}.installer_backup.${installer_backup_suffix}"
498 + fi
499 done
500
501 echo >&2 "Installing netdata ..."
@@ -504,53 +504,53 @@ run make install || exit 1
504 # restore user configurations
505 for x in $(find "${NETDATA_PREFIX}/etc/netdata/" -name '*.conf' -type f)
506 do
507 - if [ -f "${x}.installer_backup.${installer_backup_suffix}" ]
508 - then
509 - cp -p "${x}.installer_backup.${installer_backup_suffix}" "${x}"
510 - rm -f "${x}.installer_backup.${installer_backup_suffix}"
511 - fi
507 + if [ -f "${x}.installer_backup.${installer_backup_suffix}" ]
508 + then
509 + cp -p "${x}.installer_backup.${installer_backup_suffix}" "${x}"
510 + rm -f "${x}.installer_backup.${installer_backup_suffix}"
511 + fi
512 done
513
514 NETDATA_ADDED_TO_DOCKER=0
515 if [ ${UID} -eq 0 ]
516 - then
517 - getent group netdata > /dev/null
518 - if [ $? -ne 0 ]
519 - then
520 - echo >&2 "Adding netdata user group ..."
521 - run groupadd -r netdata
522 - fi
523 -
524 - getent passwd netdata > /dev/null
525 - if [ $? -ne 0 ]
526 - then
527 - echo >&2 "Adding netdata user account ..."
528 - run useradd -r -g netdata -c netdata -s $(which nologin || echo '/bin/false') -d / netdata
529 - fi
530 -
531 - getent group docker > /dev/null
532 - if [ $? -eq 0 ]
533 - then
534 - # find the users in the docker group
535 - docker=$(getent group docker | cut -d ':' -f 4)
536 - if [[ ",${docker}," =~ ,netdata, ]]
537 - then
538 - # netdata is already there
539 - :
540 - else
541 - # netdata is not in docker group
542 - echo >&2 "Adding netdata user to the docker group (needed to get container names) ..."
543 - run usermod -a -G docker netdata
544 - fi
545 - # let the uninstall script know
546 - NETDATA_ADDED_TO_DOCKER=1
547 - fi
548 -
549 - if [ -d /etc/logrotate.d -a ! -f /etc/logrotate.d/netdata ]
550 - then
551 - echo >&2 "Adding netdata logrotate configuration ..."
552 - run cp system/netdata.logrotate /etc/logrotate.d/netdata
553 - fi
516 + then
517 + getent group netdata > /dev/null
518 + if [ $? -ne 0 ]
519 + then
520 + echo >&2 "Adding netdata user group ..."
521 + run groupadd -r netdata
522 + fi
523 +
524 + getent passwd netdata > /dev/null
525 + if [ $? -ne 0 ]
526 + then
527 + echo >&2 "Adding netdata user account ..."
528 + run useradd -r -g netdata -c netdata -s $(which nologin || echo '/bin/false') -d / netdata
529 + fi
530 +
531 + getent group docker > /dev/null
532 + if [ $? -eq 0 ]
533 + then
534 + # find the users in the docker group
535 + docker=$(getent group docker | cut -d ':' -f 4)
536 + if [[ ",${docker}," =~ ,netdata, ]]
537 + then
538 + # netdata is already there
539 + :
540 + else
541 + # netdata is not in docker group
542 + echo >&2 "Adding netdata user to the docker group (needed to get container names) ..."
543 + run usermod -a -G docker netdata
544 + fi
545 + # let the uninstall script know
546 + NETDATA_ADDED_TO_DOCKER=1
547 + fi
548 +
549 + if [ -d /etc/logrotate.d -a ! -f /etc/logrotate.d/netdata ]
550 + then
551 + echo >&2 "Adding netdata logrotate configuration ..."
552 + run cp system/netdata.logrotate /etc/logrotate.d/netdata
553 + fi
554 fi
555
556
@@ -562,15 +562,15 @@ fi
562
563 # function to extract values from the config file
564 config_option() {
565 - local key="${1}" value="${2}" line=
565 + local key="${1}" value="${2}" line=
566
567 - if [ -s "${NETDATA_PREFIX}/etc/netdata/netdata.conf" ]
568 - then
569 - line="$( grep "^[[:space:]]*${key}[[:space:]]*=[[:space:]]*" "${NETDATA_PREFIX}/etc/netdata/netdata.conf" | head -n 1 )"
570 - [ ! -z "${line}" ] && value="$( echo "${line}" | cut -d '=' -f 2 | sed -e "s/^[[:space:]]\+//g" -e "s/[[:space:]]\+$//g" )"
571 - fi
567 + if [ -s "${NETDATA_PREFIX}/etc/netdata/netdata.conf" ]
568 + then
569 + line="$( grep "^[[:space:]]*${key}[[:space:]]*=[[:space:]]*" "${NETDATA_PREFIX}/etc/netdata/netdata.conf" | head -n 1 )"
570 + [ ! -z "${line}" ] && value="$( echo "${line}" | cut -d '=' -f 2 | sed -e "s/^[[:space:]]\+//g" -e "s/[[:space:]]\+$//g" )"
571 + fi
572
573 - echo "${value}"
573 + echo "${value}"
574 }
575
576 # user
@@ -612,304 +612,304 @@ NETDATA_RUN_DIR="${NETDATA_PREFIX}/var/run"
612
613 # this is needed if NETDATA_PREFIX is not empty
614 if [ ! -d "${NETDATA_RUN_DIR}" ]
615 - then
616 - mkdir -p "${NETDATA_RUN_DIR}" || exit 1
615 + then
616 + mkdir -p "${NETDATA_RUN_DIR}" || exit 1
617 fi
618
619 echo >&2
620 echo >&2 "Fixing directories (user: ${NETDATA_USER})..."
621 for x in "${NETDATA_WEB_DIR}" "${NETDATA_CONF_DIR}" "${NETDATA_CACHE_DIR}" "${NETDATA_LOG_DIR}" "${NETDATA_LIB_DIR}" "${NETDATA_CONF_DIR}/python.d" "${NETDATA_CONF_DIR}/charts.d" "${NETDATA_CONF_DIR}/node.d"
622 do
623 - if [ ! -d "${x}" ]
624 - then
625 - echo >&2 "Creating directory '${x}'"
626 - run mkdir -p "${x}" || exit 1
627 - fi
628 -
629 - if [ ${UID} -eq 0 ]
630 - then
631 - if [ "${x}" = "${NETDATA_WEB_DIR}" ]
632 - then
633 - run chown -R "${NETDATA_WEB_USER}:${NETDATA_WEB_GROUP}" "${x}" || echo >&2 "WARNING: Cannot change the ownership of the files in directory ${x} to ${NETDATA_WEB_USER}:${NETDATA_WEB_GROUP}..."
634 - else
635 - run chown -R "${NETDATA_USER}:${NETDATA_USER}" "${x}" || echo >&2 "WARNING: Cannot change the ownership of the files in directory ${x} to ${NETDATA_USER}..."
636 - fi
637 - fi
638 -
639 - run chmod 0755 "${x}" || echo >&2 "WARNING: Cannot change the permissions of the directory ${x} to 0755..."
623 + if [ ! -d "${x}" ]
624 + then
625 + echo >&2 "Creating directory '${x}'"
626 + run mkdir -p "${x}" || exit 1
627 + fi
628 +
629 + if [ ${UID} -eq 0 ]
630 + then
631 + if [ "${x}" = "${NETDATA_WEB_DIR}" ]
632 + then
633 + run chown -R "${NETDATA_WEB_USER}:${NETDATA_WEB_GROUP}" "${x}" || echo >&2 "WARNING: Cannot change the ownership of the files in directory ${x} to ${NETDATA_WEB_USER}:${NETDATA_WEB_GROUP}..."
634 + else
635 + run chown -R "${NETDATA_USER}:${NETDATA_USER}" "${x}" || echo >&2 "WARNING: Cannot change the ownership of the files in directory ${x} to ${NETDATA_USER}..."
636 + fi
637 + fi
638 +
639 + run chmod 0755 "${x}" || echo >&2 "WARNING: Cannot change the permissions of the directory ${x} to 0755..."
640 done
641
642 if [ ${UID} -eq 0 ]
643 - then
644 - run chown root "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin"
645 - run chmod 0755 "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin"
646 - run setcap cap_dac_read_search,cap_sys_ptrace+ep "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin"
647 - if [ $? -ne 0 ]
648 - then
649 - # fix apps.plugin to be setuid to root
650 - run chown root "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin"
651 - run chmod 4755 "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin"
652 - fi
643 + then
644 + run chown root "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin"
645 + run chmod 0755 "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin"
646 + run setcap cap_dac_read_search,cap_sys_ptrace+ep "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin"
647 + if [ $? -ne 0 ]
648 + then
649 + # fix apps.plugin to be setuid to root
650 + run chown root "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin"
651 + run chmod 4755 "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin"
652 + fi
653 fi
654
655 # -----------------------------------------------------------------------------
656 # check if we can re-start netdata
657
658 if [ ${DONOTSTART} -eq 1 ]
659 - then
660 - if [ ! -s "${NETDATA_PREFIX}/etc/netdata/netdata.conf" ]
661 - then
662 - echo >&2 "Generating empty config file in: ${NETDATA_PREFIX}/etc/netdata/netdata.conf"
663 - echo "# Get config from http://127.0.0.1:${NETDATA_PORT}/netdata.conf" >"${NETDATA_PREFIX}/etc/netdata/netdata.conf"
664 -
665 - if [ "${UID}" -eq 0 ]
666 - then
667 - chown "${NETDATA_USER}" "${NETDATA_PREFIX}/etc/netdata/netdata.conf"
668 - fi
669 - chmod 0664 "${NETDATA_PREFIX}/etc/netdata/netdata.conf"
670 - fi
671 - echo >&2 "OK. It is now installed and ready."
672 - exit 0
659 + then
660 + if [ ! -s "${NETDATA_PREFIX}/etc/netdata/netdata.conf" ]
661 + then
662 + echo >&2 "Generating empty config file in: ${NETDATA_PREFIX}/etc/netdata/netdata.conf"
663 + echo "# Get config from http://127.0.0.1:${NETDATA_PORT}/netdata.conf" >"${NETDATA_PREFIX}/etc/netdata/netdata.conf"
664 +
665 + if [ "${UID}" -eq 0 ]
666 + then
667 + chown "${NETDATA_USER}" "${NETDATA_PREFIX}/etc/netdata/netdata.conf"
668 + fi
669 + chmod 0664 "${NETDATA_PREFIX}/etc/netdata/netdata.conf"
670 + fi
671 + echo >&2 "OK. It is now installed and ready."
672 + exit 0
673 fi
674
675 # -----------------------------------------------------------------------------
676 # stop a running netdata
677
678 isnetdata() {
679 - [ -z "$1" -o ! -f "/proc/$1/stat" ] && return 1
680 - [ "$(cat "/proc/$1/stat" | cut -d '(' -f 2 | cut -d ')' -f 1)" = "netdata" ] && return 0
681 - return 1
679 + [ -z "$1" -o ! -f "/proc/$1/stat" ] && return 1
680 + [ "$(cat "/proc/$1/stat" | cut -d '(' -f 2 | cut -d ')' -f 1)" = "netdata" ] && return 0
681 + return 1
682 }
683
684 stop_netdata_on_pid() {
685 - local pid="$1" ret=0 count=0
685 + local pid="$1" ret=0 count=0
686
687 - isnetdata $pid || return 0
687 + isnetdata $pid || return 0
688
689 - printf >&2 "Stopping netdata on pid $pid ..."
690 - while [ ! -z "$pid" -a $ret -eq 0 ]
691 - do
692 - if [ $count -gt 45 ]
693 - then
694 - echo >&2 "Cannot stop the running netdata on pid $pid."
695 - return 1
696 - fi
689 + printf >&2 "Stopping netdata on pid $pid ..."
690 + while [ ! -z "$pid" -a $ret -eq 0 ]
691 + do
692 + if [ $count -gt 45 ]
693 + then
694 + echo >&2 "Cannot stop the running netdata on pid $pid."
695 + return 1
696 + fi
697
698 - count=$(( count + 1 ))
698 + count=$(( count + 1 ))
699
700 - run kill $pid 2>/dev/null
701 - ret=$?
700 + run kill $pid 2>/dev/null
701 + ret=$?
702
703 - test $ret -eq 0 && printf >&2 "." && sleep 2
704 - done
703 + test $ret -eq 0 && printf >&2 "." && sleep 2
704 + done
705
706 - echo >&2
707 - if [ $ret -eq 0 ]
708 - then
709 - echo >&2 "SORRY! CANNOT STOP netdata ON PID $pid !"
710 - return 1
711 - fi
706 + echo >&2
707 + if [ $ret -eq 0 ]
708 + then
709 + echo >&2 "SORRY! CANNOT STOP netdata ON PID $pid !"
710 + return 1
711 + fi
712
713 - echo >&2 "netdata on pid $pid stopped."
714 - return 0
713 + echo >&2 "netdata on pid $pid stopped."
714 + return 0
715 }
716
717 stop_all_netdata() {
718 - local p
718 + local p
719
720 - echo >&2 "Stopping a (possibly) running netdata..."
720 + echo >&2 "Stopping a (possibly) running netdata..."
721
722 - for p in $(cat "${NETDATA_RUN_DIR}/netdata.pid" 2>/dev/null) \
723 - $(cat /var/run/netdata.pid 2>/dev/null) \
724 - $(cat /var/run/netdata/netdata.pid 2>/dev/null) \
725 - $(pidof netdata 2>/dev/null)
726 - do
727 - stop_netdata_on_pid $p
728 - done
722 + for p in $(cat "${NETDATA_RUN_DIR}/netdata.pid" 2>/dev/null) \
723 + $(cat /var/run/netdata.pid 2>/dev/null) \
724 + $(cat /var/run/netdata/netdata.pid 2>/dev/null) \
725 + $(pidof netdata 2>/dev/null)
726 + do
727 + stop_netdata_on_pid $p
728 + done
729 }
730
731 # -----------------------------------------------------------------------------
732 # check netdata for systemd
733
734 issystemd() {
735 - # if the directory /etc/systemd/system does not exit, it is not systemd
736 - [ ! -d /etc/systemd/system ] && return 1
735 + # if the directory /etc/systemd/system does not exit, it is not systemd
736 + [ ! -d /etc/systemd/system ] && return 1
737
738 - # if pid 1 is systemd, it is systemd
739 - [ "$(basename $(readlink /proc/1/exe) 2>/dev/null)" = "systemd" ] && return 0
738 + # if pid 1 is systemd, it is systemd
739 + [ "$(basename $(readlink /proc/1/exe) 2>/dev/null)" = "systemd" ] && return 0
740
741 - # if systemd is running, it is systemd
742 - pidof systemd >/dev/null 2>&1 && return 0
741 + # if systemd is running, it is systemd
742 + pidof systemd >/dev/null 2>&1 && return 0
743
744 - # else, it is not systemd
745 - return 1
744 + # else, it is not systemd
745 + return 1
746 }
747
748 started=0
749 if [ "${UID}" -eq 0 ]
750 - then
751 -
752 - if issystemd
753 - then
754 - # systemd is running on this system
755 -
756 - if [ ! -f /etc/systemd/system/netdata.service ]
757 - then
758 - echo >&2 "Installing systemd service..."
759 - run cp system/netdata.service /etc/systemd/system/netdata.service && \
760 - run systemctl daemon-reload && \
761 - run systemctl enable netdata
762 - else
763 - service netdata stop
764 - fi
765 -
766 - stop_all_netdata
767 - service netdata restart && started=1
768 - fi
769 -
770 - if [ ${started} -eq 0 ]
771 - then
772 - # check if we can use the system service
773 - service netdata stop
774 - stop_all_netdata
775 - service netdata restart && started=1
776 - if [ ${started} -eq 0 ]
777 - then
778 - service netdata start && started=1
779 - fi
780 - fi
750 + then
751 +
752 + if issystemd
753 + then
754 + # systemd is running on this system
755 +
756 + if [ ! -f /etc/systemd/system/netdata.service ]
757 + then
758 + echo >&2 "Installing systemd service..."
759 + run cp system/netdata.service /etc/systemd/system/netdata.service && \
760 + run systemctl daemon-reload && \
761 + run systemctl enable netdata
762 + else
763 + service netdata stop
764 + fi
765 +
766 + stop_all_netdata
767 + service netdata restart && started=1
768 + fi
769 +
770 + if [ ${started} -eq 0 ]
771 + then
772 + # check if we can use the system service
773 + service netdata stop
774 + stop_all_netdata
775 + service netdata restart && started=1
776 + if [ ${started} -eq 0 ]
777 + then
778 + service netdata start && started=1
779 + fi
780 + fi
781 fi
782
783 if [ ${started} -eq 0 ]
784 then
785 - # still not started...
786 -
787 - stop_all_netdata
788 -
789 - echo >&2 "Starting netdata..."
790 - run ${NETDATA_PREFIX}/usr/sbin/netdata -P ${NETDATA_RUN_DIR}/netdata.pid "${@}"
791 - if [ $? -ne 0 ]
792 - then
793 - echo >&2
794 - echo >&2 "SORRY! FAILED TO START NETDATA!"
795 - exit 1
796 - else
797 - echo >&2 "OK. NetData Started!"
798 - fi
799 -
800 - echo >&2
785 + # still not started...
786 +
787 + stop_all_netdata
788 +
789 + echo >&2 "Starting netdata..."
790 + run ${NETDATA_PREFIX}/usr/sbin/netdata -P ${NETDATA_RUN_DIR}/netdata.pid "${@}"
791 + if [ $? -ne 0 ]
792 + then
793 + echo >&2
794 + echo >&2 "SORRY! FAILED TO START NETDATA!"
795 + exit 1
796 + else
797 + echo >&2 "OK. NetData Started!"
798 + fi
799 +
800 + echo >&2
801 fi
802
803 # -----------------------------------------------------------------------------
804 # save a config file, if it is not already there
805
806 if [ ! -s "${NETDATA_PREFIX}/etc/netdata/netdata.conf" ]
807 - then
808 - echo >&2
809 - echo >&2 "-------------------------------------------------------------------------------"
810 - echo >&2
811 - echo >&2 "Downloading default configuration from netdata..."
812 - sleep 5
813 -
814 - # remove a possibly obsolete download
815 - [ -f "${NETDATA_PREFIX}/etc/netdata/netdata.conf.new" ] && rm "${NETDATA_PREFIX}/etc/netdata/netdata.conf.new"
816 -
817 - # disable a proxy to get data from the local netdata
818 - export http_proxy=
819 - export https_proxy=
820 -
821 - # try wget
822 - wget 2>/dev/null -O "${NETDATA_PREFIX}/etc/netdata/netdata.conf.new" "http://localhost:${NETDATA_PORT}/netdata.conf"
823 - ret=$?
824 -
825 - # try curl
826 - if [ $ret -ne 0 -o ! -s "${NETDATA_PREFIX}/etc/netdata/netdata.conf.new" ]
827 - then
828 - curl -s -o "${NETDATA_PREFIX}/etc/netdata/netdata.conf.new" "http://localhost:${NETDATA_PORT}/netdata.conf"
829 - ret=$?
830 - fi
831 -
832 - if [ $ret -eq 0 -a -s "${NETDATA_PREFIX}/etc/netdata/netdata.conf.new" ]
833 - then
834 - mv "${NETDATA_PREFIX}/etc/netdata/netdata.conf.new" "${NETDATA_PREFIX}/etc/netdata/netdata.conf"
835 - echo >&2 "New configuration saved for you to edit at ${NETDATA_PREFIX}/etc/netdata/netdata.conf"
836 -
837 - if [ "${UID}" -eq 0 ]
838 - then
839 - chown "${NETDATA_USER}" "${NETDATA_PREFIX}/etc/netdata/netdata.conf"
840 - fi
841 - chmod 0664 "${NETDATA_PREFIX}/etc/netdata/netdata.conf"
842 - else
843 - echo >&2 "Cannnot download configuration from netdata daemon using url 'http://localhost:${NETDATA_PORT}/netdata.conf'"
844 - [ -f "${NETDATA_PREFIX}/etc/netdata/netdata.conf.new" ] && rm "${NETDATA_PREFIX}/etc/netdata/netdata.conf.new"
845 - fi
807 + then
808 + echo >&2
809 + echo >&2 "-------------------------------------------------------------------------------"
810 + echo >&2
811 + echo >&2 "Downloading default configuration from netdata..."
812 + sleep 5
813 +
814 + # remove a possibly obsolete download
815 + [ -f "${NETDATA_PREFIX}/etc/netdata/netdata.conf.new" ] && rm "${NETDATA_PREFIX}/etc/netdata/netdata.conf.new"
816 +
817 + # disable a proxy to get data from the local netdata
818 + export http_proxy=
819 + export https_proxy=
820 +
821 + # try wget
822 + wget 2>/dev/null -O "${NETDATA_PREFIX}/etc/netdata/netdata.conf.new" "http://localhost:${NETDATA_PORT}/netdata.conf"
823 + ret=$?
824 +
825 + # try curl
826 + if [ $ret -ne 0 -o ! -s "${NETDATA_PREFIX}/etc/netdata/netdata.conf.new" ]
827 + then
828 + curl -s -o "${NETDATA_PREFIX}/etc/netdata/netdata.conf.new" "http://localhost:${NETDATA_PORT}/netdata.conf"
829 + ret=$?
830 + fi
831 +
832 + if [ $ret -eq 0 -a -s "${NETDATA_PREFIX}/etc/netdata/netdata.conf.new" ]
833 + then
834 + mv "${NETDATA_PREFIX}/etc/netdata/netdata.conf.new" "${NETDATA_PREFIX}/etc/netdata/netdata.conf"
835 + echo >&2 "New configuration saved for you to edit at ${NETDATA_PREFIX}/etc/netdata/netdata.conf"
836 +
837 + if [ "${UID}" -eq 0 ]
838 + then
839 + chown "${NETDATA_USER}" "${NETDATA_PREFIX}/etc/netdata/netdata.conf"
840 + fi
841 + chmod 0664 "${NETDATA_PREFIX}/etc/netdata/netdata.conf"
842 + else
843 + echo >&2 "Cannnot download configuration from netdata daemon using url 'http://localhost:${NETDATA_PORT}/netdata.conf'"
844 + [ -f "${NETDATA_PREFIX}/etc/netdata/netdata.conf.new" ] && rm "${NETDATA_PREFIX}/etc/netdata/netdata.conf.new"
845 + fi
846 fi
847
848 # -----------------------------------------------------------------------------
849 # Check for KSM
850
851 ksm_is_available_but_disabled() {
852 - cat <<-KSM1
852 + cat <<-KSM1
853
854 - -------------------------------------------------------------------------------
855 - Memory de-duplication instructions
854 + -------------------------------------------------------------------------------
855 + Memory de-duplication instructions
856
857 - You have kernel memory de-duper (called Kernel Same-page Merging,
858 - or KSM) available, but it is not currently enabled.
857 + You have kernel memory de-duper (called Kernel Same-page Merging,
858 + or KSM) available, but it is not currently enabled.
859
860 - To enable it run:
860 + To enable it run:
861
862 - echo 1 >/sys/kernel/mm/ksm/run
863 - echo 1000 >/sys/kernel/mm/ksm/sleep_millisecs
862 + echo 1 >/sys/kernel/mm/ksm/run
863 + echo 1000 >/sys/kernel/mm/ksm/sleep_millisecs
864
865 - If you enable it, you will save 40-60% of netdata memory.
865 + If you enable it, you will save 40-60% of netdata memory.
866
867 KSM1
868 }
869
870 ksm_is_not_available() {
871 - cat <<-KSM2
871 + cat <<-KSM2
872
873 - -------------------------------------------------------------------------------
874 - Memory de-duplication not present in your kernel
873 + -------------------------------------------------------------------------------
874 + Memory de-duplication not present in your kernel
875
876 - It seems you do not have kernel memory de-duper (called Kernel Same-page
877 - Merging, or KSM) available.
876 + It seems you do not have kernel memory de-duper (called Kernel Same-page
877 + Merging, or KSM) available.
878
879 - To enable it, you need a kernel built with CONFIG_KSM=y
879 + To enable it, you need a kernel built with CONFIG_KSM=y
880
881 - If you can have it, you will save 40-60% of netdata memory.
881 + If you can have it, you will save 40-60% of netdata memory.
882
883 KSM2
884 }
885
886 if [ -f "/sys/kernel/mm/ksm/run" ]
887 - then
888 - if [ $(cat "/sys/kernel/mm/ksm/run") != "1" ]
889 - then
890 - ksm_is_available_but_disabled
891 - fi
887 + then
888 + if [ $(cat "/sys/kernel/mm/ksm/run") != "1" ]
889 + then
890 + ksm_is_available_but_disabled
891 + fi
892 else
893 - ksm_is_not_available
893 + ksm_is_not_available
894 fi
895
896 # -----------------------------------------------------------------------------
897 # Check for version.txt
898
899 if [ ! -s web/version.txt ]
900 - then
901 - cat <<-VERMSG
900 + then
901 + cat <<-VERMSG
902
903 - -------------------------------------------------------------------------------
904 - Version update check warning
903 + -------------------------------------------------------------------------------
904 + Version update check warning
905
906 - The way you downloaded netdata, we cannot find its version. This means the
907 - Update check on the dashboard, will not work.
906 + The way you downloaded netdata, we cannot find its version. This means the
907 + Update check on the dashboard, will not work.
908
909 - If you want to have version update check, please re-install it
910 - following the procedure in:
909 + If you want to have version update check, please re-install it
910 + following the procedure in:
911
912 - https://github.com/firehol/netdata/wiki/Installation
912 + https://github.com/firehol/netdata/wiki/Installation
913
914 VERMSG
915 fi
@@ -918,30 +918,30 @@ fi
918 # apps.plugin warning
919
920 if [ "${UID}" -ne 0 ]
921 - then
922 - cat <<-SETUID_WARNING
921 + then
922 + cat <<-SETUID_WARNING
923
924 - -------------------------------------------------------------------------------
925 - apps.plugin needs privileges
924 + -------------------------------------------------------------------------------
925 + apps.plugin needs privileges
926
927 - Since you have installed netdata as a normal user, to have apps.plugin collect
928 - all the needed data, you have to give it the access rights it needs, by running
929 - either of the following sets of commands:
927 + Since you have installed netdata as a normal user, to have apps.plugin collect
928 + all the needed data, you have to give it the access rights it needs, by running
929 + either of the following sets of commands:
930
931 - To run apps.plugin with escalated capabilities:
931 + To run apps.plugin with escalated capabilities:
932
933 - sudo chown root:${NETDATA_USER} "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin"
934 - sudo chmod 0750 "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin"
935 - sudo setcap cap_dac_read_search,cap_sys_ptrace+ep "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin"
933 + sudo chown root:${NETDATA_USER} "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin"
934 + sudo chmod 0750 "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin"
935 + sudo setcap cap_dac_read_search,cap_sys_ptrace+ep "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin"
936
937 - or, to run apps.plugin as root:
937 + or, to run apps.plugin as root:
938
939 - sudo chown root "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin"
940 - sudo chmod 4755 "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin"
939 + sudo chown root "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin"
940 + sudo chmod 4755 "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin"
941
942 - apps.plugin is performing a hard-coded function of data collection for all
943 - running processes. It cannot be instructed from the netdata daemon to perform
944 - any task, so it is pretty safe to do this.
942 + apps.plugin is performing a hard-coded function of data collection for all
943 + running processes. It cannot be instructed from the netdata daemon to perform
944 + any task, so it is pretty safe to do this.
945
946 SETUID_WARNING
947 fi
@@ -950,91 +950,91 @@ fi
950 # Keep un-install info
951
952 cat >netdata-uninstaller.sh <<-UNINSTALL
953 - #!/bin/bash
954 -
955 - # this script will uninstall netdata
956 -
957 - if [ "\$1" != "--force" ]
958 - then
959 - echo >&2 "This script will REMOVE netdata from your system."
960 - echo >&2 "Run it again with --force to do it."
961 - exit 1
962 - fi
963 -
964 - echo >&2 "Stopping a possibly running netdata..."
965 - for p in \$(pidof netdata); do kill \$p; done
966 - sleep 2
967 -
968 - deletedir() {
969 - if [ ! -z "\$1" -a -d "\$1" ]
970 - then
971 - echo
972 - echo "Deleting directory '\$1' ..."
973 - rm -I -R "\$1"
974 - fi
975 - }
976 -
977 - if [ ! -z "${NETDATA_PREFIX}" -a -d "${NETDATA_PREFIX}" ]
978 - then
979 - # installation prefix was given
980 -
981 - deletedir "${NETDATA_PREFIX}"
982 -
983 - else
984 - # installation prefix was NOT given
985 -
986 - if [ -f "${NETDATA_PREFIX}/usr/sbin/netdata" ]
987 - then
988 - echo "Deleting ${NETDATA_PREFIX}/usr/sbin/netdata ..."
989 - rm -i "${NETDATA_PREFIX}/usr/sbin/netdata"
990 - fi
991 -
992 - deletedir "${NETDATA_PREFIX}/etc/netdata"
993 - deletedir "${NETDATA_PREFIX}/usr/share/netdata"
994 - deletedir "${NETDATA_PREFIX}/usr/libexec/netdata"
995 - deletedir "${NETDATA_PREFIX}/var/lib/netdata"
996 - deletedir "${NETDATA_PREFIX}/var/cache/netdata"
997 - deletedir "${NETDATA_PREFIX}/var/log/netdata"
998 - fi
999 -
1000 - if [ -f /etc/logrotate.d/netdata ]
1001 - then
1002 - echo "Deleting /etc/logrotate.d/netdata ..."
1003 - rm -i /etc/logrotate.d/netdata
1004 - fi
1005 -
1006 - if [ -f /etc/systemd/system/netdata.service ]
1007 - then
1008 - echo "Deleting /etc/systemd/system/netdata.service ..."
1009 - rm -i /etc/systemd/system/netdata.service
1010 - fi
1011 -
1012 - getent passwd netdata > /dev/null
1013 - if [ $? -eq 0 ]
1014 - then
1015 - echo
1016 - echo "You may also want to remove the user netdata"
1017 - echo "by running:"
1018 - echo " userdel netdata"
1019 - fi
1020 -
1021 - getent group netdata > /dev/null
1022 - if [ $? -eq 0 ]
1023 - then
1024 - echo
1025 - echo "You may also want to remove the group netdata"
1026 - echo "by running:"
1027 - echo " groupdel netdata"
1028 - fi
1029 -
1030 - getent group docker > /dev/null
1031 - if [ $? -eq 0 -a "${NETDATA_ADDED_TO_DOCKER}" = "1" ]
1032 - then
1033 - echo
1034 - echo "You may also want to remove the netdata user from the docker group"
1035 - echo "by running:"
1036 - echo " gpasswd -d netdata docker"
1037 - fi
953 + #!/bin/bash
954 +
955 + # this script will uninstall netdata
956 +
957 + if [ "\$1" != "--force" ]
958 + then
959 + echo >&2 "This script will REMOVE netdata from your system."
960 + echo >&2 "Run it again with --force to do it."
961 + exit 1
962 + fi
963 +
964 + echo >&2 "Stopping a possibly running netdata..."
965 + for p in \$(pidof netdata); do kill \$p; done
966 + sleep 2
967 +
968 + deletedir() {
969 + if [ ! -z "\$1" -a -d "\$1" ]
970 + then
971 + echo
972 + echo "Deleting directory '\$1' ..."
973 + rm -I -R "\$1"
974 + fi
975 + }
976 +
977 + if [ ! -z "${NETDATA_PREFIX}" -a -d "${NETDATA_PREFIX}" ]
978 + then
979 + # installation prefix was given
980 +
981 + deletedir "${NETDATA_PREFIX}"
982 +
983 + else
984 + # installation prefix was NOT given
985 +
986 + if [ -f "${NETDATA_PREFIX}/usr/sbin/netdata" ]
987 + then
988 + echo "Deleting ${NETDATA_PREFIX}/usr/sbin/netdata ..."
989 + rm -i "${NETDATA_PREFIX}/usr/sbin/netdata"
990 + fi
991 +
992 + deletedir "${NETDATA_PREFIX}/etc/netdata"
993 + deletedir "${NETDATA_PREFIX}/usr/share/netdata"
994 + deletedir "${NETDATA_PREFIX}/usr/libexec/netdata"
995 + deletedir "${NETDATA_PREFIX}/var/lib/netdata"
996 + deletedir "${NETDATA_PREFIX}/var/cache/netdata"
997 + deletedir "${NETDATA_PREFIX}/var/log/netdata"
998 + fi
999 +
1000 + if [ -f /etc/logrotate.d/netdata ]
1001 + then
1002 + echo "Deleting /etc/logrotate.d/netdata ..."
1003 + rm -i /etc/logrotate.d/netdata
1004 + fi
1005 +
1006 + if [ -f /etc/systemd/system/netdata.service ]
1007 + then
1008 + echo "Deleting /etc/systemd/system/netdata.service ..."
1009 + rm -i /etc/systemd/system/netdata.service
1010 + fi
1011 +
1012 + getent passwd netdata > /dev/null
1013 + if [ $? -eq 0 ]
1014 + then
1015 + echo
1016 + echo "You may also want to remove the user netdata"
1017 + echo "by running:"
1018 + echo " userdel netdata"
1019 + fi
1020 +
1021 + getent group netdata > /dev/null
1022 + if [ $? -eq 0 ]
1023 + then
1024 + echo
1025 + echo "You may also want to remove the group netdata"
1026 + echo "by running:"
1027 + echo " groupdel netdata"
1028 + fi
1029 +
1030 + getent group docker > /dev/null
1031 + if [ $? -eq 0 -a "${NETDATA_ADDED_TO_DOCKER}" = "1" ]
1032 + then
1033 + echo
1034 + echo "You may also want to remove the netdata user from the docker group"
1035 + echo "by running:"
1036 + echo " gpasswd -d netdata docker"
1037 + fi
1038
1039 UNINSTALL
1040 chmod 750 netdata-uninstaller.sh
@@ -1044,27 +1044,27 @@ chmod 750 netdata-uninstaller.sh
1044 cat <<-END
1045
1046
1047 - -------------------------------------------------------------------------------
1047 + -------------------------------------------------------------------------------
1048
1049 - OK. NetData is installed and it is running.
1049 + OK. NetData is installed and it is running.
1050
1051 - -------------------------------------------------------------------------------
1051 + -------------------------------------------------------------------------------
1052
1053 - By default netdata listens on all IPs on port ${NETDATA_PORT},
1054 - so you can access it with:
1053 + By default netdata listens on all IPs on port ${NETDATA_PORT},
1054 + so you can access it with:
1055
1056 - http://this.machine.ip:${NETDATA_PORT}/
1056 + http://this.machine.ip:${NETDATA_PORT}/
1057
1058 - To stop netdata, just kill it, with:
1058 + To stop netdata, just kill it, with:
1059
1060 - killall netdata
1060 + killall netdata
1061
1062 - To start it, just run it:
1062 + To start it, just run it:
1063
1064 - ${NETDATA_PREFIX}/usr/sbin/netdata
1064 + ${NETDATA_PREFIX}/usr/sbin/netdata
1065
1066
1067 - Enjoy!
1067 + Enjoy!
1068
1069 END
1070 echo >&2 "Uninstall script generated: ./netdata-uninstaller.sh"
node.d/named.node.js
+551 -551
@@ -11,20 +11,20 @@
11
12 /*
13 {
14 - "enable_autodetect": true,
15 - "update_every": 5,
16 - "servers": [
17 - {
18 - "name": "bind1",
19 - "url": "http://127.0.0.1:8888/json/v1/server",
20 - "update_every": 1
21 - },
22 - {
23 - "name": "bind2",
24 - "url": "http://10.0.0.1:8888/xml/v3/server",
25 - "update_every": 2
26 - }
27 - ]
14 + "enable_autodetect": true,
15 + "update_every": 5,
16 + "servers": [
17 + {
18 + "name": "bind1",
19 + "url": "http://127.0.0.1:8888/json/v1/server",
20 + "update_every": 1
21 + },
22 + {
23 + "name": "bind2",
24 + "url": "http://10.0.0.1:8888/xml/v3/server",
25 + "update_every": 2
26 + }
27 + ]
28 }
29 */
30
@@ -44,543 +44,543 @@ var netdata = require('netdata');
44 if(netdata.options.DEBUG === true) netdata.debug('loaded ' + __filename + ' plugin');
45
46 var named = {
47 - name: __filename,
48 - enable_autodetect: true,
49 - update_every: 1,
50 - base_priority: 60000,
51 - charts: {},
52 -
53 - chartFromMembersCreate: function(service, obj, id, title_suffix, units, family, context, type, priority, algorithm, multiplier, divisor) {
54 - var chart = {
55 - id: id, // the unique id of the chart
56 - name: '', // the unique name of the chart
57 - title: service.name + ' ' + title_suffix, // the title of the chart
58 - units: units, // the units of the chart dimensions
59 - family: family, // the family of the chart
60 - context: context, // the context of the chart
61 - type: type, // the type of the chart
62 - priority: priority, // the priority relative to others in the same family
63 - update_every: service.update_every, // the expected update frequency of the chart
64 - dimensions: {}
65 - }
66 -
67 - var found = 0;
68 - for(var x in obj) {
69 - if(typeof(obj[x]) !== 'undefined' && obj[x] !== 0) {
70 - found++;
71 - chart.dimensions[x] = {
72 - id: x, // the unique id of the dimension
73 - name: x, // the name of the dimension
74 - algorithm: algorithm, // the id of the netdata algorithm
75 - multiplier: multiplier, // the multiplier
76 - divisor: divisor, // the divisor
77 - hidden: false // is hidden (boolean)
78 - }
79 - }
80 - }
81 -
82 - if(found === false)
83 - return null;
84 -
85 - chart = service.chart(id, chart);
86 - this.charts[id] = chart;
87 - return chart;
88 - },
89 -
90 - chartFromMembers: function(service, obj, id_suffix, title_suffix, units, family, context, type, priority, algorithm, multiplier, divisor) {
91 - var id = 'named_' + service.name + '.' + id_suffix;
92 - var chart = this.charts[id];
93 -
94 - if(typeof chart === 'undefined') {
95 - chart = this.chartFromMembersCreate(service, obj, id, title_suffix, units, family, context, type, priority, algorithm, multiplier, divisor);
96 - if(chart === null) return false;
97 - }
98 - else {
99 - // check if we need to re-generate the chart
100 - for(var x in obj) {
101 - if(typeof(chart.dimensions[x]) === 'undefined') {
102 - chart = this.chartFromMembersCreate(service, obj, id, title_suffix, units, family, context, type, priority, algorithm, multiplier, divisor);
103 - if(chart === null) return false;
104 - break;
105 - }
106 - }
107 - }
108 -
109 - var found = 0;
110 - service.begin(chart);
111 - for(var x in obj) {
112 - if(typeof(chart.dimensions[x]) !== 'undefined') {
113 - found++;
114 - service.set(x, obj[x]);
115 - }
116 - }
117 - service.end();
118 -
119 - if(found > 0) return true;
120 - return false;
121 - },
122 -
123 - // an index to map values to different charts
124 - lookups: {
125 - nsstats: {},
126 - resolver_stats: {},
127 - numfetch: {}
128 - },
129 -
130 - // transform the XML response of bind
131 - // to the JSON response of bind
132 - xml2js: function(service, data_xml) {
133 - var d = XML.parse(data_xml);
134 - if(d === null) return null;
135 -
136 - var data = {};
137 - var len = d.server.counters.length;
138 - while(len--) {
139 - var a = d.server.counters[len];
140 - if(typeof a.counter === 'undefined') continue;
141 - if(a.type === 'opcode') a.type = 'opcodes';
142 - else if(a.type === 'qtype') a.type = 'qtypes';
143 - else if(a.type === 'nsstat') a.type = 'nsstats';
144 - var aa = data[a.type] = {};
145 - var alen = 0
146 - var alen2 = a.counter.length;
147 - while(alen < alen2) {
148 - aa[a.counter[alen].name] = parseInt(a.counter[alen]._Data);
149 - alen++;
150 - }
151 - }
152 -
153 - data.views = {};
154 - var vlen = d.views.view.length;
155 - while(vlen--) {
156 - var vname = d.views.view[vlen].name;
157 - data.views[vname] = { resolver: {} };
158 - var len = d.views.view[vlen].counters.length;
159 - while(len--) {
160 - var a = d.views.view[vlen].counters[len];
161 - if(typeof a.counter === 'undefined') continue;
162 - if(a.type === 'resstats') a.type = 'stats';
163 - else if(a.type === 'resqtype') a.type = 'qtypes';
164 - else if(a.type === 'adbstat') a.type = 'adb';
165 - var aa = data.views[vname].resolver[a.type] = {};
166 - var alen = 0;
167 - var alen2 = a.counter.length;
168 - while(alen < alen2) {
169 - aa[a.counter[alen].name] = parseInt(a.counter[alen]._Data);
170 - alen++;
171 - }
172 - }
173 - }
174 -
175 - return data;
176 - },
177 -
178 - processResponse: function(service, data) {
179 - if(data !== null) {
180 - var r;
181 -
182 - // parse XML or JSON
183 - // pepending on the URL given
184 - if(service.request.path.match(/^\/xml/) !== null)
185 - r = named.xml2js(service, data);
186 - else
187 - r = JSON.parse(data);
188 -
189 - if(typeof r === 'undefined' || r === null) {
190 - netdata.serviceError(service, "Cannot parse these data: " + data);
191 - return;
192 - }
193 -
194 - if(service.added !== true)
195 - service.commit();
196 -
197 - if(typeof r.nsstats !== 'undefined') {
198 - // we split the nsstats object to several others
199 - var global_requests = {}, global_requests_enable = false;
200 - var global_failures = {}, global_failures_enable = false;
201 - var global_failures_detail = {}, global_failures_detail_enable = false;
202 - var global_updates = {}, global_updates_enable = false;
203 - var protocol_queries = {}, protocol_queries_enable = false;
204 - var global_queries = {}, global_queries_enable = false;
205 - var global_queries_success = {}, global_queries_success_enable = false;
206 - var default_enable = false;
207 - var RecursClients = 0;
208 -
209 - // RecursClients is an absolute value
210 - if(typeof r.nsstats['RecursClients'] !== 'undefined') {
211 - RecursClients = r.nsstats['RecursClients'];
212 - delete r.nsstats['RecursClients'];
213 - }
214 -
215 - for( var x in r.nsstats ) {
216 - // we maintain an index of the values found
217 - // mapping them to objects splitted
218 -
219 - var look = named.lookups.nsstats[x];
220 - if(typeof look === 'undefined') {
221 - // a new value, not found in the index
222 - // index it:
223 - if(x === 'Requestv4') {
224 - named.lookups.nsstats[x] = {
225 - name: 'IPv4',
226 - type: 'global_requests'
227 - };
228 - }
229 - else if(x === 'Requestv6') {
230 - named.lookups.nsstats[x] = {
231 - name: 'IPv6',
232 - type: 'global_requests'
233 - };
234 - }
235 - else if(x === 'QryFailure') {
236 - named.lookups.nsstats[x] = {
237 - name: 'failures',
238 - type: 'global_failures'
239 - };
240 - }
241 - else if(x === 'QryUDP') {
242 - named.lookups.nsstats[x] = {
243 - name: 'UDP',
244 - type: 'protocol_queries'
245 - };
246 - }
247 - else if(x === 'QryTCP') {
248 - named.lookups.nsstats[x] = {
249 - name: 'TCP',
250 - type: 'protocol_queries'
251 - };
252 - }
253 - else if(x === 'QrySuccess') {
254 - named.lookups.nsstats[x] = {
255 - name: 'queries',
256 - type: 'global_queries_success'
257 - };
258 - }
259 - else if(x.match(/QryRej$/) !== null) {
260 - named.lookups.nsstats[x] = {
261 - name: x,
262 - type: 'global_failures_detail'
263 - };
264 - }
265 - else if(x.match(/^Qry/) !== null) {
266 - named.lookups.nsstats[x] = {
267 - name: x,
268 - type: 'global_queries'
269 - };
270 - }
271 - else if(x.match(/^Update/) !== null) {
272 - named.lookups.nsstats[x] = {
273 - name: x,
274 - type: 'global_updates'
275 - };
276 - }
277 - else {
278 - // values not mapped, will remain
279 - // in the default map
280 - named.lookups.nsstats[x] = {
281 - name: x,
282 - type: 'default'
283 - };
284 - }
285 -
286 - look = named.lookups.nsstats[x];
287 - // netdata.error('lookup nsstats value: ' + x + ' >>> ' + named.lookups.nsstats[x].type);
288 - }
289 -
290 - switch(look.type) {
291 - case 'global_requests': global_requests[look.name] = r.nsstats[x]; delete r.nsstats[x]; global_requests_enable = true; break;
292 - case 'global_queries': global_queries[look.name] = r.nsstats[x]; delete r.nsstats[x]; global_queries_enable = true; break;
293 - case 'global_queries_success': global_queries_success[look.name] = r.nsstats[x]; delete r.nsstats[x]; global_queries_success_enable = true; break;
294 - case 'global_updates': global_updates[look.name] = r.nsstats[x]; delete r.nsstats[x]; global_updates_enable = true; break;
295 - case 'protocol_queries': protocol_queries[look.name] = r.nsstats[x]; delete r.nsstats[x]; protocol_queries_enable = true; break;
296 - case 'global_failures': global_failures[look.name] = r.nsstats[x]; delete r.nsstats[x]; global_failures_enable = true; break;
297 - case 'global_failures_detail': global_failures_detail[look.name] = r.nsstats[x]; delete r.nsstats[x]; global_failures_detail_enable = true; break;
298 - default: default_enable = true; break;
299 - }
300 - }
301 -
302 - if(global_requests_enable == true)
303 - service.module.chartFromMembers(service, global_requests, 'received_requests', 'Bind, Global Received Requests by IP version', 'requests/s', 'requests', 'named.requests', netdata.chartTypes.stacked, named.base_priority + 1, netdata.chartAlgorithms.incremental, 1, 1);
304 -
305 - if(global_queries_success_enable == true)
306 - service.module.chartFromMembers(service, global_queries_success, 'global_queries_success', 'Bind, Global Successful Queries', 'queries/s', 'queries', 'named.queries.succcess', netdata.chartTypes.line, named.base_priority + 2, netdata.chartAlgorithms.incremental, 1, 1);
307 -
308 - if(protocol_queries_enable == true)
309 - service.module.chartFromMembers(service, protocol_queries, 'protocols_queries', 'Bind, Global Queries by IP Protocol', 'queries/s', 'queries', 'named.protocol.queries', netdata.chartTypes.stacked, named.base_priority + 3, netdata.chartAlgorithms.incremental, 1, 1);
310 -
311 - if(global_queries_enable == true)
312 - service.module.chartFromMembers(service, global_queries, 'global_queries', 'Bind, Global Queries Analysis', 'queries/s', 'queries', 'named.global.queries', netdata.chartTypes.stacked, named.base_priority + 4, netdata.chartAlgorithms.incremental, 1, 1);
313 -
314 - if(global_updates_enable == true)
315 - service.module.chartFromMembers(service, global_updates, 'received_updates', 'Bind, Global Received Updates', 'updates/s', 'updates', 'named.global.updates', netdata.chartTypes.stacked, named.base_priority + 5, netdata.chartAlgorithms.incremental, 1, 1);
316 -
317 - if(global_failures_enable == true)
318 - service.module.chartFromMembers(service, global_failures, 'query_failures', 'Bind, Global Query Failures', 'failures/s', 'failures', 'named.global.failures', netdata.chartTypes.line, named.base_priority + 6, netdata.chartAlgorithms.incremental, 1, 1);
319 -
320 - if(global_failures_detail_enable == true)
321 - service.module.chartFromMembers(service, global_failures_detail, 'query_failures_detail', 'Bind, Global Query Failures Analysis', 'failures/s', 'failures', 'named.global.failures.detail', netdata.chartTypes.stacked, named.base_priority + 7, netdata.chartAlgorithms.incremental, 1, 1);
322 -
323 - if(default_enable === true)
324 - service.module.chartFromMembers(service, r.nsstats, 'nsstats', 'Bind, Other Global Server Statistics', 'operations/s', 'other', 'named.nsstats', netdata.chartTypes.line, named.base_priority + 8, netdata.chartAlgorithms.incremental, 1, 1);
325 -
326 - // RecursClients chart
327 - {
328 - var id = 'named_' + service.name + '.recursive_clients';
329 - var chart = named.charts[id];
330 -
331 - if(typeof chart === 'undefined') {
332 - chart = {
333 - id: id, // the unique id of the chart
334 - name: '', // the unique name of the chart
335 - title: service.name + ' Bind, Current Recursive Clients', // the title of the chart
336 - units: 'clients', // the units of the chart dimensions
337 - family: 'clients', // the family of the chart
338 - context: 'named.recursive.clients', // the context of the chart
339 - type: netdata.chartTypes.line, // the type of the chart
340 - priority: named.base_priority + 1, // the priority relative to others in the same family
341 - update_every: service.update_every, // the expected update frequency of the chart
342 - dimensions: {
343 - 'clients': {
344 - id: 'clients', // the unique id of the dimension
345 - name: '', // the name of the dimension
346 - algorithm: netdata.chartAlgorithms.absolute,// the id of the netdata algorithm
347 - multiplier: 1, // the multiplier
348 - divisor: 1, // the divisor
349 - hidden: false // is hidden (boolean)
350 - }
351 - }
352 - };
353 -
354 - chart = service.chart(id, chart);
355 - named.charts[id] = chart;
356 - }
357 -
358 - service.begin(chart);
359 - service.set('clients', RecursClients);
360 - service.end();
361 - }
362 - }
363 -
364 - if(typeof r.opcodes !== 'undefined')
365 - service.module.chartFromMembers(service, r.opcodes, 'in_opcodes', 'Bind, Global Incoming Requests by OpCode', 'requests/s', 'requests', 'named.in.opcodes', netdata.chartTypes.stacked, named.base_priority + 9, netdata.chartAlgorithms.incremental, 1, 1);
366 -
367 - if(typeof r.qtypes !== 'undefined')
368 - service.module.chartFromMembers(service, r.qtypes, 'in_qtypes', 'Bind, Global Incoming Requests by Query Type', 'requests/s', 'requests', 'named.in.qtypes', netdata.chartTypes.stacked, named.base_priority + 10, netdata.chartAlgorithms.incremental, 1, 1);
369 -
370 - if(typeof r.sockstats !== 'undefined')
371 - service.module.chartFromMembers(service, r.sockstats, 'in_sockstats', 'Bind, Global Socket Statistics', 'operations/s', 'sockets', 'named.in.sockstats', netdata.chartTypes.line, named.base_priority + 11, netdata.chartAlgorithms.incremental, 1, 1);
372 -
373 - if(typeof r.views !== 'undefined') {
374 - for( var x in r.views ) {
375 - var resolver = r.views[x].resolver;
376 -
377 - if(typeof resolver !== 'undefined') {
378 - if(typeof resolver.stats !== 'undefined') {
379 - var NumFetch = 0;
380 - var key = service.name + '.' + x;
381 - var default_enable = false;
382 - var rtt = {}, rtt_enable = false;
383 -
384 - // NumFetch is an absolute value
385 - if(typeof resolver.stats['NumFetch'] !== 'undefined') {
386 - named.lookups.numfetch[key] = true;
387 - NumFetch = resolver.stats['NumFetch'];
388 - delete resolver.stats['NumFetch'];
389 - }
390 - if(typeof resolver.stats['BucketSize'] !== 'undefined') {
391 - delete resolver.stats['BucketSize'];
392 - }
393 -
394 - // split the QryRTT* from the main chart
395 - for( var y in resolver.stats ) {
396 - // we maintain an index of the values found
397 - // mapping them to objects splitted
398 -
399 - var look = named.lookups.resolver_stats[y];
400 - if(typeof look === 'undefined') {
401 - if(y.match(/^QryRTT/) !== null) {
402 - named.lookups.resolver_stats[y] = {
403 - name: y,
404 - type: 'rtt'
405 - };
406 - }
407 - else {
408 - named.lookups.resolver_stats[y] = {
409 - name: y,
410 - type: 'default'
411 - };
412 - }
413 -
414 - look = named.lookups.resolver_stats[y];
415 - // netdata.error('lookup resolver stats value: ' + y + ' >>> ' + look.type);
416 - }
417 -
418 - switch(look.type) {
419 - case 'rtt': rtt[look.name] = resolver.stats[y]; delete resolver.stats[y]; rtt_enable = true; break;
420 - default: default_enable = true; break;
421 - }
422 - }
423 -
424 - if(rtt_enable)
425 - service.module.chartFromMembers(service, rtt, 'view_resolver_rtt_' + x, 'Bind, ' + x + ' View, Resolver Round Trip Timings', 'queries/s', 'view_' + x, 'named.resolver.rtt', netdata.chartTypes.stacked, named.base_priority + 12, netdata.chartAlgorithms.incremental, 1, 1);
426 -
427 - if(default_enable)
428 - service.module.chartFromMembers(service, resolver.stats, 'view_resolver_stats_' + x, 'Bind, ' + x + ' View, Resolver Statistics', 'operations/s', 'view_' + x, 'named.resolver.stats', netdata.chartTypes.line, named.base_priority + 13, netdata.chartAlgorithms.incremental, 1, 1);
429 -
430 - // NumFetch chart
431 - if(typeof named.lookups.numfetch[key] !== 'undefined') {
432 - var id = 'named_' + service.name + '.view_resolver_numfetch_' + x;
433 - var chart = named.charts[id];
434 -
435 - if(typeof chart === 'undefined') {
436 - chart = {
437 - id: id, // the unique id of the chart
438 - name: '', // the unique name of the chart
439 - title: service.name + ' Bind, ' + x + ' View, Resolver Active Queries', // the title of the chart
440 - units: 'queries', // the units of the chart dimensions
441 - family: 'view_' + x, // the family of the chart
442 - context: 'named.resolver.active.queries', // the context of the chart
443 - type: netdata.chartTypes.line, // the type of the chart
444 - priority: named.base_priority + 1001, // the priority relative to others in the same family
445 - update_every: service.update_every, // the expected update frequency of the chart
446 - dimensions: {
447 - 'queries': {
448 - id: 'queries', // the unique id of the dimension
449 - name: '', // the name of the dimension
450 - algorithm: netdata.chartAlgorithms.absolute,// the id of the netdata algorithm
451 - multiplier: 1, // the multiplier
452 - divisor: 1, // the divisor
453 - hidden: false // is hidden (boolean)
454 - }
455 - }
456 - };
457 -
458 - chart = service.chart(id, chart);
459 - named.charts[id] = chart;
460 - }
461 -
462 - service.begin(chart);
463 - service.set('queries', NumFetch);
464 - service.end();
465 - }
466 - }
467 - }
468 -
469 - if(typeof resolver.qtypes !== 'undefined')
470 - service.module.chartFromMembers(service, resolver.qtypes, 'view_resolver_qtypes_' + x, 'Bind, ' + x + ' View, Requests by Query Type', 'requests/s', 'view_' + x, 'named.resolver.qtypes', netdata.chartTypes.stacked, named.base_priority + 14, netdata.chartAlgorithms.incremental, 1, 1);
471 -
472 - //if(typeof resolver.cache !== 'undefined')
473 - // service.module.chartFromMembers(service, resolver.cache, 'view_resolver_cache_' + x, 'Bind, ' + x + ' View, Cache Entries', 'entries', 'view_' + x, 'named.resolver.cache', netdata.chartTypes.stacked, named.base_priority + 15, netdata.chartAlgorithms.absolute, 1, 1);
474 -
475 - if(typeof resolver.cachestats['CacheHits'] !== 'undefined' && resolver.cachestats['CacheHits'] > 0) {
476 - var id = 'named_' + service.name + '.view_resolver_cachehits_' + x;
477 - var chart = named.charts[id];
478 -
479 - if(typeof chart === 'undefined') {
480 - chart = {
481 - id: id, // the unique id of the chart
482 - name: '', // the unique name of the chart
483 - title: service.name + ' Bind, ' + x + ' View, Resolver Cache Hits', // the title of the chart
484 - units: 'operations/s', // the units of the chart dimensions
485 - family: 'view_' + x, // the family of the chart
486 - context: 'named.resolver.cache.hits', // the context of the chart
487 - type: netdata.chartTypes.area, // the type of the chart
488 - priority: named.base_priority + 1100, // the priority relative to others in the same family
489 - update_every: service.update_every, // the expected update frequency of the chart
490 - dimensions: {
491 - 'CacheHits': {
492 - id: 'CacheHits', // the unique id of the dimension
493 - name: 'hits', // the name of the dimension
494 - algorithm: netdata.chartAlgorithms.incremental,// the id of the netdata algorithm
495 - multiplier: 1, // the multiplier
496 - divisor: 1, // the divisor
497 - hidden: false // is hidden (boolean)
498 - },
499 - 'CacheMisses': {
500 - id: 'CacheMisses', // the unique id of the dimension
501 - name: 'misses', // the name of the dimension
502 - algorithm: netdata.chartAlgorithms.incremental,// the id of the netdata algorithm
503 - multiplier: -1, // the multiplier
504 - divisor: 1, // the divisor
505 - hidden: false // is hidden (boolean)
506 - }
507 - }
508 - };
509 -
510 - chart = service.chart(id, chart);
511 - named.charts[id] = chart;
512 - }
513 -
514 - service.begin(chart);
515 - service.set('CacheHits', resolver.cachestats['CacheHits']);
516 - service.set('CacheMisses', resolver.cachestats['CacheMisses']);
517 - service.end();
518 - }
519 -
520 - // this is wrong, it contains many types of info:
521 - // 1. CacheHits, CacheMisses - incremental (added above)
522 - // 2. QueryHits, QueryMisses - incremental
523 - // 3. DeleteLRU, DeleteTTL - incremental
524 - // 4. CacheNodes, CacheBuckets - absolute
525 - // 5. TreeMemTotal, TreeMemInUse - absolute
526 - // 6. HeapMemMax, HeapMemTotal, HeapMemInUse - absolute
527 - //if(typeof resolver.cachestats !== 'undefined')
528 - // service.module.chartFromMembers(service, resolver.cachestats, 'view_resolver_cachestats_' + x, 'Bind, ' + x + ' View, Cache Statistics', 'requests/s', 'view_' + x, 'named.resolver.cache.stats', netdata.chartTypes.line, named.base_priority + 1001, netdata.chartAlgorithms.incremental, 1, 1);
529 -
530 - //if(typeof resolver.adb !== 'undefined')
531 - // service.module.chartFromMembers(service, resolver.adb, 'view_resolver_adb_' + x, 'Bind, ' + x + ' View, ADB Statistics', 'entries', 'view_' + x, 'named.resolver.adb', netdata.chartTypes.line, named.base_priority + 1002, netdata.chartAlgorithms.absolute, 1, 1);
532 - }
533 - }
534 - }
535 - },
536 -
537 - // module.serviceExecute()
538 - // this function is called only from this module
539 - // its purpose is to prepare the request and call
540 - // netdata.serviceExecute()
541 - serviceExecute: function(name, a_url, update_every) {
542 - if(netdata.options.DEBUG === true) netdata.debug(this.name + ': ' + name + ': url: ' + a_url + ', update_every: ' + update_every);
543 - var service = netdata.service({
544 - name: name,
545 - request: netdata.requestFromURL(a_url),
546 - update_every: update_every,
547 - module: this
548 - });
549 -
550 - service.execute(this.processResponse);
551 - },
552 -
553 - configure: function(config) {
554 - var added = 0;
555 -
556 - if(this.enable_autodetect === true) {
557 - this.serviceExecute('local', 'http://localhost:8888/json/v1/server', this.update_every);
558 - added++;
559 - }
560 -
561 - if(typeof(config.servers) !== 'undefined') {
562 - var len = config.servers.length;
563 - while(len--) {
564 - if(typeof config.servers[len].update_every === 'undefined')
565 - config.servers[len].update_every = this.update_every;
566 -
567 - this.serviceExecute(config.servers[len].name, config.servers[len].url, config.servers[len].update_every);
568 - added++;
569 - }
570 - }
571 -
572 - return added;
573 - },
574 -
575 - // module.update()
576 - // this is called repeatidly to collect data, by calling
577 - // netdata.serviceExecute()
578 - update: function(service, callback) {
579 - service.execute(function(serv, data) {
580 - service.module.processResponse(serv, data);
581 - callback();
582 - });
583 - },
47 + name: __filename,
48 + enable_autodetect: true,
49 + update_every: 1,
50 + base_priority: 60000,
51 + charts: {},
52 +
53 + chartFromMembersCreate: function(service, obj, id, title_suffix, units, family, context, type, priority, algorithm, multiplier, divisor) {
54 + var chart = {
55 + id: id, // the unique id of the chart
56 + name: '', // the unique name of the chart
57 + title: service.name + ' ' + title_suffix, // the title of the chart
58 + units: units, // the units of the chart dimensions
59 + family: family, // the family of the chart
60 + context: context, // the context of the chart
61 + type: type, // the type of the chart
62 + priority: priority, // the priority relative to others in the same family
63 + update_every: service.update_every, // the expected update frequency of the chart
64 + dimensions: {}
65 + }
66 +
67 + var found = 0;
68 + for(var x in obj) {
69 + if(typeof(obj[x]) !== 'undefined' && obj[x] !== 0) {
70 + found++;
71 + chart.dimensions[x] = {
72 + id: x, // the unique id of the dimension
73 + name: x, // the name of the dimension
74 + algorithm: algorithm, // the id of the netdata algorithm
75 + multiplier: multiplier, // the multiplier
76 + divisor: divisor, // the divisor
77 + hidden: false // is hidden (boolean)
78 + }
79 + }
80 + }
81 +
82 + if(found === false)
83 + return null;
84 +
85 + chart = service.chart(id, chart);
86 + this.charts[id] = chart;
87 + return chart;
88 + },
89 +
90 + chartFromMembers: function(service, obj, id_suffix, title_suffix, units, family, context, type, priority, algorithm, multiplier, divisor) {
91 + var id = 'named_' + service.name + '.' + id_suffix;
92 + var chart = this.charts[id];
93 +
94 + if(typeof chart === 'undefined') {
95 + chart = this.chartFromMembersCreate(service, obj, id, title_suffix, units, family, context, type, priority, algorithm, multiplier, divisor);
96 + if(chart === null) return false;
97 + }
98 + else {
99 + // check if we need to re-generate the chart
100 + for(var x in obj) {
101 + if(typeof(chart.dimensions[x]) === 'undefined') {
102 + chart = this.chartFromMembersCreate(service, obj, id, title_suffix, units, family, context, type, priority, algorithm, multiplier, divisor);
103 + if(chart === null) return false;
104 + break;
105 + }
106 + }
107 + }
108 +
109 + var found = 0;
110 + service.begin(chart);
111 + for(var x in obj) {
112 + if(typeof(chart.dimensions[x]) !== 'undefined') {
113 + found++;
114 + service.set(x, obj[x]);
115 + }
116 + }
117 + service.end();
118 +
119 + if(found > 0) return true;
120 + return false;
121 + },
122 +
123 + // an index to map values to different charts
124 + lookups: {
125 + nsstats: {},
126 + resolver_stats: {},
127 + numfetch: {}
128 + },
129 +
130 + // transform the XML response of bind
131 + // to the JSON response of bind
132 + xml2js: function(service, data_xml) {
133 + var d = XML.parse(data_xml);
134 + if(d === null) return null;
135 +
136 + var data = {};
137 + var len = d.server.counters.length;
138 + while(len--) {
139 + var a = d.server.counters[len];
140 + if(typeof a.counter === 'undefined') continue;
141 + if(a.type === 'opcode') a.type = 'opcodes';
142 + else if(a.type === 'qtype') a.type = 'qtypes';
143 + else if(a.type === 'nsstat') a.type = 'nsstats';
144 + var aa = data[a.type] = {};
145 + var alen = 0
146 + var alen2 = a.counter.length;
147 + while(alen < alen2) {
148 + aa[a.counter[alen].name] = parseInt(a.counter[alen]._Data);
149 + alen++;
150 + }
151 + }
152 +
153 + data.views = {};
154 + var vlen = d.views.view.length;
155 + while(vlen--) {
156 + var vname = d.views.view[vlen].name;
157 + data.views[vname] = { resolver: {} };
158 + var len = d.views.view[vlen].counters.length;
159 + while(len--) {
160 + var a = d.views.view[vlen].counters[len];
161 + if(typeof a.counter === 'undefined') continue;
162 + if(a.type === 'resstats') a.type = 'stats';
163 + else if(a.type === 'resqtype') a.type = 'qtypes';
164 + else if(a.type === 'adbstat') a.type = 'adb';
165 + var aa = data.views[vname].resolver[a.type] = {};
166 + var alen = 0;
167 + var alen2 = a.counter.length;
168 + while(alen < alen2) {
169 + aa[a.counter[alen].name] = parseInt(a.counter[alen]._Data);
170 + alen++;
171 + }
172 + }
173 + }
174 +
175 + return data;
176 + },
177 +
178 + processResponse: function(service, data) {
179 + if(data !== null) {
180 + var r;
181 +
182 + // parse XML or JSON
183 + // pepending on the URL given
184 + if(service.request.path.match(/^\/xml/) !== null)
185 + r = named.xml2js(service, data);
186 + else
187 + r = JSON.parse(data);
188 +
189 + if(typeof r === 'undefined' || r === null) {
190 + netdata.serviceError(service, "Cannot parse these data: " + data);
191 + return;
192 + }
193 +
194 + if(service.added !== true)
195 + service.commit();
196 +
197 + if(typeof r.nsstats !== 'undefined') {
198 + // we split the nsstats object to several others
199 + var global_requests = {}, global_requests_enable = false;
200 + var global_failures = {}, global_failures_enable = false;
201 + var global_failures_detail = {}, global_failures_detail_enable = false;
202 + var global_updates = {}, global_updates_enable = false;
203 + var protocol_queries = {}, protocol_queries_enable = false;
204 + var global_queries = {}, global_queries_enable = false;
205 + var global_queries_success = {}, global_queries_success_enable = false;
206 + var default_enable = false;
207 + var RecursClients = 0;
208 +
209 + // RecursClients is an absolute value
210 + if(typeof r.nsstats['RecursClients'] !== 'undefined') {
211 + RecursClients = r.nsstats['RecursClients'];
212 + delete r.nsstats['RecursClients'];
213 + }
214 +
215 + for( var x in r.nsstats ) {
216 + // we maintain an index of the values found
217 + // mapping them to objects splitted
218 +
219 + var look = named.lookups.nsstats[x];
220 + if(typeof look === 'undefined') {
221 + // a new value, not found in the index
222 + // index it:
223 + if(x === 'Requestv4') {
224 + named.lookups.nsstats[x] = {
225 + name: 'IPv4',
226 + type: 'global_requests'
227 + };
228 + }
229 + else if(x === 'Requestv6') {
230 + named.lookups.nsstats[x] = {
231 + name: 'IPv6',
232 + type: 'global_requests'
233 + };
234 + }
235 + else if(x === 'QryFailure') {
236 + named.lookups.nsstats[x] = {
237 + name: 'failures',
238 + type: 'global_failures'
239 + };
240 + }
241 + else if(x === 'QryUDP') {
242 + named.lookups.nsstats[x] = {
243 + name: 'UDP',
244 + type: 'protocol_queries'
245 + };
246 + }
247 + else if(x === 'QryTCP') {
248 + named.lookups.nsstats[x] = {
249 + name: 'TCP',
250 + type: 'protocol_queries'
251 + };
252 + }
253 + else if(x === 'QrySuccess') {
254 + named.lookups.nsstats[x] = {
255 + name: 'queries',
256 + type: 'global_queries_success'
257 + };
258 + }
259 + else if(x.match(/QryRej$/) !== null) {
260 + named.lookups.nsstats[x] = {
261 + name: x,
262 + type: 'global_failures_detail'
263 + };
264 + }
265 + else if(x.match(/^Qry/) !== null) {
266 + named.lookups.nsstats[x] = {
267 + name: x,
268 + type: 'global_queries'
269 + };
270 + }
271 + else if(x.match(/^Update/) !== null) {
272 + named.lookups.nsstats[x] = {
273 + name: x,
274 + type: 'global_updates'
275 + };
276 + }
277 + else {
278 + // values not mapped, will remain
279 + // in the default map
280 + named.lookups.nsstats[x] = {
281 + name: x,
282 + type: 'default'
283 + };
284 + }
285 +
286 + look = named.lookups.nsstats[x];
287 + // netdata.error('lookup nsstats value: ' + x + ' >>> ' + named.lookups.nsstats[x].type);
288 + }
289 +
290 + switch(look.type) {
291 + case 'global_requests': global_requests[look.name] = r.nsstats[x]; delete r.nsstats[x]; global_requests_enable = true; break;
292 + case 'global_queries': global_queries[look.name] = r.nsstats[x]; delete r.nsstats[x]; global_queries_enable = true; break;
293 + case 'global_queries_success': global_queries_success[look.name] = r.nsstats[x]; delete r.nsstats[x]; global_queries_success_enable = true; break;
294 + case 'global_updates': global_updates[look.name] = r.nsstats[x]; delete r.nsstats[x]; global_updates_enable = true; break;
295 + case 'protocol_queries': protocol_queries[look.name] = r.nsstats[x]; delete r.nsstats[x]; protocol_queries_enable = true; break;
296 + case 'global_failures': global_failures[look.name] = r.nsstats[x]; delete r.nsstats[x]; global_failures_enable = true; break;
297 + case 'global_failures_detail': global_failures_detail[look.name] = r.nsstats[x]; delete r.nsstats[x]; global_failures_detail_enable = true; break;
298 + default: default_enable = true; break;
299 + }
300 + }
301 +
302 + if(global_requests_enable == true)
303 + service.module.chartFromMembers(service, global_requests, 'received_requests', 'Bind, Global Received Requests by IP version', 'requests/s', 'requests', 'named.requests', netdata.chartTypes.stacked, named.base_priority + 1, netdata.chartAlgorithms.incremental, 1, 1);
304 +
305 + if(global_queries_success_enable == true)
306 + service.module.chartFromMembers(service, global_queries_success, 'global_queries_success', 'Bind, Global Successful Queries', 'queries/s', 'queries', 'named.queries.succcess', netdata.chartTypes.line, named.base_priority + 2, netdata.chartAlgorithms.incremental, 1, 1);
307 +
308 + if(protocol_queries_enable == true)
309 + service.module.chartFromMembers(service, protocol_queries, 'protocols_queries', 'Bind, Global Queries by IP Protocol', 'queries/s', 'queries', 'named.protocol.queries', netdata.chartTypes.stacked, named.base_priority + 3, netdata.chartAlgorithms.incremental, 1, 1);
310 +
311 + if(global_queries_enable == true)
312 + service.module.chartFromMembers(service, global_queries, 'global_queries', 'Bind, Global Queries Analysis', 'queries/s', 'queries', 'named.global.queries', netdata.chartTypes.stacked, named.base_priority + 4, netdata.chartAlgorithms.incremental, 1, 1);
313 +
314 + if(global_updates_enable == true)
315 + service.module.chartFromMembers(service, global_updates, 'received_updates', 'Bind, Global Received Updates', 'updates/s', 'updates', 'named.global.updates', netdata.chartTypes.stacked, named.base_priority + 5, netdata.chartAlgorithms.incremental, 1, 1);
316 +
317 + if(global_failures_enable == true)
318 + service.module.chartFromMembers(service, global_failures, 'query_failures', 'Bind, Global Query Failures', 'failures/s', 'failures', 'named.global.failures', netdata.chartTypes.line, named.base_priority + 6, netdata.chartAlgorithms.incremental, 1, 1);
319 +
320 + if(global_failures_detail_enable == true)
321 + service.module.chartFromMembers(service, global_failures_detail, 'query_failures_detail', 'Bind, Global Query Failures Analysis', 'failures/s', 'failures', 'named.global.failures.detail', netdata.chartTypes.stacked, named.base_priority + 7, netdata.chartAlgorithms.incremental, 1, 1);
322 +
323 + if(default_enable === true)
324 + service.module.chartFromMembers(service, r.nsstats, 'nsstats', 'Bind, Other Global Server Statistics', 'operations/s', 'other', 'named.nsstats', netdata.chartTypes.line, named.base_priority + 8, netdata.chartAlgorithms.incremental, 1, 1);
325 +
326 + // RecursClients chart
327 + {
328 + var id = 'named_' + service.name + '.recursive_clients';
329 + var chart = named.charts[id];
330 +
331 + if(typeof chart === 'undefined') {
332 + chart = {
333 + id: id, // the unique id of the chart
334 + name: '', // the unique name of the chart
335 + title: service.name + ' Bind, Current Recursive Clients', // the title of the chart
336 + units: 'clients', // the units of the chart dimensions
337 + family: 'clients', // the family of the chart
338 + context: 'named.recursive.clients', // the context of the chart
339 + type: netdata.chartTypes.line, // the type of the chart
340 + priority: named.base_priority + 1, // the priority relative to others in the same family
341 + update_every: service.update_every, // the expected update frequency of the chart
342 + dimensions: {
343 + 'clients': {
344 + id: 'clients', // the unique id of the dimension
345 + name: '', // the name of the dimension
346 + algorithm: netdata.chartAlgorithms.absolute,// the id of the netdata algorithm
347 + multiplier: 1, // the multiplier
348 + divisor: 1, // the divisor
349 + hidden: false // is hidden (boolean)
350 + }
351 + }
352 + };
353 +
354 + chart = service.chart(id, chart);
355 + named.charts[id] = chart;
356 + }
357 +
358 + service.begin(chart);
359 + service.set('clients', RecursClients);
360 + service.end();
361 + }
362 + }
363 +
364 + if(typeof r.opcodes !== 'undefined')
365 + service.module.chartFromMembers(service, r.opcodes, 'in_opcodes', 'Bind, Global Incoming Requests by OpCode', 'requests/s', 'requests', 'named.in.opcodes', netdata.chartTypes.stacked, named.base_priority + 9, netdata.chartAlgorithms.incremental, 1, 1);
366 +
367 + if(typeof r.qtypes !== 'undefined')
368 + service.module.chartFromMembers(service, r.qtypes, 'in_qtypes', 'Bind, Global Incoming Requests by Query Type', 'requests/s', 'requests', 'named.in.qtypes', netdata.chartTypes.stacked, named.base_priority + 10, netdata.chartAlgorithms.incremental, 1, 1);
369 +
370 + if(typeof r.sockstats !== 'undefined')
371 + service.module.chartFromMembers(service, r.sockstats, 'in_sockstats', 'Bind, Global Socket Statistics', 'operations/s', 'sockets', 'named.in.sockstats', netdata.chartTypes.line, named.base_priority + 11, netdata.chartAlgorithms.incremental, 1, 1);
372 +
373 + if(typeof r.views !== 'undefined') {
374 + for( var x in r.views ) {
375 + var resolver = r.views[x].resolver;
376 +
377 + if(typeof resolver !== 'undefined') {
378 + if(typeof resolver.stats !== 'undefined') {
379 + var NumFetch = 0;
380 + var key = service.name + '.' + x;
381 + var default_enable = false;
382 + var rtt = {}, rtt_enable = false;
383 +
384 + // NumFetch is an absolute value
385 + if(typeof resolver.stats['NumFetch'] !== 'undefined') {
386 + named.lookups.numfetch[key] = true;
387 + NumFetch = resolver.stats['NumFetch'];
388 + delete resolver.stats['NumFetch'];
389 + }
390 + if(typeof resolver.stats['BucketSize'] !== 'undefined') {
391 + delete resolver.stats['BucketSize'];
392 + }
393 +
394 + // split the QryRTT* from the main chart
395 + for( var y in resolver.stats ) {
396 + // we maintain an index of the values found
397 + // mapping them to objects splitted
398 +
399 + var look = named.lookups.resolver_stats[y];
400 + if(typeof look === 'undefined') {
401 + if(y.match(/^QryRTT/) !== null) {
402 + named.lookups.resolver_stats[y] = {
403 + name: y,
404 + type: 'rtt'
405 + };
406 + }
407 + else {
408 + named.lookups.resolver_stats[y] = {
409 + name: y,
410 + type: 'default'
411 + };
412 + }
413 +
414 + look = named.lookups.resolver_stats[y];
415 + // netdata.error('lookup resolver stats value: ' + y + ' >>> ' + look.type);
416 + }
417 +
418 + switch(look.type) {
419 + case 'rtt': rtt[look.name] = resolver.stats[y]; delete resolver.stats[y]; rtt_enable = true; break;
420 + default: default_enable = true; break;
421 + }
422 + }
423 +
424 + if(rtt_enable)
425 + service.module.chartFromMembers(service, rtt, 'view_resolver_rtt_' + x, 'Bind, ' + x + ' View, Resolver Round Trip Timings', 'queries/s', 'view_' + x, 'named.resolver.rtt', netdata.chartTypes.stacked, named.base_priority + 12, netdata.chartAlgorithms.incremental, 1, 1);
426 +
427 + if(default_enable)
428 + service.module.chartFromMembers(service, resolver.stats, 'view_resolver_stats_' + x, 'Bind, ' + x + ' View, Resolver Statistics', 'operations/s', 'view_' + x, 'named.resolver.stats', netdata.chartTypes.line, named.base_priority + 13, netdata.chartAlgorithms.incremental, 1, 1);
429 +
430 + // NumFetch chart
431 + if(typeof named.lookups.numfetch[key] !== 'undefined') {
432 + var id = 'named_' + service.name + '.view_resolver_numfetch_' + x;
433 + var chart = named.charts[id];
434 +
435 + if(typeof chart === 'undefined') {
436 + chart = {
437 + id: id, // the unique id of the chart
438 + name: '', // the unique name of the chart
439 + title: service.name + ' Bind, ' + x + ' View, Resolver Active Queries', // the title of the chart
440 + units: 'queries', // the units of the chart dimensions
441 + family: 'view_' + x, // the family of the chart
442 + context: 'named.resolver.active.queries', // the context of the chart
443 + type: netdata.chartTypes.line, // the type of the chart
444 + priority: named.base_priority + 1001, // the priority relative to others in the same family
445 + update_every: service.update_every, // the expected update frequency of the chart
446 + dimensions: {
447 + 'queries': {
448 + id: 'queries', // the unique id of the dimension
449 + name: '', // the name of the dimension
450 + algorithm: netdata.chartAlgorithms.absolute,// the id of the netdata algorithm
451 + multiplier: 1, // the multiplier
452 + divisor: 1, // the divisor
453 + hidden: false // is hidden (boolean)
454 + }
455 + }
456 + };
457 +
458 + chart = service.chart(id, chart);
459 + named.charts[id] = chart;
460 + }
461 +
462 + service.begin(chart);
463 + service.set('queries', NumFetch);
464 + service.end();
465 + }
466 + }
467 + }
468 +
469 + if(typeof resolver.qtypes !== 'undefined')
470 + service.module.chartFromMembers(service, resolver.qtypes, 'view_resolver_qtypes_' + x, 'Bind, ' + x + ' View, Requests by Query Type', 'requests/s', 'view_' + x, 'named.resolver.qtypes', netdata.chartTypes.stacked, named.base_priority + 14, netdata.chartAlgorithms.incremental, 1, 1);
471 +
472 + //if(typeof resolver.cache !== 'undefined')
473 + // service.module.chartFromMembers(service, resolver.cache, 'view_resolver_cache_' + x, 'Bind, ' + x + ' View, Cache Entries', 'entries', 'view_' + x, 'named.resolver.cache', netdata.chartTypes.stacked, named.base_priority + 15, netdata.chartAlgorithms.absolute, 1, 1);
474 +
475 + if(typeof resolver.cachestats['CacheHits'] !== 'undefined' && resolver.cachestats['CacheHits'] > 0) {
476 + var id = 'named_' + service.name + '.view_resolver_cachehits_' + x;
477 + var chart = named.charts[id];
478 +
479 + if(typeof chart === 'undefined') {
480 + chart = {
481 + id: id, // the unique id of the chart
482 + name: '', // the unique name of the chart
483 + title: service.name + ' Bind, ' + x + ' View, Resolver Cache Hits', // the title of the chart
484 + units: 'operations/s', // the units of the chart dimensions
485 + family: 'view_' + x, // the family of the chart
486 + context: 'named.resolver.cache.hits', // the context of the chart
487 + type: netdata.chartTypes.area, // the type of the chart
488 + priority: named.base_priority + 1100, // the priority relative to others in the same family
489 + update_every: service.update_every, // the expected update frequency of the chart
490 + dimensions: {
491 + 'CacheHits': {
492 + id: 'CacheHits', // the unique id of the dimension
493 + name: 'hits', // the name of the dimension
494 + algorithm: netdata.chartAlgorithms.incremental,// the id of the netdata algorithm
495 + multiplier: 1, // the multiplier
496 + divisor: 1, // the divisor
497 + hidden: false // is hidden (boolean)
498 + },
499 + 'CacheMisses': {
500 + id: 'CacheMisses', // the unique id of the dimension
501 + name: 'misses', // the name of the dimension
502 + algorithm: netdata.chartAlgorithms.incremental,// the id of the netdata algorithm
503 + multiplier: -1, // the multiplier
504 + divisor: 1, // the divisor
505 + hidden: false // is hidden (boolean)
506 + }
507 + }
508 + };
509 +
510 + chart = service.chart(id, chart);
511 + named.charts[id] = chart;
512 + }
513 +
514 + service.begin(chart);
515 + service.set('CacheHits', resolver.cachestats['CacheHits']);
516 + service.set('CacheMisses', resolver.cachestats['CacheMisses']);
517 + service.end();
518 + }
519 +
520 + // this is wrong, it contains many types of info:
521 + // 1. CacheHits, CacheMisses - incremental (added above)
522 + // 2. QueryHits, QueryMisses - incremental
523 + // 3. DeleteLRU, DeleteTTL - incremental
524 + // 4. CacheNodes, CacheBuckets - absolute
525 + // 5. TreeMemTotal, TreeMemInUse - absolute
526 + // 6. HeapMemMax, HeapMemTotal, HeapMemInUse - absolute
527 + //if(typeof resolver.cachestats !== 'undefined')
528 + // service.module.chartFromMembers(service, resolver.cachestats, 'view_resolver_cachestats_' + x, 'Bind, ' + x + ' View, Cache Statistics', 'requests/s', 'view_' + x, 'named.resolver.cache.stats', netdata.chartTypes.line, named.base_priority + 1001, netdata.chartAlgorithms.incremental, 1, 1);
529 +
530 + //if(typeof resolver.adb !== 'undefined')
531 + // service.module.chartFromMembers(service, resolver.adb, 'view_resolver_adb_' + x, 'Bind, ' + x + ' View, ADB Statistics', 'entries', 'view_' + x, 'named.resolver.adb', netdata.chartTypes.line, named.base_priority + 1002, netdata.chartAlgorithms.absolute, 1, 1);
532 + }
533 + }
534 + }
535 + },
536 +
537 + // module.serviceExecute()
538 + // this function is called only from this module
539 + // its purpose is to prepare the request and call
540 + // netdata.serviceExecute()
541 + serviceExecute: function(name, a_url, update_every) {
542 + if(netdata.options.DEBUG === true) netdata.debug(this.name + ': ' + name + ': url: ' + a_url + ', update_every: ' + update_every);
543 + var service = netdata.service({
544 + name: name,
545 + request: netdata.requestFromURL(a_url),
546 + update_every: update_every,
547 + module: this
548 + });
549 +
550 + service.execute(this.processResponse);
551 + },
552 +
553 + configure: function(config) {
554 + var added = 0;
555 +
556 + if(this.enable_autodetect === true) {
557 + this.serviceExecute('local', 'http://localhost:8888/json/v1/server', this.update_every);
558 + added++;
559 + }
560 +
561 + if(typeof(config.servers) !== 'undefined') {
562 + var len = config.servers.length;
563 + while(len--) {
564 + if(typeof config.servers[len].update_every === 'undefined')
565 + config.servers[len].update_every = this.update_every;
566 +
567 + this.serviceExecute(config.servers[len].name, config.servers[len].url, config.servers[len].update_every);
568 + added++;
569 + }
570 + }
571 +
572 + return added;
573 + },
574 +
575 + // module.update()
576 + // this is called repeatidly to collect data, by calling
577 + // netdata.serviceExecute()
578 + update: function(service, callback) {
579 + service.execute(function(serv, data) {
580 + service.module.processResponse(serv, data);
581 + callback();
582 + });
583 + },
584 };
585
586 module.exports = named;
node.d/sma_webbox.node.js
+216 -216
@@ -6,20 +6,20 @@
6 // example configuration in /etc/netdata/sma_webbox.conf
7 /*
8 {
9 - "enable_autodetect": false,
10 - "update_every": 5,
11 - "servers": [
12 - {
13 - "name": "plant1",
14 - "hostname": "10.0.1.1",
15 - "update_every": 10
16 - },
17 - {
18 - "name": "plant2",
19 - "hostname": "10.0.2.1",
20 - "update_every": 15
21 - }
22 - ]
9 + "enable_autodetect": false,
10 + "update_every": 5,
11 + "servers": [
12 + {
13 + "name": "plant1",
14 + "hostname": "10.0.1.1",
15 + "update_every": 10
16 + },
17 + {
18 + "name": "plant2",
19 + "hostname": "10.0.2.1",
20 + "update_every": 15
21 + }
22 + ]
23 }
24 */
25
@@ -30,208 +30,208 @@ var netdata = require('netdata');
30 if(netdata.options.DEBUG === true) netdata.debug('loaded ' + __filename + ' plugin');
31
32 var webbox = {
33 - name: __filename,
34 - enable_autodetect: true,
35 - update_every: 1,
36 - base_priority: 60000,
37 - charts: {},
38 -
39 - processResponse: function(service, data) {
40 - if(data !== null) {
41 - var r = JSON.parse(data);
42 -
43 - var d = {
44 - 'GriPwr': {
45 - unit: null,
46 - value: null
47 - },
48 - 'GriEgyTdy': {
49 - unit: null,
50 - value: null
51 - },
52 - 'GriEgyTot': {
53 - unit: null,
54 - value: null
55 - }
56 - };
57 -
58 - // parse the webbox response
59 - // and put it in our d object
60 - var found = 0;
61 - var len = r.result.overview.length;
62 - while(len--) {
63 - var e = r.result.overview[len];
64 - if(typeof(d[e.meta]) !== 'undefined') {
65 - found++;
66 - d[e.meta].value = e.value;
67 - d[e.meta].unit = e.unit;
68 - }
69 - }
70 -
71 - // add the service
72 - if(found > 0 && service.added !== true)
73 - service.commit();
74 -
75 - // Grid Current Power Chart
76 - if(d['GriPwr'].value !== null) {
77 - var id = 'sma_webbox_' + service.name + '.current';
78 - var chart = webbox.charts[id];
79 -
80 - if(typeof chart === 'undefined') {
81 - chart = {
82 - id: id, // the unique id of the chart
83 - name: '', // the unique name of the chart
84 - title: service.name + ' Current Grid Power', // the title of the chart
85 - units: d['GriPwr'].unit, // the units of the chart dimensions
86 - family: 'now', // the family of the chart
87 - context: 'sma_webbox.grid.power', // the context of the chart
88 - type: netdata.chartTypes.area, // the type of the chart
89 - priority: webbox.base_priority + 1, // the priority relative to others in the same family
90 - update_every: service.update_every, // the expected update frequency of the chart
91 - dimensions: {
92 - 'GriPwr': {
93 - id: 'GriPwr', // the unique id of the dimension
94 - name: 'power', // the name of the dimension
95 - algorithm: netdata.chartAlgorithms.absolute,// the id of the netdata algorithm
96 - multiplier: 1, // the multiplier
97 - divisor: 1, // the divisor
98 - hidden: false // is hidden (boolean)
99 - }
100 - }
101 - };
102 -
103 - chart = service.chart(id, chart);
104 - webbox.charts[id] = chart;
105 - }
106 -
107 - service.begin(chart);
108 - service.set('GriPwr', Math.round(d['GriPwr'].value));
109 - service.end();
110 - }
111 -
112 - if(d['GriEgyTdy'].value !== null) {
113 - var id = 'sma_webbox_' + service.name + '.today';
114 - var chart = webbox.charts[id];
115 -
116 - if(typeof chart === 'undefined') {
117 - chart = {
118 - id: id, // the unique id of the chart
119 - name: '', // the unique name of the chart
120 - title: service.name + ' Today Grid Power', // the title of the chart
121 - units: d['GriEgyTdy'].unit, // the units of the chart dimensions
122 - family: 'today', // the family of the chart
123 - context: 'sma_webbox.grid.power.today', // the context of the chart
124 - type: netdata.chartTypes.area, // the type of the chart
125 - priority: webbox.base_priority + 2, // the priority relative to others in the same family
126 - update_every: service.update_every, // the expected update frequency of the chart
127 - dimensions: {
128 - 'GriEgyTdy': {
129 - id: 'GriEgyTdy', // the unique id of the dimension
130 - name: 'power', // the name of the dimension
131 - algorithm: netdata.chartAlgorithms.absolute,// the id of the netdata algorithm
132 - multiplier: 1, // the multiplier
133 - divisor: 1000, // the divisor
134 - hidden: false // is hidden (boolean)
135 - }
136 - }
137 - };
138 -
139 - chart = service.chart(id, chart);
140 - webbox.charts[id] = chart;
141 - }
142 -
143 - service.begin(chart);
144 - service.set('GriEgyTdy', Math.round(d['GriEgyTdy'].value * 1000));
145 - service.end();
146 - }
147 -
148 - if(d['GriEgyTot'].value !== null) {
149 - var id = 'sma_webbox_' + service.name + '.total';
150 - var chart = webbox.charts[id];
151 -
152 - if(typeof chart === 'undefined') {
153 - chart = {
154 - id: id, // the unique id of the chart
155 - name: '', // the unique name of the chart
156 - title: service.name + ' Total Grid Power', // the title of the chart
157 - units: d['GriEgyTot'].unit, // the units of the chart dimensions
158 - family: 'total', // the family of the chart
159 - context: 'sma_webbox.grid.power.total', // the context of the chart
160 - type: netdata.chartTypes.area, // the type of the chart
161 - priority: webbox.base_priority + 3, // the priority relative to others in the same family
162 - update_every: service.update_every, // the expected update frequency of the chart
163 - dimensions: {
164 - 'GriEgyTot': {
165 - id: 'GriEgyTot', // the unique id of the dimension
166 - name: 'power', // the name of the dimension
167 - algorithm: netdata.chartAlgorithms.absolute,// the id of the netdata algorithm
168 - multiplier: 1, // the multiplier
169 - divisor: 1000, // the divisor
170 - hidden: false // is hidden (boolean)
171 - }
172 - }
173 - };
174 -
175 - chart = service.chart(id, chart);
176 - webbox.charts[id] = chart;
177 - }
178 -
179 - service.begin(chart);
180 - service.set('GriEgyTot', Math.round(d['GriEgyTot'].value * 1000));
181 - service.end();
182 - }
183 - }
184 - },
185 -
186 - // module.serviceExecute()
187 - // this function is called only from this module
188 - // its purpose is to prepare the request and call
189 - // netdata.serviceExecute()
190 - serviceExecute: function(name, hostname, update_every) {
191 - if(netdata.options.DEBUG === true) netdata.debug(this.name + ': ' + name + ': hostname: ' + hostname + ', update_every: ' + update_every);
192 -
193 - var service = netdata.service({
194 - name: name,
195 - request: netdata.requestFromURL('http://' + hostname + '/rpc'),
196 - update_every: update_every,
197 - module: this
198 - });
199 - service.postData = 'RPC={"proc":"GetPlantOverview","format":"JSON","version":"1.0","id":"1"}';
200 - service.request.method = 'POST';
201 - service.request.headers['Content-Length'] = service.postData.length;
202 -
203 - service.execute(this.processResponse);
204 - },
205 -
206 - configure: function(config) {
207 - var added = 0;
208 -
209 - if(typeof(config.servers) !== 'undefined') {
210 - var len = config.servers.length;
211 - while(len--) {
212 - if(typeof config.servers[len].update_every === 'undefined')
213 - config.servers[len].update_every = this.update_every;
214 -
215 - if(config.servers[len].update_every < 5)
216 - config.servers[len].update_every = 5;
217 -
218 - this.serviceExecute(config.servers[len].name, config.servers[len].hostname, config.servers[len].update_every);
219 - added++;
220 - }
221 - }
222 -
223 - return added;
224 - },
225 -
226 - // module.update()
227 - // this is called repeatidly to collect data, by calling
228 - // netdata.serviceExecute()
229 - update: function(service, callback) {
230 - service.execute(function(serv, data) {
231 - service.module.processResponse(serv, data);
232 - callback();
233 - });
234 - },
33 + name: __filename,
34 + enable_autodetect: true,
35 + update_every: 1,
36 + base_priority: 60000,
37 + charts: {},
38 +
39 + processResponse: function(service, data) {
40 + if(data !== null) {
41 + var r = JSON.parse(data);
42 +
43 + var d = {
44 + 'GriPwr': {
45 + unit: null,
46 + value: null
47 + },
48 + 'GriEgyTdy': {
49 + unit: null,
50 + value: null
51 + },
52 + 'GriEgyTot': {
53 + unit: null,
54 + value: null
55 + }
56 + };
57 +
58 + // parse the webbox response
59 + // and put it in our d object
60 + var found = 0;
61 + var len = r.result.overview.length;
62 + while(len--) {
63 + var e = r.result.overview[len];
64 + if(typeof(d[e.meta]) !== 'undefined') {
65 + found++;
66 + d[e.meta].value = e.value;
67 + d[e.meta].unit = e.unit;
68 + }
69 + }
70 +
71 + // add the service
72 + if(found > 0 && service.added !== true)
73 + service.commit();
74 +
75 + // Grid Current Power Chart
76 + if(d['GriPwr'].value !== null) {
77 + var id = 'sma_webbox_' + service.name + '.current';
78 + var chart = webbox.charts[id];
79 +
80 + if(typeof chart === 'undefined') {
81 + chart = {
82 + id: id, // the unique id of the chart
83 + name: '', // the unique name of the chart
84 + title: service.name + ' Current Grid Power', // the title of the chart
85 + units: d['GriPwr'].unit, // the units of the chart dimensions
86 + family: 'now', // the family of the chart
87 + context: 'sma_webbox.grid.power', // the context of the chart
88 + type: netdata.chartTypes.area, // the type of the chart
89 + priority: webbox.base_priority + 1, // the priority relative to others in the same family
90 + update_every: service.update_every, // the expected update frequency of the chart
91 + dimensions: {
92 + 'GriPwr': {
93 + id: 'GriPwr', // the unique id of the dimension
94 + name: 'power', // the name of the dimension
95 + algorithm: netdata.chartAlgorithms.absolute,// the id of the netdata algorithm
96 + multiplier: 1, // the multiplier
97 + divisor: 1, // the divisor
98 + hidden: false // is hidden (boolean)
99 + }
100 + }
101 + };
102 +
103 + chart = service.chart(id, chart);
104 + webbox.charts[id] = chart;
105 + }
106 +
107 + service.begin(chart);
108 + service.set('GriPwr', Math.round(d['GriPwr'].value));
109 + service.end();
110 + }
111 +
112 + if(d['GriEgyTdy'].value !== null) {
113 + var id = 'sma_webbox_' + service.name + '.today';
114 + var chart = webbox.charts[id];
115 +
116 + if(typeof chart === 'undefined') {
117 + chart = {
118 + id: id, // the unique id of the chart
119 + name: '', // the unique name of the chart
120 + title: service.name + ' Today Grid Power', // the title of the chart
121 + units: d['GriEgyTdy'].unit, // the units of the chart dimensions
122 + family: 'today', // the family of the chart
123 + context: 'sma_webbox.grid.power.today', // the context of the chart
124 + type: netdata.chartTypes.area, // the type of the chart
125 + priority: webbox.base_priority + 2, // the priority relative to others in the same family
126 + update_every: service.update_every, // the expected update frequency of the chart
127 + dimensions: {
128 + 'GriEgyTdy': {
129 + id: 'GriEgyTdy', // the unique id of the dimension
130 + name: 'power', // the name of the dimension
131 + algorithm: netdata.chartAlgorithms.absolute,// the id of the netdata algorithm
132 + multiplier: 1, // the multiplier
133 + divisor: 1000, // the divisor
134 + hidden: false // is hidden (boolean)
135 + }
136 + }
137 + };
138 +
139 + chart = service.chart(id, chart);
140 + webbox.charts[id] = chart;
141 + }
142 +
143 + service.begin(chart);
144 + service.set('GriEgyTdy', Math.round(d['GriEgyTdy'].value * 1000));
145 + service.end();
146 + }
147 +
148 + if(d['GriEgyTot'].value !== null) {
149 + var id = 'sma_webbox_' + service.name + '.total';
150 + var chart = webbox.charts[id];
151 +
152 + if(typeof chart === 'undefined') {
153 + chart = {
154 + id: id, // the unique id of the chart
155 + name: '', // the unique name of the chart
156 + title: service.name + ' Total Grid Power', // the title of the chart
157 + units: d['GriEgyTot'].unit, // the units of the chart dimensions
158 + family: 'total', // the family of the chart
159 + context: 'sma_webbox.grid.power.total', // the context of the chart
160 + type: netdata.chartTypes.area, // the type of the chart
161 + priority: webbox.base_priority + 3, // the priority relative to others in the same family
162 + update_every: service.update_every, // the expected update frequency of the chart
163 + dimensions: {
164 + 'GriEgyTot': {
165 + id: 'GriEgyTot', // the unique id of the dimension
166 + name: 'power', // the name of the dimension
167 + algorithm: netdata.chartAlgorithms.absolute,// the id of the netdata algorithm
168 + multiplier: 1, // the multiplier
169 + divisor: 1000, // the divisor
170 + hidden: false // is hidden (boolean)
171 + }
172 + }
173 + };
174 +
175 + chart = service.chart(id, chart);
176 + webbox.charts[id] = chart;
177 + }
178 +
179 + service.begin(chart);
180 + service.set('GriEgyTot', Math.round(d['GriEgyTot'].value * 1000));
181 + service.end();
182 + }
183 + }
184 + },
185 +
186 + // module.serviceExecute()
187 + // this function is called only from this module
188 + // its purpose is to prepare the request and call
189 + // netdata.serviceExecute()
190 + serviceExecute: function(name, hostname, update_every) {
191 + if(netdata.options.DEBUG === true) netdata.debug(this.name + ': ' + name + ': hostname: ' + hostname + ', update_every: ' + update_every);
192 +
193 + var service = netdata.service({
194 + name: name,
195 + request: netdata.requestFromURL('http://' + hostname + '/rpc'),
196 + update_every: update_every,
197 + module: this
198 + });
199 + service.postData = 'RPC={"proc":"GetPlantOverview","format":"JSON","version":"1.0","id":"1"}';
200 + service.request.method = 'POST';
201 + service.request.headers['Content-Length'] = service.postData.length;
202 +
203 + service.execute(this.processResponse);
204 + },
205 +
206 + configure: function(config) {
207 + var added = 0;
208 +
209 + if(typeof(config.servers) !== 'undefined') {
210 + var len = config.servers.length;
211 + while(len--) {
212 + if(typeof config.servers[len].update_every === 'undefined')
213 + config.servers[len].update_every = this.update_every;
214 +
215 + if(config.servers[len].update_every < 5)
216 + config.servers[len].update_every = 5;
217 +
218 + this.serviceExecute(config.servers[len].name, config.servers[len].hostname, config.servers[len].update_every);
219 + added++;
220 + }
221 + }
222 +
223 + return added;
224 + },
225 +
226 + // module.update()
227 + // this is called repeatidly to collect data, by calling
228 + // netdata.serviceExecute()
229 + update: function(service, callback) {
230 + service.execute(function(serv, data) {
231 + service.module.processResponse(serv, data);
232 + callback();
233 + });
234 + },
235 };
236
237 module.exports = webbox;
node.d/snmp.node.js
+405 -405
@@ -5,60 +5,60 @@
5 // example configuration in /etc/netdata/snmp.conf
6 /*
7 {
8 - "enable_autodetect": false,
9 - "update_every": 5,
10 - "max_request_size": 50,
11 - "servers": [
12 - {
13 - "hostname": "10.11.12.8",
14 - "community": "public",
15 - "update_every": 10,
16 - "max_request_size": 50,
17 - "options": { "timeout": 10000 },
18 - "charts": {
19 - "snmp_switch.bandwidth_port1": {
20 - "title": "Switch Bandwidth for port 1",
21 - "units": "kilobits/s",
22 - "type": "area",
23 - "priority": 1,
24 - "dimensions": {
25 - "in": {
26 - "oid": ".1.3.6.1.2.1.2.2.1.10.1",
27 - "algorithm": "incremental",
28 - "multiplier": 8,
29 - "divisor": 1024
30 - },
31 - "out": {
32 - "oid": ".1.3.6.1.2.1.2.2.1.16.1",
33 - "algorithm": "incremental",
34 - "multiplier": -8,
35 - "divisor": 1024
36 - }
37 - }
38 - },
39 - "snmp_switch.bandwidth_port2": {
40 - "title": "Switch Bandwidth for port 2",
41 - "units": "kilobits/s",
42 - "type": "area",
43 - "priority": 1,
44 - "dimensions": {
45 - "in": {
46 - "oid": ".1.3.6.1.2.1.2.2.1.10.2",
47 - "algorithm": "incremental",
48 - "multiplier": 8,
49 - "divisor": 1024
50 - },
51 - "out": {
52 - "oid": ".1.3.6.1.2.1.2.2.1.16.2",
53 - "algorithm": "incremental",
54 - "multiplier": -8,
55 - "divisor": 1024
56 - }
57 - }
58 - }
59 - }
60 - }
61 - ]
8 + "enable_autodetect": false,
9 + "update_every": 5,
10 + "max_request_size": 50,
11 + "servers": [
12 + {
13 + "hostname": "10.11.12.8",
14 + "community": "public",
15 + "update_every": 10,
16 + "max_request_size": 50,
17 + "options": { "timeout": 10000 },
18 + "charts": {
19 + "snmp_switch.bandwidth_port1": {
20 + "title": "Switch Bandwidth for port 1",
21 + "units": "kilobits/s",
22 + "type": "area",
23 + "priority": 1,
24 + "dimensions": {
25 + "in": {
26 + "oid": ".1.3.6.1.2.1.2.2.1.10.1",
27 + "algorithm": "incremental",
28 + "multiplier": 8,
29 + "divisor": 1024
30 + },
31 + "out": {
32 + "oid": ".1.3.6.1.2.1.2.2.1.16.1",
33 + "algorithm": "incremental",
34 + "multiplier": -8,
35 + "divisor": 1024
36 + }
37 + }
38 + },
39 + "snmp_switch.bandwidth_port2": {
40 + "title": "Switch Bandwidth for port 2",
41 + "units": "kilobits/s",
42 + "type": "area",
43 + "priority": 1,
44 + "dimensions": {
45 + "in": {
46 + "oid": ".1.3.6.1.2.1.2.2.1.10.2",
47 + "algorithm": "incremental",
48 + "multiplier": 8,
49 + "divisor": 1024
50 + },
51 + "out": {
52 + "oid": ".1.3.6.1.2.1.2.2.1.16.2",
53 + "algorithm": "incremental",
54 + "multiplier": -8,
55 + "divisor": 1024
56 + }
57 + }
58 + }
59 + }
60 + }
61 + ]
62 }
63 */
64
@@ -67,41 +67,41 @@
67 // so that 24 charts will be created.
68 /*
69 {
70 - "enable_autodetect": false,
71 - "update_every": 10,
72 - "max_request_size": 50,
73 - "servers": [
74 - {
75 - "hostname": "10.11.12.8",
76 - "community": "public",
77 - "update_every": 10,
78 - "max_request_size": 50,
79 - "options": { "timeout": 20000 },
80 - "charts": {
81 - "snmp_switch.bandwidth_port": {
82 - "title": "Switch Bandwidth for port ",
83 - "units": "kilobits/s",
84 - "type": "area",
85 - "priority": 1,
86 - "multiply_range": [ 1, 24 ],
87 - "dimensions": {
88 - "in": {
89 - "oid": ".1.3.6.1.2.1.2.2.1.10.",
90 - "algorithm": "incremental",
91 - "multiplier": 8,
92 - "divisor": 1024
93 - },
94 - "out": {
95 - "oid": ".1.3.6.1.2.1.2.2.1.16.",
96 - "algorithm": "incremental",
97 - "multiplier": -8,
98 - "divisor": 1024
99 - }
100 - }
101 - }
102 - }
103 - }
104 - ]
70 + "enable_autodetect": false,
71 + "update_every": 10,
72 + "max_request_size": 50,
73 + "servers": [
74 + {
75 + "hostname": "10.11.12.8",
76 + "community": "public",
77 + "update_every": 10,
78 + "max_request_size": 50,
79 + "options": { "timeout": 20000 },
80 + "charts": {
81 + "snmp_switch.bandwidth_port": {
82 + "title": "Switch Bandwidth for port ",
83 + "units": "kilobits/s",
84 + "type": "area",
85 + "priority": 1,
86 + "multiply_range": [ 1, 24 ],
87 + "dimensions": {
88 + "in": {
89 + "oid": ".1.3.6.1.2.1.2.2.1.10.",
90 + "algorithm": "incremental",
91 + "multiplier": 8,
92 + "divisor": 1024
93 + },
94 + "out": {
95 + "oid": ".1.3.6.1.2.1.2.2.1.16.",
96 + "algorithm": "incremental",
97 + "multiplier": -8,
98 + "divisor": 1024
99 + }
100 + }
101 + }
102 + }
103 + }
104 + ]
105 }
106 */
107
@@ -112,325 +112,325 @@ var netdata = require('netdata');
112 if(netdata.options.DEBUG === true) netdata.debug('loaded ' + __filename + ' plugin');
113
114 netdata.processors.snmp = {
115 - name: 'snmp',
116 -
117 - fixoid: function(oid) {
118 - if(typeof oid !== 'string')
119 - return oid;
120 -
121 - if(oid.charAt(0) === '.')
122 - return oid.substring(1, oid.length);
123 -
124 - return oid;
125 - },
126 -
127 - prepare: function(service) {
128 - if(typeof service.snmp_oids === 'undefined' || service.snmp_oids === null || service.snmp_oids.length === 0) {
129 - // this is the first time we see this service
130 -
131 - if(netdata.options.DEBUG === true)
132 - netdata.debug(service.module.name + ': ' + service.name + ': preparing ' + this.name + ' OIDs');
133 -
134 - // build an index of all OIDs
135 - service.snmp_oids_index = {};
136 - for(var c in service.request.charts) {
137 - // for each chart
138 -
139 - if(netdata.options.DEBUG === true)
140 - netdata.debug(service.module.name + ': ' + service.name + ': indexing ' + this.name + ' chart: ' + c);
141 -
142 - if(typeof service.request.charts[c].titleoid !== 'undefined') {
143 - service.snmp_oids_index[this.fixoid(service.request.charts[c].titleoid)] = {
144 - type: 'title',
145 - link: service.request.charts[c]
146 - };
147 - }
148 -
149 - for(var d in service.request.charts[c].dimensions) {
150 - // for each dimension in the chart
151 -
152 - var oid = this.fixoid(service.request.charts[c].dimensions[d].oid);
153 - var oidname = this.fixoid(service.request.charts[c].dimensions[d].oidname);
154 -
155 - if(netdata.options.DEBUG === true)
156 - netdata.debug(service.module.name + ': ' + service.name + ': indexing ' + this.name + ' chart: ' + c + ', dimension: ' + d + ', OID: ' + oid + ", OID name: " + oidname);
157 -
158 - // link it to the point we need to set the value to
159 - service.snmp_oids_index[oid] = {
160 - type: 'value',
161 - link: service.request.charts[c].dimensions[d]
162 - };
163 -
164 - if(typeof oidname !== 'undefined')
165 - service.snmp_oids_index[oidname] = {
166 - type: 'name',
167 - link: service.request.charts[c].dimensions[d]
168 - };
169 -
170 - // and set the value to null
171 - service.request.charts[c].dimensions[d].value = null;
172 - }
173 - }
174 -
175 - if(netdata.options.DEBUG === true)
176 - netdata.debug(service.module.name + ': ' + service.name + ': indexed ' + this.name + ' OIDs: ' + netdata.stringify(service.snmp_oids_index));
177 -
178 - // now create the array of OIDs needed by net-snmp
179 - service.snmp_oids = new Array();
180 - for(var o in service.snmp_oids_index)
181 - service.snmp_oids.push(o);
182 -
183 - if(netdata.options.DEBUG === true)
184 - netdata.debug(service.module.name + ': ' + service.name + ': final list of ' + this.name + ' OIDs: ' + netdata.stringify(service.snmp_oids));
185 -
186 - service.snmp_oids_cleaned = 0;
187 - }
188 - else if(service.snmp_oids_cleaned === 0) {
189 - service.snmp_oids_cleaned = 1;
190 -
191 - // the second time, keep only values
192 - service.snmp_oids = new Array();
193 - for(var o in service.snmp_oids_index)
194 - if(service.snmp_oids_index[o].type === 'value')
195 - service.snmp_oids.push(o);
196 - }
197 - },
198 -
199 - getdata: function(service, index, ok, failed, callback) {
200 - var that = this;
201 -
202 - if(index >= service.snmp_oids.length) {
203 - callback((ok > 0)?{ ok: ok, failed: failed }:null);
204 - return;
205 - }
206 -
207 - var slice;
208 - if(service.snmp_oids.length <= service.request.max_request_size) {
209 - slice = service.snmp_oids;
210 - index = service.snmp_oids.length;
211 - }
212 - else if(service.snmp_oids.length - index <= service.request.max_request_size) {
213 - slice = service.snmp_oids.slice(index, service.snmp_oids.length);
214 - index = service.snmp_oids.length;
215 - }
216 - else {
217 - slice = service.snmp_oids.slice(index, index + service.request.max_request_size);
218 - index += service.request.max_request_size;
219 - }
220 -
221 - if(netdata.options.DEBUG === true)
222 - netdata.debug(service.module.name + ': ' + service.name + ': making ' + slice.length + ' entries request, max is: ' + service.request.max_request_size);
223 -
224 - service.snmp_session.get(slice, function(error, varbinds) {
225 - if(error) {
226 - service.error('Received error = ' + netdata.stringify(error) + ' varbinds = ' + netdata.stringify(varbinds));
227 -
228 - // make all values null
229 - var len = slice.length;
230 - while(len--)
231 - service.snmp_oids_index[slice[len]].value = null;
232 - }
233 - else {
234 - if(netdata.options.DEBUG === true)
235 - netdata.debug(service.module.name + ': ' + service.name + ': got valid ' + service.module.name + ' response: ' + netdata.stringify(varbinds));
236 -
237 - for(var i = 0; i < varbinds.length; i++) {
238 - var value = null;
239 -
240 - if(net_snmp.isVarbindError(varbinds[i])) {
241 - if(netdata.options.DEBUG === true)
242 - netdata.debug(service.module.name + ': ' + service.name + ': failed ' + service.module.name + ' get for OIDs ' + varbinds[i].oid);
243 -
244 - service.error('OID ' + varbinds[i].oid + ' gave error: ' + snmp.varbindError(varbinds[i]));
245 - value = null;
246 - failed++;
247 - }
248 - else {
249 - if(netdata.options.DEBUG === true)
250 - netdata.debug(service.module.name + ': ' + service.name + ': found ' + service.module.name + ' value of OIDs ' + varbinds[i].oid + " = " + varbinds[i].value);
251 -
252 - value = varbinds[i].value;
253 - ok++;
254 - }
255 -
256 - if(value !== null) {
257 - switch(service.snmp_oids_index[varbinds[i].oid].type) {
258 - case 'title': service.snmp_oids_index[varbinds[i].oid].link.title += ' ' + value; break;
259 - case 'name' : service.snmp_oids_index[varbinds[i].oid].link.name = value; break;
260 - case 'value': service.snmp_oids_index[varbinds[i].oid].link.value = value; break;
261 - }
262 - }
263 - }
264 -
265 - if(netdata.options.DEBUG === true)
266 - netdata.debug(service.module.name + ': ' + service.name + ': finished ' + service.module.name + ' with ' + ok + ' successful and ' + failed + ' failed values');
267 - }
268 - that.getdata(service, index, ok, failed, callback);
269 - });
270 - },
271 -
272 - process: function(service, callback) {
273 - this.prepare(service);
274 -
275 - if(service.snmp_oids.length === 0) {
276 - // no OIDs found for this service
277 -
278 - if(netdata.options.DEBUG === true)
279 - service.error('no OIDs to process.');
280 -
281 - callback(null);
282 - return;
283 - }
284 -
285 - if(typeof service.snmp_session === 'undefined' || service.snmp_session === null) {
286 - // no SNMP session has been created for this service
287 - // the SNMP session is just the initialization of NET-SNMP
288 -
289 - if(netdata.options.DEBUG === true)
290 - netdata.debug(service.module.name + ': ' + service.name + ': opening ' + this.name + ' session on ' + service.request.hostname + ' community ' + service.request.community + ' options ' + netdata.stringify(service.request.options));
291 -
292 - // create the SNMP session
293 - service.snmp_session = net_snmp.createSession (service.request.hostname, service.request.community, service.request.options);
294 -
295 - if(netdata.options.DEBUG === true)
296 - netdata.debug(service.module.name + ': ' + service.name + ': got ' + this.name + ' session: ' + netdata.stringify(service.snmp_session));
297 -
298 - // if we later need traps, this is how to do it:
299 - //service.snmp_session.trap(net_snmp.TrapType.LinkDown, function(error) {
300 - // if(error) console.error('trap error: ' + netdata.stringify(error));
301 - //});
302 - }
303 -
304 - // do it, get the SNMP values for the sessions we need
305 - this.getdata(service, 0, 0, 0, callback);
306 - }
115 + name: 'snmp',
116 +
117 + fixoid: function(oid) {
118 + if(typeof oid !== 'string')
119 + return oid;
120 +
121 + if(oid.charAt(0) === '.')
122 + return oid.substring(1, oid.length);
123 +
124 + return oid;
125 + },
126 +
127 + prepare: function(service) {
128 + if(typeof service.snmp_oids === 'undefined' || service.snmp_oids === null || service.snmp_oids.length === 0) {
129 + // this is the first time we see this service
130 +
131 + if(netdata.options.DEBUG === true)
132 + netdata.debug(service.module.name + ': ' + service.name + ': preparing ' + this.name + ' OIDs');
133 +
134 + // build an index of all OIDs
135 + service.snmp_oids_index = {};
136 + for(var c in service.request.charts) {
137 + // for each chart
138 +
139 + if(netdata.options.DEBUG === true)
140 + netdata.debug(service.module.name + ': ' + service.name + ': indexing ' + this.name + ' chart: ' + c);
141 +
142 + if(typeof service.request.charts[c].titleoid !== 'undefined') {
143 + service.snmp_oids_index[this.fixoid(service.request.charts[c].titleoid)] = {
144 + type: 'title',
145 + link: service.request.charts[c]
146 + };
147 + }
148 +
149 + for(var d in service.request.charts[c].dimensions) {
150 + // for each dimension in the chart
151 +
152 + var oid = this.fixoid(service.request.charts[c].dimensions[d].oid);
153 + var oidname = this.fixoid(service.request.charts[c].dimensions[d].oidname);
154 +
155 + if(netdata.options.DEBUG === true)
156 + netdata.debug(service.module.name + ': ' + service.name + ': indexing ' + this.name + ' chart: ' + c + ', dimension: ' + d + ', OID: ' + oid + ", OID name: " + oidname);
157 +
158 + // link it to the point we need to set the value to
159 + service.snmp_oids_index[oid] = {
160 + type: 'value',
161 + link: service.request.charts[c].dimensions[d]
162 + };
163 +
164 + if(typeof oidname !== 'undefined')
165 + service.snmp_oids_index[oidname] = {
166 + type: 'name',
167 + link: service.request.charts[c].dimensions[d]
168 + };
169 +
170 + // and set the value to null
171 + service.request.charts[c].dimensions[d].value = null;
172 + }
173 + }
174 +
175 + if(netdata.options.DEBUG === true)
176 + netdata.debug(service.module.name + ': ' + service.name + ': indexed ' + this.name + ' OIDs: ' + netdata.stringify(service.snmp_oids_index));
177 +
178 + // now create the array of OIDs needed by net-snmp
179 + service.snmp_oids = new Array();
180 + for(var o in service.snmp_oids_index)
181 + service.snmp_oids.push(o);
182 +
183 + if(netdata.options.DEBUG === true)
184 + netdata.debug(service.module.name + ': ' + service.name + ': final list of ' + this.name + ' OIDs: ' + netdata.stringify(service.snmp_oids));
185 +
186 + service.snmp_oids_cleaned = 0;
187 + }
188 + else if(service.snmp_oids_cleaned === 0) {
189 + service.snmp_oids_cleaned = 1;
190 +
191 + // the second time, keep only values
192 + service.snmp_oids = new Array();
193 + for(var o in service.snmp_oids_index)
194 + if(service.snmp_oids_index[o].type === 'value')
195 + service.snmp_oids.push(o);
196 + }
197 + },
198 +
199 + getdata: function(service, index, ok, failed, callback) {
200 + var that = this;
201 +
202 + if(index >= service.snmp_oids.length) {
203 + callback((ok > 0)?{ ok: ok, failed: failed }:null);
204 + return;
205 + }
206 +
207 + var slice;
208 + if(service.snmp_oids.length <= service.request.max_request_size) {
209 + slice = service.snmp_oids;
210 + index = service.snmp_oids.length;
211 + }
212 + else if(service.snmp_oids.length - index <= service.request.max_request_size) {
213 + slice = service.snmp_oids.slice(index, service.snmp_oids.length);
214 + index = service.snmp_oids.length;
215 + }
216 + else {
217 + slice = service.snmp_oids.slice(index, index + service.request.max_request_size);
218 + index += service.request.max_request_size;
219 + }
220 +
221 + if(netdata.options.DEBUG === true)
222 + netdata.debug(service.module.name + ': ' + service.name + ': making ' + slice.length + ' entries request, max is: ' + service.request.max_request_size);
223 +
224 + service.snmp_session.get(slice, function(error, varbinds) {
225 + if(error) {
226 + service.error('Received error = ' + netdata.stringify(error) + ' varbinds = ' + netdata.stringify(varbinds));
227 +
228 + // make all values null
229 + var len = slice.length;
230 + while(len--)
231 + service.snmp_oids_index[slice[len]].value = null;
232 + }
233 + else {
234 + if(netdata.options.DEBUG === true)
235 + netdata.debug(service.module.name + ': ' + service.name + ': got valid ' + service.module.name + ' response: ' + netdata.stringify(varbinds));
236 +
237 + for(var i = 0; i < varbinds.length; i++) {
238 + var value = null;
239 +
240 + if(net_snmp.isVarbindError(varbinds[i])) {
241 + if(netdata.options.DEBUG === true)
242 + netdata.debug(service.module.name + ': ' + service.name + ': failed ' + service.module.name + ' get for OIDs ' + varbinds[i].oid);
243 +
244 + service.error('OID ' + varbinds[i].oid + ' gave error: ' + snmp.varbindError(varbinds[i]));
245 + value = null;
246 + failed++;
247 + }
248 + else {
249 + if(netdata.options.DEBUG === true)
250 + netdata.debug(service.module.name + ': ' + service.name + ': found ' + service.module.name + ' value of OIDs ' + varbinds[i].oid + " = " + varbinds[i].value);
251 +
252 + value = varbinds[i].value;
253 + ok++;
254 + }
255 +
256 + if(value !== null) {
257 + switch(service.snmp_oids_index[varbinds[i].oid].type) {
258 + case 'title': service.snmp_oids_index[varbinds[i].oid].link.title += ' ' + value; break;
259 + case 'name' : service.snmp_oids_index[varbinds[i].oid].link.name = value; break;
260 + case 'value': service.snmp_oids_index[varbinds[i].oid].link.value = value; break;
261 + }
262 + }
263 + }
264 +
265 + if(netdata.options.DEBUG === true)
266 + netdata.debug(service.module.name + ': ' + service.name + ': finished ' + service.module.name + ' with ' + ok + ' successful and ' + failed + ' failed values');
267 + }
268 + that.getdata(service, index, ok, failed, callback);
269 + });
270 + },
271 +
272 + process: function(service, callback) {
273 + this.prepare(service);
274 +
275 + if(service.snmp_oids.length === 0) {
276 + // no OIDs found for this service
277 +
278 + if(netdata.options.DEBUG === true)
279 + service.error('no OIDs to process.');
280 +
281 + callback(null);
282 + return;
283 + }
284 +
285 + if(typeof service.snmp_session === 'undefined' || service.snmp_session === null) {
286 + // no SNMP session has been created for this service
287 + // the SNMP session is just the initialization of NET-SNMP
288 +
289 + if(netdata.options.DEBUG === true)
290 + netdata.debug(service.module.name + ': ' + service.name + ': opening ' + this.name + ' session on ' + service.request.hostname + ' community ' + service.request.community + ' options ' + netdata.stringify(service.request.options));
291 +
292 + // create the SNMP session
293 + service.snmp_session = net_snmp.createSession (service.request.hostname, service.request.community, service.request.options);
294 +
295 + if(netdata.options.DEBUG === true)
296 + netdata.debug(service.module.name + ': ' + service.name + ': got ' + this.name + ' session: ' + netdata.stringify(service.snmp_session));
297 +
298 + // if we later need traps, this is how to do it:
299 + //service.snmp_session.trap(net_snmp.TrapType.LinkDown, function(error) {
300 + // if(error) console.error('trap error: ' + netdata.stringify(error));
301 + //});
302 + }
303 +
304 + // do it, get the SNMP values for the sessions we need
305 + this.getdata(service, 0, 0, 0, callback);
306 + }
307 };
308
309 var snmp = {
310 - name: __filename,
311 - enable_autodetect: true,
312 - update_every: 1,
313 - base_priority: 50000,
314 -
315 - charts: {},
316 -
317 - processResponse: function(service, data) {
318 - if(data !== null) {
319 - if(service.added !== true)
320 - service.commit();
321 -
322 - for(var c in service.request.charts) {
323 - var chart = snmp.charts[c];
324 -
325 - if(typeof chart === 'undefined') {
326 - chart = service.chart(c, service.request.charts[c]);
327 - snmp.charts[c] = chart;
328 - }
329 -
330 - service.begin(chart);
331 -
332 - for( var d in service.request.charts[c].dimensions )
333 - if(service.request.charts[c].dimensions[d].value !== null)
334 - service.set(d, service.request.charts[c].dimensions[d].value);
335 -
336 - service.end();
337 - }
338 - }
339 - },
340 -
341 - // module.serviceExecute()
342 - // this function is called only from this module
343 - // its purpose is to prepare the request and call
344 - // netdata.serviceExecute()
345 - serviceExecute: function(conf) {
346 - if(netdata.options.DEBUG === true)
347 - netdata.debug(this.name + ': snmp hostname: ' + conf.hostname + ', update_every: ' + conf.update_every);
348 -
349 - var service = netdata.service({
350 - name: conf.hostname,
351 - request: conf,
352 - update_every: conf.update_every,
353 - module: this,
354 - processor: netdata.processors.snmp
355 - });
356 -
357 - // multiply the charts, if required
358 - for(var c in service.request.charts) {
359 - if(netdata.options.DEBUG === true)
360 - netdata.debug(this.name + ': snmp hostname: ' + conf.hostname + ', examining chart: ' + c);
361 -
362 - if(typeof service.request.charts[c].update_every === 'undefined')
363 - service.request.charts[c].update_every = service.update_every;
364 -
365 - if(typeof service.request.charts[c].multiply_range !== 'undefined') {
366 - var from = service.request.charts[c].multiply_range[0];
367 - var to = service.request.charts[c].multiply_range[1];
368 - var prio = service.request.charts[c].priority || 1;
369 -
370 - if(prio < snmp.base_priority) prio += snmp.base_priority;
371 -
372 - while(from <= to) {
373 - var id = c + from.toString();
374 - var chart = extend(true, {}, service.request.charts[c]);
375 - chart.title += from.toString();
376 -
377 - if(typeof chart.titleoid !== 'undefined')
378 - chart.titleoid += from.toString();
379 -
380 - chart.priority = prio++;
381 - for(var d in chart.dimensions) {
382 - chart.dimensions[d].oid += from.toString();
383 -
384 - if(typeof chart.dimensions[d].oidname !== 'undefined')
385 - chart.dimensions[d].oidname += from.toString();
386 - }
387 - service.request.charts[id] = chart;
388 - from++;
389 - }
390 -
391 - delete service.request.charts[c];
392 - }
393 - else {
394 - if(service.request.charts[c].priority < snmp.base_priority)
395 - service.request.charts[c].priority += snmp.base_priority;
396 - }
397 - }
398 -
399 - service.execute(this.processResponse);
400 - },
401 -
402 - configure: function(config) {
403 - var added = 0;
404 -
405 - if(typeof config.max_request_size === 'undefined')
406 - config.max_request_size = 50;
407 -
408 - if(typeof(config.servers) !== 'undefined') {
409 - var len = config.servers.length;
410 - while(len--) {
411 - if(typeof config.servers[len].update_every === 'undefined')
412 - config.servers[len].update_every = this.update_every;
413 -
414 - if(typeof config.servers[len].max_request_size === 'undefined')
415 - config.servers[len].max_request_size = config.max_request_size;
416 -
417 - this.serviceExecute(config.servers[len]);
418 - added++;
419 - }
420 - }
421 -
422 - return added;
423 - },
424 -
425 - // module.update()
426 - // this is called repeatidly to collect data, by calling
427 - // service.execute()
428 - update: function(service, callback) {
429 - service.execute(function(serv, data) {
430 - service.module.processResponse(serv, data);
431 - callback();
432 - });
433 - },
310 + name: __filename,
311 + enable_autodetect: true,
312 + update_every: 1,
313 + base_priority: 50000,
314 +
315 + charts: {},
316 +
317 + processResponse: function(service, data) {
318 + if(data !== null) {
319 + if(service.added !== true)
320 + service.commit();
321 +
322 + for(var c in service.request.charts) {
323 + var chart = snmp.charts[c];
324 +
325 + if(typeof chart === 'undefined') {
326 + chart = service.chart(c, service.request.charts[c]);
327 + snmp.charts[c] = chart;
328 + }
329 +
330 + service.begin(chart);
331 +
332 + for( var d in service.request.charts[c].dimensions )
333 + if(service.request.charts[c].dimensions[d].value !== null)
334 + service.set(d, service.request.charts[c].dimensions[d].value);
335 +
336 + service.end();
337 + }
338 + }
339 + },
340 +
341 + // module.serviceExecute()
342 + // this function is called only from this module
343 + // its purpose is to prepare the request and call
344 + // netdata.serviceExecute()
345 + serviceExecute: function(conf) {
346 + if(netdata.options.DEBUG === true)
347 + netdata.debug(this.name + ': snmp hostname: ' + conf.hostname + ', update_every: ' + conf.update_every);
348 +
349 + var service = netdata.service({
350 + name: conf.hostname,
351 + request: conf,
352 + update_every: conf.update_every,
353 + module: this,
354 + processor: netdata.processors.snmp
355 + });
356 +
357 + // multiply the charts, if required
358 + for(var c in service.request.charts) {
359 + if(netdata.options.DEBUG === true)
360 + netdata.debug(this.name + ': snmp hostname: ' + conf.hostname + ', examining chart: ' + c);
361 +
362 + if(typeof service.request.charts[c].update_every === 'undefined')
363 + service.request.charts[c].update_every = service.update_every;
364 +
365 + if(typeof service.request.charts[c].multiply_range !== 'undefined') {
366 + var from = service.request.charts[c].multiply_range[0];
367 + var to = service.request.charts[c].multiply_range[1];
368 + var prio = service.request.charts[c].priority || 1;
369 +
370 + if(prio < snmp.base_priority) prio += snmp.base_priority;
371 +
372 + while(from <= to) {
373 + var id = c + from.toString();
374 + var chart = extend(true, {}, service.request.charts[c]);
375 + chart.title += from.toString();
376 +
377 + if(typeof chart.titleoid !== 'undefined')
378 + chart.titleoid += from.toString();
379 +
380 + chart.priority = prio++;
381 + for(var d in chart.dimensions) {
382 + chart.dimensions[d].oid += from.toString();
383 +
384 + if(typeof chart.dimensions[d].oidname !== 'undefined')
385 + chart.dimensions[d].oidname += from.toString();
386 + }
387 + service.request.charts[id] = chart;
388 + from++;
389 + }
390 +
391 + delete service.request.charts[c];
392 + }
393 + else {
394 + if(service.request.charts[c].priority < snmp.base_priority)
395 + service.request.charts[c].priority += snmp.base_priority;
396 + }
397 + }
398 +
399 + service.execute(this.processResponse);
400 + },
401 +
402 + configure: function(config) {
403 + var added = 0;
404 +
405 + if(typeof config.max_request_size === 'undefined')
406 + config.max_request_size = 50;
407 +
408 + if(typeof(config.servers) !== 'undefined') {
409 + var len = config.servers.length;
410 + while(len--) {
411 + if(typeof config.servers[len].update_every === 'undefined')
412 + config.servers[len].update_every = this.update_every;
413 +
414 + if(typeof config.servers[len].max_request_size === 'undefined')
415 + config.servers[len].max_request_size = config.max_request_size;
416 +
417 + this.serviceExecute(config.servers[len]);
418 + added++;
419 + }
420 + }
421 +
422 + return added;
423 + },
424 +
425 + // module.update()
426 + // this is called repeatidly to collect data, by calling
427 + // service.execute()
428 + update: function(service, callback) {
429 + service.execute(function(serv, data) {
430 + service.module.processResponse(serv, data);
431 + callback();
432 + });
433 + },
434 };
435
436 module.exports = snmp;
plugins.d/cgroup-name.sh
+45 -45
@@ -9,66 +9,66 @@ CGROUP="${1}"
9 NAME=
10
11 if [ -z "${CGROUP}" ]
12 - then
13 - echo >&2 "${0}: called without a cgroup name. Nothing to do."
14 - exit 1
12 + then
13 + echo >&2 "${0}: called without a cgroup name. Nothing to do."
14 + exit 1
15 fi
16
17 if [ -f "${CONFIG}" ]
18 - then
19 - NAME="$(cat "${CONFIG}" | grep "^${CGROUP} " | sed "s/[[:space:]]\+/ /g" | cut -d ' ' -f 2)"
20 - if [ -z "${NAME}" ]
21 - then
22 - echo >&2 "${0}: cannot find cgroup '${CGROUP}' in '${CONFIG}'."
23 - fi
18 + then
19 + NAME="$(cat "${CONFIG}" | grep "^${CGROUP} " | sed "s/[[:space:]]\+/ /g" | cut -d ' ' -f 2)"
20 + if [ -z "${NAME}" ]
21 + then
22 + echo >&2 "${0}: cannot find cgroup '${CGROUP}' in '${CONFIG}'."
23 + fi
24 #else
25 -# echo >&2 "${0}: configuration file '${CONFIG}' is not available."
25 +# echo >&2 "${0}: configuration file '${CONFIG}' is not available."
26 fi
27
28 function get_name_classic {
29 - DOCKERID=$1
30 - echo >&2 "Running command: docker ps --filter=id=\"${DOCKERID}\" --format=\"{{.Names}}\""
31 - NAME="$( docker ps --filter=id="${DOCKERID}" --format="{{.Names}}" )"
29 + DOCKERID=$1
30 + echo >&2 "Running command: docker ps --filter=id=\"${DOCKERID}\" --format=\"{{.Names}}\""
31 + NAME="$( docker ps --filter=id="${DOCKERID}" --format="{{.Names}}" )"
32 }
33
34 function get_name_api {
35 - DOCKERID=$1
36 - if [ ! -S "/var/run/docker.sock" ]
37 - then
38 - echo >&2 "Can't find /var/run/docker.sock"
39 - return
40 - fi
41 - echo >&2 "Running API command: /containers/${DOCKERID}/json"
42 - JSON=$(echo -e "GET /containers/${DOCKERID}/json HTTP/1.0\r\n" | nc -U /var/run/docker.sock | egrep '^{.*')
43 - NAME=$(echo $JSON | jq -r .Name,.Config.Hostname | grep -v null | head -n1 | sed 's|^/||')
35 + DOCKERID=$1
36 + if [ ! -S "/var/run/docker.sock" ]
37 + then
38 + echo >&2 "Can't find /var/run/docker.sock"
39 + return
40 + fi
41 + echo >&2 "Running API command: /containers/${DOCKERID}/json"
42 + JSON=$(echo -e "GET /containers/${DOCKERID}/json HTTP/1.0\r\n" | nc -U /var/run/docker.sock | egrep '^{.*')
43 + NAME=$(echo $JSON | jq -r .Name,.Config.Hostname | grep -v null | head -n1 | sed 's|^/||')
44 }
45
46 if [ -z "${NAME}" ]
47 - then
48 - if [[ "${CGROUP}" =~ ^.*docker[-/\.][a-fA-F0-9]+[-\.]?.*$ ]]
49 - then
50 - DOCKERID="$( echo "${CGROUP}" | sed "s|^.*docker[-/]\([a-fA-F0-9]\+\)[-\.]\?.*$|\1|" )"
47 + then
48 + if [[ "${CGROUP}" =~ ^.*docker[-/\.][a-fA-F0-9]+[-\.]?.*$ ]]
49 + then
50 + DOCKERID="$( echo "${CGROUP}" | sed "s|^.*docker[-/]\([a-fA-F0-9]\+\)[-\.]\?.*$|\1|" )"
51
52 - if [ ! -z "${DOCKERID}" -a \( ${#DOCKERID} -eq 64 -o ${#DOCKERID} -eq 12 \) ]
53 - then
54 - if hash docker 2>/dev/null
55 - then
56 - get_name_classic $DOCKERID
57 - else
58 - get_name_api $DOCKERID
59 - fi
60 - if [ -z "${NAME}" ]
61 - then
62 - echo >&2 "Cannot find the name of docker container '${DOCKERID}'"
63 - NAME="${DOCKERID:0:12}"
64 - else
65 - echo >&2 "Docker container '${DOCKERID}' is named '${NAME}'"
66 - fi
67 - fi
68 - fi
52 + if [ ! -z "${DOCKERID}" -a \( ${#DOCKERID} -eq 64 -o ${#DOCKERID} -eq 12 \) ]
53 + then
54 + if hash docker 2>/dev/null
55 + then
56 + get_name_classic $DOCKERID
57 + else
58 + get_name_api $DOCKERID
59 + fi
60 + if [ -z "${NAME}" ]
61 + then
62 + echo >&2 "Cannot find the name of docker container '${DOCKERID}'"
63 + NAME="${DOCKERID:0:12}"
64 + else
65 + echo >&2 "Docker container '${DOCKERID}' is named '${NAME}'"
66 + fi
67 + fi
68 + fi
69
70 - [ -z "${NAME}" ] && NAME="${CGROUP}"
71 - [ ${#NAME} -gt 50 ] && NAME="${NAME:0:50}"
70 + [ -z "${NAME}" ] && NAME="${CGROUP}"
71 + [ ${#NAME} -gt 50 ] && NAME="${NAME:0:50}"
72 fi
73
74 echo >&2 "${0}: cgroup '${CGROUP}' is called '${NAME}'"
plugins.d/charts.d.dryrun-helper.sh
+23 -23
@@ -14,7 +14,7 @@ tmp1="`mktemp`"
14 tmp2="`mktemp`"
15
16 myset() {
17 - set | grep -v "^_=" | grep -v "^PIPESTATUS=" | grep -v "^BASH_LINENO="
17 + set | grep -v "^_=" | grep -v "^PIPESTATUS=" | grep -v "^BASH_LINENO="
18 }
19
20 # save 2 'set'
@@ -25,9 +25,9 @@ myset >"$tmp2"
25 diff "$tmp1" "$tmp2" >/dev/null 2>&1
26 if [ $? -ne 0 ]
27 then
28 - # they differ, we cannot do the check
29 - echo >&2 "$me: cannot check with diff."
30 - can_diff=0
28 + # they differ, we cannot do the check
29 + echo >&2 "$me: cannot check with diff."
30 + can_diff=0
31 fi
32
33 # do it again, now including the script
@@ -36,21 +36,21 @@ myset >"$tmp1"
36 # include the plugin and its config
37 if [ -f "$conf" ]
38 then
39 - . "$conf"
40 - if [ $? -ne 0 ]
41 - then
42 - echo >&2 "$me: cannot load config file $conf"
43 - rm "$tmp1" "$tmp2"
44 - exit 1
45 - fi
39 + . "$conf"
40 + if [ $? -ne 0 ]
41 + then
42 + echo >&2 "$me: cannot load config file $conf"
43 + rm "$tmp1" "$tmp2"
44 + exit 1
45 + fi
46 fi
47
48 . "$chart"
49 if [ $? -ne 0 ]
50 then
51 - echo >&2 "$me: cannot load chart file $chart"
52 - rm "$tmp1" "$tmp2"
53 - exit 1
51 + echo >&2 "$me: cannot load chart file $chart"
52 + rm "$tmp1" "$tmp2"
53 + exit 1
54 fi
55
56 # remove all variables starting with the plugin name
@@ -58,15 +58,15 @@ myset | grep -v "^$name" >"$tmp2"
58
59 if [ $can_diff -eq 1 ]
60 then
61 - # check if they are different
62 - # make sure they don't differ
63 - diff "$tmp1" "$tmp2" >&2
64 - if [ $? -ne 0 ]
65 - then
66 - # they differ
67 - rm "$tmp1" "$tmp2"
68 - exit 1
69 - fi
61 + # check if they are different
62 + # make sure they don't differ
63 + diff "$tmp1" "$tmp2" >&2
64 + if [ $? -ne 0 ]
65 + then
66 + # they differ
67 + rm "$tmp1" "$tmp2"
68 + exit 1
69 + fi
70 fi
71
72 rm "$tmp1" "$tmp2"
plugins.d/charts.d.plugin
+414 -414
@@ -14,24 +14,24 @@ echo >&2 "$PROGRAM_NAME: started from '$PROGRAM_FILE' with options: $*"
14
15 if [ $(( ${BASH_VERSINFO[0]} )) -lt 4 ]
16 then
17 - echo >&2
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."
22 - echo >&2
23 - exit 1
17 + echo >&2
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."
22 + echo >&2
23 + exit 1
24 fi
25
26 # check a few commands
27 require_cmd() {
28 - which "$1" >/dev/null
29 - if [ $? -ne 0 ]
30 - then
31 - echo >&2 "$PROGRAM_NAME: ERROR: Command '$1' is not found in the system path."
32 - return 1
33 - fi
34 - return 0
28 + which "$1" >/dev/null
29 + if [ $? -ne 0 ]
30 + then
31 + echo >&2 "$PROGRAM_NAME: ERROR: Command '$1' is not found in the system path."
32 + return 1
33 + fi
34 + return 0
35 }
36
37 require_cmd date || exit 1
@@ -61,7 +61,7 @@ chartsd="$pluginsd/../charts.d"
61 myconfig="$confd/$PROGRAM_NAME.conf"
62
63 minimum_update_frequency="${NETDATA_UPDATE_EVERY-1}"
64 -update_every=${minimum_update_frequency} # this will be overwritten by the command line
64 +update_every=${minimum_update_frequency} # this will be overwritten by the command line
65
66 # work around for non BASH shells
67 charts_create="_create"
@@ -106,50 +106,50 @@ check=0
106 chart_only=
107 while [ ! -z "$1" ]
108 do
109 - if [ "$1" = "check" ]
110 - then
111 - check=1
112 - shift
113 - continue
114 - fi
115 -
116 - if [ "$1" = "debug" -o "$1" = "all" ]
117 - then
118 - debug=1
119 - shift
120 - continue
121 - fi
122 -
123 - if [ -f "$chartsd/$1.chart.sh" ]
124 - then
125 - debug=1
126 - chart_only="$( echo $1.chart.sh | sed "s/\.chart\.sh$//g" )"
127 - shift
128 - continue
129 - fi
130 -
131 - if [ -f "$chartsd/$1" ]
132 - then
133 - debug=1
134 - chart_only="$( echo $1 | sed "s/\.chart\.sh$//g" )"
135 - shift
136 - continue
137 - fi
138 -
139 - # number check
140 - n="$1"
141 - x=$(( n ))
142 - if [ "$x" = "$n" ]
143 - then
144 - shift
145 - update_every=$x
146 - [ $update_every -lt $minimum_update_frequency ] && update_every=$minimum_update_frequency
147 - continue
148 - fi
149 -
150 - echo >&2 "Cannot understand parameter $1. Aborting."
151 - echo "DISABLE"
152 - exit 1
109 + if [ "$1" = "check" ]
110 + then
111 + check=1
112 + shift
113 + continue
114 + fi
115 +
116 + if [ "$1" = "debug" -o "$1" = "all" ]
117 + then
118 + debug=1
119 + shift
120 + continue
121 + fi
122 +
123 + if [ -f "$chartsd/$1.chart.sh" ]
124 + then
125 + debug=1
126 + chart_only="$( echo $1.chart.sh | sed "s/\.chart\.sh$//g" )"
127 + shift
128 + continue
129 + fi
130 +
131 + if [ -f "$chartsd/$1" ]
132 + then
133 + debug=1
134 + chart_only="$( echo $1 | sed "s/\.chart\.sh$//g" )"
135 + shift
136 + continue
137 + fi
138 +
139 + # number check
140 + n="$1"
141 + x=$(( n ))
142 + if [ "$x" = "$n" ]
143 + then
144 + shift
145 + update_every=$x
146 + [ $update_every -lt $minimum_update_frequency ] && update_every=$minimum_update_frequency
147 + continue
148 + fi
149 +
150 + echo >&2 "Cannot understand parameter $1. Aborting."
151 + echo "DISABLE"
152 + exit 1
153 done
154
155
@@ -157,26 +157,26 @@ done
157 # load my configuration
158
159 if [ -f "$myconfig" ]
160 - then
161 - . "$myconfig"
162 - if [ $? -ne 0 ]
163 - then
164 - echo >&2 "$PROGRAM_NAME: cannot load $myconfig"
165 - echo "DISABLE"
166 - exit 1
167 - fi
168 - time_divisor=$((time_divisor))
169 - [ $time_divisor -lt 10 ] && time_divisor=10
170 - [ $time_divisor -gt 100 ] && time_divisor=100
160 + then
161 + . "$myconfig"
162 + if [ $? -ne 0 ]
163 + then
164 + echo >&2 "$PROGRAM_NAME: cannot load $myconfig"
165 + echo "DISABLE"
166 + exit 1
167 + fi
168 + time_divisor=$((time_divisor))
169 + [ $time_divisor -lt 10 ] && time_divisor=10
170 + [ $time_divisor -gt 100 ] && time_divisor=100
171 else
172 - echo >&2 "$PROGRAM_NAME: configuration file '$myconfig' not found. Using defaults."
172 + echo >&2 "$PROGRAM_NAME: configuration file '$myconfig' not found. Using defaults."
173 fi
174
175 if [ "$pause_method" = "suspend" ]
176 then
177 - # enable bash job control
178 - # this is required for suspend to work
179 - set -m
177 + # enable bash job control
178 + # this is required for suspend to work
179 + set -m
180 fi
181
182 # we check for the timeout command, after we load our
@@ -185,22 +185,22 @@ fi
185 # can emulate the timeout command we need:
186 # > timeout SECONDS command ...
187 if [ $check_for_timeout -eq 1 ]
188 - then
189 - require_cmd timeout || exit 1
188 + then
189 + require_cmd timeout || exit 1
190 fi
191
192 # -----------------------------------------------------------------------------
193 # internal checks
194
195 # netdata passes the requested update frequency as the first argument
196 -update_every=$(( update_every + 1 - 1)) # makes sure it is a number
196 +update_every=$(( update_every + 1 - 1)) # makes sure it is a number
197 test $update_every -eq 0 && update_every=1 # if it is zero, make it 1
198
199 # check the charts.d directory
200 if [ ! -d "$chartsd" ]
201 - then
202 - echo >&2 "$PROGRAM_NAME: cannot find charts directory '$chartsd'"
203 - echo "DISABLE"
201 + then
202 + echo >&2 "$PROGRAM_NAME: cannot find charts directory '$chartsd'"
203 + echo "DISABLE"
204 fi
205
206
@@ -210,13 +210,13 @@ fi
210 # default sleep function
211 LOOPSLEEPMS_HIGHRES=0
212 loopsleepms() {
213 - [ "$1" = "tellwork" ] && shift
214 - sleep $1
213 + [ "$1" = "tellwork" ] && shift
214 + sleep $1
215 }
216
217 now_ms=
218 current_time_ms() {
219 - now_ms="$(date +'%s')000"
219 + now_ms="$(date +'%s')000"
220 }
221
222 # if found and included, this file overwrites loopsleepms()
@@ -229,10 +229,10 @@ current_time_ms() {
229 # library functions
230
231 fixid() {
232 - echo "$*" |\
233 - tr -c "[A-Z][a-z][0-9]" "_" |\
234 - sed -e "s|^_\+||g" -e "s|_\+$||g" -e "s|_\+|_|g" |\
235 - tr "[A-Z]" "[a-z]"
232 + echo "$*" |\
233 + tr -c "[A-Z][a-z][0-9]" "_" |\
234 + sed -e "s|^_\+||g" -e "s|_\+$||g" -e "s|_\+|_|g" |\
235 + tr "[A-Z]" "[a-z]"
236 }
237
238 # convert any floating point number
@@ -241,57 +241,57 @@ fixid() {
241 # so that no fork is necessary
242 # the multiplier must be a power of 10
243 float2int() {
244 - local f m="$2" a b l v=($1)
245 - f=${v[0]}
246 -
247 - # echo >&2 "value='${1}' f='${f}', m='${m}'"
248 -
249 - # the length of the multiplier - 1
250 - l=$(( ${#m} - 1 ))
251 -
252 - # check if the number is in scientific notation
253 - if [[ ${f} =~ ^[[:space:]]*(-)?[0-9.]+(e|E)(\+|-)[0-9]+ ]]
254 - then
255 - # convert it to decimal
256 - # unfortunately, this fork cannot be avoided
257 - # if you know of a way to avoid it, please let me know
258 - f=$(printf "%0.${l}f" ${f})
259 - fi
260 -
261 - # split the floating point number
262 - # in integer (a) and decimal (b)
263 - a=${f/.*/}
264 - b=${f/*./}
265 -
266 - # if the integer part is missing
267 - # set it to zero
268 - [ -z "${a}" ] && a="0"
269 -
270 - # strip leading zeros from the integer part
271 - # base 10 convertion
272 - a=$((10#$a))
273 -
274 - # check the length of the decimal part
275 - # against the length of the multiplier
276 - if [ ${#b} -gt ${l} ]
277 - then
278 - # too many digits - take the most significant
279 - b=${b:0:${l}}
280 -
281 - elif [ ${#b} -lt ${l} ]
282 - then
283 - # too few digits - pad with zero on the right
284 - local z="00000000000000000000000" r=$((l - ${#b}))
285 - b="${b}${z:0:${r}}"
286 - fi
287 -
288 - # strip leading zeros from the decimal part
289 - # base 10 convertion
290 - b=$((10#$b))
291 -
292 - # store the result
293 - FLOAT2INT_RESULT=$(( (a * m) + b ))
294 - #echo >&2 "FLOAT2INT_RESULT='${FLOAT2INT_RESULT}'"
244 + local f m="$2" a b l v=($1)
245 + f=${v[0]}
246 +
247 + # echo >&2 "value='${1}' f='${f}', m='${m}'"
248 +
249 + # the length of the multiplier - 1
250 + l=$(( ${#m} - 1 ))
251 +
252 + # check if the number is in scientific notation
253 + if [[ ${f} =~ ^[[:space:]]*(-)?[0-9.]+(e|E)(\+|-)[0-9]+ ]]
254 + then
255 + # convert it to decimal
256 + # unfortunately, this fork cannot be avoided
257 + # if you know of a way to avoid it, please let me know
258 + f=$(printf "%0.${l}f" ${f})
259 + fi
260 +
261 + # split the floating point number
262 + # in integer (a) and decimal (b)
263 + a=${f/.*/}
264 + b=${f/*./}
265 +
266 + # if the integer part is missing
267 + # set it to zero
268 + [ -z "${a}" ] && a="0"
269 +
270 + # strip leading zeros from the integer part
271 + # base 10 convertion
272 + a=$((10#$a))
273 +
274 + # check the length of the decimal part
275 + # against the length of the multiplier
276 + if [ ${#b} -gt ${l} ]
277 + then
278 + # too many digits - take the most significant
279 + b=${b:0:${l}}
280 +
281 + elif [ ${#b} -lt ${l} ]
282 + then
283 + # too few digits - pad with zero on the right
284 + local z="00000000000000000000000" r=$((l - ${#b}))
285 + b="${b}${z:0:${r}}"
286 + fi
287 +
288 + # strip leading zeros from the decimal part
289 + # base 10 convertion
290 + b=$((10#$b))
291 +
292 + # store the result
293 + FLOAT2INT_RESULT=$(( (a * m) + b ))
294 + #echo >&2 "FLOAT2INT_RESULT='${FLOAT2INT_RESULT}'"
295 }
296
297
@@ -299,105 +299,105 @@ float2int() {
299 # charts check functions
300
301 all_charts() {
302 - cd "$chartsd"
303 - [ $? -ne 0 ] && echo >&2 "$PROGRAM_NAME: Cannot cd to $chartsd" && return 1
302 + cd "$chartsd"
303 + [ $? -ne 0 ] && echo >&2 "$PROGRAM_NAME: Cannot cd to $chartsd" && return 1
304
305 - ls *.chart.sh | sed "s/\.chart\.sh$//g"
305 + ls *.chart.sh | sed "s/\.chart\.sh$//g"
306 }
307
308 declare -A charts_enable_keyword=(
309 - ['apache']="force"
310 - ['cpu_apps']="force"
311 - ['cpufreq']="force"
312 - ['example']="force"
313 - ['exim']="force"
314 - ['hddtemp']="force"
315 - ['load_average']="force"
316 - ['mem_apps']="force"
317 - ['mysql']="force"
318 - ['nginx']="force"
319 - ['phpfpm']="force"
320 - ['postfix']="force"
321 - ['sensors']="force"
322 - ['squid']="force"
323 - ['tomcat']="force"
324 - )
309 + ['apache']="force"
310 + ['cpu_apps']="force"
311 + ['cpufreq']="force"
312 + ['example']="force"
313 + ['exim']="force"
314 + ['hddtemp']="force"
315 + ['load_average']="force"
316 + ['mem_apps']="force"
317 + ['mysql']="force"
318 + ['nginx']="force"
319 + ['phpfpm']="force"
320 + ['postfix']="force"
321 + ['sensors']="force"
322 + ['squid']="force"
323 + ['tomcat']="force"
324 + )
325
326 all_enabled_charts() {
327 - local charts= enabled= required=
328 -
329 - # find all enabled charts
330 -
331 - for chart in $( all_charts )
332 - do
333 - eval "enabled=\$$chart"
334 - if [ -z "${enabled}" ]
335 - then
336 - enabled="${enable_all_charts}"
337 - fi
338 -
339 - required="${charts_enable_keyword[${chart}]}"
340 - [ -z "${required}" ] && required="yes"
341 -
342 - if [ ! "${enabled}" = "${required}" ]
343 - then
344 - echo >&2 "$PROGRAM_NAME: '$chart' is NOT enabled. Add a line with $chart=$required in $myconfig to enable it (or remove the line that disables it)."
345 - else
346 - [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: '$chart' is enabled."
347 - local charts="$charts $chart"
348 - fi
349 - done
350 -
351 - local charts2=
352 - for chart in $charts
353 - do
354 - # check the enabled charts
355 - local check="$( cat "$chartsd/$chart.chart.sh" | sed "s/^ \+//g" | grep "^$chart$charts_check()" )"
356 - if [ -z "$check" ]
357 - then
358 - echo >&2 "$PROGRAM_NAME: chart '$chart' does not seem to have a $chart$charts_check() function. Disabling it."
359 - continue
360 - fi
361 -
362 - local create="$( cat "$chartsd/$chart.chart.sh" | sed "s/^ \+//g" | grep "^$chart$charts_create()" )"
363 - if [ -z "$create" ]
364 - then
365 - echo >&2 "$PROGRAM_NAME: chart '$chart' does not seem to have a $chart$charts_create() function. Disabling it."
366 - continue
367 - fi
368 -
369 - local update="$( cat "$chartsd/$chart.chart.sh" | sed "s/^ \+//g" | grep "^$chart$charts_update()" )"
370 - if [ -z "$update" ]
371 - then
372 - echo >&2 "$PROGRAM_NAME: chart '$chart' does not seem to have a $chart$charts_update() function. Disabling it."
373 - continue
374 - fi
375 -
376 - # check its config
377 - #if [ -f "$confd/$chart.conf" ]
378 - #then
379 - # if [ ! -z "$( cat "$confd/$chart.conf" | sed "s/^ \+//g" | grep -v "^$" | grep -v "^#" | grep -v "^$chart$charts_undescore" )" ]
380 - # then
381 - # echo >&2 "$PROGRAM_NAME: chart's $chart config $confd/$chart.conf should only have lines starting with $chart$charts_undescore . Disabling it."
382 - # continue
383 - # fi
384 - #fi
385 -
386 - #if [ $dryrunner -eq 1 ]
387 - # then
388 - # "$pluginsd/charts.d.dryrun-helper.sh" "$chart" "$chartsd/$chart.chart.sh" "$confd/$chart.conf" >/dev/null
389 - # if [ $? -ne 0 ]
390 - # then
391 - # 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."
392 - # continue
393 - # fi
394 - #fi
395 -
396 - local charts2="$charts2 $chart"
397 - done
398 -
399 - echo $charts2
400 - [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: enabled charts: $charts2"
327 + local charts= enabled= required=
328 +
329 + # find all enabled charts
330 +
331 + for chart in $( all_charts )
332 + do
333 + eval "enabled=\$$chart"
334 + if [ -z "${enabled}" ]
335 + then
336 + enabled="${enable_all_charts}"
337 + fi
338 +
339 + required="${charts_enable_keyword[${chart}]}"
340 + [ -z "${required}" ] && required="yes"
341 +
342 + if [ ! "${enabled}" = "${required}" ]
343 + then
344 + echo >&2 "$PROGRAM_NAME: '$chart' is NOT enabled. Add a line with $chart=$required in $myconfig to enable it (or remove the line that disables it)."
345 + else
346 + [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: '$chart' is enabled."
347 + local charts="$charts $chart"
348 + fi
349 + done
350 +
351 + local charts2=
352 + for chart in $charts
353 + do
354 + # check the enabled charts
355 + local check="$( cat "$chartsd/$chart.chart.sh" | sed "s/^ \+//g" | grep "^$chart$charts_check()" )"
356 + if [ -z "$check" ]
357 + then
358 + echo >&2 "$PROGRAM_NAME: chart '$chart' does not seem to have a $chart$charts_check() function. Disabling it."
359 + continue
360 + fi
361 +
362 + local create="$( cat "$chartsd/$chart.chart.sh" | sed "s/^ \+//g" | grep "^$chart$charts_create()" )"
363 + if [ -z "$create" ]
364 + then
365 + echo >&2 "$PROGRAM_NAME: chart '$chart' does not seem to have a $chart$charts_create() function. Disabling it."
366 + continue
367 + fi
368 +
369 + local update="$( cat "$chartsd/$chart.chart.sh" | sed "s/^ \+//g" | grep "^$chart$charts_update()" )"
370 + if [ -z "$update" ]
371 + then
372 + echo >&2 "$PROGRAM_NAME: chart '$chart' does not seem to have a $chart$charts_update() function. Disabling it."
373 + continue
374 + fi
375 +
376 + # check its config
377 + #if [ -f "$confd/$chart.conf" ]
378 + #then
379 + # if [ ! -z "$( cat "$confd/$chart.conf" | sed "s/^ \+//g" | grep -v "^$" | grep -v "^#" | grep -v "^$chart$charts_undescore" )" ]
380 + # then
381 + # echo >&2 "$PROGRAM_NAME: chart's $chart config $confd/$chart.conf should only have lines starting with $chart$charts_undescore . Disabling it."
382 + # continue
383 + # fi
384 + #fi
385 +
386 + #if [ $dryrunner -eq 1 ]
387 + # then
388 + # "$pluginsd/charts.d.dryrun-helper.sh" "$chart" "$chartsd/$chart.chart.sh" "$confd/$chart.conf" >/dev/null
389 + # if [ $? -ne 0 ]
390 + # then
391 + # 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."
392 + # continue
393 + # fi
394 + #fi
395 +
396 + local charts2="$charts2 $chart"
397 + done
398 +
399 + echo $charts2
400 + [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: enabled charts: $charts2"
401 }
402
403
@@ -408,36 +408,36 @@ suffix_update_every="_update_every"
408 active_charts=
409 for chart in $( all_enabled_charts )
410 do
411 - [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: loading chart: '$chartsd/$chart.chart.sh'"
412 - . "$chartsd/$chart.chart.sh"
413 -
414 - if [ -f "$confd/charts.d/$chart.conf" ]
415 - then
416 - [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: loading chart options: '$confd/charts.d/$chart.conf'"
417 - . "$confd/charts.d/$chart.conf"
418 - elif [ -f "$confd/$chart.conf" ]
419 - then
420 - [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: loading chart options: '$confd/$chart.conf'"
421 - . "$confd/$chart.conf"
422 - else
423 - echo >&2 "$PROGRAM_NAME: $chart: configuration file '$confd/charts.d/$chart.conf' not found. Using defaults."
424 - fi
425 -
426 - eval "dt=\$$chart$suffix_update_every"
427 - dt=$(( dt + 1 - 1 )) # make sure it is a number
428 - if [ $dt -lt $update_every ]
429 - then
430 - eval "$chart$suffix_update_every=$update_every"
431 - fi
432 -
433 - $chart$charts_check
434 - if [ $? -eq 0 ]
435 - then
436 - [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: '$chart' activated"
437 - active_charts="$active_charts $chart"
438 - else
439 - echo >&2 "$PROGRAM_NAME: chart '$chart' check() function reports failure."
440 - fi
411 + [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: loading chart: '$chartsd/$chart.chart.sh'"
412 + . "$chartsd/$chart.chart.sh"
413 +
414 + if [ -f "$confd/charts.d/$chart.conf" ]
415 + then
416 + [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: loading chart options: '$confd/charts.d/$chart.conf'"
417 + . "$confd/charts.d/$chart.conf"
418 + elif [ -f "$confd/$chart.conf" ]
419 + then
420 + [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: loading chart options: '$confd/$chart.conf'"
421 + . "$confd/$chart.conf"
422 + else
423 + echo >&2 "$PROGRAM_NAME: $chart: configuration file '$confd/charts.d/$chart.conf' not found. Using defaults."
424 + fi
425 +
426 + eval "dt=\$$chart$suffix_update_every"
427 + dt=$(( dt + 1 - 1 )) # make sure it is a number
428 + if [ $dt -lt $update_every ]
429 + then
430 + eval "$chart$suffix_update_every=$update_every"
431 + fi
432 +
433 + $chart$charts_check
434 + if [ $? -eq 0 ]
435 + then
436 + [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: '$chart' activated"
437 + active_charts="$active_charts $chart"
438 + else
439 + echo >&2 "$PROGRAM_NAME: chart '$chart' check() function reports failure."
440 + fi
441 done
442 [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: activated charts: $active_charts"
443
@@ -452,26 +452,26 @@ test $debug -eq 1 && debug_time=tellwork
452 # if we only need a specific chart, remove all the others
453 if [ ! -z "${chart_only}" ]
454 then
455 - [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: requested to run only for: '${chart_only}'"
456 - check_charts=
457 - for chart in $active_charts
458 - do
459 - if [ "$chart" = "$chart_only" ]
460 - then
461 - check_charts="$chart"
462 - break
463 - fi
464 - done
465 - active_charts="$check_charts"
455 + [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: requested to run only for: '${chart_only}'"
456 + check_charts=
457 + for chart in $active_charts
458 + do
459 + if [ "$chart" = "$chart_only" ]
460 + then
461 + check_charts="$chart"
462 + break
463 + fi
464 + done
465 + active_charts="$check_charts"
466 fi
467 [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: activated charts: $active_charts"
468
469 # stop if we just need a pre-check
470 if [ $check -eq 1 ]
471 then
472 - echo >&2 "CHECK RESULT"
473 - echo >&2 "Will run the charts: $active_charts"
474 - exit 0
472 + echo >&2 "CHECK RESULT"
473 + echo >&2 "Will run the charts: $active_charts"
474 + exit 0
475 fi
476
477 # -----------------------------------------------------------------------------
@@ -479,13 +479,13 @@ fi
479
480 TMP_DIR=
481 chartsd_cleanup() {
482 - cd /tmp
483 - if [ ! -z "$TMP_DIR" -a -d "$TMP_DIR" ]
484 - then
485 - [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: cleaning up temporary directory $TMP_DIR ..."
486 - rm -rf "$TMP_DIR"
487 - fi
488 - exit 0
482 + cd /tmp
483 + if [ ! -z "$TMP_DIR" -a -d "$TMP_DIR" ]
484 + then
485 + [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: cleaning up temporary directory $TMP_DIR ..."
486 + rm -rf "$TMP_DIR"
487 + fi
488 + exit 0
489 }
490 trap chartsd_cleanup EXIT
491 trap chartsd_cleanup SIGHUP
@@ -493,9 +493,9 @@ trap chartsd_cleanup INT
493
494 if [ $UID = "0" ]
495 then
496 - TMP_DIR="$( mktemp -d /var/run/netdata-${PROGRAM_NAME}-XXXXXXXXXX )"
496 + TMP_DIR="$( mktemp -d /var/run/netdata-${PROGRAM_NAME}-XXXXXXXXXX )"
497 else
498 - TMP_DIR="$( mktemp -d /tmp/.netdata-${PROGRAM_NAME}-XXXXXXXXXX )"
498 + TMP_DIR="$( mktemp -d /tmp/.netdata-${PROGRAM_NAME}-XXXXXXXXXX )"
499 fi
500
501 cd "$TMP_DIR" || exit 1
@@ -506,15 +506,15 @@ cd "$TMP_DIR" || exit 1
506 run_charts=
507 for chart in $active_charts
508 do
509 - [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: Calling '$chart$charts_create()'..."
510 - $chart$charts_create
511 - if [ $? -eq 0 ]
512 - then
513 - run_charts="$run_charts $chart"
514 - [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: '$chart' has initialized."
515 - else
516 - echo >&2 "$PROGRAM_NAME: chart '$chart' function '$chart$charts_create()' reports failure."
517 - fi
509 + [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: Calling '$chart$charts_create()'..."
510 + $chart$charts_create
511 + if [ $? -eq 0 ]
512 + then
513 + run_charts="$run_charts $chart"
514 + [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: '$chart' has initialized."
515 + else
516 + echo >&2 "$PROGRAM_NAME: chart '$chart' function '$chart$charts_create()' reports failure."
517 + fi
518 done
519 [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: run_charts='$run_charts'"
520
@@ -523,131 +523,131 @@ done
523 # update dimensions
524
525 if [ -z "$run_charts" ]
526 - then
527 - echo >&2 "$PROGRAM_NAME: No charts to collect data from."
528 - echo "DISABLE"
529 - exit 1
526 + then
527 + echo >&2 "$PROGRAM_NAME: No charts to collect data from."
528 + echo "DISABLE"
529 + exit 1
530 fi
531
532 declare -A charts_last_update=() charts_update_every=() charts_next_update=() charts_run_counter=() charts_serial_failures=()
533 global_update() {
534 - local exit_at \
535 - c=0 dt ret last_ms exec_start_ms exec_end_ms \
536 - chart now_charts=() next_charts=($run_charts) \
537 - next_ms x seconds millis
538 -
539 - # return the current time in ms in $now_ms
540 - current_time_ms
541 -
542 - exit_at=$(( now_ms + (restart_timeout * 1000) ))
543 -
544 - for chart in $run_charts
545 - do
546 - eval "charts_update_every[$chart]=\$$chart$suffix_update_every"
547 - test -z "${charts_update_every[$chart]}" && charts_update_every[$charts]=$update_every
548 - charts_last_update[$chart]=$((now_ms - (now_ms % (charts_update_every[$chart] * 1000) ) ))
549 - charts_next_update[$chart]=$(( charts_last_update[$chart] + (charts_update_every[$chart] * 1000) ))
550 - charts_run_counter[$chart]=0
551 - charts_serial_failures[$chart]=0
552 -
553 - echo "CHART netdata.plugin_chartsd_$chart '' 'Execution time for $chart plugin' 'milliseconds / run' charts.d netdata.plugin_charts area 145000 ${charts_update_every[$chart]}"
554 - echo "DIMENSION run_time 'run time' absolute 1 1"
555 - done
556 -
557 - # the main loop
558 - while [ "${#next_charts[@]}" -gt 0 ]
559 - do
560 - c=$((c + 1))
561 - now_charts=("${next_charts[@]}")
562 - next_charts=()
563 -
564 - # return the current time in ms in $now_ms
565 - current_time_ms
566 -
567 - for chart in "${now_charts[@]}"
568 - do
569 - # echo >&2 "DEBUG: chart: $chart last: ${charts_last_update[$chart]}, next: ${charts_next_update[$chart]}, now: ${now_ms}"
570 - if [ ${now_ms} -ge ${charts_next_update[$chart]} ]
571 - then
572 - last_ms=${charts_last_update[$chart]}
573 - dt=$(( (now_ms - last_ms) ))
574 - # echo >&2 "DEBUG: chart: $chart last: ${charts_last_update[$chart]}, next: ${charts_next_update[$chart]}, now: ${now_ms}, dt: ${dt}"
575 -
576 - charts_last_update[$chart]=${now_ms}
577 -
578 - while [ ${charts_next_update[$chart]} -lt ${now_ms} ]
579 - do
580 - charts_next_update[$chart]=$(( charts_next_update[$chart] + (charts_update_every[$chart] * 1000) ))
581 - done
582 -
583 - # the first call should not give a duration
584 - # so that netdata calibrates to current time
585 - dt=$(( dt * 1000 ))
586 - charts_run_counter[$chart]=$(( charts_run_counter[$chart] + 1 ))
587 - if [ ${charts_run_counter[$chart]} -eq 1 ]
588 - then
589 - dt=
590 - fi
591 -
592 - exec_start_ms=$now_ms
593 - $chart$charts_update $dt
594 - ret=$?
595 -
596 - # return the current time in ms in $now_ms
597 - current_time_ms; exec_end_ms=$now_ms
598 -
599 - echo "BEGIN netdata.plugin_chartsd_$chart $dt"
600 - echo "SET run_time = $(( exec_end_ms - exec_start_ms ))"
601 - echo "END"
602 -
603 - if [ $ret -eq 0 ]
604 - then
605 - charts_serial_failures[$chart]=0
606 - next_charts+=($chart)
607 - else
608 - charts_serial_failures[$chart]=$(( charts_serial_failures[$chart] + 1 ))
609 -
610 - if [ ${charts_serial_failures[$chart]} -gt 10 ]
611 - then
612 - echo >&2 "$PROGRAM_NAME: chart '$chart' update() function reported failure ${charts_serial_failures[$chart]} times. Disabling it."
613 - else
614 - echo >&2 "$PROGRAM_NAME: chart '$chart' update() function reports failure. Will keep trying for a while."
615 - next_charts+=($chart)
616 - fi
617 - fi
618 - else
619 - next_charts+=($chart)
620 - fi
621 - done
622 -
623 - if [ "$pause_method" = "suspend" ]
624 - then
625 - echo "STOPPING_WAKE_ME_UP_PLEASE"
626 - suspend || ( echo >&2 "$PROGRAM_NAME: suspend returned error $?, falling back to sleep."; loopsleepms $debug_time $update_every $time_divisor)
627 - else
628 - # wait the time you are required to
629 - next_ms=$((now_ms + (update_every * 1000 * 100) ))
630 - for x in "${charts_next_update[@]}"; do [ ${x} -lt ${next_ms} ] && next_ms=${x}; done
631 - next_ms=$((next_ms - now_ms))
632 -
633 - if [ ${LOOPSLEEPMS_HIGHRES} -eq 1 -a ${next_ms} -gt 0 ]
634 - then
635 - seconds=$(( next_ms / 1000 ))
636 - millis=$(( next_ms % 1000 ))
637 - [ ${millis} -lt 10 ] && millis="0${millis}"
638 - [ ${millis} -lt 100 ] && millis="0${millis}"
639 - [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: sleeping for ${seconds}.${millis} seconds."
640 - sleep ${seconds}.${millis}
641 - else
642 - sleep $update_every
643 - fi
644 - fi
645 -
646 - test ${now_ms} -ge ${exit_at} && exit 0
647 - done
648 -
649 - echo >&2 "$PROGRAM_NAME: Nothing left to do. Disabling charts.d.plugin."
650 - echo "DISABLE"
534 + local exit_at \
535 + c=0 dt ret last_ms exec_start_ms exec_end_ms \
536 + chart now_charts=() next_charts=($run_charts) \
537 + next_ms x seconds millis
538 +
539 + # return the current time in ms in $now_ms
540 + current_time_ms
541 +
542 + exit_at=$(( now_ms + (restart_timeout * 1000) ))
543 +
544 + for chart in $run_charts
545 + do
546 + eval "charts_update_every[$chart]=\$$chart$suffix_update_every"
547 + test -z "${charts_update_every[$chart]}" && charts_update_every[$charts]=$update_every
548 + charts_last_update[$chart]=$((now_ms - (now_ms % (charts_update_every[$chart] * 1000) ) ))
549 + charts_next_update[$chart]=$(( charts_last_update[$chart] + (charts_update_every[$chart] * 1000) ))
550 + charts_run_counter[$chart]=0
551 + charts_serial_failures[$chart]=0
552 +
553 + echo "CHART netdata.plugin_chartsd_$chart '' 'Execution time for $chart plugin' 'milliseconds / run' charts.d netdata.plugin_charts area 145000 ${charts_update_every[$chart]}"
554 + echo "DIMENSION run_time 'run time' absolute 1 1"
555 + done
556 +
557 + # the main loop
558 + while [ "${#next_charts[@]}" -gt 0 ]
559 + do
560 + c=$((c + 1))
561 + now_charts=("${next_charts[@]}")
562 + next_charts=()
563 +
564 + # return the current time in ms in $now_ms
565 + current_time_ms
566 +
567 + for chart in "${now_charts[@]}"
568 + do
569 + # echo >&2 "DEBUG: chart: $chart last: ${charts_last_update[$chart]}, next: ${charts_next_update[$chart]}, now: ${now_ms}"
570 + if [ ${now_ms} -ge ${charts_next_update[$chart]} ]
571 + then
572 + last_ms=${charts_last_update[$chart]}
573 + dt=$(( (now_ms - last_ms) ))
574 + # echo >&2 "DEBUG: chart: $chart last: ${charts_last_update[$chart]}, next: ${charts_next_update[$chart]}, now: ${now_ms}, dt: ${dt}"
575 +
576 + charts_last_update[$chart]=${now_ms}
577 +
578 + while [ ${charts_next_update[$chart]} -lt ${now_ms} ]
579 + do
580 + charts_next_update[$chart]=$(( charts_next_update[$chart] + (charts_update_every[$chart] * 1000) ))
581 + done
582 +
583 + # the first call should not give a duration
584 + # so that netdata calibrates to current time
585 + dt=$(( dt * 1000 ))
586 + charts_run_counter[$chart]=$(( charts_run_counter[$chart] + 1 ))
587 + if [ ${charts_run_counter[$chart]} -eq 1 ]
588 + then
589 + dt=
590 + fi
591 +
592 + exec_start_ms=$now_ms
593 + $chart$charts_update $dt
594 + ret=$?
595 +
596 + # return the current time in ms in $now_ms
597 + current_time_ms; exec_end_ms=$now_ms
598 +
599 + echo "BEGIN netdata.plugin_chartsd_$chart $dt"
600 + echo "SET run_time = $(( exec_end_ms - exec_start_ms ))"
601 + echo "END"
602 +
603 + if [ $ret -eq 0 ]
604 + then
605 + charts_serial_failures[$chart]=0
606 + next_charts+=($chart)
607 + else
608 + charts_serial_failures[$chart]=$(( charts_serial_failures[$chart] + 1 ))
609 +
610 + if [ ${charts_serial_failures[$chart]} -gt 10 ]
611 + then
612 + echo >&2 "$PROGRAM_NAME: chart '$chart' update() function reported failure ${charts_serial_failures[$chart]} times. Disabling it."
613 + else
614 + echo >&2 "$PROGRAM_NAME: chart '$chart' update() function reports failure. Will keep trying for a while."
615 + next_charts+=($chart)
616 + fi
617 + fi
618 + else
619 + next_charts+=($chart)
620 + fi
621 + done
622 +
623 + if [ "$pause_method" = "suspend" ]
624 + then
625 + echo "STOPPING_WAKE_ME_UP_PLEASE"
626 + suspend || ( echo >&2 "$PROGRAM_NAME: suspend returned error $?, falling back to sleep."; loopsleepms $debug_time $update_every $time_divisor)
627 + else
628 + # wait the time you are required to
629 + next_ms=$((now_ms + (update_every * 1000 * 100) ))
630 + for x in "${charts_next_update[@]}"; do [ ${x} -lt ${next_ms} ] && next_ms=${x}; done
631 + next_ms=$((next_ms - now_ms))
632 +
633 + if [ ${LOOPSLEEPMS_HIGHRES} -eq 1 -a ${next_ms} -gt 0 ]
634 + then
635 + seconds=$(( next_ms / 1000 ))
636 + millis=$(( next_ms % 1000 ))
637 + [ ${millis} -lt 10 ] && millis="0${millis}"
638 + [ ${millis} -lt 100 ] && millis="0${millis}"
639 + [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: sleeping for ${seconds}.${millis} seconds."
640 + sleep ${seconds}.${millis}
641 + else
642 + sleep $update_every
643 + fi
644 + fi
645 +
646 + test ${now_ms} -ge ${exit_at} && exit 0
647 + done
648 +
649 + echo >&2 "$PROGRAM_NAME: Nothing left to do. Disabling charts.d.plugin."
650 + echo "DISABLE"
651 }
652
653 global_update
plugins.d/loopsleepms.sh.inc
+53 -53
@@ -7,9 +7,9 @@
7
8 LOOPSLEEP_DATE="$(which date)"
9 if [ -z "$LOOPSLEEP_DATE" ]
10 - then
11 - echo >&2 "$0: ERROR: Cannot find the command 'date' in the system path."
12 - exit 1
10 + then
11 + echo >&2 "$0: ERROR: Cannot find the command 'date' in the system path."
12 + exit 1
13 fi
14
15 LOOPSLEEPMS_LASTRUN=0
@@ -21,70 +21,70 @@ test "$($LOOPSLEEP_DATE +%N)" = "%N" && LOOPSLEEPMS_HIGHRES=0
21
22 now_ms=
23 current_time_ms() {
24 - # if high resolution is not supported
25 - # just sleep the time requested, in seconds
26 - if [ $LOOPSLEEPMS_HIGHRES -eq 0 ]
27 - then
28 - now_ms="$($LOOPSLEEP_DATE +'%s')000"
29 - else
30 - now_ms="$(( $( $LOOPSLEEP_DATE +'%s * 1000 + %-N / 1000000' ) ))"
31 - fi
24 + # if high resolution is not supported
25 + # just sleep the time requested, in seconds
26 + if [ $LOOPSLEEPMS_HIGHRES -eq 0 ]
27 + then
28 + now_ms="$($LOOPSLEEP_DATE +'%s')000"
29 + else
30 + now_ms="$(( $( $LOOPSLEEP_DATE +'%s * 1000 + %-N / 1000000' ) ))"
31 + fi
32 }
33
34 loopsleepms() {
35 - local tellwork=0 t="$1" div s m now mstosleep
35 + local tellwork=0 t="$1" div s m now mstosleep
36
37 - if [ "$t" = "tellwork" ]
38 - then
39 - tellwork=1
40 - shift
41 - t="$1"
42 - fi
43 - div="${2-100}"
37 + if [ "$t" = "tellwork" ]
38 + then
39 + tellwork=1
40 + shift
41 + t="$1"
42 + fi
43 + div="${2-100}"
44
45 - # $t = the time in seconds to wait
45 + # $t = the time in seconds to wait
46
47 - # if high resolution is not supported
48 - # just sleep the time requested, in seconds
49 - if [ $LOOPSLEEPMS_HIGHRES -eq 0 ]
50 - then
51 - sleep $t
52 - return
53 - fi
47 + # if high resolution is not supported
48 + # just sleep the time requested, in seconds
49 + if [ $LOOPSLEEPMS_HIGHRES -eq 0 ]
50 + then
51 + sleep $t
52 + return
53 + fi
54
55 - # get the current time, in ms
56 - # milliseconds since epoch (1-1-1970)
57 - now="$(( $( $LOOPSLEEP_DATE +'%s * 1000 + %-N / 1000000' ) ))"
55 + # get the current time, in ms
56 + # milliseconds since epoch (1-1-1970)
57 + now="$(( $( $LOOPSLEEP_DATE +'%s * 1000 + %-N / 1000000' ) ))"
58
59 - # calculate required sleep in ms
60 - t=$((t * 1000 * div / 100))
59 + # calculate required sleep in ms
60 + t=$((t * 1000 * div / 100))
61
62 - # this is our first run
63 - # just wait the requested time
64 - test $LOOPSLEEPMS_LASTRUN -eq 0 && LOOPSLEEPMS_LASTRUN=$now
62 + # this is our first run
63 + # just wait the requested time
64 + test $LOOPSLEEPMS_LASTRUN -eq 0 && LOOPSLEEPMS_LASTRUN=$now
65
66 - # calculate ms since last run
67 - LOOPSLEEPMS_LASTWORK=$((now - LOOPSLEEPMS_LASTRUN - LOOPSLEEPMS_LASTSLEEP))
68 - # echo "# last loop's work took $LOOPSLEEPMS_LASTWORK ms"
66 + # calculate ms since last run
67 + LOOPSLEEPMS_LASTWORK=$((now - LOOPSLEEPMS_LASTRUN - LOOPSLEEPMS_LASTSLEEP))
68 + # echo "# last loop's work took $LOOPSLEEPMS_LASTWORK ms"
69
70 - # calculate ms to sleep
71 - mstosleep=$(( t - LOOPSLEEPMS_LASTWORK ))
72 - # echo "# mstosleep is $mstosleep ms"
70 + # calculate ms to sleep
71 + mstosleep=$(( t - LOOPSLEEPMS_LASTWORK ))
72 + # echo "# mstosleep is $mstosleep ms"
73
74 - # if we are too slow, sleep some time
75 - test $mstosleep -lt 200 && mstosleep=200
74 + # if we are too slow, sleep some time
75 + test $mstosleep -lt 200 && mstosleep=200
76
77 - s=$((mstosleep / 1000))
78 - m=$((mstosleep - (s * 1000)))
77 + s=$((mstosleep / 1000))
78 + m=$((mstosleep - (s * 1000)))
79
80 - test $tellwork -eq 1 && echo >&2 " >>> PERFORMANCE >>> WORK TOOK $LOOPSLEEPMS_LASTWORK ms ( $((LOOPSLEEPMS_LASTWORK * 100 / 1000)).$((LOOPSLEEPMS_LASTWORK % 10))% cpu ) >>> SLEEPING $mstosleep ms"
80 + test $tellwork -eq 1 && echo >&2 " >>> PERFORMANCE >>> WORK TOOK $LOOPSLEEPMS_LASTWORK ms ( $((LOOPSLEEPMS_LASTWORK * 100 / 1000)).$((LOOPSLEEPMS_LASTWORK % 10))% cpu ) >>> SLEEPING $mstosleep ms"
81
82 - # echo "# sleeping $s.$m"
83 - # echo
84 - sleep $s.$m
82 + # echo "# sleeping $s.$m"
83 + # echo
84 + sleep $s.$m
85
86 - # keep the values we need
87 - # for our next run
88 - LOOPSLEEPMS_LASTRUN=$now
89 - LOOPSLEEPMS_LASTSLEEP=$mstosleep
86 + # keep the values we need
87 + # for our next run
88 + LOOPSLEEPMS_LASTRUN=$now
89 + LOOPSLEEPMS_LASTSLEEP=$mstosleep
90 }
plugins.d/node.d.plugin
+181 -181
@@ -40,60 +40,60 @@ var netdata = require('netdata');
40 // configuration
41
42 function pluginConfig(filename) {
43 - var f = path.basename(filename);
43 + var f = path.basename(filename);
44
45 - // node.d.plugin configuration
46 - var m = f.match('.plugin' + '$');
47 - if(m !== null)
48 - return netdata.options.paths.config + '/' + f.substring(0, m.index) + '.conf';
45 + // node.d.plugin configuration
46 + var m = f.match('.plugin' + '$');
47 + if(m !== null)
48 + return netdata.options.paths.config + '/' + f.substring(0, m.index) + '.conf';
49
50 - // node.d modules configuration
51 - m = f.match('.node.js' + '$');
52 - if(m !== null)
53 - return netdata.options.paths.config + '/node.d/' + f.substring(0, m.index) + '.conf';
50 + // node.d modules configuration
51 + m = f.match('.node.js' + '$');
52 + if(m !== null)
53 + return netdata.options.paths.config + '/node.d/' + f.substring(0, m.index) + '.conf';
54
55 - return netdata.options.paths.config + '/node.d/' + f + '.conf';
55 + return netdata.options.paths.config + '/node.d/' + f + '.conf';
56 }
57
58 // internal defaults
59 extend(true, netdata.options, {
60 - filename: path.basename(__filename),
60 + filename: path.basename(__filename),
61
62 - update_every: NETDATA_UPDATE_EVERY,
62 + update_every: NETDATA_UPDATE_EVERY,
63
64 - exit_after_ms: 3600 * 4 * 1000,
64 + exit_after_ms: 3600 * 4 * 1000,
65
66 - paths: {
67 - plugins: NETDATA_PLUGINS_DIR,
68 - config: NETDATA_CONFIG_DIR,
69 - modules: [],
70 - },
66 + paths: {
67 + plugins: NETDATA_PLUGINS_DIR,
68 + config: NETDATA_CONFIG_DIR,
69 + modules: [],
70 + },
71
72 - modules_enable_autodetect: true,
73 - modules_enable_all: true,
74 - modules: {},
72 + modules_enable_autodetect: true,
73 + modules_enable_all: true,
74 + modules: {},
75 });
76 netdata.options.config_filename = pluginConfig(__filename);
77
78 // load configuration file
79 try {
80 - netdata.options_loaded = JSON.parse(fs.readFileSync(netdata.options.config_filename, 'utf8'));
81 - extend(true, netdata.options, netdata.options_loaded);
82 - console.error('merged netdata object:');
83 - console.error(netdata);
80 + netdata.options_loaded = JSON.parse(fs.readFileSync(netdata.options.config_filename, 'utf8'));
81 + extend(true, netdata.options, netdata.options_loaded);
82 + console.error('merged netdata object:');
83 + console.error(netdata);
84 }
85 catch(e) {
86 - netdata.error('Cannot read configuration file ' + netdata.options.config_filename + ': ' + e.message + ', using internal defaults.');
87 - netdata.options_loaded = undefined;
88 - dumpError(e);
86 + netdata.error('Cannot read configuration file ' + netdata.options.config_filename + ': ' + e.message + ', using internal defaults.');
87 + netdata.options_loaded = undefined;
88 + dumpError(e);
89 }
90
91
92 // apply module paths to node.js process
93 function applyModulePaths() {
94 - var len = netdata.options.paths.modules.length;
95 - while(len--)
96 - process.mainModule.paths.unshift(netdata.options.paths.modules[len]);
94 + var len = netdata.options.paths.modules.length;
95 + while(len--)
96 + process.mainModule.paths.unshift(netdata.options.paths.modules[len]);
97 }
98 applyModulePaths();
99
@@ -102,165 +102,165 @@ applyModulePaths();
102 // tracing
103
104 function dumpError(err) {
105 - if (typeof err === 'object') {
106 - if (err.stack) {
107 - netdata.debug(err.stack);
108 - }
109 - }
105 + if (typeof err === 'object') {
106 + if (err.stack) {
107 + netdata.debug(err.stack);
108 + }
109 + }
110 }
111
112 // --------------------------------------------------------------------------------------------------------------------
113 // get command line arguments
114 {
115 - var found_myself = false;
116 - var found_number = false;
117 - var found_modules = false;
118 - process.argv.forEach(function (val, index, array) {
119 - netdata.debug('PARAM: ' + val);
120 -
121 - if(!found_myself) {
122 - if(val === __filename)
123 - found_myself = true;
124 - }
125 - else {
126 - switch(val) {
127 - case 'debug':
128 - netdata.options.DEBUG = true;
129 - netdata.debug('DEBUG enabled');
130 - break;
131 -
132 - default:
133 - if(found_number === true) {
134 - if(found_modules === false) {
135 - for(var i in netdata.options.modules)
136 - netdata.options.modules[i].enabled = false;
137 - }
138 -
139 - if(typeof netdata.options.modules[val] === 'undefined')
140 - netdata.options.modules[val] = {};
141 -
142 - netdata.options.modules[val].enabled = true;
143 - netdata.options.modules_enable_all = false;
144 - netdata.debug('enabled module ' + val);
145 - }
146 - else {
147 - try {
148 - var x = parseInt(val);
149 - if(x > 0) {
150 - netdata.options.update_every = x;
151 - if(netdata.options.update_every < NETDATA_UPDATE_EVERY) {
152 - netdata.options.update_every = NETDATA_UPDATE_EVERY;
153 - netdata.debug('Update frequency ' + x + 's is too low');
154 - }
155 -
156 - found_number = true;
157 - netdata.debug('Update frequency set to ' + netdata.options.update_every + ' seconds');
158 - }
159 - else netdata.error('Ignoring parameter: ' + val);
160 - }
161 - catch(e) {
162 - netdata.error('Cannot get value of parameter: ' + val);
163 - dumpError(e);
164 - }
165 - }
166 - break;
167 - }
168 - }
169 - });
115 + var found_myself = false;
116 + var found_number = false;
117 + var found_modules = false;
118 + process.argv.forEach(function (val, index, array) {
119 + netdata.debug('PARAM: ' + val);
120 +
121 + if(!found_myself) {
122 + if(val === __filename)
123 + found_myself = true;
124 + }
125 + else {
126 + switch(val) {
127 + case 'debug':
128 + netdata.options.DEBUG = true;
129 + netdata.debug('DEBUG enabled');
130 + break;
131 +
132 + default:
133 + if(found_number === true) {
134 + if(found_modules === false) {
135 + for(var i in netdata.options.modules)
136 + netdata.options.modules[i].enabled = false;
137 + }
138 +
139 + if(typeof netdata.options.modules[val] === 'undefined')
140 + netdata.options.modules[val] = {};
141 +
142 + netdata.options.modules[val].enabled = true;
143 + netdata.options.modules_enable_all = false;
144 + netdata.debug('enabled module ' + val);
145 + }
146 + else {
147 + try {
148 + var x = parseInt(val);
149 + if(x > 0) {
150 + netdata.options.update_every = x;
151 + if(netdata.options.update_every < NETDATA_UPDATE_EVERY) {
152 + netdata.options.update_every = NETDATA_UPDATE_EVERY;
153 + netdata.debug('Update frequency ' + x + 's is too low');
154 + }
155 +
156 + found_number = true;
157 + netdata.debug('Update frequency set to ' + netdata.options.update_every + ' seconds');
158 + }
159 + else netdata.error('Ignoring parameter: ' + val);
160 + }
161 + catch(e) {
162 + netdata.error('Cannot get value of parameter: ' + val);
163 + dumpError(e);
164 + }
165 + }
166 + break;
167 + }
168 + }
169 + });
170 }
171
172 if(netdata.options.update_every < 1) {
173 - netdata.debug('Adjusting update frequency to 1 second');
174 - netdata.options.update_every = 1;
173 + netdata.debug('Adjusting update frequency to 1 second');
174 + netdata.options.update_every = 1;
175 }
176
177 // --------------------------------------------------------------------------------------------------------------------
178 // find modules
179
180 function findModules() {
181 - var found = 0;
182 -
183 - var files = fs.readdirSync(NODE_D_DIR);
184 - var len = files.length;
185 - while(len--) {
186 - var m = files[len].match('.node.js' + '$');
187 - if(m !== null) {
188 - var n = files[len].substring(0, m.index);
189 -
190 - if(typeof(netdata.options.modules[n]) === 'undefined')
191 - netdata.options.modules[n] = { name: n, enabled: netdata.options.modules_enable_all };
192 -
193 - if(netdata.options.modules[n].enabled === true) {
194 - netdata.options.modules[n].name = n;
195 - netdata.options.modules[n].filename = NODE_D_DIR + '/' + files[len];
196 - netdata.options.modules[n].loaded = false;
197 -
198 - if(typeof(netdata.options.modules[n].config_filename) !== 'string')
199 - netdata.options.modules[n].config_filename = pluginConfig(files[len]);
200 -
201 - // load the module
202 - try {
203 - netdata.debug('loading module ' + netdata.options.modules[n].filename);
204 - netdata.options.modules[n].module = require(netdata.options.modules[n].filename);
205 - netdata.options.modules[n].module.name = n;
206 - netdata.debug('loaded module ' + netdata.options.modules[n].name + ' from ' + netdata.options.modules[n].filename);
207 - }
208 - catch(e) {
209 - netdata.options.modules[n].enabled = false;
210 - netdata.error('Cannot load module: ' + netdata.options.modules[n].filename + ' exception: ' + e);
211 - dumpError(e);
212 - continue;
213 - }
214 -
215 - // load its configuration
216 - var c = {
217 - enable_autodetect: netdata.options.modules_enable_autodetect,
218 - update_every: netdata.options.update_every
219 - };
220 - try {
221 - netdata.debug('loading module\'s ' + netdata.options.modules[n].name + ' config ' + netdata.options.modules[n].config_filename);
222 - var c2 = JSON.parse(fs.readFileSync(netdata.options.modules[n].config_filename, 'utf8'));
223 - extend(true, c, c2);
224 - netdata.debug('loaded module\'s ' + netdata.options.modules[n].name + ' config ' + netdata.options.modules[n].config_filename);
225 - }
226 - catch(e) {
227 - netdata.error('Cannot load module\'s ' + netdata.options.modules[n].name + ' config from ' + netdata.options.modules[n].config_filename + ' exception: ' + e + ', using internal defaults.');
228 - dumpError(e);
229 - }
230 -
231 - // call module auto-detection / configuration
232 - try {
233 - netdata.modules_configuring++;
234 - netdata.debug('Configuring module ' + netdata.options.modules[n].name);
235 - var serv = netdata.configure(netdata.options.modules[n].module, c, function() {
236 - netdata.debug('Configured module ' + netdata.options.modules[n].name);
237 - netdata.modules_configuring--;
238 - });
239 -
240 - netdata.debug('Configuring module ' + netdata.options.modules[n].name + ' reports ' + serv + ' eligible services.');
241 - }
242 - catch(e) {
243 - netdata.modules_configuring--;
244 - netdata.options.modules[n].enabled = false;
245 - netdata.error('Failed module auto-detection: ' + netdata.options.modules[n].name + ' exception: ' + e + ', disabling module.');
246 - dumpError(e);
247 - continue;
248 - }
249 -
250 - netdata.options.modules[n].loaded = true;
251 - found++;
252 - }
253 - }
254 - }
255 -
256 - // netdata.debug(netdata.options.modules);
257 - return found;
181 + var found = 0;
182 +
183 + var files = fs.readdirSync(NODE_D_DIR);
184 + var len = files.length;
185 + while(len--) {
186 + var m = files[len].match('.node.js' + '$');
187 + if(m !== null) {
188 + var n = files[len].substring(0, m.index);
189 +
190 + if(typeof(netdata.options.modules[n]) === 'undefined')
191 + netdata.options.modules[n] = { name: n, enabled: netdata.options.modules_enable_all };
192 +
193 + if(netdata.options.modules[n].enabled === true) {
194 + netdata.options.modules[n].name = n;
195 + netdata.options.modules[n].filename = NODE_D_DIR + '/' + files[len];
196 + netdata.options.modules[n].loaded = false;
197 +
198 + if(typeof(netdata.options.modules[n].config_filename) !== 'string')
199 + netdata.options.modules[n].config_filename = pluginConfig(files[len]);
200 +
201 + // load the module
202 + try {
203 + netdata.debug('loading module ' + netdata.options.modules[n].filename);
204 + netdata.options.modules[n].module = require(netdata.options.modules[n].filename);
205 + netdata.options.modules[n].module.name = n;
206 + netdata.debug('loaded module ' + netdata.options.modules[n].name + ' from ' + netdata.options.modules[n].filename);
207 + }
208 + catch(e) {
209 + netdata.options.modules[n].enabled = false;
210 + netdata.error('Cannot load module: ' + netdata.options.modules[n].filename + ' exception: ' + e);
211 + dumpError(e);
212 + continue;
213 + }
214 +
215 + // load its configuration
216 + var c = {
217 + enable_autodetect: netdata.options.modules_enable_autodetect,
218 + update_every: netdata.options.update_every
219 + };
220 + try {
221 + netdata.debug('loading module\'s ' + netdata.options.modules[n].name + ' config ' + netdata.options.modules[n].config_filename);
222 + var c2 = JSON.parse(fs.readFileSync(netdata.options.modules[n].config_filename, 'utf8'));
223 + extend(true, c, c2);
224 + netdata.debug('loaded module\'s ' + netdata.options.modules[n].name + ' config ' + netdata.options.modules[n].config_filename);
225 + }
226 + catch(e) {
227 + netdata.error('Cannot load module\'s ' + netdata.options.modules[n].name + ' config from ' + netdata.options.modules[n].config_filename + ' exception: ' + e + ', using internal defaults.');
228 + dumpError(e);
229 + }
230 +
231 + // call module auto-detection / configuration
232 + try {
233 + netdata.modules_configuring++;
234 + netdata.debug('Configuring module ' + netdata.options.modules[n].name);
235 + var serv = netdata.configure(netdata.options.modules[n].module, c, function() {
236 + netdata.debug('Configured module ' + netdata.options.modules[n].name);
237 + netdata.modules_configuring--;
238 + });
239 +
240 + netdata.debug('Configuring module ' + netdata.options.modules[n].name + ' reports ' + serv + ' eligible services.');
241 + }
242 + catch(e) {
243 + netdata.modules_configuring--;
244 + netdata.options.modules[n].enabled = false;
245 + netdata.error('Failed module auto-detection: ' + netdata.options.modules[n].name + ' exception: ' + e + ', disabling module.');
246 + dumpError(e);
247 + continue;
248 + }
249 +
250 + netdata.options.modules[n].loaded = true;
251 + found++;
252 + }
253 + }
254 + }
255 +
256 + // netdata.debug(netdata.options.modules);
257 + return found;
258 }
259
260 if(findModules() === 0) {
261 - netdata.error('Cannot load any .node.js module from: ' + NODE_D_DIR);
262 - netdata.disableNodePlugin();
263 - process.exit(1);
261 + netdata.error('Cannot load any .node.js module from: ' + NODE_D_DIR);
262 + netdata.disableNodePlugin();
263 + process.exit(1);
264 }
265
266
@@ -268,14 +268,14 @@ if(findModules() === 0) {
268 // start
269
270 function start_when_configuring_ends() {
271 - if(netdata.modules_configuring > 0) {
272 - netdata.debug('Waiting modules configuration, still running ' + netdata.modules_configuring);
273 - setTimeout(start_when_configuring_ends, 500);
274 - return;
275 - }
276 -
277 - netdata.modules_configuring = 0;
278 - netdata.start();
271 + if(netdata.modules_configuring > 0) {
272 + netdata.debug('Waiting modules configuration, still running ' + netdata.modules_configuring);
273 + setTimeout(start_when_configuring_ends, 500);
274 + return;
275 + }
276 +
277 + netdata.modules_configuring = 0;
278 + netdata.start();
279 }
280 start_when_configuring_ends();
281
plugins.d/tc-qos-helper.sh
+52 -52
@@ -23,21 +23,21 @@ update_every=$((t))
23
24 # allow the user to override our defaults
25 if [ -f "${config_dir}/tc-qos-helper.conf" ]
26 - then
27 - source "${config_dir}/tc-qos-helper.conf"
26 + then
27 + source "${config_dir}/tc-qos-helper.conf"
28 fi
29
30 # default time function
31 now_ms=
32 current_time_ms() {
33 - now_ms="$(date +'%s')000"
33 + now_ms="$(date +'%s')000"
34 }
35
36 # default sleep function
37 LOOPSLEEPMS_LASTWORK=0
38 loopsleepms() {
39 - [ "$1" = "tellwork" ] && shift
40 - sleep $1
39 + [ "$1" = "tellwork" ] && shift
40 + sleep $1
41 }
42
43 # if found and included, this file overwrites loopsleepms()
@@ -45,49 +45,49 @@ loopsleepms() {
45 . "${plugins_dir}/loopsleepms.sh.inc"
46
47 if [ -z "${tc}" -o ! -x "${tc}" ]
48 - then
49 - echo >&2 "${PROGRAM_NAME}: Cannot find command 'tc' in this system."
50 - exit 1
48 + then
49 + echo >&2 "${PROGRAM_NAME}: Cannot find command 'tc' in this system."
50 + exit 1
51 fi
52
53 devices=
54 fix_names=
55
56 setclassname() {
57 - echo "SETCLASSNAME $3 $2"
57 + echo "SETCLASSNAME $3 $2"
58 }
59
60 show_tc() {
61 - local x="${1}" interface_dev interface_classes interface_classes_monitor
62 -
63 - echo "BEGIN ${x}"
64 - ${tc} -s class show dev ${x}
65 -
66 - # check FireQOS names for classes
67 - if [ ! -z "${fix_names}" -a -f "${fireqos_run_dir}/ifaces/${x}" ]
68 - then
69 - name="$(<"${fireqos_run_dir}/ifaces/${x}")"
70 - echo "SETDEVICENAME ${name}"
71 -
72 - interface_dev=
73 - interface_classes=
74 - interface_classes_monitor=
75 - source "${fireqos_run_dir}/${name}.conf"
76 - for n in ${interface_classes_monitor}
77 - do
78 - setclassname ${n//|/ }
79 - done
80 - [ ! -z "${interface_dev}" ] && echo "SETDEVICEGROUP ${interface_dev}"
81 - fi
82 - echo "END ${x}"
61 + local x="${1}" interface_dev interface_classes interface_classes_monitor
62 +
63 + echo "BEGIN ${x}"
64 + ${tc} -s class show dev ${x}
65 +
66 + # check FireQOS names for classes
67 + if [ ! -z "${fix_names}" -a -f "${fireqos_run_dir}/ifaces/${x}" ]
68 + then
69 + name="$(<"${fireqos_run_dir}/ifaces/${x}")"
70 + echo "SETDEVICENAME ${name}"
71 +
72 + interface_dev=
73 + interface_classes=
74 + interface_classes_monitor=
75 + source "${fireqos_run_dir}/${name}.conf"
76 + for n in ${interface_classes_monitor}
77 + do
78 + setclassname ${n//|/ }
79 + done
80 + [ ! -z "${interface_dev}" ] && echo "SETDEVICEGROUP ${interface_dev}"
81 + fi
82 + echo "END ${x}"
83 }
84
85 all_devices() {
86 - cat /proc/net/dev | grep ":" | cut -d ':' -f 1 | while read dev
87 - do
88 - l=$(${tc} class show dev ${dev} | wc -l)
89 - [ $l -ne 0 ] && echo ${dev}
90 - done
86 + cat /proc/net/dev | grep ":" | cut -d ':' -f 1 | while read dev
87 + do
88 + l=$(${tc} class show dev ${dev} | wc -l)
89 + [ $l -ne 0 ] && echo ${dev}
90 + done
91 }
92
93 # update devices and class names
@@ -102,25 +102,25 @@ c=0
102 gc=0
103 while [ 1 ]
104 do
105 - fix_names=
106 - c=$((c + 1))
107 - gc=$((gc + 1))
105 + fix_names=
106 + c=$((c + 1))
107 + gc=$((gc + 1))
108
109 - if [ ${c} -le 1 -o ${c} -ge ${names_every} ]
110 - then
111 - c=1
112 - fix_names="YES"
113 - devices="$( all_devices )"
114 - fi
109 + if [ ${c} -le 1 -o ${c} -ge ${names_every} ]
110 + then
111 + c=1
112 + fix_names="YES"
113 + devices="$( all_devices )"
114 + fi
115
116 - for d in ${devices}
117 - do
118 - show_tc ${d}
119 - done
116 + for d in ${devices}
117 + do
118 + show_tc ${d}
119 + done
120
121 - echo "WORKTIME ${LOOPSLEEPMS_LASTWORK}"
121 + echo "WORKTIME ${LOOPSLEEPMS_LASTWORK}"
122
123 - loopsleepms ${update_every}
123 + loopsleepms ${update_every}
124
125 - [ ${gc} -gt ${exit_after} ] && exit 0
125 + [ ${gc} -gt ${exit_after} ] && exit 0
126 done
src/appconfig.c
+324 -324
@@ -13,33 +13,33 @@ pthread_mutex_t config_mutex = PTHREAD_MUTEX_INITIALIZER;
13 #define CONFIG_VALUE_CHECKED 0x08 // has been checked if the value is different from the default
14
15 struct config_value {
16 - avl avl; // the index - this has to be first!
16 + avl avl; // the index - this has to be first!
17
18 - uint8_t flags;
19 - uint32_t hash; // a simple hash to speed up searching
20 - // we first compare hashes, and only if the hashes are equal we do string comparisons
18 + uint8_t flags;
19 + uint32_t hash; // a simple hash to speed up searching
20 + // we first compare hashes, and only if the hashes are equal we do string comparisons
21
22 - char *name;
23 - char *value;
22 + char *name;
23 + char *value;
24
25 - struct config_value *next; // config->mutex protects just this
25 + struct config_value *next; // config->mutex protects just this
26 };
27
28 struct config {
29 - avl avl;
29 + avl avl;
30
31 - uint32_t hash; // a simple hash to speed up searching
32 - // we first compare hashes, and only if the hashes are equal we do string comparisons
31 + uint32_t hash; // a simple hash to speed up searching
32 + // we first compare hashes, and only if the hashes are equal we do string comparisons
33
34 - char *name;
34 + char *name;
35
36 - struct config *next; // gloabl config_mutex protects just this
36 + struct config *next; // gloabl config_mutex protects just this
37
38 - struct config_value *values;
39 - avl_tree_lock values_index;
38 + struct config_value *values;
39 + avl_tree_lock values_index;
40
41 - pthread_mutex_t mutex; // this locks only the writers, to ensure atomic updates
42 - // readers are protected using the rwlock in avl_tree_lock
41 + pthread_mutex_t mutex; // this locks only the writers, to ensure atomic updates
42 + // readers are protected using the rwlock in avl_tree_lock
43 } *config_root = NULL;
44
45
@@ -47,19 +47,19 @@ struct config {
47 // locking
48
49 static inline void config_global_write_lock(void) {
50 - pthread_mutex_lock(&config_mutex);
50 + pthread_mutex_lock(&config_mutex);
51 }
52
53 static inline void config_global_unlock(void) {
54 - pthread_mutex_unlock(&config_mutex);
54 + pthread_mutex_unlock(&config_mutex);
55 }
56
57 static inline void config_section_write_lock(struct config *co) {
58 - pthread_mutex_lock(&co->mutex);
58 + pthread_mutex_lock(&co->mutex);
59 }
60
61 static inline void config_section_unlock(struct config *co) {
62 - pthread_mutex_unlock(&co->mutex);
62 + pthread_mutex_unlock(&co->mutex);
63 }
64
65
@@ -67,20 +67,20 @@ static inline void config_section_unlock(struct config *co) {
67 // config name-value index
68
69 static int config_value_compare(void* a, void* b) {
70 - if(((struct config_value *)a)->hash < ((struct config_value *)b)->hash) return -1;
71 - else if(((struct config_value *)a)->hash > ((struct config_value *)b)->hash) return 1;
72 - else return strcmp(((struct config_value *)a)->name, ((struct config_value *)b)->name);
70 + if(((struct config_value *)a)->hash < ((struct config_value *)b)->hash) return -1;
71 + else if(((struct config_value *)a)->hash > ((struct config_value *)b)->hash) return 1;
72 + else return strcmp(((struct config_value *)a)->name, ((struct config_value *)b)->name);
73 }
74
75 #define config_value_index_add(co, cv) avl_insert_lock(&((co)->values_index), (avl *)(cv))
76 #define config_value_index_del(co, cv) avl_remove_lock(&((co)->values_index), (avl *)(cv))
77
78 static struct config_value *config_value_index_find(struct config *co, const char *name, uint32_t hash) {
79 - struct config_value tmp;
80 - tmp.hash = (hash)?hash:simple_hash(name);
81 - tmp.name = (char *)name;
79 + struct config_value tmp;
80 + tmp.hash = (hash)?hash:simple_hash(name);
81 + tmp.name = (char *)name;
82
83 - return (struct config_value *)avl_search_lock(&(co->values_index), (avl *) &tmp);
83 + return (struct config_value *)avl_search_lock(&(co->values_index), (avl *) &tmp);
84 }
85
86
@@ -88,25 +88,25 @@ static struct config_value *config_value_index_find(struct config *co, const cha
88 // config sections index
89
90 static int config_compare(void* a, void* b) {
91 - if(((struct config *)a)->hash < ((struct config *)b)->hash) return -1;
92 - else if(((struct config *)a)->hash > ((struct config *)b)->hash) return 1;
93 - else return strcmp(((struct config *)a)->name, ((struct config *)b)->name);
91 + if(((struct config *)a)->hash < ((struct config *)b)->hash) return -1;
92 + else if(((struct config *)a)->hash > ((struct config *)b)->hash) return 1;
93 + else return strcmp(((struct config *)a)->name, ((struct config *)b)->name);
94 }
95
96 avl_tree_lock config_root_index = {
97 - { NULL, config_compare },
98 - AVL_LOCK_INITIALIZER
97 + { NULL, config_compare },
98 + AVL_LOCK_INITIALIZER
99 };
100
101 #define config_index_add(cfg) avl_insert_lock(&config_root_index, (avl *)(cfg))
102 #define config_index_del(cfg) avl_remove_lock(&config_root_index, (avl *)(cfg))
103
104 static struct config *config_index_find(const char *name, uint32_t hash) {
105 - struct config tmp;
106 - tmp.hash = (hash)?hash:simple_hash(name);
107 - tmp.name = (char *)name;
105 + struct config tmp;
106 + tmp.hash = (hash)?hash:simple_hash(name);
107 + tmp.name = (char *)name;
108
109 - return (struct config *)avl_search_lock(&config_root_index, (avl *) &tmp);
109 + return (struct config *)avl_search_lock(&config_root_index, (avl *) &tmp);
110 }
111
112
@@ -114,31 +114,31 @@ static struct config *config_index_find(const char *name, uint32_t hash) {
114 // config section methods
115
116 static inline struct config *config_section_find(const char *section) {
117 - return config_index_find(section, 0);
117 + return config_index_find(section, 0);
118 }
119
120 static inline struct config *config_section_create(const char *section)
121 {
122 - debug(D_CONFIG, "Creating section '%s'.", section);
122 + debug(D_CONFIG, "Creating section '%s'.", section);
123
124 - struct config *co = callocz(1, sizeof(struct config));
125 - co->name = strdupz(section);
126 - co->hash = simple_hash(co->name);
124 + struct config *co = callocz(1, sizeof(struct config));
125 + co->name = strdupz(section);
126 + co->hash = simple_hash(co->name);
127
128 - avl_init_lock(&co->values_index, config_value_compare);
128 + avl_init_lock(&co->values_index, config_value_compare);
129
130 - config_index_add(co);
130 + config_index_add(co);
131
132 - config_global_write_lock();
133 - struct config *co2 = config_root;
134 - if(co2) {
135 - while (co2->next) co2 = co2->next;
136 - co2->next = co;
137 - }
138 - else config_root = co;
139 - config_global_unlock();
132 + config_global_write_lock();
133 + struct config *co2 = config_root;
134 + if(co2) {
135 + while (co2->next) co2 = co2->next;
136 + co2->next = co;
137 + }
138 + else config_root = co;
139 + config_global_unlock();
140
141 - return co;
141 + return co;
142 }
143
144
@@ -147,221 +147,221 @@ static inline struct config *config_section_create(const char *section)
147
148 static inline struct config_value *config_value_create(struct config *co, const char *name, const char *value)
149 {
150 - debug(D_CONFIG, "Creating config entry for name '%s', value '%s', in section '%s'.", name, value, co->name);
150 + debug(D_CONFIG, "Creating config entry for name '%s', value '%s', in section '%s'.", name, value, co->name);
151
152 - struct config_value *cv = callocz(1, sizeof(struct config_value));
153 - cv->name = strdupz(name);
154 - cv->hash = simple_hash(cv->name);
155 - cv->value = strdupz(value);
152 + struct config_value *cv = callocz(1, sizeof(struct config_value));
153 + cv->name = strdupz(name);
154 + cv->hash = simple_hash(cv->name);
155 + cv->value = strdupz(value);
156
157 - config_value_index_add(co, cv);
157 + config_value_index_add(co, cv);
158
159 - config_section_write_lock(co);
160 - struct config_value *cv2 = co->values;
161 - if(cv2) {
162 - while (cv2->next) cv2 = cv2->next;
163 - cv2->next = cv;
164 - }
165 - else co->values = cv;
166 - config_section_unlock(co);
159 + config_section_write_lock(co);
160 + struct config_value *cv2 = co->values;
161 + if(cv2) {
162 + while (cv2->next) cv2 = cv2->next;
163 + cv2->next = cv;
164 + }
165 + else co->values = cv;
166 + config_section_unlock(co);
167
168 - return cv;
168 + return cv;
169 }
170
171 int config_exists(const char *section, const char *name) {
172 - struct config_value *cv;
172 + struct config_value *cv;
173
174 - debug(D_CONFIG, "request to get config in section '%s', name '%s'", section, name);
174 + debug(D_CONFIG, "request to get config in section '%s', name '%s'", section, name);
175
176 - struct config *co = config_section_find(section);
177 - if(!co) return 0;
176 + struct config *co = config_section_find(section);
177 + if(!co) return 0;
178
179 - cv = config_value_index_find(co, name, 0);
180 - if(!cv) return 0;
179 + cv = config_value_index_find(co, name, 0);
180 + if(!cv) return 0;
181
182 - return 1;
182 + return 1;
183 }
184
185 int config_rename(const char *section, const char *old, const char *new) {
186 - struct config_value *cv, *cv2;
186 + struct config_value *cv, *cv2;
187
188 - debug(D_CONFIG, "request to rename config in section '%s', old name '%s', new name '%s'", section, old, new);
188 + debug(D_CONFIG, "request to rename config in section '%s', old name '%s', new name '%s'", section, old, new);
189
190 - struct config *co = config_section_find(section);
191 - if(!co) return -1;
190 + struct config *co = config_section_find(section);
191 + if(!co) return -1;
192
193 - config_section_write_lock(co);
193 + config_section_write_lock(co);
194
195 - cv = config_value_index_find(co, old, 0);
196 - if(!cv) goto cleanup;
195 + cv = config_value_index_find(co, old, 0);
196 + if(!cv) goto cleanup;
197
198 - cv2 = config_value_index_find(co, new, 0);
199 - if(cv2) goto cleanup;
198 + cv2 = config_value_index_find(co, new, 0);
199 + if(cv2) goto cleanup;
200
201 - config_value_index_del(co, cv);
201 + config_value_index_del(co, cv);
202
203 - freez(cv->name);
204 - cv->name = strdupz(new);
203 + freez(cv->name);
204 + cv->name = strdupz(new);
205
206 - cv->hash = simple_hash(cv->name);
206 + cv->hash = simple_hash(cv->name);
207
208 - config_value_index_add(co, cv);
209 - config_section_unlock(co);
208 + config_value_index_add(co, cv);
209 + config_section_unlock(co);
210
211 - return 0;
211 + return 0;
212
213 cleanup:
214 - config_section_unlock(co);
215 - return -1;
214 + config_section_unlock(co);
215 + return -1;
216 }
217
218 char *config_get(const char *section, const char *name, const char *default_value)
219 {
220 - struct config_value *cv;
221 -
222 - debug(D_CONFIG, "request to get config in section '%s', name '%s', default_value '%s'", section, name, default_value);
223 -
224 - struct config *co = config_section_find(section);
225 - if(!co) co = config_section_create(section);
226 -
227 - cv = config_value_index_find(co, name, 0);
228 - if(!cv) {
229 - cv = config_value_create(co, name, default_value);
230 - if(!cv) return NULL;
231 - }
232 - cv->flags |= CONFIG_VALUE_USED;
233 -
234 - if((cv->flags & CONFIG_VALUE_LOADED) || (cv->flags & CONFIG_VALUE_CHANGED)) {
235 - // this is a loaded value from the config file
236 - // if it is different that the default, mark it
237 - if(!(cv->flags & CONFIG_VALUE_CHECKED)) {
238 - if(strcmp(cv->value, default_value) != 0) cv->flags |= CONFIG_VALUE_CHANGED;
239 - cv->flags |= CONFIG_VALUE_CHECKED;
240 - }
241 - }
242 -
243 - return(cv->value);
220 + struct config_value *cv;
221 +
222 + debug(D_CONFIG, "request to get config in section '%s', name '%s', default_value '%s'", section, name, default_value);
223 +
224 + struct config *co = config_section_find(section);
225 + if(!co) co = config_section_create(section);
226 +
227 + cv = config_value_index_find(co, name, 0);
228 + if(!cv) {
229 + cv = config_value_create(co, name, default_value);
230 + if(!cv) return NULL;
231 + }
232 + cv->flags |= CONFIG_VALUE_USED;
233 +
234 + if((cv->flags & CONFIG_VALUE_LOADED) || (cv->flags & CONFIG_VALUE_CHANGED)) {
235 + // this is a loaded value from the config file
236 + // if it is different that the default, mark it
237 + if(!(cv->flags & CONFIG_VALUE_CHECKED)) {
238 + if(strcmp(cv->value, default_value) != 0) cv->flags |= CONFIG_VALUE_CHANGED;
239 + cv->flags |= CONFIG_VALUE_CHECKED;
240 + }
241 + }
242 +
243 + return(cv->value);
244 }
245
246 long long config_get_number(const char *section, const char *name, long long value)
247 {
248 - char buffer[100], *s;
249 - sprintf(buffer, "%lld", value);
248 + char buffer[100], *s;
249 + sprintf(buffer, "%lld", value);
250
251 - s = config_get(section, name, buffer);
252 - if(!s) return value;
251 + s = config_get(section, name, buffer);
252 + if(!s) return value;
253
254 - return strtoll(s, NULL, 0);
254 + return strtoll(s, NULL, 0);
255 }
256
257 int config_get_boolean(const char *section, const char *name, int value)
258 {
259 - char *s;
260 - if(value) s = "yes";
261 - else s = "no";
259 + char *s;
260 + if(value) s = "yes";
261 + else s = "no";
262
263 - s = config_get(section, name, s);
264 - if(!s) return value;
263 + s = config_get(section, name, s);
264 + if(!s) return value;
265
266 - if(!strcmp(s, "yes") || !strcmp(s, "auto") || !strcmp(s, "on demand")) return 1;
267 - return 0;
266 + if(!strcmp(s, "yes") || !strcmp(s, "auto") || !strcmp(s, "on demand")) return 1;
267 + return 0;
268 }
269
270 int config_get_boolean_ondemand(const char *section, const char *name, int value)
271 {
272 - char *s;
272 + char *s;
273
274 - if(value == CONFIG_ONDEMAND_ONDEMAND)
275 - s = "auto";
274 + if(value == CONFIG_ONDEMAND_ONDEMAND)
275 + s = "auto";
276
277 - else if(value == CONFIG_ONDEMAND_NO)
278 - s = "no";
277 + else if(value == CONFIG_ONDEMAND_NO)
278 + s = "no";
279
280 - else
281 - s = "yes";
280 + else
281 + s = "yes";
282
283 - s = config_get(section, name, s);
284 - if(!s) return value;
283 + s = config_get(section, name, s);
284 + if(!s) return value;
285
286 - if(!strcmp(s, "yes"))
287 - return CONFIG_ONDEMAND_YES;
288 - else if(!strcmp(s, "no"))
289 - return CONFIG_ONDEMAND_NO;
290 - else if(!strcmp(s, "auto") || !strcmp(s, "on demand"))
291 - return CONFIG_ONDEMAND_ONDEMAND;
286 + if(!strcmp(s, "yes"))
287 + return CONFIG_ONDEMAND_YES;
288 + else if(!strcmp(s, "no"))
289 + return CONFIG_ONDEMAND_NO;
290 + else if(!strcmp(s, "auto") || !strcmp(s, "on demand"))
291 + return CONFIG_ONDEMAND_ONDEMAND;
292
293 - return value;
293 + return value;
294 }
295
296 const char *config_set_default(const char *section, const char *name, const char *value)
297 {
298 - struct config_value *cv;
298 + struct config_value *cv;
299
300 - debug(D_CONFIG, "request to set config in section '%s', name '%s', value '%s'", section, name, value);
300 + debug(D_CONFIG, "request to set config in section '%s', name '%s', value '%s'", section, name, value);
301
302 - struct config *co = config_section_find(section);
303 - if(!co) return config_set(section, name, value);
302 + struct config *co = config_section_find(section);
303 + if(!co) return config_set(section, name, value);
304
305 - cv = config_value_index_find(co, name, 0);
306 - if(!cv) return config_set(section, name, value);
305 + cv = config_value_index_find(co, name, 0);
306 + if(!cv) return config_set(section, name, value);
307
308 - cv->flags |= CONFIG_VALUE_USED;
308 + cv->flags |= CONFIG_VALUE_USED;
309
310 - if(cv->flags & CONFIG_VALUE_LOADED)
311 - return cv->value;
310 + if(cv->flags & CONFIG_VALUE_LOADED)
311 + return cv->value;
312
313 - if(strcmp(cv->value, value) != 0) {
314 - cv->flags |= CONFIG_VALUE_CHANGED;
313 + if(strcmp(cv->value, value) != 0) {
314 + cv->flags |= CONFIG_VALUE_CHANGED;
315
316 - freez(cv->value);
317 - cv->value = strdupz(value);
318 - }
316 + freez(cv->value);
317 + cv->value = strdupz(value);
318 + }
319
320 - return cv->value;
320 + return cv->value;
321 }
322
323 const char *config_set(const char *section, const char *name, const char *value)
324 {
325 - struct config_value *cv;
325 + struct config_value *cv;
326
327 - debug(D_CONFIG, "request to set config in section '%s', name '%s', value '%s'", section, name, value);
327 + debug(D_CONFIG, "request to set config in section '%s', name '%s', value '%s'", section, name, value);
328
329 - struct config *co = config_section_find(section);
330 - if(!co) co = config_section_create(section);
329 + struct config *co = config_section_find(section);
330 + if(!co) co = config_section_create(section);
331
332 - cv = config_value_index_find(co, name, 0);
333 - if(!cv) cv = config_value_create(co, name, value);
334 - cv->flags |= CONFIG_VALUE_USED;
332 + cv = config_value_index_find(co, name, 0);
333 + if(!cv) cv = config_value_create(co, name, value);
334 + cv->flags |= CONFIG_VALUE_USED;
335
336 - if(strcmp(cv->value, value) != 0) {
337 - cv->flags |= CONFIG_VALUE_CHANGED;
336 + if(strcmp(cv->value, value) != 0) {
337 + cv->flags |= CONFIG_VALUE_CHANGED;
338
339 - freez(cv->value);
340 - cv->value = strdupz(value);
341 - }
339 + freez(cv->value);
340 + cv->value = strdupz(value);
341 + }
342
343 - return value;
343 + return value;
344 }
345
346 long long config_set_number(const char *section, const char *name, long long value)
347 {
348 - char buffer[100];
349 - sprintf(buffer, "%lld", value);
348 + char buffer[100];
349 + sprintf(buffer, "%lld", value);
350
351 - config_set(section, name, buffer);
351 + config_set(section, name, buffer);
352
353 - return value;
353 + return value;
354 }
355
356 int config_set_boolean(const char *section, const char *name, int value)
357 {
358 - char *s;
359 - if(value) s = "yes";
360 - else s = "no";
358 + char *s;
359 + if(value) s = "yes";
360 + else s = "no";
361
362 - config_set(section, name, s);
362 + config_set(section, name, s);
363
364 - return value;
364 + return value;
365 }
366
367
@@ -370,151 +370,151 @@ int config_set_boolean(const char *section, const char *name, int value)
370
371 int load_config(char *filename, int overwrite_used)
372 {
373 - int line = 0;
374 - struct config *co = NULL;
375 -
376 - char buffer[CONFIG_FILE_LINE_MAX + 1], *s;
377 -
378 - if(!filename) filename = CONFIG_DIR "/" CONFIG_FILENAME;
379 - FILE *fp = fopen(filename, "r");
380 - if(!fp) {
381 - error("Cannot open file '%s'", filename);
382 - return 0;
383 - }
384 -
385 - while(fgets(buffer, CONFIG_FILE_LINE_MAX, fp) != NULL) {
386 - buffer[CONFIG_FILE_LINE_MAX] = '\0';
387 - line++;
388 -
389 - s = trim(buffer);
390 - if(!s) {
391 - debug(D_CONFIG, "Ignoring line %d, it is empty.", line);
392 - continue;
393 - }
394 -
395 - int len = (int) strlen(s);
396 - if(*s == '[' && s[len - 1] == ']') {
397 - // new section
398 - s[len - 1] = '\0';
399 - s++;
400 -
401 - co = config_section_find(s);
402 - if(!co) co = config_section_create(s);
403 -
404 - continue;
405 - }
406 -
407 - if(!co) {
408 - // line outside a section
409 - error("Ignoring line %d ('%s'), it is outside all sections.", line, s);
410 - continue;
411 - }
412 -
413 - char *name = s;
414 - char *value = strchr(s, '=');
415 - if(!value) {
416 - error("Ignoring line %d ('%s'), there is no = in it.", line, s);
417 - continue;
418 - }
419 - *value = '\0';
420 - value++;
421 -
422 - name = trim(name);
423 - value = trim(value);
424 -
425 - if(!name) {
426 - error("Ignoring line %d, name is empty.", line);
427 - continue;
428 - }
429 - if(!value) {
430 - debug(D_CONFIG, "Ignoring line %d, value is empty.", line);
431 - continue;
432 - }
433 -
434 - struct config_value *cv = config_value_index_find(co, name, 0);
435 -
436 - if(!cv) cv = config_value_create(co, name, value);
437 - else {
438 - if(((cv->flags & CONFIG_VALUE_USED) && overwrite_used) || !(cv->flags & CONFIG_VALUE_USED)) {
439 - debug(D_CONFIG, "Line %d, overwriting '%s/%s'.", line, co->name, cv->name);
440 - freez(cv->value);
441 - cv->value = strdupz(value);
442 - }
443 - else
444 - debug(D_CONFIG, "Ignoring line %d, '%s/%s' is already present and used.", line, co->name, cv->name);
445 - }
446 - cv->flags |= CONFIG_VALUE_LOADED;
447 - }
448 -
449 - fclose(fp);
450 -
451 - return 1;
373 + int line = 0;
374 + struct config *co = NULL;
375 +
376 + char buffer[CONFIG_FILE_LINE_MAX + 1], *s;
377 +
378 + if(!filename) filename = CONFIG_DIR "/" CONFIG_FILENAME;
379 + FILE *fp = fopen(filename, "r");
380 + if(!fp) {
381 + error("Cannot open file '%s'", filename);
382 + return 0;
383 + }
384 +
385 + while(fgets(buffer, CONFIG_FILE_LINE_MAX, fp) != NULL) {
386 + buffer[CONFIG_FILE_LINE_MAX] = '\0';
387 + line++;
388 +
389 + s = trim(buffer);
390 + if(!s) {
391 + debug(D_CONFIG, "Ignoring line %d, it is empty.", line);
392 + continue;
393 + }
394 +
395 + int len = (int) strlen(s);
396 + if(*s == '[' && s[len - 1] == ']') {
397 + // new section
398 + s[len - 1] = '\0';
399 + s++;
400 +
401 + co = config_section_find(s);
402 + if(!co) co = config_section_create(s);
403 +
404 + continue;
405 + }
406 +
407 + if(!co) {
408 + // line outside a section
409 + error("Ignoring line %d ('%s'), it is outside all sections.", line, s);
410 + continue;
411 + }
412 +
413 + char *name = s;
414 + char *value = strchr(s, '=');
415 + if(!value) {
416 + error("Ignoring line %d ('%s'), there is no = in it.", line, s);
417 + continue;
418 + }
419 + *value = '\0';
420 + value++;
421 +
422 + name = trim(name);
423 + value = trim(value);
424 +
425 + if(!name) {
426 + error("Ignoring line %d, name is empty.", line);
427 + continue;
428 + }
429 + if(!value) {
430 + debug(D_CONFIG, "Ignoring line %d, value is empty.", line);
431 + continue;
432 + }
433 +
434 + struct config_value *cv = config_value_index_find(co, name, 0);
435 +
436 + if(!cv) cv = config_value_create(co, name, value);
437 + else {
438 + if(((cv->flags & CONFIG_VALUE_USED) && overwrite_used) || !(cv->flags & CONFIG_VALUE_USED)) {
439 + debug(D_CONFIG, "Line %d, overwriting '%s/%s'.", line, co->name, cv->name);
440 + freez(cv->value);
441 + cv->value = strdupz(value);
442 + }
443 + else
444 + debug(D_CONFIG, "Ignoring line %d, '%s/%s' is already present and used.", line, co->name, cv->name);
445 + }
446 + cv->flags |= CONFIG_VALUE_LOADED;
447 + }
448 +
449 + fclose(fp);
450 +
451 + return 1;
452 }
453
454 void generate_config(BUFFER *wb, int only_changed)
455 {
456 - int i, pri;
457 - struct config *co;
458 - struct config_value *cv;
459 -
460 - for(i = 0; i < 3 ;i++) {
461 - switch(i) {
462 - case 0:
463 - buffer_strcat(wb,
464 - "# NetData Configuration\n"
465 - "# You can uncomment and change any of the options below.\n"
466 - "# The value shown in the commented settings, is the default value.\n"
467 - "\n# global netdata configuration\n");
468 - break;
469 -
470 - case 1:
471 - buffer_strcat(wb, "\n\n# per plugin configuration\n");
472 - break;
473 -
474 - case 2:
475 - buffer_strcat(wb, "\n\n# per chart configuration\n");
476 - break;
477 - }
478 -
479 - config_global_write_lock();
480 - for(co = config_root; co ; co = co->next) {
481 - if(strcmp(co->name, "global") == 0 || strcmp(co->name, "plugins") == 0 || strcmp(co->name, "registry") == 0) pri = 0;
482 - else if(strncmp(co->name, "plugin:", 7) == 0) pri = 1;
483 - else pri = 2;
484 -
485 - if(i == pri) {
486 - int used = 0;
487 - int changed = 0;
488 - int count = 0;
489 -
490 - config_section_write_lock(co);
491 - for(cv = co->values; cv ; cv = cv->next) {
492 - used += (cv->flags & CONFIG_VALUE_USED)?1:0;
493 - changed += (cv->flags & CONFIG_VALUE_CHANGED)?1:0;
494 - count++;
495 - }
496 - config_section_unlock(co);
497 -
498 - if(!count) continue;
499 - if(only_changed && !changed) continue;
500 -
501 - if(!used) {
502 - buffer_sprintf(wb, "\n# node '%s' is not used.", co->name);
503 - }
504 -
505 - buffer_sprintf(wb, "\n[%s]\n", co->name);
506 -
507 - config_section_write_lock(co);
508 - for(cv = co->values; cv ; cv = cv->next) {
509 -
510 - if(used && !(cv->flags & CONFIG_VALUE_USED)) {
511 - buffer_sprintf(wb, "\n\t# option '%s' is not used.\n", cv->name);
512 - }
513 - buffer_sprintf(wb, "\t%s%s = %s\n", ((!(cv->flags & CONFIG_VALUE_CHANGED)) && (cv->flags & CONFIG_VALUE_USED))?"# ":"", cv->name, cv->value);
514 - }
515 - config_section_unlock(co);
516 - }
517 - }
518 - config_global_unlock();
519 - }
456 + int i, pri;
457 + struct config *co;
458 + struct config_value *cv;
459 +
460 + for(i = 0; i < 3 ;i++) {
461 + switch(i) {
462 + case 0:
463 + buffer_strcat(wb,
464 + "# NetData Configuration\n"
465 + "# You can uncomment and change any of the options below.\n"
466 + "# The value shown in the commented settings, is the default value.\n"
467 + "\n# global netdata configuration\n");
468 + break;
469 +
470 + case 1:
471 + buffer_strcat(wb, "\n\n# per plugin configuration\n");
472 + break;
473 +
474 + case 2:
475 + buffer_strcat(wb, "\n\n# per chart configuration\n");
476 + break;
477 + }
478 +
479 + config_global_write_lock();
480 + for(co = config_root; co ; co = co->next) {
481 + if(strcmp(co->name, "global") == 0 || strcmp(co->name, "plugins") == 0 || strcmp(co->name, "registry") == 0) pri = 0;
482 + else if(strncmp(co->name, "plugin:", 7) == 0) pri = 1;
483 + else pri = 2;
484 +
485 + if(i == pri) {
486 + int used = 0;
487 + int changed = 0;
488 + int count = 0;
489 +
490 + config_section_write_lock(co);
491 + for(cv = co->values; cv ; cv = cv->next) {
492 + used += (cv->flags & CONFIG_VALUE_USED)?1:0;
493 + changed += (cv->flags & CONFIG_VALUE_CHANGED)?1:0;
494 + count++;
495 + }
496 + config_section_unlock(co);
497 +
498 + if(!count) continue;
499 + if(only_changed && !changed) continue;
500 +
501 + if(!used) {
502 + buffer_sprintf(wb, "\n# node '%s' is not used.", co->name);
503 + }
504 +
505 + buffer_sprintf(wb, "\n[%s]\n", co->name);
506 +
507 + config_section_write_lock(co);
508 + for(cv = co->values; cv ; cv = cv->next) {
509 +
510 + if(used && !(cv->flags & CONFIG_VALUE_USED)) {
511 + buffer_sprintf(wb, "\n\t# option '%s' is not used.\n", cv->name);
512 + }
513 + buffer_sprintf(wb, "\t%s%s = %s\n", ((!(cv->flags & CONFIG_VALUE_CHANGED)) && (cv->flags & CONFIG_VALUE_USED))?"# ":"", cv->name, cv->value);
514 + }
515 + config_section_unlock(co);
516 + }
517 + }
518 + config_global_unlock();
519 + }
520 }
src/apps_plugin.c
+2331 -2331
@@ -36,7 +36,7 @@ int enable_guest_charts = 0;
36 // ----------------------------------------------------------------------------
37
38 void netdata_cleanup_and_exit(int ret) {
39 - exit(ret);
39 + exit(ret);
40 }
41
42
@@ -45,55 +45,55 @@ void netdata_cleanup_and_exit(int ret) {
45 // to retrieve settings of the system
46
47 long get_system_cpus(void) {
48 - procfile *ff = NULL;
48 + procfile *ff = NULL;
49
50 - int processors = 0;
50 + int processors = 0;
51
52 - char filename[FILENAME_MAX + 1];
53 - snprintfz(filename, FILENAME_MAX, "%s/proc/stat", host_prefix);
52 + char filename[FILENAME_MAX + 1];
53 + snprintfz(filename, FILENAME_MAX, "%s/proc/stat", host_prefix);
54
55 - ff = procfile_open(filename, NULL, PROCFILE_FLAG_DEFAULT);
56 - if(!ff) return 1;
55 + ff = procfile_open(filename, NULL, PROCFILE_FLAG_DEFAULT);
56 + if(!ff) return 1;
57
58 - ff = procfile_readall(ff);
59 - if(!ff) {
60 - procfile_close(ff);
61 - return 1;
62 - }
58 + ff = procfile_readall(ff);
59 + if(!ff) {
60 + procfile_close(ff);
61 + return 1;
62 + }
63
64 - unsigned int i;
65 - for(i = 0; i < procfile_lines(ff); i++) {
66 - if(!procfile_linewords(ff, i)) continue;
64 + unsigned int i;
65 + for(i = 0; i < procfile_lines(ff); i++) {
66 + if(!procfile_linewords(ff, i)) continue;
67
68 - if(strncmp(procfile_lineword(ff, i, 0), "cpu", 3) == 0) processors++;
69 - }
70 - processors--;
71 - if(processors < 1) processors = 1;
68 + if(strncmp(procfile_lineword(ff, i, 0), "cpu", 3) == 0) processors++;
69 + }
70 + processors--;
71 + if(processors < 1) processors = 1;
72
73 - procfile_close(ff);
74 - return processors;
73 + procfile_close(ff);
74 + return processors;
75 }
76
77 pid_t get_system_pid_max(void) {
78 - procfile *ff = NULL;
79 - pid_t mpid = 32768;
80 -
81 - char filename[FILENAME_MAX + 1];
82 - snprintfz(filename, FILENAME_MAX, "%s/proc/sys/kernel/pid_max", host_prefix);
83 - ff = procfile_open(filename, NULL, PROCFILE_FLAG_DEFAULT);
84 - if(!ff) return mpid;
85 -
86 - ff = procfile_readall(ff);
87 - if(!ff) {
88 - procfile_close(ff);
89 - return mpid;
90 - }
78 + procfile *ff = NULL;
79 + pid_t mpid = 32768;
80 +
81 + char filename[FILENAME_MAX + 1];
82 + snprintfz(filename, FILENAME_MAX, "%s/proc/sys/kernel/pid_max", host_prefix);
83 + ff = procfile_open(filename, NULL, PROCFILE_FLAG_DEFAULT);
84 + if(!ff) return mpid;
85 +
86 + ff = procfile_readall(ff);
87 + if(!ff) {
88 + procfile_close(ff);
89 + return mpid;
90 + }
91
92 - mpid = (pid_t)atoi(procfile_lineword(ff, 0, 0));
93 - if(!mpid) mpid = 32768;
92 + mpid = (pid_t)atoi(procfile_lineword(ff, 0, 0));
93 + if(!mpid) mpid = 32768;
94
95 - procfile_close(ff);
96 - return mpid;
95 + procfile_close(ff);
96 + return mpid;
97 }
98
99 // ----------------------------------------------------------------------------
@@ -101,68 +101,68 @@ pid_t get_system_pid_max(void) {
101 // target is the structure that process data are aggregated
102
103 struct target {
104 - char compare[MAX_COMPARE_NAME + 1];
105 - uint32_t comparehash;
106 - size_t comparelen;
107 -
108 - char id[MAX_NAME + 1];
109 - uint32_t idhash;
110 -
111 - char name[MAX_NAME + 1];
112 -
113 - uid_t uid;
114 - gid_t gid;
115 -
116 - unsigned long long minflt;
117 - unsigned long long cminflt;
118 - unsigned long long majflt;
119 - unsigned long long cmajflt;
120 - unsigned long long utime;
121 - unsigned long long stime;
122 - unsigned long long gtime;
123 - unsigned long long cutime;
124 - unsigned long long cstime;
125 - unsigned long long cgtime;
126 - unsigned long long num_threads;
127 - unsigned long long rss;
128 -
129 - unsigned long long statm_size;
130 - unsigned long long statm_resident;
131 - unsigned long long statm_share;
132 - unsigned long long statm_text;
133 - unsigned long long statm_lib;
134 - unsigned long long statm_data;
135 - unsigned long long statm_dirty;
136 -
137 - unsigned long long io_logical_bytes_read;
138 - unsigned long long io_logical_bytes_written;
139 - unsigned long long io_read_calls;
140 - unsigned long long io_write_calls;
141 - unsigned long long io_storage_bytes_read;
142 - unsigned long long io_storage_bytes_written;
143 - unsigned long long io_cancelled_write_bytes;
144 -
145 - int *fds;
146 - unsigned long long openfiles;
147 - unsigned long long openpipes;
148 - unsigned long long opensockets;
149 - unsigned long long openinotifies;
150 - unsigned long long openeventfds;
151 - unsigned long long opentimerfds;
152 - unsigned long long opensignalfds;
153 - unsigned long long openeventpolls;
154 - unsigned long long openother;
155 -
156 - unsigned long processes; // how many processes have been merged to this
157 - int exposed; // if set, we have sent this to netdata
158 - int hidden; // if set, we set the hidden flag on the dimension
159 - int debug;
160 - int ends_with;
161 - int starts_with; // if set, the compare string matches only the
162 - // beginning of the command
163 -
164 - struct target *target; // the one that will be reported to netdata
165 - struct target *next;
104 + char compare[MAX_COMPARE_NAME + 1];
105 + uint32_t comparehash;
106 + size_t comparelen;
107 +
108 + char id[MAX_NAME + 1];
109 + uint32_t idhash;
110 +
111 + char name[MAX_NAME + 1];
112 +
113 + uid_t uid;
114 + gid_t gid;
115 +
116 + unsigned long long minflt;
117 + unsigned long long cminflt;
118 + unsigned long long majflt;
119 + unsigned long long cmajflt;
120 + unsigned long long utime;
121 + unsigned long long stime;
122 + unsigned long long gtime;
123 + unsigned long long cutime;
124 + unsigned long long cstime;
125 + unsigned long long cgtime;
126 + unsigned long long num_threads;
127 + unsigned long long rss;
128 +
129 + unsigned long long statm_size;
130 + unsigned long long statm_resident;
131 + unsigned long long statm_share;
132 + unsigned long long statm_text;
133 + unsigned long long statm_lib;
134 + unsigned long long statm_data;
135 + unsigned long long statm_dirty;
136 +
137 + unsigned long long io_logical_bytes_read;
138 + unsigned long long io_logical_bytes_written;
139 + unsigned long long io_read_calls;
140 + unsigned long long io_write_calls;
141 + unsigned long long io_storage_bytes_read;
142 + unsigned long long io_storage_bytes_written;
143 + unsigned long long io_cancelled_write_bytes;
144 +
145 + int *fds;
146 + unsigned long long openfiles;
147 + unsigned long long openpipes;
148 + unsigned long long opensockets;
149 + unsigned long long openinotifies;
150 + unsigned long long openeventfds;
151 + unsigned long long opentimerfds;
152 + unsigned long long opensignalfds;
153 + unsigned long long openeventpolls;
154 + unsigned long long openother;
155 +
156 + unsigned long processes; // how many processes have been merged to this
157 + int exposed; // if set, we have sent this to netdata
158 + int hidden; // if set, we set the hidden flag on the dimension
159 + int debug;
160 + int ends_with;
161 + int starts_with; // if set, the compare string matches only the
162 + // beginning of the command
163 +
164 + struct target *target; // the one that will be reported to netdata
165 + struct target *next;
166 };
167
168
@@ -179,214 +179,214 @@ struct target *groups_root_target = NULL;
179
180 struct target *get_users_target(uid_t uid)
181 {
182 - struct target *w;
183 - for(w = users_root_target ; w ; w = w->next)
184 - if(w->uid == uid) return w;
182 + struct target *w;
183 + for(w = users_root_target ; w ; w = w->next)
184 + if(w->uid == uid) return w;
185
186 - w = callocz(sizeof(struct target), 1);
187 - snprintfz(w->compare, MAX_COMPARE_NAME, "%u", uid);
188 - w->comparehash = simple_hash(w->compare);
189 - w->comparelen = strlen(w->compare);
186 + w = callocz(sizeof(struct target), 1);
187 + snprintfz(w->compare, MAX_COMPARE_NAME, "%u", uid);
188 + w->comparehash = simple_hash(w->compare);
189 + w->comparelen = strlen(w->compare);
190
191 - snprintfz(w->id, MAX_NAME, "%u", uid);
192 - w->idhash = simple_hash(w->id);
191 + snprintfz(w->id, MAX_NAME, "%u", uid);
192 + w->idhash = simple_hash(w->id);
193
194 - struct passwd *pw = getpwuid(uid);
195 - if(!pw)
196 - snprintfz(w->name, MAX_NAME, "%u", uid);
197 - else
198 - snprintfz(w->name, MAX_NAME, "%s", pw->pw_name);
194 + struct passwd *pw = getpwuid(uid);
195 + if(!pw)
196 + snprintfz(w->name, MAX_NAME, "%u", uid);
197 + else
198 + snprintfz(w->name, MAX_NAME, "%s", pw->pw_name);
199
200 - netdata_fix_chart_name(w->name);
200 + netdata_fix_chart_name(w->name);
201
202 - w->uid = uid;
202 + w->uid = uid;
203
204 - w->next = users_root_target;
205 - users_root_target = w;
204 + w->next = users_root_target;
205 + users_root_target = w;
206
207 - if(unlikely(debug))
208 - fprintf(stderr, "apps.plugin: added uid %u ('%s') target\n", w->uid, w->name);
207 + if(unlikely(debug))
208 + fprintf(stderr, "apps.plugin: added uid %u ('%s') target\n", w->uid, w->name);
209
210 - return w;
210 + return w;
211 }
212
213 struct target *get_groups_target(gid_t gid)
214 {
215 - struct target *w;
216 - for(w = groups_root_target ; w ; w = w->next)
217 - if(w->gid == gid) return w;
215 + struct target *w;
216 + for(w = groups_root_target ; w ; w = w->next)
217 + if(w->gid == gid) return w;
218
219 - w = callocz(sizeof(struct target), 1);
220 - snprintfz(w->compare, MAX_COMPARE_NAME, "%u", gid);
221 - w->comparehash = simple_hash(w->compare);
222 - w->comparelen = strlen(w->compare);
219 + w = callocz(sizeof(struct target), 1);
220 + snprintfz(w->compare, MAX_COMPARE_NAME, "%u", gid);
221 + w->comparehash = simple_hash(w->compare);
222 + w->comparelen = strlen(w->compare);
223
224 - snprintfz(w->id, MAX_NAME, "%u", gid);
225 - w->idhash = simple_hash(w->id);
224 + snprintfz(w->id, MAX_NAME, "%u", gid);
225 + w->idhash = simple_hash(w->id);
226
227 - struct group *gr = getgrgid(gid);
228 - if(!gr)
229 - snprintfz(w->name, MAX_NAME, "%u", gid);
230 - else
231 - snprintfz(w->name, MAX_NAME, "%s", gr->gr_name);
227 + struct group *gr = getgrgid(gid);
228 + if(!gr)
229 + snprintfz(w->name, MAX_NAME, "%u", gid);
230 + else
231 + snprintfz(w->name, MAX_NAME, "%s", gr->gr_name);
232
233 - netdata_fix_chart_name(w->name);
233 + netdata_fix_chart_name(w->name);
234
235 - w->gid = gid;
235 + w->gid = gid;
236
237 - w->next = groups_root_target;
238 - groups_root_target = w;
237 + w->next = groups_root_target;
238 + groups_root_target = w;
239
240 - if(unlikely(debug))
241 - fprintf(stderr, "apps.plugin: added gid %u ('%s') target\n", w->gid, w->name);
240 + if(unlikely(debug))
241 + fprintf(stderr, "apps.plugin: added gid %u ('%s') target\n", w->gid, w->name);
242
243 - return w;
243 + return w;
244 }
245
246 // find or create a new target
247 // there are targets that are just aggregated to other target (the second argument)
248 struct target *get_apps_groups_target(const char *id, struct target *target) {
249 - int tdebug = 0, thidden = 0, ends_with = 0;
250 - const char *nid = id;
251 -
252 - while(nid[0] == '-' || nid[0] == '+' || nid[0] == '*') {
253 - if(nid[0] == '-') thidden = 1;
254 - if(nid[0] == '+') tdebug = 1;
255 - if(nid[0] == '*') ends_with = 1;
256 - nid++;
257 - }
258 - uint32_t hash = simple_hash(id);
259 -
260 - struct target *w, *last = apps_groups_root_target;
261 - for(w = apps_groups_root_target ; w ; w = w->next) {
262 - if(w->idhash == hash && strncmp(nid, w->id, MAX_NAME) == 0)
263 - return w;
264 -
265 - last = w;
266 - }
267 -
268 - w = callocz(sizeof(struct target), 1);
269 - strncpyz(w->id, nid, MAX_NAME);
270 - w->idhash = simple_hash(w->id);
271 -
272 - strncpyz(w->name, nid, MAX_NAME);
273 -
274 - strncpyz(w->compare, nid, MAX_COMPARE_NAME);
275 - size_t len = strlen(w->compare);
276 - if(w->compare[len - 1] == '*') {
277 - w->compare[len - 1] = '\0';
278 - w->starts_with = 1;
279 - }
280 - w->ends_with = ends_with;
281 -
282 - if(w->starts_with && w->ends_with)
283 - proc_pid_cmdline_is_needed = 1;
284 -
285 - w->comparehash = simple_hash(w->compare);
286 - w->comparelen = strlen(w->compare);
287 -
288 - w->hidden = thidden;
289 - w->debug = tdebug;
290 - w->target = target;
291 -
292 - // append it, to maintain the order in apps_groups.conf
293 - if(last) last->next = w;
294 - else apps_groups_root_target = w;
295 -
296 - if(unlikely(debug))
297 - fprintf(stderr, "apps.plugin: ADDING TARGET ID '%s', process name '%s' (%s), aggregated on target '%s', options: %s %s\n"
298 - , w->id
299 - , w->compare, (w->starts_with && w->ends_with)?"substring":((w->starts_with)?"prefix":((w->ends_with)?"suffix":"exact"))
300 - , w->target?w->target->id:w->id
301 - , (w->hidden)?"hidden":"-"
302 - , (w->debug)?"debug":"-"
303 - );
304 -
305 - return w;
249 + int tdebug = 0, thidden = 0, ends_with = 0;
250 + const char *nid = id;
251 +
252 + while(nid[0] == '-' || nid[0] == '+' || nid[0] == '*') {
253 + if(nid[0] == '-') thidden = 1;
254 + if(nid[0] == '+') tdebug = 1;
255 + if(nid[0] == '*') ends_with = 1;
256 + nid++;
257 + }
258 + uint32_t hash = simple_hash(id);
259 +
260 + struct target *w, *last = apps_groups_root_target;
261 + for(w = apps_groups_root_target ; w ; w = w->next) {
262 + if(w->idhash == hash && strncmp(nid, w->id, MAX_NAME) == 0)
263 + return w;
264 +
265 + last = w;
266 + }
267 +
268 + w = callocz(sizeof(struct target), 1);
269 + strncpyz(w->id, nid, MAX_NAME);
270 + w->idhash = simple_hash(w->id);
271 +
272 + strncpyz(w->name, nid, MAX_NAME);
273 +
274 + strncpyz(w->compare, nid, MAX_COMPARE_NAME);
275 + size_t len = strlen(w->compare);
276 + if(w->compare[len - 1] == '*') {
277 + w->compare[len - 1] = '\0';
278 + w->starts_with = 1;
279 + }
280 + w->ends_with = ends_with;
281 +
282 + if(w->starts_with && w->ends_with)
283 + proc_pid_cmdline_is_needed = 1;
284 +
285 + w->comparehash = simple_hash(w->compare);
286 + w->comparelen = strlen(w->compare);
287 +
288 + w->hidden = thidden;
289 + w->debug = tdebug;
290 + w->target = target;
291 +
292 + // append it, to maintain the order in apps_groups.conf
293 + if(last) last->next = w;
294 + else apps_groups_root_target = w;
295 +
296 + if(unlikely(debug))
297 + fprintf(stderr, "apps.plugin: ADDING TARGET ID '%s', process name '%s' (%s), aggregated on target '%s', options: %s %s\n"
298 + , w->id
299 + , w->compare, (w->starts_with && w->ends_with)?"substring":((w->starts_with)?"prefix":((w->ends_with)?"suffix":"exact"))
300 + , w->target?w->target->id:w->id
301 + , (w->hidden)?"hidden":"-"
302 + , (w->debug)?"debug":"-"
303 + );
304 +
305 + return w;
306 }
307
308 // read the apps_groups.conf file
309 int read_apps_groups_conf(const char *name)
310 {
311 - char filename[FILENAME_MAX + 1];
312 -
313 - snprintfz(filename, FILENAME_MAX, "%s/apps_%s.conf", config_dir, name);
311 + char filename[FILENAME_MAX + 1];
312
315 - if(unlikely(debug))
316 - fprintf(stderr, "apps.plugin: process groups file: '%s'\n", filename);
313 + snprintfz(filename, FILENAME_MAX, "%s/apps_%s.conf", config_dir, name);
314
318 - // ----------------------------------------
315 + if(unlikely(debug))
316 + fprintf(stderr, "apps.plugin: process groups file: '%s'\n", filename);
317
320 - procfile *ff = procfile_open(filename, " :\t", PROCFILE_FLAG_DEFAULT);
321 - if(!ff) return 1;
318 + // ----------------------------------------
319
323 - procfile_set_quotes(ff, "'\"");
320 + procfile *ff = procfile_open(filename, " :\t", PROCFILE_FLAG_DEFAULT);
321 + if(!ff) return 1;
322
325 - ff = procfile_readall(ff);
326 - if(!ff) {
327 - procfile_close(ff);
328 - return 1;
329 - }
323 + procfile_set_quotes(ff, "'\"");
324
331 - unsigned long line, lines = procfile_lines(ff);
332 -
333 - for(line = 0; line < lines ;line++) {
334 - unsigned long word, words = procfile_linewords(ff, line);
335 - struct target *w = NULL;
336 -
337 - char *t = procfile_lineword(ff, line, 0);
338 - if(!t || !*t) continue;
325 + ff = procfile_readall(ff);
326 + if(!ff) {
327 + procfile_close(ff);
328 + return 1;
329 + }
330
340 - for(word = 0; word < words ;word++) {
341 - char *s = procfile_lineword(ff, line, word);
342 - if(!s || !*s) continue;
343 - if(*s == '#') break;
331 + unsigned long line, lines = procfile_lines(ff);
332
345 - if(t == s) continue;
333 + for(line = 0; line < lines ;line++) {
334 + unsigned long word, words = procfile_linewords(ff, line);
335 + struct target *w = NULL;
336
347 - struct target *n = get_apps_groups_target(s, w);
348 - if(!n) {
349 - error("Cannot create target '%s' (line %lu, word %lu)", s, line, word);
350 - continue;
351 - }
337 + char *t = procfile_lineword(ff, line, 0);
338 + if(!t || !*t) continue;
339
353 - if(!w) w = n;
354 - }
340 + for(word = 0; word < words ;word++) {
341 + char *s = procfile_lineword(ff, line, word);
342 + if(!s || !*s) continue;
343 + if(*s == '#') break;
344
356 - if(w) {
357 - int tdebug = 0, thidden = 0;
345 + if(t == s) continue;
346
359 - while(t[0] == '-' || t[0] == '+') {
360 - if(t[0] == '-') thidden = 1;
361 - if(t[0] == '+') tdebug = 1;
362 - t++;
363 - }
347 + struct target *n = get_apps_groups_target(s, w);
348 + if(!n) {
349 + error("Cannot create target '%s' (line %lu, word %lu)", s, line, word);
350 + continue;
351 + }
352
365 - strncpyz(w->name, t, MAX_NAME);
366 - w->hidden = thidden;
367 - w->debug = tdebug;
353 + if(!w) w = n;
354 + }
355
369 - if(unlikely(debug))
370 - fprintf(stderr, "apps.plugin: AGGREGATION TARGET NAME '%s' on ID '%s', process name '%s' (%s), aggregated on target '%s', options: %s %s\n"
371 - , w->name
372 - , w->id
373 - , w->compare, (w->starts_with && w->ends_with)?"substring":((w->starts_with)?"prefix":((w->ends_with)?"suffix":"exact"))
374 - , w->target?w->target->id:w->id
375 - , (w->hidden)?"hidden":"-"
376 - , (w->debug)?"debug":"-"
377 - );
378 - }
379 - }
356 + if(w) {
357 + int tdebug = 0, thidden = 0;
358 +
359 + while(t[0] == '-' || t[0] == '+') {
360 + if(t[0] == '-') thidden = 1;
361 + if(t[0] == '+') tdebug = 1;
362 + t++;
363 + }
364 +
365 + strncpyz(w->name, t, MAX_NAME);
366 + w->hidden = thidden;
367 + w->debug = tdebug;
368 +
369 + if(unlikely(debug))
370 + fprintf(stderr, "apps.plugin: AGGREGATION TARGET NAME '%s' on ID '%s', process name '%s' (%s), aggregated on target '%s', options: %s %s\n"
371 + , w->name
372 + , w->id
373 + , w->compare, (w->starts_with && w->ends_with)?"substring":((w->starts_with)?"prefix":((w->ends_with)?"suffix":"exact"))
374 + , w->target?w->target->id:w->id
375 + , (w->hidden)?"hidden":"-"
376 + , (w->debug)?"debug":"-"
377 + );
378 + }
379 + }
380
381 - procfile_close(ff);
381 + procfile_close(ff);
382
383 - apps_groups_default_target = get_apps_groups_target("p+!o@w#e$i^r&7*5(-i)l-o_", NULL); // match nothing
384 - if(!apps_groups_default_target)
385 - error("Cannot create default target");
386 - else
387 - strncpyz(apps_groups_default_target->name, "other", MAX_NAME);
383 + apps_groups_default_target = get_apps_groups_target("p+!o@w#e$i^r&7*5(-i)l-o_", NULL); // match nothing
384 + if(!apps_groups_default_target)
385 + error("Cannot create default target");
386 + else
387 + strncpyz(apps_groups_default_target->name, "other", MAX_NAME);
388
389 - return 0;
389 + return 0;
390 }
391
392
@@ -395,174 +395,174 @@ int read_apps_groups_conf(const char *name)
395 // see: man proc
396
397 struct pid_stat {
398 - int32_t pid;
399 - char comm[MAX_COMPARE_NAME + 1];
400 - char cmdline[MAX_CMDLINE + 1];
401 -
402 - // char state;
403 - int32_t ppid;
404 - // int32_t pgrp;
405 - // int32_t session;
406 - // int32_t tty_nr;
407 - // int32_t tpgid;
408 - // uint64_t flags;
409 -
410 - // these are raw values collected
411 - unsigned long long minflt_raw;
412 - unsigned long long cminflt_raw;
413 - unsigned long long majflt_raw;
414 - unsigned long long cmajflt_raw;
415 - unsigned long long utime_raw;
416 - unsigned long long stime_raw;
417 - unsigned long long gtime_raw; // guest_time
418 - unsigned long long cutime_raw;
419 - unsigned long long cstime_raw;
420 - unsigned long long cgtime_raw; // cguest_time
421 -
422 - // these are rates
423 - unsigned long long minflt;
424 - unsigned long long cminflt;
425 - unsigned long long majflt;
426 - unsigned long long cmajflt;
427 - unsigned long long utime;
428 - unsigned long long stime;
429 - unsigned long long gtime;
430 - unsigned long long cutime;
431 - unsigned long long cstime;
432 - unsigned long long cgtime;
433 -
434 - // int64_t priority;
435 - // int64_t nice;
436 - int32_t num_threads;
437 - // int64_t itrealvalue;
438 - // unsigned long long starttime;
439 - // unsigned long long vsize;
440 - unsigned long long rss;
441 - // unsigned long long rsslim;
442 - // unsigned long long starcode;
443 - // unsigned long long endcode;
444 - // unsigned long long startstack;
445 - // unsigned long long kstkesp;
446 - // unsigned long long kstkeip;
447 - // uint64_t signal;
448 - // uint64_t blocked;
449 - // uint64_t sigignore;
450 - // uint64_t sigcatch;
451 - // uint64_t wchan;
452 - // uint64_t nswap;
453 - // uint64_t cnswap;
454 - // int32_t exit_signal;
455 - // int32_t processor;
456 - // uint32_t rt_priority;
457 - // uint32_t policy;
458 - // unsigned long long delayacct_blkio_ticks;
459 -
460 - uid_t uid;
461 - gid_t gid;
462 -
463 - unsigned long long statm_size;
464 - unsigned long long statm_resident;
465 - unsigned long long statm_share;
466 - unsigned long long statm_text;
467 - unsigned long long statm_lib;
468 - unsigned long long statm_data;
469 - unsigned long long statm_dirty;
470 -
471 - unsigned long long io_logical_bytes_read_raw;
472 - unsigned long long io_logical_bytes_written_raw;
473 - unsigned long long io_read_calls_raw;
474 - unsigned long long io_write_calls_raw;
475 - unsigned long long io_storage_bytes_read_raw;
476 - unsigned long long io_storage_bytes_written_raw;
477 - unsigned long long io_cancelled_write_bytes_raw;
478 -
479 - unsigned long long io_logical_bytes_read;
480 - unsigned long long io_logical_bytes_written;
481 - unsigned long long io_read_calls;
482 - unsigned long long io_write_calls;
483 - unsigned long long io_storage_bytes_read;
484 - unsigned long long io_storage_bytes_written;
485 - unsigned long long io_cancelled_write_bytes;
486 -
487 - int *fds; // array of fds it uses
488 - int fds_size; // the size of the fds array
489 -
490 - int children_count; // number of processes directly referencing this
491 - int keep; // 1 when we need to keep this process in memory even after it exited
492 - int keeploops; // increases by 1 every time keep is 1 and updated 0
493 - int updated; // 1 when the process is currently running
494 - int merged; // 1 when it has been merged to its parent
495 - int new_entry; // 1 when this is a new process, just saw for the first time
496 - int read; // 1 when we have already read this process for this iteration
497 - int sortlist; // higher numbers = top on the process tree
498 - // each process gets a unique number
499 -
500 - struct target *target; // app_groups.conf targets
501 - struct target *user_target; // uid based targets
502 - struct target *group_target; // gid based targets
503 -
504 - unsigned long long stat_collected_usec;
505 - unsigned long long last_stat_collected_usec;
506 -
507 - unsigned long long io_collected_usec;
508 - unsigned long long last_io_collected_usec;
509 -
510 - char *stat_filename;
511 - char *statm_filename;
512 - char *io_filename;
513 - char *cmdline_filename;
514 -
515 - struct pid_stat *parent;
516 - struct pid_stat *prev;
517 - struct pid_stat *next;
398 + int32_t pid;
399 + char comm[MAX_COMPARE_NAME + 1];
400 + char cmdline[MAX_CMDLINE + 1];
401 +
402 + // char state;
403 + int32_t ppid;
404 + // int32_t pgrp;
405 + // int32_t session;
406 + // int32_t tty_nr;
407 + // int32_t tpgid;
408 + // uint64_t flags;
409 +
410 + // these are raw values collected
411 + unsigned long long minflt_raw;
412 + unsigned long long cminflt_raw;
413 + unsigned long long majflt_raw;
414 + unsigned long long cmajflt_raw;
415 + unsigned long long utime_raw;
416 + unsigned long long stime_raw;
417 + unsigned long long gtime_raw; // guest_time
418 + unsigned long long cutime_raw;
419 + unsigned long long cstime_raw;
420 + unsigned long long cgtime_raw; // cguest_time
421 +
422 + // these are rates
423 + unsigned long long minflt;
424 + unsigned long long cminflt;
425 + unsigned long long majflt;
426 + unsigned long long cmajflt;
427 + unsigned long long utime;
428 + unsigned long long stime;
429 + unsigned long long gtime;
430 + unsigned long long cutime;
431 + unsigned long long cstime;
432 + unsigned long long cgtime;
433 +
434 + // int64_t priority;
435 + // int64_t nice;
436 + int32_t num_threads;
437 + // int64_t itrealvalue;
438 + // unsigned long long starttime;
439 + // unsigned long long vsize;
440 + unsigned long long rss;
441 + // unsigned long long rsslim;
442 + // unsigned long long starcode;
443 + // unsigned long long endcode;
444 + // unsigned long long startstack;
445 + // unsigned long long kstkesp;
446 + // unsigned long long kstkeip;
447 + // uint64_t signal;
448 + // uint64_t blocked;
449 + // uint64_t sigignore;
450 + // uint64_t sigcatch;
451 + // uint64_t wchan;
452 + // uint64_t nswap;
453 + // uint64_t cnswap;
454 + // int32_t exit_signal;
455 + // int32_t processor;
456 + // uint32_t rt_priority;
457 + // uint32_t policy;
458 + // unsigned long long delayacct_blkio_ticks;
459 +
460 + uid_t uid;
461 + gid_t gid;
462 +
463 + unsigned long long statm_size;
464 + unsigned long long statm_resident;
465 + unsigned long long statm_share;
466 + unsigned long long statm_text;
467 + unsigned long long statm_lib;
468 + unsigned long long statm_data;
469 + unsigned long long statm_dirty;
470 +
471 + unsigned long long io_logical_bytes_read_raw;
472 + unsigned long long io_logical_bytes_written_raw;
473 + unsigned long long io_read_calls_raw;
474 + unsigned long long io_write_calls_raw;
475 + unsigned long long io_storage_bytes_read_raw;
476 + unsigned long long io_storage_bytes_written_raw;
477 + unsigned long long io_cancelled_write_bytes_raw;
478 +
479 + unsigned long long io_logical_bytes_read;
480 + unsigned long long io_logical_bytes_written;
481 + unsigned long long io_read_calls;
482 + unsigned long long io_write_calls;
483 + unsigned long long io_storage_bytes_read;
484 + unsigned long long io_storage_bytes_written;
485 + unsigned long long io_cancelled_write_bytes;
486 +
487 + int *fds; // array of fds it uses
488 + int fds_size; // the size of the fds array
489 +
490 + int children_count; // number of processes directly referencing this
491 + int keep; // 1 when we need to keep this process in memory even after it exited
492 + int keeploops; // increases by 1 every time keep is 1 and updated 0
493 + int updated; // 1 when the process is currently running
494 + int merged; // 1 when it has been merged to its parent
495 + int new_entry; // 1 when this is a new process, just saw for the first time
496 + int read; // 1 when we have already read this process for this iteration
497 + int sortlist; // higher numbers = top on the process tree
498 + // each process gets a unique number
499 +
500 + struct target *target; // app_groups.conf targets
501 + struct target *user_target; // uid based targets
502 + struct target *group_target; // gid based targets
503 +
504 + unsigned long long stat_collected_usec;
505 + unsigned long long last_stat_collected_usec;
506 +
507 + unsigned long long io_collected_usec;
508 + unsigned long long last_io_collected_usec;
509 +
510 + char *stat_filename;
511 + char *statm_filename;
512 + char *io_filename;
513 + char *cmdline_filename;
514 +
515 + struct pid_stat *parent;
516 + struct pid_stat *prev;
517 + struct pid_stat *next;
518 } *root_of_pids = NULL, **all_pids;
519
520 long all_pids_count = 0;
521
522 struct pid_stat *get_pid_entry(pid_t pid) {
523 - if(all_pids[pid]) {
524 - all_pids[pid]->new_entry = 0;
525 - return all_pids[pid];
526 - }
523 + if(all_pids[pid]) {
524 + all_pids[pid]->new_entry = 0;
525 + return all_pids[pid];
526 + }
527
528 - all_pids[pid] = callocz(sizeof(struct pid_stat), 1);
529 - all_pids[pid]->fds = callocz(sizeof(int), 100);
530 - all_pids[pid]->fds_size = 100;
528 + all_pids[pid] = callocz(sizeof(struct pid_stat), 1);
529 + all_pids[pid]->fds = callocz(sizeof(int), 100);
530 + all_pids[pid]->fds_size = 100;
531
532 - if(root_of_pids) root_of_pids->prev = all_pids[pid];
533 - all_pids[pid]->next = root_of_pids;
534 - root_of_pids = all_pids[pid];
532 + if(root_of_pids) root_of_pids->prev = all_pids[pid];
533 + all_pids[pid]->next = root_of_pids;
534 + root_of_pids = all_pids[pid];
535
536 - all_pids[pid]->pid = pid;
537 - all_pids[pid]->new_entry = 1;
536 + all_pids[pid]->pid = pid;
537 + all_pids[pid]->new_entry = 1;
538
539 - all_pids_count++;
539 + all_pids_count++;
540
541 - return all_pids[pid];
541 + return all_pids[pid];
542 }
543
544 void del_pid_entry(pid_t pid) {
545 - if(!all_pids[pid]) {
546 - error("attempted to free pid %d that is not allocated.", pid);
547 - return;
548 - }
549 -
550 - if(unlikely(debug))
551 - fprintf(stderr, "apps.plugin: process %d %s exited, deleting it.\n", pid, all_pids[pid]->comm);
552 -
553 - if(root_of_pids == all_pids[pid]) root_of_pids = all_pids[pid]->next;
554 - if(all_pids[pid]->next) all_pids[pid]->next->prev = all_pids[pid]->prev;
555 - if(all_pids[pid]->prev) all_pids[pid]->prev->next = all_pids[pid]->next;
556 -
557 - if(all_pids[pid]->fds) freez(all_pids[pid]->fds);
558 - if(all_pids[pid]->stat_filename) freez(all_pids[pid]->stat_filename);
559 - if(all_pids[pid]->statm_filename) freez(all_pids[pid]->statm_filename);
560 - if(all_pids[pid]->io_filename) freez(all_pids[pid]->io_filename);
561 - if(all_pids[pid]->cmdline_filename) freez(all_pids[pid]->cmdline_filename);
562 - freez(all_pids[pid]);
563 -
564 - all_pids[pid] = NULL;
565 - all_pids_count--;
545 + if(!all_pids[pid]) {
546 + error("attempted to free pid %d that is not allocated.", pid);
547 + return;
548 + }
549 +
550 + if(unlikely(debug))
551 + fprintf(stderr, "apps.plugin: process %d %s exited, deleting it.\n", pid, all_pids[pid]->comm);
552 +
553 + if(root_of_pids == all_pids[pid]) root_of_pids = all_pids[pid]->next;
554 + if(all_pids[pid]->next) all_pids[pid]->next->prev = all_pids[pid]->prev;
555 + if(all_pids[pid]->prev) all_pids[pid]->prev->next = all_pids[pid]->next;
556 +
557 + if(all_pids[pid]->fds) freez(all_pids[pid]->fds);
558 + if(all_pids[pid]->stat_filename) freez(all_pids[pid]->stat_filename);
559 + if(all_pids[pid]->statm_filename) freez(all_pids[pid]->statm_filename);
560 + if(all_pids[pid]->io_filename) freez(all_pids[pid]->io_filename);
561 + if(all_pids[pid]->cmdline_filename) freez(all_pids[pid]->cmdline_filename);
562 + freez(all_pids[pid]);
563 +
564 + all_pids[pid] = NULL;
565 + all_pids_count--;
566 }
567
568
@@ -570,160 +570,160 @@ void del_pid_entry(pid_t pid) {
570 // update pids from proc
571
572 int read_proc_pid_cmdline(struct pid_stat *p) {
573 -
574 - if(unlikely(!p->cmdline_filename)) {
575 - char filename[FILENAME_MAX + 1];
576 - snprintfz(filename, FILENAME_MAX, "%s/proc/%d/cmdline", host_prefix, p->pid);
577 - p->cmdline_filename = strdupz(filename);
578 - }
573 +
574 + if(unlikely(!p->cmdline_filename)) {
575 + char filename[FILENAME_MAX + 1];
576 + snprintfz(filename, FILENAME_MAX, "%s/proc/%d/cmdline", host_prefix, p->pid);
577 + p->cmdline_filename = strdupz(filename);
578 + }
579
580 - int fd = open(p->cmdline_filename, O_RDONLY, 0666);
581 - if(unlikely(fd == -1)) goto cleanup;
580 + int fd = open(p->cmdline_filename, O_RDONLY, 0666);
581 + if(unlikely(fd == -1)) goto cleanup;
582
583 - ssize_t i, bytes = read(fd, p->cmdline, MAX_CMDLINE);
584 - close(fd);
583 + ssize_t i, bytes = read(fd, p->cmdline, MAX_CMDLINE);
584 + close(fd);
585
586 - if(unlikely(bytes <= 0)) goto cleanup;
586 + if(unlikely(bytes <= 0)) goto cleanup;
587
588 - p->cmdline[bytes] = '\0';
589 - for(i = 0; i < bytes ; i++)
590 - if(unlikely(!p->cmdline[i])) p->cmdline[i] = ' ';
588 + p->cmdline[bytes] = '\0';
589 + for(i = 0; i < bytes ; i++)
590 + if(unlikely(!p->cmdline[i])) p->cmdline[i] = ' ';
591
592 - if(unlikely(debug))
593 - fprintf(stderr, "Read file '%s' contents: %s\n", p->cmdline_filename, p->cmdline);
592 + if(unlikely(debug))
593 + fprintf(stderr, "Read file '%s' contents: %s\n", p->cmdline_filename, p->cmdline);
594
595 - return 0;
595 + return 0;
596
597 cleanup:
598 - // copy the command to the command line
599 - strncpyz(p->cmdline, p->comm, MAX_CMDLINE);
600 - return 0;
598 + // copy the command to the command line
599 + strncpyz(p->cmdline, p->comm, MAX_CMDLINE);
600 + return 0;
601 }
602
603 int read_proc_pid_ownership(struct pid_stat *p) {
604 - if(unlikely(!p->stat_filename)) {
605 - error("pid %d does not have a stat_filename", p->pid);
606 - return 1;
607 - }
604 + if(unlikely(!p->stat_filename)) {
605 + error("pid %d does not have a stat_filename", p->pid);
606 + return 1;
607 + }
608
609 - // ----------------------------------------
610 - // read uid and gid
609 + // ----------------------------------------
610 + // read uid and gid
611
612 - struct stat st;
613 - if(stat(p->stat_filename, &st) != 0) {
614 - error("Cannot stat file '%s'", p->stat_filename);
615 - return 1;
616 - }
612 + struct stat st;
613 + if(stat(p->stat_filename, &st) != 0) {
614 + error("Cannot stat file '%s'", p->stat_filename);
615 + return 1;
616 + }
617
618 - p->uid = st.st_uid;
619 - p->gid = st.st_gid;
618 + p->uid = st.st_uid;
619 + p->gid = st.st_gid;
620
621 - return 0;
621 + return 0;
622 }
623
624 int read_proc_pid_stat(struct pid_stat *p) {
625 - static procfile *ff = NULL;
626 -
627 - if(unlikely(!p->stat_filename)) {
628 - char filename[FILENAME_MAX + 1];
629 - snprintfz(filename, FILENAME_MAX, "%s/proc/%d/stat", host_prefix, p->pid);
630 - p->stat_filename = strdupz(filename);
631 - }
632 -
633 - int set_quotes = (!ff)?1:0;
634 -
635 - ff = procfile_reopen(ff, p->stat_filename, NULL, PROCFILE_FLAG_NO_ERROR_ON_FILE_IO);
636 - if(unlikely(!ff)) goto cleanup;
637 -
638 - // if(set_quotes) procfile_set_quotes(ff, "()");
639 - if(set_quotes) procfile_set_open_close(ff, "(", ")");
640 -
641 - ff = procfile_readall(ff);
642 - if(unlikely(!ff)) goto cleanup;
643 -
644 - p->last_stat_collected_usec = p->stat_collected_usec;
645 - p->stat_collected_usec = time_usec();
646 - file_counter++;
647 -
648 - // p->pid = atol(procfile_lineword(ff, 0, 0+i));
649 -
650 - strncpyz(p->comm, procfile_lineword(ff, 0, 1), MAX_COMPARE_NAME);
651 -
652 - // p->state = *(procfile_lineword(ff, 0, 2));
653 - p->ppid = (int32_t) atol(procfile_lineword(ff, 0, 3));
654 - // p->pgrp = atol(procfile_lineword(ff, 0, 4));
655 - // p->session = atol(procfile_lineword(ff, 0, 5));
656 - // p->tty_nr = atol(procfile_lineword(ff, 0, 6));
657 - // p->tpgid = atol(procfile_lineword(ff, 0, 7));
658 - // p->flags = strtoull(procfile_lineword(ff, 0, 8), NULL, 10);
659 -
660 - unsigned long long last;
661 -
662 - last = p->minflt_raw;
663 - p->minflt_raw = strtoull(procfile_lineword(ff, 0, 9), NULL, 10);
664 - p->minflt = (p->minflt_raw - last) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
665 -
666 - last = p->cminflt_raw;
667 - p->cminflt_raw = strtoull(procfile_lineword(ff, 0, 10), NULL, 10);
668 - p->cminflt = (p->cminflt_raw - last) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
669 -
670 - last = p->majflt_raw;
671 - p->majflt_raw = strtoull(procfile_lineword(ff, 0, 11), NULL, 10);
672 - p->majflt = (p->majflt_raw - last) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
673 -
674 - last = p->cmajflt_raw;
675 - p->cmajflt_raw = strtoull(procfile_lineword(ff, 0, 12), NULL, 10);
676 - p->cmajflt = (p->cmajflt_raw - last) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
677 -
678 - last = p->utime_raw;
679 - p->utime_raw = strtoull(procfile_lineword(ff, 0, 13), NULL, 10);
680 - p->utime = (p->utime_raw - last) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
681 -
682 - last = p->stime_raw;
683 - p->stime_raw = strtoull(procfile_lineword(ff, 0, 14), NULL, 10);
684 - p->stime = (p->stime_raw - last) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
685 -
686 - last = p->cutime_raw;
687 - p->cutime_raw = strtoull(procfile_lineword(ff, 0, 15), NULL, 10);
688 - p->cutime = (p->cutime_raw - last) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
689 -
690 - last = p->cstime_raw;
691 - p->cstime_raw = strtoull(procfile_lineword(ff, 0, 16), NULL, 10);
692 - p->cstime = (p->cstime_raw - last) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
693 -
694 - // p->priority = strtoull(procfile_lineword(ff, 0, 17), NULL, 10);
695 - // p->nice = strtoull(procfile_lineword(ff, 0, 18), NULL, 10);
696 - p->num_threads = (int32_t) atol(procfile_lineword(ff, 0, 19));
697 - // p->itrealvalue = strtoull(procfile_lineword(ff, 0, 20), NULL, 10);
698 - // p->starttime = strtoull(procfile_lineword(ff, 0, 21), NULL, 10);
699 - // p->vsize = strtoull(procfile_lineword(ff, 0, 22), NULL, 10);
700 - p->rss = strtoull(procfile_lineword(ff, 0, 23), NULL, 10);
701 - // p->rsslim = strtoull(procfile_lineword(ff, 0, 24), NULL, 10);
702 - // p->starcode = strtoull(procfile_lineword(ff, 0, 25), NULL, 10);
703 - // p->endcode = strtoull(procfile_lineword(ff, 0, 26), NULL, 10);
704 - // p->startstack = strtoull(procfile_lineword(ff, 0, 27), NULL, 10);
705 - // p->kstkesp = strtoull(procfile_lineword(ff, 0, 28), NULL, 10);
706 - // p->kstkeip = strtoull(procfile_lineword(ff, 0, 29), NULL, 10);
707 - // p->signal = strtoull(procfile_lineword(ff, 0, 30), NULL, 10);
708 - // p->blocked = strtoull(procfile_lineword(ff, 0, 31), NULL, 10);
709 - // p->sigignore = strtoull(procfile_lineword(ff, 0, 32), NULL, 10);
710 - // p->sigcatch = strtoull(procfile_lineword(ff, 0, 33), NULL, 10);
711 - // p->wchan = strtoull(procfile_lineword(ff, 0, 34), NULL, 10);
712 - // p->nswap = strtoull(procfile_lineword(ff, 0, 35), NULL, 10);
713 - // p->cnswap = strtoull(procfile_lineword(ff, 0, 36), NULL, 10);
714 - // p->exit_signal = atol(procfile_lineword(ff, 0, 37));
715 - // p->processor = atol(procfile_lineword(ff, 0, 38));
716 - // p->rt_priority = strtoul(procfile_lineword(ff, 0, 39), NULL, 10);
717 - // p->policy = strtoul(procfile_lineword(ff, 0, 40), NULL, 10);
718 - // p->delayacct_blkio_ticks = strtoull(procfile_lineword(ff, 0, 41), NULL, 10);
625 + static procfile *ff = NULL;
626 +
627 + if(unlikely(!p->stat_filename)) {
628 + char filename[FILENAME_MAX + 1];
629 + snprintfz(filename, FILENAME_MAX, "%s/proc/%d/stat", host_prefix, p->pid);
630 + p->stat_filename = strdupz(filename);
631 + }
632 +
633 + int set_quotes = (!ff)?1:0;
634 +
635 + ff = procfile_reopen(ff, p->stat_filename, NULL, PROCFILE_FLAG_NO_ERROR_ON_FILE_IO);
636 + if(unlikely(!ff)) goto cleanup;
637 +
638 + // if(set_quotes) procfile_set_quotes(ff, "()");
639 + if(set_quotes) procfile_set_open_close(ff, "(", ")");
640 +
641 + ff = procfile_readall(ff);
642 + if(unlikely(!ff)) goto cleanup;
643 +
644 + p->last_stat_collected_usec = p->stat_collected_usec;
645 + p->stat_collected_usec = time_usec();
646 + file_counter++;
647 +
648 + // p->pid = atol(procfile_lineword(ff, 0, 0+i));
649 +
650 + strncpyz(p->comm, procfile_lineword(ff, 0, 1), MAX_COMPARE_NAME);
651 +
652 + // p->state = *(procfile_lineword(ff, 0, 2));
653 + p->ppid = (int32_t) atol(procfile_lineword(ff, 0, 3));
654 + // p->pgrp = atol(procfile_lineword(ff, 0, 4));
655 + // p->session = atol(procfile_lineword(ff, 0, 5));
656 + // p->tty_nr = atol(procfile_lineword(ff, 0, 6));
657 + // p->tpgid = atol(procfile_lineword(ff, 0, 7));
658 + // p->flags = strtoull(procfile_lineword(ff, 0, 8), NULL, 10);
659 +
660 + unsigned long long last;
661 +
662 + last = p->minflt_raw;
663 + p->minflt_raw = strtoull(procfile_lineword(ff, 0, 9), NULL, 10);
664 + p->minflt = (p->minflt_raw - last) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
665 +
666 + last = p->cminflt_raw;
667 + p->cminflt_raw = strtoull(procfile_lineword(ff, 0, 10), NULL, 10);
668 + p->cminflt = (p->cminflt_raw - last) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
669 +
670 + last = p->majflt_raw;
671 + p->majflt_raw = strtoull(procfile_lineword(ff, 0, 11), NULL, 10);
672 + p->majflt = (p->majflt_raw - last) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
673 +
674 + last = p->cmajflt_raw;
675 + p->cmajflt_raw = strtoull(procfile_lineword(ff, 0, 12), NULL, 10);
676 + p->cmajflt = (p->cmajflt_raw - last) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
677 +
678 + last = p->utime_raw;
679 + p->utime_raw = strtoull(procfile_lineword(ff, 0, 13), NULL, 10);
680 + p->utime = (p->utime_raw - last) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
681 +
682 + last = p->stime_raw;
683 + p->stime_raw = strtoull(procfile_lineword(ff, 0, 14), NULL, 10);
684 + p->stime = (p->stime_raw - last) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
685 +
686 + last = p->cutime_raw;
687 + p->cutime_raw = strtoull(procfile_lineword(ff, 0, 15), NULL, 10);
688 + p->cutime = (p->cutime_raw - last) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
689 +
690 + last = p->cstime_raw;
691 + p->cstime_raw = strtoull(procfile_lineword(ff, 0, 16), NULL, 10);
692 + p->cstime = (p->cstime_raw - last) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
693 +
694 + // p->priority = strtoull(procfile_lineword(ff, 0, 17), NULL, 10);
695 + // p->nice = strtoull(procfile_lineword(ff, 0, 18), NULL, 10);
696 + p->num_threads = (int32_t) atol(procfile_lineword(ff, 0, 19));
697 + // p->itrealvalue = strtoull(procfile_lineword(ff, 0, 20), NULL, 10);
698 + // p->starttime = strtoull(procfile_lineword(ff, 0, 21), NULL, 10);
699 + // p->vsize = strtoull(procfile_lineword(ff, 0, 22), NULL, 10);
700 + p->rss = strtoull(procfile_lineword(ff, 0, 23), NULL, 10);
701 + // p->rsslim = strtoull(procfile_lineword(ff, 0, 24), NULL, 10);
702 + // p->starcode = strtoull(procfile_lineword(ff, 0, 25), NULL, 10);
703 + // p->endcode = strtoull(procfile_lineword(ff, 0, 26), NULL, 10);
704 + // p->startstack = strtoull(procfile_lineword(ff, 0, 27), NULL, 10);
705 + // p->kstkesp = strtoull(procfile_lineword(ff, 0, 28), NULL, 10);
706 + // p->kstkeip = strtoull(procfile_lineword(ff, 0, 29), NULL, 10);
707 + // p->signal = strtoull(procfile_lineword(ff, 0, 30), NULL, 10);
708 + // p->blocked = strtoull(procfile_lineword(ff, 0, 31), NULL, 10);
709 + // p->sigignore = strtoull(procfile_lineword(ff, 0, 32), NULL, 10);
710 + // p->sigcatch = strtoull(procfile_lineword(ff, 0, 33), NULL, 10);
711 + // p->wchan = strtoull(procfile_lineword(ff, 0, 34), NULL, 10);
712 + // p->nswap = strtoull(procfile_lineword(ff, 0, 35), NULL, 10);
713 + // p->cnswap = strtoull(procfile_lineword(ff, 0, 36), NULL, 10);
714 + // p->exit_signal = atol(procfile_lineword(ff, 0, 37));
715 + // p->processor = atol(procfile_lineword(ff, 0, 38));
716 + // p->rt_priority = strtoul(procfile_lineword(ff, 0, 39), NULL, 10);
717 + // p->policy = strtoul(procfile_lineword(ff, 0, 40), NULL, 10);
718 + // p->delayacct_blkio_ticks = strtoull(procfile_lineword(ff, 0, 41), NULL, 10);
719
720 if(enable_guest_charts) {
721 last = p->gtime_raw;
722 - p->gtime_raw = strtoull(procfile_lineword(ff, 0, 42), NULL, 10);
722 + p->gtime_raw = strtoull(procfile_lineword(ff, 0, 42), NULL, 10);
723 p->gtime = (p->gtime_raw - last) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
724
725 last = p->cgtime_raw;
726 - p->cgtime_raw = strtoull(procfile_lineword(ff, 0, 43), NULL, 10);
726 + p->cgtime_raw = strtoull(procfile_lineword(ff, 0, 43), NULL, 10);
727 p->cgtime = (p->cgtime_raw - last) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
728
729 if (show_guest_time || p->gtime || p->cgtime) {
@@ -733,150 +733,150 @@ int read_proc_pid_stat(struct pid_stat *p) {
733 }
734 }
735
736 - if(unlikely(debug || (p->target && p->target->debug)))
737 - fprintf(stderr, "apps.plugin: READ PROC/PID/STAT: %s/proc/%d/stat, process: '%s' on target '%s' (dt=%llu) VALUES: utime=%llu, stime=%llu, cutime=%llu, cstime=%llu, minflt=%llu, majflt=%llu, cminflt=%llu, cmajflt=%llu, threads=%d\n", host_prefix, p->pid, p->comm, (p->target)?p->target->name:"UNSET", p->stat_collected_usec - p->last_stat_collected_usec, p->utime, p->stime, p->cutime, p->cstime, p->minflt, p->majflt, p->cminflt, p->cmajflt, p->num_threads);
738 -
739 - if(unlikely(global_iterations_counter == 1)) {
740 - p->minflt = 0;
741 - p->cminflt = 0;
742 - p->majflt = 0;
743 - p->cmajflt = 0;
744 - p->utime = 0;
745 - p->stime = 0;
746 - p->gtime = 0;
747 - p->cutime = 0;
748 - p->cstime = 0;
749 - p->cgtime = 0;
750 - }
736 + if(unlikely(debug || (p->target && p->target->debug)))
737 + fprintf(stderr, "apps.plugin: READ PROC/PID/STAT: %s/proc/%d/stat, process: '%s' on target '%s' (dt=%llu) VALUES: utime=%llu, stime=%llu, cutime=%llu, cstime=%llu, minflt=%llu, majflt=%llu, cminflt=%llu, cmajflt=%llu, threads=%d\n", host_prefix, p->pid, p->comm, (p->target)?p->target->name:"UNSET", p->stat_collected_usec - p->last_stat_collected_usec, p->utime, p->stime, p->cutime, p->cstime, p->minflt, p->majflt, p->cminflt, p->cmajflt, p->num_threads);
738 +
739 + if(unlikely(global_iterations_counter == 1)) {
740 + p->minflt = 0;
741 + p->cminflt = 0;
742 + p->majflt = 0;
743 + p->cmajflt = 0;
744 + p->utime = 0;
745 + p->stime = 0;
746 + p->gtime = 0;
747 + p->cutime = 0;
748 + p->cstime = 0;
749 + p->cgtime = 0;
750 + }
751
752 - return 0;
752 + return 0;
753
754 cleanup:
755 - p->minflt = 0;
756 - p->cminflt = 0;
757 - p->majflt = 0;
758 - p->cmajflt = 0;
759 - p->utime = 0;
760 - p->stime = 0;
761 - p->gtime = 0;
762 - p->cutime = 0;
763 - p->cstime = 0;
764 - p->cgtime = 0;
765 - p->num_threads = 0;
766 - p->rss = 0;
767 - return 1;
755 + p->minflt = 0;
756 + p->cminflt = 0;
757 + p->majflt = 0;
758 + p->cmajflt = 0;
759 + p->utime = 0;
760 + p->stime = 0;
761 + p->gtime = 0;
762 + p->cutime = 0;
763 + p->cstime = 0;
764 + p->cgtime = 0;
765 + p->num_threads = 0;
766 + p->rss = 0;
767 + return 1;
768 }
769
770 int read_proc_pid_statm(struct pid_stat *p) {
771 - static procfile *ff = NULL;
771 + static procfile *ff = NULL;
772
773 - if(unlikely(!p->statm_filename)) {
774 - char filename[FILENAME_MAX + 1];
775 - snprintfz(filename, FILENAME_MAX, "%s/proc/%d/statm", host_prefix, p->pid);
776 - p->statm_filename = strdupz(filename);
777 - }
773 + if(unlikely(!p->statm_filename)) {
774 + char filename[FILENAME_MAX + 1];
775 + snprintfz(filename, FILENAME_MAX, "%s/proc/%d/statm", host_prefix, p->pid);
776 + p->statm_filename = strdupz(filename);
777 + }
778
779 - ff = procfile_reopen(ff, p->statm_filename, NULL, PROCFILE_FLAG_NO_ERROR_ON_FILE_IO);
780 - if(unlikely(!ff)) goto cleanup;
779 + ff = procfile_reopen(ff, p->statm_filename, NULL, PROCFILE_FLAG_NO_ERROR_ON_FILE_IO);
780 + if(unlikely(!ff)) goto cleanup;
781
782 - ff = procfile_readall(ff);
783 - if(unlikely(!ff)) goto cleanup;
782 + ff = procfile_readall(ff);
783 + if(unlikely(!ff)) goto cleanup;
784
785 - file_counter++;
785 + file_counter++;
786
787 - p->statm_size = strtoull(procfile_lineword(ff, 0, 0), NULL, 10);
788 - p->statm_resident = strtoull(procfile_lineword(ff, 0, 1), NULL, 10);
789 - p->statm_share = strtoull(procfile_lineword(ff, 0, 2), NULL, 10);
790 - p->statm_text = strtoull(procfile_lineword(ff, 0, 3), NULL, 10);
791 - p->statm_lib = strtoull(procfile_lineword(ff, 0, 4), NULL, 10);
792 - p->statm_data = strtoull(procfile_lineword(ff, 0, 5), NULL, 10);
793 - p->statm_dirty = strtoull(procfile_lineword(ff, 0, 6), NULL, 10);
787 + p->statm_size = strtoull(procfile_lineword(ff, 0, 0), NULL, 10);
788 + p->statm_resident = strtoull(procfile_lineword(ff, 0, 1), NULL, 10);
789 + p->statm_share = strtoull(procfile_lineword(ff, 0, 2), NULL, 10);
790 + p->statm_text = strtoull(procfile_lineword(ff, 0, 3), NULL, 10);
791 + p->statm_lib = strtoull(procfile_lineword(ff, 0, 4), NULL, 10);
792 + p->statm_data = strtoull(procfile_lineword(ff, 0, 5), NULL, 10);
793 + p->statm_dirty = strtoull(procfile_lineword(ff, 0, 6), NULL, 10);
794
795 - return 0;
795 + return 0;
796
797 cleanup:
798 - p->statm_size = 0;
799 - p->statm_resident = 0;
800 - p->statm_share = 0;
801 - p->statm_text = 0;
802 - p->statm_lib = 0;
803 - p->statm_data = 0;
804 - p->statm_dirty = 0;
805 - return 1;
798 + p->statm_size = 0;
799 + p->statm_resident = 0;
800 + p->statm_share = 0;
801 + p->statm_text = 0;
802 + p->statm_lib = 0;
803 + p->statm_data = 0;
804 + p->statm_dirty = 0;
805 + return 1;
806 }
807
808 int read_proc_pid_io(struct pid_stat *p) {
809 - static procfile *ff = NULL;
809 + static procfile *ff = NULL;
810
811 - if(unlikely(!p->io_filename)) {
812 - char filename[FILENAME_MAX + 1];
813 - snprintfz(filename, FILENAME_MAX, "%s/proc/%d/io", host_prefix, p->pid);
814 - p->io_filename = strdupz(filename);
815 - }
811 + if(unlikely(!p->io_filename)) {
812 + char filename[FILENAME_MAX + 1];
813 + snprintfz(filename, FILENAME_MAX, "%s/proc/%d/io", host_prefix, p->pid);
814 + p->io_filename = strdupz(filename);
815 + }
816
817 - // open the file
818 - ff = procfile_reopen(ff, p->io_filename, NULL, PROCFILE_FLAG_NO_ERROR_ON_FILE_IO);
819 - if(unlikely(!ff)) goto cleanup;
817 + // open the file
818 + ff = procfile_reopen(ff, p->io_filename, NULL, PROCFILE_FLAG_NO_ERROR_ON_FILE_IO);
819 + if(unlikely(!ff)) goto cleanup;
820
821 - ff = procfile_readall(ff);
822 - if(unlikely(!ff)) goto cleanup;
821 + ff = procfile_readall(ff);
822 + if(unlikely(!ff)) goto cleanup;
823
824 - file_counter++;
824 + file_counter++;
825
826 - p->last_io_collected_usec = p->io_collected_usec;
827 - p->io_collected_usec = time_usec();
826 + p->last_io_collected_usec = p->io_collected_usec;
827 + p->io_collected_usec = time_usec();
828
829 - unsigned long long last;
829 + unsigned long long last;
830
831 - last = p->io_logical_bytes_read_raw;
832 - p->io_logical_bytes_read_raw = strtoull(procfile_lineword(ff, 0, 1), NULL, 10);
833 - p->io_logical_bytes_read = (p->io_logical_bytes_read_raw - last) * (1000000ULL * RATES_DETAIL) / (p->io_collected_usec - p->last_io_collected_usec);
831 + last = p->io_logical_bytes_read_raw;
832 + p->io_logical_bytes_read_raw = strtoull(procfile_lineword(ff, 0, 1), NULL, 10);
833 + p->io_logical_bytes_read = (p->io_logical_bytes_read_raw - last) * (1000000ULL * RATES_DETAIL) / (p->io_collected_usec - p->last_io_collected_usec);
834
835 - last = p->io_logical_bytes_written_raw;
836 - p->io_logical_bytes_written_raw = strtoull(procfile_lineword(ff, 1, 1), NULL, 10);
837 - p->io_logical_bytes_written = (p->io_logical_bytes_written_raw - last) * (1000000ULL * RATES_DETAIL) / (p->io_collected_usec - p->last_io_collected_usec);
835 + last = p->io_logical_bytes_written_raw;
836 + p->io_logical_bytes_written_raw = strtoull(procfile_lineword(ff, 1, 1), NULL, 10);
837 + p->io_logical_bytes_written = (p->io_logical_bytes_written_raw - last) * (1000000ULL * RATES_DETAIL) / (p->io_collected_usec - p->last_io_collected_usec);
838
839 - last = p->io_read_calls_raw;
840 - p->io_read_calls_raw = strtoull(procfile_lineword(ff, 2, 1), NULL, 10);
841 - p->io_read_calls = (p->io_read_calls_raw - last) * (1000000ULL * RATES_DETAIL) / (p->io_collected_usec - p->last_io_collected_usec);
839 + last = p->io_read_calls_raw;
840 + p->io_read_calls_raw = strtoull(procfile_lineword(ff, 2, 1), NULL, 10);
841 + p->io_read_calls = (p->io_read_calls_raw - last) * (1000000ULL * RATES_DETAIL) / (p->io_collected_usec - p->last_io_collected_usec);
842
843 - last = p->io_write_calls_raw;
844 - p->io_write_calls_raw = strtoull(procfile_lineword(ff, 3, 1), NULL, 10);
845 - p->io_write_calls = (p->io_write_calls_raw - last) * (1000000ULL * RATES_DETAIL) / (p->io_collected_usec - p->last_io_collected_usec);
843 + last = p->io_write_calls_raw;
844 + p->io_write_calls_raw = strtoull(procfile_lineword(ff, 3, 1), NULL, 10);
845 + p->io_write_calls = (p->io_write_calls_raw - last) * (1000000ULL * RATES_DETAIL) / (p->io_collected_usec - p->last_io_collected_usec);
846
847 - last = p->io_storage_bytes_read_raw;
848 - p->io_storage_bytes_read_raw = strtoull(procfile_lineword(ff, 4, 1), NULL, 10);
849 - p->io_storage_bytes_read = (p->io_storage_bytes_read_raw - last) * (1000000ULL * RATES_DETAIL) / (p->io_collected_usec - p->last_io_collected_usec);
847 + last = p->io_storage_bytes_read_raw;
848 + p->io_storage_bytes_read_raw = strtoull(procfile_lineword(ff, 4, 1), NULL, 10);
849 + p->io_storage_bytes_read = (p->io_storage_bytes_read_raw - last) * (1000000ULL * RATES_DETAIL) / (p->io_collected_usec - p->last_io_collected_usec);
850
851 - last = p->io_storage_bytes_written_raw;
852 - p->io_storage_bytes_written_raw = strtoull(procfile_lineword(ff, 5, 1), NULL, 10);
853 - p->io_storage_bytes_written = (p->io_storage_bytes_written_raw - last) * (1000000ULL * RATES_DETAIL) / (p->io_collected_usec - p->last_io_collected_usec);
851 + last = p->io_storage_bytes_written_raw;
852 + p->io_storage_bytes_written_raw = strtoull(procfile_lineword(ff, 5, 1), NULL, 10);
853 + p->io_storage_bytes_written = (p->io_storage_bytes_written_raw - last) * (1000000ULL * RATES_DETAIL) / (p->io_collected_usec - p->last_io_collected_usec);
854
855 - last = p->io_cancelled_write_bytes_raw;
856 - p->io_cancelled_write_bytes_raw = strtoull(procfile_lineword(ff, 6, 1), NULL, 10);
857 - p->io_cancelled_write_bytes = (p->io_cancelled_write_bytes_raw - last) * (1000000ULL * RATES_DETAIL) / (p->io_collected_usec - p->last_io_collected_usec);
855 + last = p->io_cancelled_write_bytes_raw;
856 + p->io_cancelled_write_bytes_raw = strtoull(procfile_lineword(ff, 6, 1), NULL, 10);
857 + p->io_cancelled_write_bytes = (p->io_cancelled_write_bytes_raw - last) * (1000000ULL * RATES_DETAIL) / (p->io_collected_usec - p->last_io_collected_usec);
858
859 - if(unlikely(global_iterations_counter == 1)) {
860 - p->io_logical_bytes_read = 0;
861 - p->io_logical_bytes_written = 0;
862 - p->io_read_calls = 0;
863 - p->io_write_calls = 0;
864 - p->io_storage_bytes_read = 0;
865 - p->io_storage_bytes_written = 0;
866 - p->io_cancelled_write_bytes = 0;
867 - }
859 + if(unlikely(global_iterations_counter == 1)) {
860 + p->io_logical_bytes_read = 0;
861 + p->io_logical_bytes_written = 0;
862 + p->io_read_calls = 0;
863 + p->io_write_calls = 0;
864 + p->io_storage_bytes_read = 0;
865 + p->io_storage_bytes_written = 0;
866 + p->io_cancelled_write_bytes = 0;
867 + }
868
869 - return 0;
869 + return 0;
870
871 cleanup:
872 - p->io_logical_bytes_read = 0;
873 - p->io_logical_bytes_written = 0;
874 - p->io_read_calls = 0;
875 - p->io_write_calls = 0;
876 - p->io_storage_bytes_read = 0;
877 - p->io_storage_bytes_written = 0;
878 - p->io_cancelled_write_bytes = 0;
879 - return 1;
872 + p->io_logical_bytes_read = 0;
873 + p->io_logical_bytes_written = 0;
874 + p->io_read_calls = 0;
875 + p->io_write_calls = 0;
876 + p->io_storage_bytes_read = 0;
877 + p->io_storage_bytes_written = 0;
878 + p->io_cancelled_write_bytes = 0;
879 + return 1;
880 }
881
882 unsigned long long global_utime = 0;
@@ -884,38 +884,38 @@ unsigned long long global_stime = 0;
884 unsigned long long global_gtime = 0;
885
886 int read_proc_stat() {
887 - static char filename[FILENAME_MAX + 1] = "";
888 - static procfile *ff = NULL;
889 - static unsigned long long utime_raw = 0, stime_raw = 0, gtime_raw = 0, gntime_raw = 0, ntime_raw = 0, collected_usec = 0, last_collected_usec = 0;
890 -
891 - if(unlikely(!ff)) {
892 - snprintfz(filename, FILENAME_MAX, "%s/proc/stat", host_prefix);
893 - ff = procfile_open(filename, " \t:", PROCFILE_FLAG_DEFAULT);
894 - if(unlikely(!ff)) goto cleanup;
895 - }
887 + static char filename[FILENAME_MAX + 1] = "";
888 + static procfile *ff = NULL;
889 + static unsigned long long utime_raw = 0, stime_raw = 0, gtime_raw = 0, gntime_raw = 0, ntime_raw = 0, collected_usec = 0, last_collected_usec = 0;
890 +
891 + if(unlikely(!ff)) {
892 + snprintfz(filename, FILENAME_MAX, "%s/proc/stat", host_prefix);
893 + ff = procfile_open(filename, " \t:", PROCFILE_FLAG_DEFAULT);
894 + if(unlikely(!ff)) goto cleanup;
895 + }
896
897 - ff = procfile_readall(ff);
898 - if(unlikely(!ff)) goto cleanup;
897 + ff = procfile_readall(ff);
898 + if(unlikely(!ff)) goto cleanup;
899
900 - last_collected_usec = collected_usec;
901 - collected_usec = time_usec();
900 + last_collected_usec = collected_usec;
901 + collected_usec = time_usec();
902
903 - file_counter++;
903 + file_counter++;
904
905 - unsigned long long last;
905 + unsigned long long last;
906
907 - last = utime_raw;
908 - utime_raw = strtoull(procfile_lineword(ff, 0, 1), NULL, 10);
909 - global_utime = (utime_raw - last) * (1000000ULL * RATES_DETAIL) / (collected_usec - last_collected_usec);
907 + last = utime_raw;
908 + utime_raw = strtoull(procfile_lineword(ff, 0, 1), NULL, 10);
909 + global_utime = (utime_raw - last) * (1000000ULL * RATES_DETAIL) / (collected_usec - last_collected_usec);
910
911 // nice time, on user time
912 - last = ntime_raw;
913 - ntime_raw = strtoull(procfile_lineword(ff, 0, 2), NULL, 10);
914 - global_utime += (ntime_raw - last) * (1000000ULL * RATES_DETAIL) / (collected_usec - last_collected_usec);
912 + last = ntime_raw;
913 + ntime_raw = strtoull(procfile_lineword(ff, 0, 2), NULL, 10);
914 + global_utime += (ntime_raw - last) * (1000000ULL * RATES_DETAIL) / (collected_usec - last_collected_usec);
915
916 - last = stime_raw;
917 - stime_raw = strtoull(procfile_lineword(ff, 0, 3), NULL, 10);
918 - global_stime = (stime_raw - last) * (1000000ULL * RATES_DETAIL) / (collected_usec - last_collected_usec);
916 + last = stime_raw;
917 + stime_raw = strtoull(procfile_lineword(ff, 0, 3), NULL, 10);
918 + global_stime = (stime_raw - last) * (1000000ULL * RATES_DETAIL) / (collected_usec - last_collected_usec);
919
920 last = gtime_raw;
921 gtime_raw = strtoull(procfile_lineword(ff, 0, 10), NULL, 10);
@@ -931,19 +931,19 @@ int read_proc_stat() {
931 global_utime -= (global_utime > global_gtime) ? global_gtime : global_utime;
932 }
933
934 - if(unlikely(global_iterations_counter == 1)) {
935 - global_utime = 0;
936 - global_stime = 0;
937 - global_gtime = 0;
938 - }
934 + if(unlikely(global_iterations_counter == 1)) {
935 + global_utime = 0;
936 + global_stime = 0;
937 + global_gtime = 0;
938 + }
939
940 - return 0;
940 + return 0;
941
942 cleanup:
943 - global_utime = 0;
944 - global_stime = 0;
945 - global_gtime = 0;
946 - return 1;
943 + global_utime = 0;
944 + global_stime = 0;
945 + global_gtime = 0;
946 + return 1;
947 }
948
949
@@ -955,15 +955,15 @@ cleanup:
955 #define FILE_DESCRIPTORS_INCREASE_STEP 100
956
957 struct file_descriptor {
958 - avl avl;
958 + avl avl;
959 #ifdef NETDATA_INTERNAL_CHECKS
960 - uint32_t magic;
960 + uint32_t magic;
961 #endif /* NETDATA_INTERNAL_CHECKS */
962 - uint32_t hash;
963 - const char *name;
964 - int type;
965 - int count;
966 - int pos;
962 + uint32_t hash;
963 + const char *name;
964 + int type;
965 + int count;
966 + int pos;
967 } *all_files = NULL;
968
969 int all_files_len = 0;
@@ -971,38 +971,38 @@ int all_files_size = 0;
971
972 int file_descriptor_compare(void* a, void* b) {
973 #ifdef NETDATA_INTERNAL_CHECKS
974 - if(((struct file_descriptor *)a)->magic != 0x0BADCAFE || ((struct file_descriptor *)b)->magic != 0x0BADCAFE)
975 - error("Corrupted index data detected. Please report this.");
974 + if(((struct file_descriptor *)a)->magic != 0x0BADCAFE || ((struct file_descriptor *)b)->magic != 0x0BADCAFE)
975 + error("Corrupted index data detected. Please report this.");
976 #endif /* NETDATA_INTERNAL_CHECKS */
977
978 - if(((struct file_descriptor *)a)->hash < ((struct file_descriptor *)b)->hash)
979 - return -1;
978 + if(((struct file_descriptor *)a)->hash < ((struct file_descriptor *)b)->hash)
979 + return -1;
980
981 - else if(((struct file_descriptor *)a)->hash > ((struct file_descriptor *)b)->hash)
982 - return 1;
981 + else if(((struct file_descriptor *)a)->hash > ((struct file_descriptor *)b)->hash)
982 + return 1;
983
984 - else
985 - return strcmp(((struct file_descriptor *)a)->name, ((struct file_descriptor *)b)->name);
984 + else
985 + return strcmp(((struct file_descriptor *)a)->name, ((struct file_descriptor *)b)->name);
986 }
987
988 int file_descriptor_iterator(avl *a) { if(a) {}; return 0; }
989
990 avl_tree all_files_index = {
991 - NULL,
992 - file_descriptor_compare
991 + NULL,
992 + file_descriptor_compare
993 };
994
995 static struct file_descriptor *file_descriptor_find(const char *name, uint32_t hash) {
996 - struct file_descriptor tmp;
997 - tmp.hash = (hash)?hash:simple_hash(name);
998 - tmp.name = name;
999 - tmp.count = 0;
1000 - tmp.pos = 0;
996 + struct file_descriptor tmp;
997 + tmp.hash = (hash)?hash:simple_hash(name);
998 + tmp.name = name;
999 + tmp.count = 0;
1000 + tmp.pos = 0;
1001 #ifdef NETDATA_INTERNAL_CHECKS
1002 - tmp.magic = 0x0BADCAFE;
1002 + tmp.magic = 0x0BADCAFE;
1003 #endif /* NETDATA_INTERNAL_CHECKS */
1004
1005 - return (struct file_descriptor *)avl_search(&all_files_index, (avl *) &tmp);
1005 + return (struct file_descriptor *)avl_search(&all_files_index, (avl *) &tmp);
1006 }
1007
1008 #define file_descriptor_add(fd) avl_insert(&all_files_index, (avl *)(fd))
@@ -1020,526 +1020,526 @@ static struct file_descriptor *file_descriptor_find(const char *name, uint32_t h
1020
1021 void file_descriptor_not_used(int id)
1022 {
1023 - if(id > 0 && id < all_files_size) {
1023 + if(id > 0 && id < all_files_size) {
1024
1025 #ifdef NETDATA_INTERNAL_CHECKS
1026 - if(all_files[id].magic != 0x0BADCAFE) {
1027 - error("Ignoring request to remove empty file id %d.", id);
1028 - return;
1029 - }
1026 + if(all_files[id].magic != 0x0BADCAFE) {
1027 + error("Ignoring request to remove empty file id %d.", id);
1028 + return;
1029 + }
1030 #endif /* NETDATA_INTERNAL_CHECKS */
1031
1032 - if(unlikely(debug))
1033 - fprintf(stderr, "apps.plugin: decreasing slot %d (count = %d).\n", id, all_files[id].count);
1032 + if(unlikely(debug))
1033 + fprintf(stderr, "apps.plugin: decreasing slot %d (count = %d).\n", id, all_files[id].count);
1034
1035 - if(all_files[id].count > 0) {
1036 - all_files[id].count--;
1035 + if(all_files[id].count > 0) {
1036 + all_files[id].count--;
1037
1038 - if(!all_files[id].count) {
1039 - if(unlikely(debug))
1040 - fprintf(stderr, "apps.plugin: >> slot %d is empty.\n", id);
1038 + if(!all_files[id].count) {
1039 + if(unlikely(debug))
1040 + fprintf(stderr, "apps.plugin: >> slot %d is empty.\n", id);
1041
1042 - file_descriptor_remove(&all_files[id]);
1042 + file_descriptor_remove(&all_files[id]);
1043 #ifdef NETDATA_INTERNAL_CHECKS
1044 - all_files[id].magic = 0x00000000;
1044 + all_files[id].magic = 0x00000000;
1045 #endif /* NETDATA_INTERNAL_CHECKS */
1046 - all_files_len--;
1047 - }
1048 - }
1049 - else
1050 - error("Request to decrease counter of fd %d (%s), while the use counter is 0", id, all_files[id].name);
1051 - }
1052 - else error("Request to decrease counter of fd %d, which is outside the array size (1 to %d)", id, all_files_size);
1046 + all_files_len--;
1047 + }
1048 + }
1049 + else
1050 + error("Request to decrease counter of fd %d (%s), while the use counter is 0", id, all_files[id].name);
1051 + }
1052 + else error("Request to decrease counter of fd %d, which is outside the array size (1 to %d)", id, all_files_size);
1053 }
1054
1055 int file_descriptor_find_or_add(const char *name)
1056 {
1057 - static int last_pos = 0;
1058 - uint32_t hash = simple_hash(name);
1059 -
1060 - if(unlikely(debug))
1061 - fprintf(stderr, "apps.plugin: adding or finding name '%s' with hash %u\n", name, hash);
1062 -
1063 - struct file_descriptor *fd = file_descriptor_find(name, hash);
1064 - if(fd) {
1065 - // found
1066 - if(unlikely(debug))
1067 - fprintf(stderr, "apps.plugin: >> found on slot %d\n", fd->pos);
1068 -
1069 - fd->count++;
1070 - return fd->pos;
1071 - }
1072 - // not found
1073 -
1074 - // check we have enough memory to add it
1075 - if(!all_files || all_files_len == all_files_size) {
1076 - void *old = all_files;
1077 - int i;
1078 -
1079 - // there is no empty slot
1080 - if(unlikely(debug))
1081 - fprintf(stderr, "apps.plugin: extending fd array to %d entries\n", all_files_size + FILE_DESCRIPTORS_INCREASE_STEP);
1082 -
1083 - all_files = reallocz(all_files, (all_files_size + FILE_DESCRIPTORS_INCREASE_STEP) * sizeof(struct file_descriptor));
1084 -
1085 - // if the address changed, we have to rebuild the index
1086 - // since all pointers are now invalid
1087 - if(old && old != (void *)all_files) {
1088 - if(unlikely(debug))
1089 - fprintf(stderr, "apps.plugin: >> re-indexing.\n");
1090 -
1091 - all_files_index.root = NULL;
1092 - for(i = 0; i < all_files_size; i++) {
1093 - if(!all_files[i].count) continue;
1094 - file_descriptor_add(&all_files[i]);
1095 - }
1096 -
1097 - if(unlikely(debug))
1098 - fprintf(stderr, "apps.plugin: >> re-indexing done.\n");
1099 - }
1100 -
1101 - for(i = all_files_size; i < (all_files_size + FILE_DESCRIPTORS_INCREASE_STEP); i++) {
1102 - all_files[i].count = 0;
1103 - all_files[i].name = NULL;
1057 + static int last_pos = 0;
1058 + uint32_t hash = simple_hash(name);
1059 +
1060 + if(unlikely(debug))
1061 + fprintf(stderr, "apps.plugin: adding or finding name '%s' with hash %u\n", name, hash);
1062 +
1063 + struct file_descriptor *fd = file_descriptor_find(name, hash);
1064 + if(fd) {
1065 + // found
1066 + if(unlikely(debug))
1067 + fprintf(stderr, "apps.plugin: >> found on slot %d\n", fd->pos);
1068 +
1069 + fd->count++;
1070 + return fd->pos;
1071 + }
1072 + // not found
1073 +
1074 + // check we have enough memory to add it
1075 + if(!all_files || all_files_len == all_files_size) {
1076 + void *old = all_files;
1077 + int i;
1078 +
1079 + // there is no empty slot
1080 + if(unlikely(debug))
1081 + fprintf(stderr, "apps.plugin: extending fd array to %d entries\n", all_files_size + FILE_DESCRIPTORS_INCREASE_STEP);
1082 +
1083 + all_files = reallocz(all_files, (all_files_size + FILE_DESCRIPTORS_INCREASE_STEP) * sizeof(struct file_descriptor));
1084 +
1085 + // if the address changed, we have to rebuild the index
1086 + // since all pointers are now invalid
1087 + if(old && old != (void *)all_files) {
1088 + if(unlikely(debug))
1089 + fprintf(stderr, "apps.plugin: >> re-indexing.\n");
1090 +
1091 + all_files_index.root = NULL;
1092 + for(i = 0; i < all_files_size; i++) {
1093 + if(!all_files[i].count) continue;
1094 + file_descriptor_add(&all_files[i]);
1095 + }
1096 +
1097 + if(unlikely(debug))
1098 + fprintf(stderr, "apps.plugin: >> re-indexing done.\n");
1099 + }
1100 +
1101 + for(i = all_files_size; i < (all_files_size + FILE_DESCRIPTORS_INCREASE_STEP); i++) {
1102 + all_files[i].count = 0;
1103 + all_files[i].name = NULL;
1104 #ifdef NETDATA_INTERNAL_CHECKS
1105 - all_files[i].magic = 0x00000000;
1105 + all_files[i].magic = 0x00000000;
1106 #endif /* NETDATA_INTERNAL_CHECKS */
1107 - all_files[i].pos = i;
1108 - }
1107 + all_files[i].pos = i;
1108 + }
1109
1110 - if(!all_files_size) all_files_len = 1;
1111 - all_files_size += FILE_DESCRIPTORS_INCREASE_STEP;
1112 - }
1110 + if(!all_files_size) all_files_len = 1;
1111 + all_files_size += FILE_DESCRIPTORS_INCREASE_STEP;
1112 + }
1113
1114 - if(unlikely(debug))
1115 - fprintf(stderr, "apps.plugin: >> searching for empty slot.\n");
1114 + if(unlikely(debug))
1115 + fprintf(stderr, "apps.plugin: >> searching for empty slot.\n");
1116
1117 - // search for an empty slot
1118 - int i, c;
1119 - for(i = 0, c = last_pos ; i < all_files_size ; i++, c++) {
1120 - if(c >= all_files_size) c = 0;
1121 - if(c == 0) continue;
1117 + // search for an empty slot
1118 + int i, c;
1119 + for(i = 0, c = last_pos ; i < all_files_size ; i++, c++) {
1120 + if(c >= all_files_size) c = 0;
1121 + if(c == 0) continue;
1122
1123 - if(!all_files[c].count) {
1124 - if(unlikely(debug))
1125 - fprintf(stderr, "apps.plugin: >> Examining slot %d.\n", c);
1123 + if(!all_files[c].count) {
1124 + if(unlikely(debug))
1125 + fprintf(stderr, "apps.plugin: >> Examining slot %d.\n", c);
1126
1127 #ifdef NETDATA_INTERNAL_CHECKS
1128 - if(all_files[c].magic == 0x0BADCAFE && all_files[c].name && file_descriptor_find(all_files[c].name, all_files[c].hash))
1129 - error("fd on position %d is not cleared properly. It still has %s in it.\n", c, all_files[c].name);
1128 + if(all_files[c].magic == 0x0BADCAFE && all_files[c].name && file_descriptor_find(all_files[c].name, all_files[c].hash))
1129 + error("fd on position %d is not cleared properly. It still has %s in it.\n", c, all_files[c].name);
1130 #endif /* NETDATA_INTERNAL_CHECKS */
1131
1132 - if(unlikely(debug))
1133 - fprintf(stderr, "apps.plugin: >> %s fd position %d for %s (last name: %s)\n", all_files[c].name?"re-using":"using", c, name, all_files[c].name);
1134 -
1135 - if(all_files[c].name) freez((void *)all_files[c].name);
1136 - all_files[c].name = NULL;
1137 - last_pos = c;
1138 - break;
1139 - }
1140 - }
1141 - if(i == all_files_size) {
1142 - fatal("We should find an empty slot, but there isn't any");
1143 - exit(1);
1144 - }
1145 -
1146 - if(unlikely(debug))
1147 - fprintf(stderr, "apps.plugin: >> updating slot %d.\n", c);
1148 -
1149 - all_files_len++;
1150 -
1151 - // else we have an empty slot in 'c'
1152 -
1153 - int type;
1154 - if(name[0] == '/') type = FILETYPE_FILE;
1155 - else if(strncmp(name, "pipe:", 5) == 0) type = FILETYPE_PIPE;
1156 - else if(strncmp(name, "socket:", 7) == 0) type = FILETYPE_SOCKET;
1157 - else if(strcmp(name, "anon_inode:inotify") == 0 || strcmp(name, "inotify") == 0) type = FILETYPE_INOTIFY;
1158 - else if(strcmp(name, "anon_inode:[eventfd]") == 0) type = FILETYPE_EVENTFD;
1159 - else if(strcmp(name, "anon_inode:[eventpoll]") == 0) type = FILETYPE_EVENTPOLL;
1160 - else if(strcmp(name, "anon_inode:[timerfd]") == 0) type = FILETYPE_TIMERFD;
1161 - else if(strcmp(name, "anon_inode:[signalfd]") == 0) type = FILETYPE_SIGNALFD;
1162 - else if(strncmp(name, "anon_inode:", 11) == 0) {
1163 - if(unlikely(debug))
1164 - fprintf(stderr, "apps.plugin: FIXME: unknown anonymous inode: %s\n", name);
1165 -
1166 - type = FILETYPE_OTHER;
1167 - }
1168 - else {
1169 - if(unlikely(debug))
1170 - fprintf(stderr, "apps.plugin: FIXME: cannot understand linkname: %s\n", name);
1171 -
1172 - type = FILETYPE_OTHER;
1173 - }
1174 -
1175 - all_files[c].name = strdupz(name);
1176 - all_files[c].hash = hash;
1177 - all_files[c].type = type;
1178 - all_files[c].pos = c;
1179 - all_files[c].count = 1;
1132 + if(unlikely(debug))
1133 + fprintf(stderr, "apps.plugin: >> %s fd position %d for %s (last name: %s)\n", all_files[c].name?"re-using":"using", c, name, all_files[c].name);
1134 +
1135 + if(all_files[c].name) freez((void *)all_files[c].name);
1136 + all_files[c].name = NULL;
1137 + last_pos = c;
1138 + break;
1139 + }
1140 + }
1141 + if(i == all_files_size) {
1142 + fatal("We should find an empty slot, but there isn't any");
1143 + exit(1);
1144 + }
1145 +
1146 + if(unlikely(debug))
1147 + fprintf(stderr, "apps.plugin: >> updating slot %d.\n", c);
1148 +
1149 + all_files_len++;
1150 +
1151 + // else we have an empty slot in 'c'
1152 +
1153 + int type;
1154 + if(name[0] == '/') type = FILETYPE_FILE;
1155 + else if(strncmp(name, "pipe:", 5) == 0) type = FILETYPE_PIPE;
1156 + else if(strncmp(name, "socket:", 7) == 0) type = FILETYPE_SOCKET;
1157 + else if(strcmp(name, "anon_inode:inotify") == 0 || strcmp(name, "inotify") == 0) type = FILETYPE_INOTIFY;
1158 + else if(strcmp(name, "anon_inode:[eventfd]") == 0) type = FILETYPE_EVENTFD;
1159 + else if(strcmp(name, "anon_inode:[eventpoll]") == 0) type = FILETYPE_EVENTPOLL;
1160 + else if(strcmp(name, "anon_inode:[timerfd]") == 0) type = FILETYPE_TIMERFD;
1161 + else if(strcmp(name, "anon_inode:[signalfd]") == 0) type = FILETYPE_SIGNALFD;
1162 + else if(strncmp(name, "anon_inode:", 11) == 0) {
1163 + if(unlikely(debug))
1164 + fprintf(stderr, "apps.plugin: FIXME: unknown anonymous inode: %s\n", name);
1165 +
1166 + type = FILETYPE_OTHER;
1167 + }
1168 + else {
1169 + if(unlikely(debug))
1170 + fprintf(stderr, "apps.plugin: FIXME: cannot understand linkname: %s\n", name);
1171 +
1172 + type = FILETYPE_OTHER;
1173 + }
1174 +
1175 + all_files[c].name = strdupz(name);
1176 + all_files[c].hash = hash;
1177 + all_files[c].type = type;
1178 + all_files[c].pos = c;
1179 + all_files[c].count = 1;
1180 #ifdef NETDATA_INTERNAL_CHECKS
1181 - all_files[c].magic = 0x0BADCAFE;
1181 + all_files[c].magic = 0x0BADCAFE;
1182 #endif /* NETDATA_INTERNAL_CHECKS */
1183 - file_descriptor_add(&all_files[c]);
1183 + file_descriptor_add(&all_files[c]);
1184
1185 - if(unlikely(debug))
1186 - fprintf(stderr, "apps.plugin: using fd position %d (name: %s)\n", c, all_files[c].name);
1185 + if(unlikely(debug))
1186 + fprintf(stderr, "apps.plugin: using fd position %d (name: %s)\n", c, all_files[c].name);
1187
1188 - return c;
1188 + return c;
1189 }
1190
1191 int read_pid_file_descriptors(struct pid_stat *p) {
1192 - char dirname[FILENAME_MAX+1];
1193 -
1194 - snprintfz(dirname, FILENAME_MAX, "%s/proc/%d/fd", host_prefix, p->pid);
1195 - DIR *fds = opendir(dirname);
1196 - if(fds) {
1197 - int c;
1198 - struct dirent *de;
1199 - char fdname[FILENAME_MAX + 1];
1200 - char linkname[FILENAME_MAX + 1];
1201 -
1202 - // make the array negative
1203 - for(c = 0 ; c < p->fds_size ; c++)
1204 - p->fds[c] = -p->fds[c];
1205 -
1206 - while((de = readdir(fds))) {
1207 - if(strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0)
1208 - continue;
1209 -
1210 - // check if the fds array is small
1211 - int fdid = atoi(de->d_name);
1212 - if(fdid < 0) continue;
1213 - if(fdid >= p->fds_size) {
1214 - // it is small, extend it
1215 - if(unlikely(debug))
1216 - fprintf(stderr, "apps.plugin: extending fd memory slots for %s from %d to %d\n", p->comm, p->fds_size, fdid + 100);
1217 -
1218 - p->fds = reallocz(p->fds, (fdid + 100) * sizeof(int));
1219 - if(!p->fds) {
1220 - fatal("Cannot re-allocate fds for %s", p->comm);
1221 - break;
1222 - }
1223 -
1224 - // and initialize it
1225 - for(c = p->fds_size ; c < (fdid + 100) ; c++) p->fds[c] = 0;
1226 - p->fds_size = fdid + 100;
1227 - }
1228 -
1229 - if(p->fds[fdid] == 0) {
1230 - // we don't know this fd, get it
1231 -
1232 - sprintf(fdname, "%s/proc/%d/fd/%s", host_prefix, p->pid, de->d_name);
1233 - ssize_t l = readlink(fdname, linkname, FILENAME_MAX);
1234 - if(l == -1) {
1235 - if(debug || (p->target && p->target->debug)) {
1236 - if(debug || (p->target && p->target->debug))
1237 - error("Cannot read link %s", fdname);
1238 - }
1239 - continue;
1240 - }
1241 - linkname[l] = '\0';
1242 - file_counter++;
1243 -
1244 - // if another process already has this, we will get
1245 - // the same id
1246 - p->fds[fdid] = file_descriptor_find_or_add(linkname);
1247 - }
1248 -
1249 - // else make it positive again, we need it
1250 - // of course, the actual file may have changed, but we don't care so much
1251 - // FIXME: we could compare the inode as returned by readdir direct structure
1252 - else p->fds[fdid] = -p->fds[fdid];
1253 - }
1254 - closedir(fds);
1255 -
1256 - // remove all the negative file descriptors
1257 - for(c = 0 ; c < p->fds_size ; c++) if(p->fds[c] < 0) {
1258 - file_descriptor_not_used(-p->fds[c]);
1259 - p->fds[c] = 0;
1260 - }
1261 - }
1262 - else return 1;
1263 -
1264 - return 0;
1192 + char dirname[FILENAME_MAX+1];
1193 +
1194 + snprintfz(dirname, FILENAME_MAX, "%s/proc/%d/fd", host_prefix, p->pid);
1195 + DIR *fds = opendir(dirname);
1196 + if(fds) {
1197 + int c;
1198 + struct dirent *de;
1199 + char fdname[FILENAME_MAX + 1];
1200 + char linkname[FILENAME_MAX + 1];
1201 +
1202 + // make the array negative
1203 + for(c = 0 ; c < p->fds_size ; c++)
1204 + p->fds[c] = -p->fds[c];
1205 +
1206 + while((de = readdir(fds))) {
1207 + if(strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0)
1208 + continue;
1209 +
1210 + // check if the fds array is small
1211 + int fdid = atoi(de->d_name);
1212 + if(fdid < 0) continue;
1213 + if(fdid >= p->fds_size) {
1214 + // it is small, extend it
1215 + if(unlikely(debug))
1216 + fprintf(stderr, "apps.plugin: extending fd memory slots for %s from %d to %d\n", p->comm, p->fds_size, fdid + 100);
1217 +
1218 + p->fds = reallocz(p->fds, (fdid + 100) * sizeof(int));
1219 + if(!p->fds) {
1220 + fatal("Cannot re-allocate fds for %s", p->comm);
1221 + break;
1222 + }
1223 +
1224 + // and initialize it
1225 + for(c = p->fds_size ; c < (fdid + 100) ; c++) p->fds[c] = 0;
1226 + p->fds_size = fdid + 100;
1227 + }
1228 +
1229 + if(p->fds[fdid] == 0) {
1230 + // we don't know this fd, get it
1231 +
1232 + sprintf(fdname, "%s/proc/%d/fd/%s", host_prefix, p->pid, de->d_name);
1233 + ssize_t l = readlink(fdname, linkname, FILENAME_MAX);
1234 + if(l == -1) {
1235 + if(debug || (p->target && p->target->debug)) {
1236 + if(debug || (p->target && p->target->debug))
1237 + error("Cannot read link %s", fdname);
1238 + }
1239 + continue;
1240 + }
1241 + linkname[l] = '\0';
1242 + file_counter++;
1243 +
1244 + // if another process already has this, we will get
1245 + // the same id
1246 + p->fds[fdid] = file_descriptor_find_or_add(linkname);
1247 + }
1248 +
1249 + // else make it positive again, we need it
1250 + // of course, the actual file may have changed, but we don't care so much
1251 + // FIXME: we could compare the inode as returned by readdir direct structure
1252 + else p->fds[fdid] = -p->fds[fdid];
1253 + }
1254 + closedir(fds);
1255 +
1256 + // remove all the negative file descriptors
1257 + for(c = 0 ; c < p->fds_size ; c++) if(p->fds[c] < 0) {
1258 + file_descriptor_not_used(-p->fds[c]);
1259 + p->fds[c] = 0;
1260 + }
1261 + }
1262 + else return 1;
1263 +
1264 + return 0;
1265 }
1266
1267 // ----------------------------------------------------------------------------
1268
1269 int print_process_and_parents(struct pid_stat *p, unsigned long long time) {
1270 - char *prefix = "\\_ ";
1271 - int indent = 0;
1272 -
1273 - if(p->parent)
1274 - indent = print_process_and_parents(p->parent, p->stat_collected_usec);
1275 - else
1276 - prefix = " > ";
1277 -
1278 - char buffer[indent + 1];
1279 - int i;
1280 -
1281 - for(i = 0; i < indent ;i++) buffer[i] = ' ';
1282 - buffer[i] = '\0';
1283 -
1284 - fprintf(stderr, " %s %s%s (%d %s %lld"
1285 - , buffer
1286 - , prefix
1287 - , p->comm
1288 - , p->pid
1289 - , p->updated?"running":"exited"
1290 - , (long long)p->stat_collected_usec - (long long)time
1291 - );
1292 -
1293 - if(p->utime) fprintf(stderr, " utime=%llu", p->utime);
1294 - if(p->stime) fprintf(stderr, " stime=%llu", p->stime);
1295 - if(p->gtime) fprintf(stderr, " gtime=%llu", p->gtime);
1296 - if(p->cutime) fprintf(stderr, " cutime=%llu", p->cutime);
1297 - if(p->cstime) fprintf(stderr, " cstime=%llu", p->cstime);
1298 - if(p->cgtime) fprintf(stderr, " cgtime=%llu", p->cgtime);
1299 - if(p->minflt) fprintf(stderr, " minflt=%llu", p->minflt);
1300 - if(p->cminflt) fprintf(stderr, " cminflt=%llu", p->cminflt);
1301 - if(p->majflt) fprintf(stderr, " majflt=%llu", p->majflt);
1302 - if(p->cmajflt) fprintf(stderr, " cmajflt=%llu", p->cmajflt);
1303 - fprintf(stderr, ")\n");
1304 -
1305 - return indent + 1;
1270 + char *prefix = "\\_ ";
1271 + int indent = 0;
1272 +
1273 + if(p->parent)
1274 + indent = print_process_and_parents(p->parent, p->stat_collected_usec);
1275 + else
1276 + prefix = " > ";
1277 +
1278 + char buffer[indent + 1];
1279 + int i;
1280 +
1281 + for(i = 0; i < indent ;i++) buffer[i] = ' ';
1282 + buffer[i] = '\0';
1283 +
1284 + fprintf(stderr, " %s %s%s (%d %s %lld"
1285 + , buffer
1286 + , prefix
1287 + , p->comm
1288 + , p->pid
1289 + , p->updated?"running":"exited"
1290 + , (long long)p->stat_collected_usec - (long long)time
1291 + );
1292 +
1293 + if(p->utime) fprintf(stderr, " utime=%llu", p->utime);
1294 + if(p->stime) fprintf(stderr, " stime=%llu", p->stime);
1295 + if(p->gtime) fprintf(stderr, " gtime=%llu", p->gtime);
1296 + if(p->cutime) fprintf(stderr, " cutime=%llu", p->cutime);
1297 + if(p->cstime) fprintf(stderr, " cstime=%llu", p->cstime);
1298 + if(p->cgtime) fprintf(stderr, " cgtime=%llu", p->cgtime);
1299 + if(p->minflt) fprintf(stderr, " minflt=%llu", p->minflt);
1300 + if(p->cminflt) fprintf(stderr, " cminflt=%llu", p->cminflt);
1301 + if(p->majflt) fprintf(stderr, " majflt=%llu", p->majflt);
1302 + if(p->cmajflt) fprintf(stderr, " cmajflt=%llu", p->cmajflt);
1303 + fprintf(stderr, ")\n");
1304 +
1305 + return indent + 1;
1306 }
1307
1308 void print_process_tree(struct pid_stat *p, char *msg) {
1309 - log_date(stderr);
1310 - fprintf(stderr, "%s: process %s (%d, %s) with parents:\n", msg, p->comm, p->pid, p->updated?"running":"exited");
1311 - print_process_and_parents(p, p->stat_collected_usec);
1309 + log_date(stderr);
1310 + fprintf(stderr, "%s: process %s (%d, %s) with parents:\n", msg, p->comm, p->pid, p->updated?"running":"exited");
1311 + print_process_and_parents(p, p->stat_collected_usec);
1312 }
1313
1314 void find_lost_child_debug(struct pid_stat *pe, unsigned long long lost, int type) {
1315 - int found = 0;
1316 - struct pid_stat *p = NULL;
1317 -
1318 - for(p = root_of_pids; p ; p = p->next) {
1319 - if(p == pe) continue;
1320 -
1321 - switch(type) {
1322 - case 1:
1323 - if(p->cminflt > lost) {
1324 - fprintf(stderr, " > process %d (%s) could use the lost exited child minflt %llu of process %d (%s)\n", p->pid, p->comm, lost, pe->pid, pe->comm);
1325 - found++;
1326 - }
1327 - break;
1328 -
1329 - case 2:
1330 - if(p->cmajflt > lost) {
1331 - fprintf(stderr, " > process %d (%s) could use the lost exited child majflt %llu of process %d (%s)\n", p->pid, p->comm, lost, pe->pid, pe->comm);
1332 - found++;
1333 - }
1334 - break;
1335 -
1336 - case 3:
1337 - if(p->cutime > lost) {
1338 - fprintf(stderr, " > process %d (%s) could use the lost exited child utime %llu of process %d (%s)\n", p->pid, p->comm, lost, pe->pid, pe->comm);
1339 - found++;
1340 - }
1341 - break;
1342 -
1343 - case 4:
1344 - if(p->cstime > lost) {
1345 - fprintf(stderr, " > process %d (%s) could use the lost exited child stime %llu of process %d (%s)\n", p->pid, p->comm, lost, pe->pid, pe->comm);
1346 - found++;
1347 - }
1348 - break;
1349 -
1350 - case 5:
1351 - if(p->cgtime > lost) {
1352 - fprintf(stderr, " > process %d (%s) could use the lost exited child gtime %llu of process %d (%s)\n", p->pid, p->comm, lost, pe->pid, pe->comm);
1353 - found++;
1354 - }
1355 - break;
1356 - }
1357 - }
1358 -
1359 - if(!found) {
1360 - switch(type) {
1361 - case 1:
1362 - fprintf(stderr, " > cannot find any process to use the lost exited child minflt %llu of process %d (%s)\n", lost, pe->pid, pe->comm);
1363 - break;
1364 -
1365 - case 2:
1366 - fprintf(stderr, " > cannot find any process to use the lost exited child majflt %llu of process %d (%s)\n", lost, pe->pid, pe->comm);
1367 - break;
1368 -
1369 - case 3:
1370 - fprintf(stderr, " > cannot find any process to use the lost exited child utime %llu of process %d (%s)\n", lost, pe->pid, pe->comm);
1371 - break;
1372 -
1373 - case 4:
1374 - fprintf(stderr, " > cannot find any process to use the lost exited child stime %llu of process %d (%s)\n", lost, pe->pid, pe->comm);
1375 - break;
1376 -
1377 - case 5:
1378 - fprintf(stderr, " > cannot find any process to use the lost exited child gtime %llu of process %d (%s)\n", lost, pe->pid, pe->comm);
1379 - break;
1380 - }
1381 - }
1315 + int found = 0;
1316 + struct pid_stat *p = NULL;
1317 +
1318 + for(p = root_of_pids; p ; p = p->next) {
1319 + if(p == pe) continue;
1320 +
1321 + switch(type) {
1322 + case 1:
1323 + if(p->cminflt > lost) {
1324 + fprintf(stderr, " > process %d (%s) could use the lost exited child minflt %llu of process %d (%s)\n", p->pid, p->comm, lost, pe->pid, pe->comm);
1325 + found++;
1326 + }
1327 + break;
1328 +
1329 + case 2:
1330 + if(p->cmajflt > lost) {
1331 + fprintf(stderr, " > process %d (%s) could use the lost exited child majflt %llu of process %d (%s)\n", p->pid, p->comm, lost, pe->pid, pe->comm);
1332 + found++;
1333 + }
1334 + break;
1335 +
1336 + case 3:
1337 + if(p->cutime > lost) {
1338 + fprintf(stderr, " > process %d (%s) could use the lost exited child utime %llu of process %d (%s)\n", p->pid, p->comm, lost, pe->pid, pe->comm);
1339 + found++;
1340 + }
1341 + break;
1342 +
1343 + case 4:
1344 + if(p->cstime > lost) {
1345 + fprintf(stderr, " > process %d (%s) could use the lost exited child stime %llu of process %d (%s)\n", p->pid, p->comm, lost, pe->pid, pe->comm);
1346 + found++;
1347 + }
1348 + break;
1349 +
1350 + case 5:
1351 + if(p->cgtime > lost) {
1352 + fprintf(stderr, " > process %d (%s) could use the lost exited child gtime %llu of process %d (%s)\n", p->pid, p->comm, lost, pe->pid, pe->comm);
1353 + found++;
1354 + }
1355 + break;
1356 + }
1357 + }
1358 +
1359 + if(!found) {
1360 + switch(type) {
1361 + case 1:
1362 + fprintf(stderr, " > cannot find any process to use the lost exited child minflt %llu of process %d (%s)\n", lost, pe->pid, pe->comm);
1363 + break;
1364 +
1365 + case 2:
1366 + fprintf(stderr, " > cannot find any process to use the lost exited child majflt %llu of process %d (%s)\n", lost, pe->pid, pe->comm);
1367 + break;
1368 +
1369 + case 3:
1370 + fprintf(stderr, " > cannot find any process to use the lost exited child utime %llu of process %d (%s)\n", lost, pe->pid, pe->comm);
1371 + break;
1372 +
1373 + case 4:
1374 + fprintf(stderr, " > cannot find any process to use the lost exited child stime %llu of process %d (%s)\n", lost, pe->pid, pe->comm);
1375 + break;
1376 +
1377 + case 5:
1378 + fprintf(stderr, " > cannot find any process to use the lost exited child gtime %llu of process %d (%s)\n", lost, pe->pid, pe->comm);
1379 + break;
1380 + }
1381 + }
1382 }
1383
1384 unsigned long long remove_exited_child_from_parent(unsigned long long *field, unsigned long long *pfield) {
1385 - unsigned long long absorbed = 0;
1386 -
1387 - if(*field > *pfield) {
1388 - absorbed += *pfield;
1389 - *field -= *pfield;
1390 - *pfield = 0;
1391 - }
1392 - else {
1393 - absorbed += *field;
1394 - *pfield -= *field;
1395 - *field = 0;
1396 - }
1397 -
1398 - return absorbed;
1385 + unsigned long long absorbed = 0;
1386 +
1387 + if(*field > *pfield) {
1388 + absorbed += *pfield;
1389 + *field -= *pfield;
1390 + *pfield = 0;
1391 + }
1392 + else {
1393 + absorbed += *field;
1394 + *pfield -= *field;
1395 + *field = 0;
1396 + }
1397 +
1398 + return absorbed;
1399 }
1400
1401 void process_exited_processes() {
1402 - struct pid_stat *p;
1403 -
1404 - for(p = root_of_pids; p ; p = p->next) {
1405 - if(p->updated || !p->stat_collected_usec)
1406 - continue;
1407 -
1408 - struct pid_stat *pp = p->parent;
1409 -
1410 - unsigned long long utime = (p->utime_raw + p->cutime_raw) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
1411 - unsigned long long stime = (p->stime_raw + p->cstime_raw) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
1412 - unsigned long long gtime = (p->gtime_raw + p->cgtime_raw) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
1413 - unsigned long long minflt = (p->minflt_raw + p->cminflt_raw) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
1414 - unsigned long long majflt = (p->majflt_raw + p->cmajflt_raw) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
1415 -
1416 - if(utime + stime + gtime + minflt + majflt == 0)
1417 - continue;
1418 -
1419 - if(unlikely(debug)) {
1420 - log_date(stderr);
1421 - fprintf(stderr, "Absorb %s (%d %s total resources: utime=%llu stime=%llu gtime=%llu minflt=%llu majflt=%llu)\n"
1422 - , p->comm
1423 - , p->pid
1424 - , p->updated?"running":"exited"
1425 - , utime
1426 - , stime
1427 - , gtime
1428 - , minflt
1429 - , majflt
1430 - );
1431 - print_process_tree(p, "Searching parents");
1432 - }
1433 -
1434 - for(pp = p->parent; pp ; pp = pp->parent) {
1435 - if(!pp->updated) continue;
1436 -
1437 - unsigned long long absorbed;
1438 - absorbed = remove_exited_child_from_parent(&utime, &pp->cutime);
1439 - if(unlikely(debug && absorbed))
1440 - fprintf(stderr, " > process %s (%d %s) absorbed %llu utime (remaining: %llu)\n", pp->comm, pp->pid, pp->updated?"running":"exited", absorbed, utime);
1441 -
1442 - absorbed = remove_exited_child_from_parent(&stime, &pp->cstime);
1443 - if(unlikely(debug && absorbed))
1444 - fprintf(stderr, " > process %s (%d %s) absorbed %llu stime (remaining: %llu)\n", pp->comm, pp->pid, pp->updated?"running":"exited", absorbed, stime);
1445 -
1446 - absorbed = remove_exited_child_from_parent(&gtime, &pp->cgtime);
1447 - if(unlikely(debug && absorbed))
1448 - fprintf(stderr, " > process %s (%d %s) absorbed %llu gtime (remaining: %llu)\n", pp->comm, pp->pid, pp->updated?"running":"exited", absorbed, gtime);
1449 -
1450 - absorbed = remove_exited_child_from_parent(&minflt, &pp->cminflt);
1451 - if(unlikely(debug && absorbed))
1452 - fprintf(stderr, " > process %s (%d %s) absorbed %llu minflt (remaining: %llu)\n", pp->comm, pp->pid, pp->updated?"running":"exited", absorbed, minflt);
1453 -
1454 - absorbed = remove_exited_child_from_parent(&majflt, &pp->cmajflt);
1455 - if(unlikely(debug && absorbed))
1456 - fprintf(stderr, " > process %s (%d %s) absorbed %llu majflt (remaining: %llu)\n", pp->comm, pp->pid, pp->updated?"running":"exited", absorbed, majflt);
1457 - }
1458 -
1459 - if(unlikely(utime + stime + gtime + minflt + majflt > 0)) {
1460 - if(unlikely(debug)) {
1461 - if(utime) find_lost_child_debug(p, utime, 3);
1462 - if(stime) find_lost_child_debug(p, stime, 4);
1463 - if(gtime) find_lost_child_debug(p, gtime, 5);
1464 - if(minflt) find_lost_child_debug(p, minflt, 1);
1465 - if(majflt) find_lost_child_debug(p, majflt, 2);
1466 - }
1467 -
1468 - p->keep = 1;
1469 -
1470 - if(unlikely(debug))
1471 - fprintf(stderr, " > remaining resources - KEEP - for another loop: %s (%d %s total resources: utime=%llu stime=%llu gtime=%llu minflt=%llu majflt=%llu)\n"
1472 - , p->comm
1473 - , p->pid
1474 - , p->updated?"running":"exited"
1475 - , utime
1476 - , stime
1477 - , gtime
1478 - , minflt
1479 - , majflt
1480 - );
1481 -
1482 - for(pp = p->parent; pp ; pp = pp->parent) {
1483 - if(pp->updated) break;
1484 - pp->keep = 1;
1485 -
1486 - if(unlikely(debug))
1487 - fprintf(stderr, " > - KEEP - parent for another loop: %s (%d %s)\n"
1488 - , pp->comm
1489 - , pp->pid
1490 - , pp->updated?"running":"exited"
1491 - );
1492 - }
1493 -
1494 - p->utime_raw = utime * (p->stat_collected_usec - p->last_stat_collected_usec) / (1000000ULL * RATES_DETAIL);
1495 - p->stime_raw = stime * (p->stat_collected_usec - p->last_stat_collected_usec) / (1000000ULL * RATES_DETAIL);
1496 - p->gtime_raw = gtime * (p->stat_collected_usec - p->last_stat_collected_usec) / (1000000ULL * RATES_DETAIL);
1497 - p->minflt_raw = minflt * (p->stat_collected_usec - p->last_stat_collected_usec) / (1000000ULL * RATES_DETAIL);
1498 - p->majflt_raw = majflt * (p->stat_collected_usec - p->last_stat_collected_usec) / (1000000ULL * RATES_DETAIL);
1499 - p->cutime_raw = p->cstime_raw = p->cgtime_raw = p->cminflt_raw = p->cmajflt_raw = 0;
1500 -
1501 - if(unlikely(debug))
1502 - fprintf(stderr, "\n");
1503 - }
1504 - else if(unlikely(debug)) {
1505 - fprintf(stderr, " > totally absorbed - DONE - %s (%d %s)\n"
1506 - , p->comm
1507 - , p->pid
1508 - , p->updated?"running":"exited"
1509 - );
1510 - }
1511 - }
1402 + struct pid_stat *p;
1403 +
1404 + for(p = root_of_pids; p ; p = p->next) {
1405 + if(p->updated || !p->stat_collected_usec)
1406 + continue;
1407 +
1408 + struct pid_stat *pp = p->parent;
1409 +
1410 + unsigned long long utime = (p->utime_raw + p->cutime_raw) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
1411 + unsigned long long stime = (p->stime_raw + p->cstime_raw) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
1412 + unsigned long long gtime = (p->gtime_raw + p->cgtime_raw) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
1413 + unsigned long long minflt = (p->minflt_raw + p->cminflt_raw) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
1414 + unsigned long long majflt = (p->majflt_raw + p->cmajflt_raw) * (1000000ULL * RATES_DETAIL) / (p->stat_collected_usec - p->last_stat_collected_usec);
1415 +
1416 + if(utime + stime + gtime + minflt + majflt == 0)
1417 + continue;
1418 +
1419 + if(unlikely(debug)) {
1420 + log_date(stderr);
1421 + fprintf(stderr, "Absorb %s (%d %s total resources: utime=%llu stime=%llu gtime=%llu minflt=%llu majflt=%llu)\n"
1422 + , p->comm
1423 + , p->pid
1424 + , p->updated?"running":"exited"
1425 + , utime
1426 + , stime
1427 + , gtime
1428 + , minflt
1429 + , majflt
1430 + );
1431 + print_process_tree(p, "Searching parents");
1432 + }
1433 +
1434 + for(pp = p->parent; pp ; pp = pp->parent) {
1435 + if(!pp->updated) continue;
1436 +
1437 + unsigned long long absorbed;
1438 + absorbed = remove_exited_child_from_parent(&utime, &pp->cutime);
1439 + if(unlikely(debug && absorbed))
1440 + fprintf(stderr, " > process %s (%d %s) absorbed %llu utime (remaining: %llu)\n", pp->comm, pp->pid, pp->updated?"running":"exited", absorbed, utime);
1441 +
1442 + absorbed = remove_exited_child_from_parent(&stime, &pp->cstime);
1443 + if(unlikely(debug && absorbed))
1444 + fprintf(stderr, " > process %s (%d %s) absorbed %llu stime (remaining: %llu)\n", pp->comm, pp->pid, pp->updated?"running":"exited", absorbed, stime);
1445 +
1446 + absorbed = remove_exited_child_from_parent(&gtime, &pp->cgtime);
1447 + if(unlikely(debug && absorbed))
1448 + fprintf(stderr, " > process %s (%d %s) absorbed %llu gtime (remaining: %llu)\n", pp->comm, pp->pid, pp->updated?"running":"exited", absorbed, gtime);
1449 +
1450 + absorbed = remove_exited_child_from_parent(&minflt, &pp->cminflt);
1451 + if(unlikely(debug && absorbed))
1452 + fprintf(stderr, " > process %s (%d %s) absorbed %llu minflt (remaining: %llu)\n", pp->comm, pp->pid, pp->updated?"running":"exited", absorbed, minflt);
1453 +
1454 + absorbed = remove_exited_child_from_parent(&majflt, &pp->cmajflt);
1455 + if(unlikely(debug && absorbed))
1456 + fprintf(stderr, " > process %s (%d %s) absorbed %llu majflt (remaining: %llu)\n", pp->comm, pp->pid, pp->updated?"running":"exited", absorbed, majflt);
1457 + }
1458 +
1459 + if(unlikely(utime + stime + gtime + minflt + majflt > 0)) {
1460 + if(unlikely(debug)) {
1461 + if(utime) find_lost_child_debug(p, utime, 3);
1462 + if(stime) find_lost_child_debug(p, stime, 4);
1463 + if(gtime) find_lost_child_debug(p, gtime, 5);
1464 + if(minflt) find_lost_child_debug(p, minflt, 1);
1465 + if(majflt) find_lost_child_debug(p, majflt, 2);
1466 + }
1467 +
1468 + p->keep = 1;
1469 +
1470 + if(unlikely(debug))
1471 + fprintf(stderr, " > remaining resources - KEEP - for another loop: %s (%d %s total resources: utime=%llu stime=%llu gtime=%llu minflt=%llu majflt=%llu)\n"
1472 + , p->comm
1473 + , p->pid
1474 + , p->updated?"running":"exited"
1475 + , utime
1476 + , stime
1477 + , gtime
1478 + , minflt
1479 + , majflt
1480 + );
1481 +
1482 + for(pp = p->parent; pp ; pp = pp->parent) {
1483 + if(pp->updated) break;
1484 + pp->keep = 1;
1485 +
1486 + if(unlikely(debug))
1487 + fprintf(stderr, " > - KEEP - parent for another loop: %s (%d %s)\n"
1488 + , pp->comm
1489 + , pp->pid
1490 + , pp->updated?"running":"exited"
1491 + );
1492 + }
1493 +
1494 + p->utime_raw = utime * (p->stat_collected_usec - p->last_stat_collected_usec) / (1000000ULL * RATES_DETAIL);
1495 + p->stime_raw = stime * (p->stat_collected_usec - p->last_stat_collected_usec) / (1000000ULL * RATES_DETAIL);
1496 + p->gtime_raw = gtime * (p->stat_collected_usec - p->last_stat_collected_usec) / (1000000ULL * RATES_DETAIL);
1497 + p->minflt_raw = minflt * (p->stat_collected_usec - p->last_stat_collected_usec) / (1000000ULL * RATES_DETAIL);
1498 + p->majflt_raw = majflt * (p->stat_collected_usec - p->last_stat_collected_usec) / (1000000ULL * RATES_DETAIL);
1499 + p->cutime_raw = p->cstime_raw = p->cgtime_raw = p->cminflt_raw = p->cmajflt_raw = 0;
1500 +
1501 + if(unlikely(debug))
1502 + fprintf(stderr, "\n");
1503 + }
1504 + else if(unlikely(debug)) {
1505 + fprintf(stderr, " > totally absorbed - DONE - %s (%d %s)\n"
1506 + , p->comm
1507 + , p->pid
1508 + , p->updated?"running":"exited"
1509 + );
1510 + }
1511 + }
1512 }
1513
1514 void link_all_processes_to_their_parents(void) {
1515 - struct pid_stat *p, *pp;
1516 -
1517 - // link all children to their parents
1518 - // and update children count on parents
1519 - for(p = root_of_pids; p ; p = p->next) {
1520 - // for each process found
1521 -
1522 - p->sortlist = 0;
1523 - p->parent = NULL;
1524 -
1525 - if(unlikely(!p->ppid)) {
1526 - p->parent = NULL;
1527 - continue;
1528 - }
1529 -
1530 - pp = all_pids[p->ppid];
1531 - if(likely(pp)) {
1532 - p->parent = pp;
1533 - pp->children_count++;
1534 -
1535 - if(unlikely(debug || (p->target && p->target->debug)))
1536 - fprintf(stderr, "apps.plugin: \tchild %d (%s, %s) on target '%s' has parent %d (%s, %s). Parent: utime=%llu, stime=%llu, gtime=%llu, minflt=%llu, majflt=%llu, cutime=%llu, cstime=%llu, cgtime=%llu, cminflt=%llu, cmajflt=%llu\n", p->pid, p->comm, p->updated?"running":"exited", (p->target)?p->target->name:"UNSET", pp->pid, pp->comm, pp->updated?"running":"exited", pp->utime, pp->stime, pp->gtime, pp->minflt, pp->majflt, pp->cutime, pp->cstime, pp->cgtime, pp->cminflt, pp->cmajflt);
1537 - }
1538 - else {
1539 - p->parent = NULL;
1540 - error("pid %d %s states parent %d, but the later does not exist.", p->pid, p->comm, p->ppid);
1541 - }
1542 - }
1515 + struct pid_stat *p, *pp;
1516 +
1517 + // link all children to their parents
1518 + // and update children count on parents
1519 + for(p = root_of_pids; p ; p = p->next) {
1520 + // for each process found
1521 +
1522 + p->sortlist = 0;
1523 + p->parent = NULL;
1524 +
1525 + if(unlikely(!p->ppid)) {
1526 + p->parent = NULL;
1527 + continue;
1528 + }
1529 +
1530 + pp = all_pids[p->ppid];
1531 + if(likely(pp)) {
1532 + p->parent = pp;
1533 + pp->children_count++;
1534 +
1535 + if(unlikely(debug || (p->target && p->target->debug)))
1536 + fprintf(stderr, "apps.plugin: \tchild %d (%s, %s) on target '%s' has parent %d (%s, %s). Parent: utime=%llu, stime=%llu, gtime=%llu, minflt=%llu, majflt=%llu, cutime=%llu, cstime=%llu, cgtime=%llu, cminflt=%llu, cmajflt=%llu\n", p->pid, p->comm, p->updated?"running":"exited", (p->target)?p->target->name:"UNSET", pp->pid, pp->comm, pp->updated?"running":"exited", pp->utime, pp->stime, pp->gtime, pp->minflt, pp->majflt, pp->cutime, pp->cstime, pp->cgtime, pp->cminflt, pp->cmajflt);
1537 + }
1538 + else {
1539 + p->parent = NULL;
1540 + error("pid %d %s states parent %d, but the later does not exist.", p->pid, p->comm, p->ppid);
1541 + }
1542 + }
1543 }
1544
1545 // ----------------------------------------------------------------------------
@@ -1562,203 +1562,203 @@ void link_all_processes_to_their_parents(void) {
1562
1563 static int compar_pid(const void *pid1, const void *pid2) {
1564
1565 - struct pid_stat *p1 = all_pids[*((pid_t *)pid1)];
1566 - struct pid_stat *p2 = all_pids[*((pid_t *)pid2)];
1565 + struct pid_stat *p1 = all_pids[*((pid_t *)pid1)];
1566 + struct pid_stat *p2 = all_pids[*((pid_t *)pid2)];
1567
1568 - if(p1->sortlist > p2->sortlist)
1569 - return -1;
1570 - else
1571 - return 1;
1568 + if(p1->sortlist > p2->sortlist)
1569 + return -1;
1570 + else
1571 + return 1;
1572 }
1573
1574 void collect_data_for_pid(pid_t pid) {
1575 - if(unlikely(pid <= 0 || pid > pid_max)) {
1576 - error("Invalid pid %d read (expected 1 to %d). Ignoring process.", pid, pid_max);
1577 - return;
1578 - }
1579 -
1580 - struct pid_stat *p = get_pid_entry(pid);
1581 - if(unlikely(!p || p->read)) return;
1582 - p->read = 1;
1583 -
1584 - // fprintf(stderr, "Reading process %d (%s), sortlist %d\n", p->pid, p->comm, p->sortlist);
1585 -
1586 - // --------------------------------------------------------------------
1587 - // /proc/<pid>/stat
1588 -
1589 - if(unlikely(read_proc_pid_stat(p))) {
1590 - if(errno != ENOENT || debug)
1591 - error("Cannot process %s/proc/%d/stat (command '%s')", host_prefix, pid, p->comm);
1592 - else
1593 - errno = 0;
1594 - // there is no reason to proceed if we cannot get its status
1595 - return;
1596 - }
1597 -
1598 - read_proc_pid_ownership(p);
1599 -
1600 - // check its parent pid
1601 - if(unlikely(p->ppid < 0 || p->ppid > pid_max)) {
1602 - error("Pid %d (command '%s') states invalid parent pid %d. Using 0.", pid, p->comm, p->ppid);
1603 - p->ppid = 0;
1604 - }
1605 -
1606 - // --------------------------------------------------------------------
1607 - // /proc/<pid>/io
1608 -
1609 - if(unlikely(read_proc_pid_io(p))) {
1610 - if(errno != ENOENT || debug)
1611 - error("Cannot process %s/proc/%d/io (command '%s')", host_prefix, pid, p->comm);
1612 - else
1613 - errno = 0;
1614 - }
1615 -
1616 - // --------------------------------------------------------------------
1617 - // /proc/<pid>/statm
1618 -
1619 - if(unlikely(read_proc_pid_statm(p))) {
1620 - if(errno != ENOENT || debug)
1621 - error("Cannot process %s/proc/%d/statm (command '%s')", host_prefix, pid, p->comm);
1622 - else
1623 - errno = 0;
1624 - // there is no reason to proceed if we cannot get its memory status
1625 - return;
1626 - }
1627 -
1628 - // --------------------------------------------------------------------
1629 - // link it
1630 -
1631 - // check if it is target
1632 - // we do this only once, the first time this pid is loaded
1633 - if(unlikely(p->new_entry)) {
1634 - // /proc/<pid>/cmdline
1635 - if(likely(proc_pid_cmdline_is_needed)) {
1636 - if(unlikely(read_proc_pid_cmdline(p))) {
1637 - if(errno != ENOENT || debug)
1638 - error("Cannot process %s/proc/%d/cmdline (command '%s')", host_prefix, pid, p->comm);
1639 - else
1640 - errno = 0;
1641 - }
1642 - }
1643 -
1644 - if(unlikely(debug))
1645 - fprintf(stderr, "apps.plugin: \tJust added %d (%s)\n", pid, p->comm);
1646 -
1647 - uint32_t hash = simple_hash(p->comm);
1648 - size_t pclen = strlen(p->comm);
1649 -
1650 - struct target *w;
1651 - for(w = apps_groups_root_target; w ; w = w->next) {
1652 - // if(debug || (p->target && p->target->debug)) fprintf(stderr, "apps.plugin: \t\tcomparing '%s' with '%s'\n", w->compare, p->comm);
1653 -
1654 - // find it - 4 cases:
1655 - // 1. the target is not a pattern
1656 - // 2. the target has the prefix
1657 - // 3. the target has the suffix
1658 - // 4. the target is something inside cmdline
1659 - if( (!w->starts_with && !w->ends_with && w->comparehash == hash && !strcmp(w->compare, p->comm))
1660 - || (w->starts_with && !w->ends_with && !strncmp(w->compare, p->comm, w->comparelen))
1661 - || (!w->starts_with && w->ends_with && pclen >= w->comparelen && !strcmp(w->compare, &p->comm[pclen - w->comparelen]))
1662 - || (proc_pid_cmdline_is_needed && w->starts_with && w->ends_with && strstr(p->cmdline, w->compare))
1663 - ) {
1664 - if(w->target) p->target = w->target;
1665 - else p->target = w;
1666 -
1667 - if(debug || (p->target && p->target->debug))
1668 - fprintf(stderr, "apps.plugin: \t\t%s linked to target %s\n", p->comm, p->target->name);
1669 -
1670 - break;
1671 - }
1672 - }
1673 - }
1674 -
1675 - // --------------------------------------------------------------------
1676 - // /proc/<pid>/fd
1677 -
1678 - if(unlikely(read_pid_file_descriptors(p))) {
1679 - if(errno != ENOENT || debug)
1680 - error("Cannot process entries in %s/proc/%d/fd (command '%s')", host_prefix, pid, p->comm);
1681 - else
1682 - errno = 0;
1683 - }
1684 -
1685 - // --------------------------------------------------------------------
1686 - // done!
1687 -
1688 - if(unlikely(debug && include_exited_childs && all_pids_count && p->ppid && all_pids[p->ppid] && !all_pids[p->ppid]->read))
1689 - fprintf(stderr, "Read process %d (%s) sortlisted %d, but its parent %d (%s) sortlisted %d, is not read\n", p->pid, p->comm, p->sortlist, all_pids[p->ppid]->pid, all_pids[p->ppid]->comm, all_pids[p->ppid]->sortlist);
1690 -
1691 - // mark it as updated
1692 - p->updated = 1;
1693 - p->keep = 0;
1694 - p->keeploops = 0;
1575 + if(unlikely(pid <= 0 || pid > pid_max)) {
1576 + error("Invalid pid %d read (expected 1 to %d). Ignoring process.", pid, pid_max);
1577 + return;
1578 + }
1579 +
1580 + struct pid_stat *p = get_pid_entry(pid);
1581 + if(unlikely(!p || p->read)) return;
1582 + p->read = 1;
1583 +
1584 + // fprintf(stderr, "Reading process %d (%s), sortlist %d\n", p->pid, p->comm, p->sortlist);
1585 +
1586 + // --------------------------------------------------------------------
1587 + // /proc/<pid>/stat
1588 +
1589 + if(unlikely(read_proc_pid_stat(p))) {
1590 + if(errno != ENOENT || debug)
1591 + error("Cannot process %s/proc/%d/stat (command '%s')", host_prefix, pid, p->comm);
1592 + else
1593 + errno = 0;
1594 + // there is no reason to proceed if we cannot get its status
1595 + return;
1596 + }
1597 +
1598 + read_proc_pid_ownership(p);
1599 +
1600 + // check its parent pid
1601 + if(unlikely(p->ppid < 0 || p->ppid > pid_max)) {
1602 + error("Pid %d (command '%s') states invalid parent pid %d. Using 0.", pid, p->comm, p->ppid);
1603 + p->ppid = 0;
1604 + }
1605 +
1606 + // --------------------------------------------------------------------
1607 + // /proc/<pid>/io
1608 +
1609 + if(unlikely(read_proc_pid_io(p))) {
1610 + if(errno != ENOENT || debug)
1611 + error("Cannot process %s/proc/%d/io (command '%s')", host_prefix, pid, p->comm);
1612 + else
1613 + errno = 0;
1614 + }
1615 +
1616 + // --------------------------------------------------------------------
1617 + // /proc/<pid>/statm
1618 +
1619 + if(unlikely(read_proc_pid_statm(p))) {
1620 + if(errno != ENOENT || debug)
1621 + error("Cannot process %s/proc/%d/statm (command '%s')", host_prefix, pid, p->comm);
1622 + else
1623 + errno = 0;
1624 + // there is no reason to proceed if we cannot get its memory status
1625 + return;
1626 + }
1627 +
1628 + // --------------------------------------------------------------------
1629 + // link it
1630 +
1631 + // check if it is target
1632 + // we do this only once, the first time this pid is loaded
1633 + if(unlikely(p->new_entry)) {
1634 + // /proc/<pid>/cmdline
1635 + if(likely(proc_pid_cmdline_is_needed)) {
1636 + if(unlikely(read_proc_pid_cmdline(p))) {
1637 + if(errno != ENOENT || debug)
1638 + error("Cannot process %s/proc/%d/cmdline (command '%s')", host_prefix, pid, p->comm);
1639 + else
1640 + errno = 0;
1641 + }
1642 + }
1643 +
1644 + if(unlikely(debug))
1645 + fprintf(stderr, "apps.plugin: \tJust added %d (%s)\n", pid, p->comm);
1646 +
1647 + uint32_t hash = simple_hash(p->comm);
1648 + size_t pclen = strlen(p->comm);
1649 +
1650 + struct target *w;
1651 + for(w = apps_groups_root_target; w ; w = w->next) {
1652 + // if(debug || (p->target && p->target->debug)) fprintf(stderr, "apps.plugin: \t\tcomparing '%s' with '%s'\n", w->compare, p->comm);
1653 +
1654 + // find it - 4 cases:
1655 + // 1. the target is not a pattern
1656 + // 2. the target has the prefix
1657 + // 3. the target has the suffix
1658 + // 4. the target is something inside cmdline
1659 + if( (!w->starts_with && !w->ends_with && w->comparehash == hash && !strcmp(w->compare, p->comm))
1660 + || (w->starts_with && !w->ends_with && !strncmp(w->compare, p->comm, w->comparelen))
1661 + || (!w->starts_with && w->ends_with && pclen >= w->comparelen && !strcmp(w->compare, &p->comm[pclen - w->comparelen]))
1662 + || (proc_pid_cmdline_is_needed && w->starts_with && w->ends_with && strstr(p->cmdline, w->compare))
1663 + ) {
1664 + if(w->target) p->target = w->target;
1665 + else p->target = w;
1666 +
1667 + if(debug || (p->target && p->target->debug))
1668 + fprintf(stderr, "apps.plugin: \t\t%s linked to target %s\n", p->comm, p->target->name);
1669 +
1670 + break;
1671 + }
1672 + }
1673 + }
1674 +
1675 + // --------------------------------------------------------------------
1676 + // /proc/<pid>/fd
1677 +
1678 + if(unlikely(read_pid_file_descriptors(p))) {
1679 + if(errno != ENOENT || debug)
1680 + error("Cannot process entries in %s/proc/%d/fd (command '%s')", host_prefix, pid, p->comm);
1681 + else
1682 + errno = 0;
1683 + }
1684 +
1685 + // --------------------------------------------------------------------
1686 + // done!
1687 +
1688 + if(unlikely(debug && include_exited_childs && all_pids_count && p->ppid && all_pids[p->ppid] && !all_pids[p->ppid]->read))
1689 + fprintf(stderr, "Read process %d (%s) sortlisted %d, but its parent %d (%s) sortlisted %d, is not read\n", p->pid, p->comm, p->sortlist, all_pids[p->ppid]->pid, all_pids[p->ppid]->comm, all_pids[p->ppid]->sortlist);
1690 +
1691 + // mark it as updated
1692 + p->updated = 1;
1693 + p->keep = 0;
1694 + p->keeploops = 0;
1695 }
1696
1697 int collect_data_for_all_processes_from_proc(void) {
1698 - struct pid_stat *p = NULL;
1699 -
1700 - if(all_pids_count) {
1701 - // read parents before childs
1702 - // this is needed to prevent a situation where
1703 - // a child is found running, but until we read
1704 - // its parent, it has exited and its parent
1705 - // has accumulated its resources
1706 -
1707 - long slc = 0;
1708 - for(p = root_of_pids; p ; p = p->next) {
1709 - p->read = 0;
1710 - p->updated = 0;
1711 - p->new_entry = 0;
1712 - p->merged = 0;
1713 - p->children_count = 0;
1714 - p->parent = NULL;
1715 -
1716 - all_pids_sortlist[slc++] = p->pid;
1717 - }
1718 -
1719 - if(unlikely(slc != all_pids_count)) {
1720 - error("Internal error: I was thinking I had %ld processes in my arrays, but it seems there are more.", all_pids_count);
1721 - all_pids_count = slc;
1722 - }
1723 -
1724 - if(include_exited_childs) {
1725 - qsort((void *)all_pids_sortlist, all_pids_count, sizeof(pid_t), compar_pid);
1726 - for(slc = 0; slc < all_pids_count; slc++)
1727 - collect_data_for_pid(all_pids_sortlist[slc]);
1728 - }
1729 - }
1730 -
1731 - char dirname[FILENAME_MAX + 1];
1732 -
1733 - snprintfz(dirname, FILENAME_MAX, "%s/proc", host_prefix);
1734 - DIR *dir = opendir(dirname);
1735 - if(!dir) return 0;
1736 -
1737 - struct dirent *file = NULL;
1738 -
1739 - while((file = readdir(dir))) {
1740 - char *endptr = file->d_name;
1741 - pid_t pid = (pid_t) strtoul(file->d_name, &endptr, 10);
1742 -
1743 - // make sure we read a valid number
1744 - if(unlikely(endptr == file->d_name || *endptr != '\0'))
1745 - continue;
1746 -
1747 - collect_data_for_pid(pid);
1748 - }
1749 - closedir(dir);
1750 -
1751 - // normally this is done
1752 - // however we may have processes exited while we collected values
1753 - // so let's find the exited ones
1754 - // we do this by collecting the ownership of process
1755 - // if we manage to get the ownership, the process still runs
1756 -
1757 - read_proc_stat();
1758 - link_all_processes_to_their_parents();
1759 - process_exited_processes();
1760 -
1761 - return 1;
1698 + struct pid_stat *p = NULL;
1699 +
1700 + if(all_pids_count) {
1701 + // read parents before childs
1702 + // this is needed to prevent a situation where
1703 + // a child is found running, but until we read
1704 + // its parent, it has exited and its parent
1705 + // has accumulated its resources
1706 +
1707 + long slc = 0;
1708 + for(p = root_of_pids; p ; p = p->next) {
1709 + p->read = 0;
1710 + p->updated = 0;
1711 + p->new_entry = 0;
1712 + p->merged = 0;
1713 + p->children_count = 0;
1714 + p->parent = NULL;
1715 +
1716 + all_pids_sortlist[slc++] = p->pid;
1717 + }
1718 +
1719 + if(unlikely(slc != all_pids_count)) {
1720 + error("Internal error: I was thinking I had %ld processes in my arrays, but it seems there are more.", all_pids_count);
1721 + all_pids_count = slc;
1722 + }
1723 +
1724 + if(include_exited_childs) {
1725 + qsort((void *)all_pids_sortlist, all_pids_count, sizeof(pid_t), compar_pid);
1726 + for(slc = 0; slc < all_pids_count; slc++)
1727 + collect_data_for_pid(all_pids_sortlist[slc]);
1728 + }
1729 + }
1730 +
1731 + char dirname[FILENAME_MAX + 1];
1732 +
1733 + snprintfz(dirname, FILENAME_MAX, "%s/proc", host_prefix);
1734 + DIR *dir = opendir(dirname);
1735 + if(!dir) return 0;
1736 +
1737 + struct dirent *file = NULL;
1738 +
1739 + while((file = readdir(dir))) {
1740 + char *endptr = file->d_name;
1741 + pid_t pid = (pid_t) strtoul(file->d_name, &endptr, 10);
1742 +
1743 + // make sure we read a valid number
1744 + if(unlikely(endptr == file->d_name || *endptr != '\0'))
1745 + continue;
1746 +
1747 + collect_data_for_pid(pid);
1748 + }
1749 + closedir(dir);
1750 +
1751 + // normally this is done
1752 + // however we may have processes exited while we collected values
1753 + // so let's find the exited ones
1754 + // we do this by collecting the ownership of process
1755 + // if we manage to get the ownership, the process still runs
1756 +
1757 + read_proc_stat();
1758 + link_all_processes_to_their_parents();
1759 + process_exited_processes();
1760 +
1761 + return 1;
1762 }
1763
1764 // ----------------------------------------------------------------------------
@@ -1778,371 +1778,371 @@ int collect_data_for_all_processes_from_proc(void) {
1778 // check: update_apps_groups_statistics()
1779
1780 void cleanup_exited_pids(void) {
1781 - int c;
1782 - struct pid_stat *p = NULL;
1783 -
1784 - for(p = root_of_pids; p ;) {
1785 - if(!p->updated && (!p->keep || p->keeploops > 0)) {
1786 -// fprintf(stderr, "\tEXITED %d %s [parent %d %s, target %s] utime=%llu, stime=%llu, gtime=%llu, cutime=%llu, cstime=%llu, cgtime=%llu, minflt=%llu, majflt=%llu, cminflt=%llu, cmajflt=%llu\n", p->pid, p->comm, p->parent->pid, p->parent->comm, p->target->name, p->utime, p->stime, p->gtime, p->cutime, p->cstime, p->cgtime, p->minflt, p->majflt, p->cminflt, p->cmajflt);
1787 -
1788 - if(unlikely(debug && (p->keep || p->keeploops)))
1789 - fprintf(stderr, " > CLEANUP cannot keep exited process %d (%s) anymore - removing it.\n", p->pid, p->comm);
1790 -
1791 - for(c = 0 ; c < p->fds_size ; c++) if(p->fds[c] > 0) {
1792 - file_descriptor_not_used(p->fds[c]);
1793 - p->fds[c] = 0;
1794 - }
1795 -
1796 - pid_t r = p->pid;
1797 - p = p->next;
1798 - del_pid_entry(r);
1799 - }
1800 - else {
1801 - if(unlikely(p->keep)) p->keeploops++;
1802 - p->keep = 0;
1803 - p = p->next;
1804 - }
1805 - }
1781 + int c;
1782 + struct pid_stat *p = NULL;
1783 +
1784 + for(p = root_of_pids; p ;) {
1785 + if(!p->updated && (!p->keep || p->keeploops > 0)) {
1786 +// fprintf(stderr, "\tEXITED %d %s [parent %d %s, target %s] utime=%llu, stime=%llu, gtime=%llu, cutime=%llu, cstime=%llu, cgtime=%llu, minflt=%llu, majflt=%llu, cminflt=%llu, cmajflt=%llu\n", p->pid, p->comm, p->parent->pid, p->parent->comm, p->target->name, p->utime, p->stime, p->gtime, p->cutime, p->cstime, p->cgtime, p->minflt, p->majflt, p->cminflt, p->cmajflt);
1787 +
1788 + if(unlikely(debug && (p->keep || p->keeploops)))
1789 + fprintf(stderr, " > CLEANUP cannot keep exited process %d (%s) anymore - removing it.\n", p->pid, p->comm);
1790 +
1791 + for(c = 0 ; c < p->fds_size ; c++) if(p->fds[c] > 0) {
1792 + file_descriptor_not_used(p->fds[c]);
1793 + p->fds[c] = 0;
1794 + }
1795 +
1796 + pid_t r = p->pid;
1797 + p = p->next;
1798 + del_pid_entry(r);
1799 + }
1800 + else {
1801 + if(unlikely(p->keep)) p->keeploops++;
1802 + p->keep = 0;
1803 + p = p->next;
1804 + }
1805 + }
1806 }
1807
1808 void apply_apps_groups_targets_inheritance(void) {
1809 - struct pid_stat *p = NULL;
1810 -
1811 - // children that do not have a target
1812 - // inherit their target from their parent
1813 - int found = 1, loops = 0;
1814 - while(found) {
1815 - if(unlikely(debug)) loops++;
1816 - found = 0;
1817 - for(p = root_of_pids; p ; p = p->next) {
1818 - // if this process does not have a target
1819 - // and it has a parent
1820 - // and its parent has a target
1821 - // then, set the parent's target to this process
1822 - if(unlikely(!p->target && p->parent && p->parent->target)) {
1823 - p->target = p->parent->target;
1824 - found++;
1825 -
1826 - if(debug || (p->target && p->target->debug))
1827 - fprintf(stderr, "apps.plugin: \t\tTARGET INHERITANCE: %s is inherited by %d (%s) from its parent %d (%s).\n", p->target->name, p->pid, p->comm, p->parent->pid, p->parent->comm);
1828 - }
1829 - }
1830 - }
1831 -
1832 - // find all the procs with 0 childs and merge them to their parents
1833 - // repeat, until nothing more can be done.
1834 - int sortlist = 1;
1835 - found = 1;
1836 - while(found) {
1837 - if(unlikely(debug)) loops++;
1838 - found = 0;
1839 -
1840 - for(p = root_of_pids; p ; p = p->next) {
1841 - if(unlikely(!p->sortlist && !p->children_count))
1842 - p->sortlist = sortlist++;
1843 -
1844 - // if this process does not have any children
1845 - // and is not already merged
1846 - // and has a parent
1847 - // and its parent has children
1848 - // and the target of this process and its parent is the same, or the parent does not have a target
1849 - // and its parent is not init
1850 - // then, mark them as merged.
1851 - if(unlikely(
1852 - !p->children_count
1853 - && !p->merged
1854 - && p->parent
1855 - && p->parent->children_count
1856 - && (p->target == p->parent->target || !p->parent->target)
1857 - && p->ppid != 1
1858 - )) {
1859 - p->parent->children_count--;
1860 - p->merged = 1;
1861 -
1862 - // the parent inherits the child's target, if it does not have a target itself
1863 - if(unlikely(p->target && !p->parent->target)) {
1864 - p->parent->target = p->target;
1865 -
1866 - if(debug || (p->target && p->target->debug))
1867 - fprintf(stderr, "apps.plugin: \t\tTARGET INHERITANCE: %s is inherited by %d (%s) from its child %d (%s).\n", p->target->name, p->parent->pid, p->parent->comm, p->pid, p->comm);
1868 - }
1869 -
1870 - found++;
1871 - }
1872 - }
1873 -
1874 - if(unlikely(debug))
1875 - fprintf(stderr, "apps.plugin: TARGET INHERITANCE: merged %d processes\n", found);
1876 - }
1877 -
1878 - // init goes always to default target
1879 - if(all_pids[1])
1880 - all_pids[1]->target = apps_groups_default_target;
1881 -
1882 - // give a default target on all top level processes
1883 - if(unlikely(debug)) loops++;
1884 - for(p = root_of_pids; p ; p = p->next) {
1885 - // if the process is not merged itself
1886 - // then is is a top level process
1887 - if(unlikely(!p->merged && !p->target))
1888 - p->target = apps_groups_default_target;
1889 -
1890 - // make sure all processes have a sortlist
1891 - if(unlikely(!p->sortlist))
1892 - p->sortlist = sortlist++;
1893 - }
1894 -
1895 - if(all_pids[1])
1896 - all_pids[1]->sortlist = sortlist++;
1897 -
1898 - // give a target to all merged child processes
1899 - found = 1;
1900 - while(found) {
1901 - if(unlikely(debug)) loops++;
1902 - found = 0;
1903 - for(p = root_of_pids; p ; p = p->next) {
1904 - if(unlikely(!p->target && p->merged && p->parent && p->parent->target)) {
1905 - p->target = p->parent->target;
1906 - found++;
1907 -
1908 - if(debug || (p->target && p->target->debug))
1909 - fprintf(stderr, "apps.plugin: \t\tTARGET INHERITANCE: %s is inherited by %d (%s) from its parent %d (%s) at phase 2.\n", p->target->name, p->pid, p->comm, p->parent->pid, p->parent->comm);
1910 - }
1911 - }
1912 - }
1913 -
1914 - if(unlikely(debug))
1915 - fprintf(stderr, "apps.plugin: apply_apps_groups_targets_inheritance() made %d loops on the process tree\n", loops);
1809 + struct pid_stat *p = NULL;
1810 +
1811 + // children that do not have a target
1812 + // inherit their target from their parent
1813 + int found = 1, loops = 0;
1814 + while(found) {
1815 + if(unlikely(debug)) loops++;
1816 + found = 0;
1817 + for(p = root_of_pids; p ; p = p->next) {
1818 + // if this process does not have a target
1819 + // and it has a parent
1820 + // and its parent has a target
1821 + // then, set the parent's target to this process
1822 + if(unlikely(!p->target && p->parent && p->parent->target)) {
1823 + p->target = p->parent->target;
1824 + found++;
1825 +
1826 + if(debug || (p->target && p->target->debug))
1827 + fprintf(stderr, "apps.plugin: \t\tTARGET INHERITANCE: %s is inherited by %d (%s) from its parent %d (%s).\n", p->target->name, p->pid, p->comm, p->parent->pid, p->parent->comm);
1828 + }
1829 + }
1830 + }
1831 +
1832 + // find all the procs with 0 childs and merge them to their parents
1833 + // repeat, until nothing more can be done.
1834 + int sortlist = 1;
1835 + found = 1;
1836 + while(found) {
1837 + if(unlikely(debug)) loops++;
1838 + found = 0;
1839 +
1840 + for(p = root_of_pids; p ; p = p->next) {
1841 + if(unlikely(!p->sortlist && !p->children_count))
1842 + p->sortlist = sortlist++;
1843 +
1844 + // if this process does not have any children
1845 + // and is not already merged
1846 + // and has a parent
1847 + // and its parent has children
1848 + // and the target of this process and its parent is the same, or the parent does not have a target
1849 + // and its parent is not init
1850 + // then, mark them as merged.
1851 + if(unlikely(
1852 + !p->children_count
1853 + && !p->merged
1854 + && p->parent
1855 + && p->parent->children_count
1856 + && (p->target == p->parent->target || !p->parent->target)
1857 + && p->ppid != 1
1858 + )) {
1859 + p->parent->children_count--;
1860 + p->merged = 1;
1861 +
1862 + // the parent inherits the child's target, if it does not have a target itself
1863 + if(unlikely(p->target && !p->parent->target)) {
1864 + p->parent->target = p->target;
1865 +
1866 + if(debug || (p->target && p->target->debug))
1867 + fprintf(stderr, "apps.plugin: \t\tTARGET INHERITANCE: %s is inherited by %d (%s) from its child %d (%s).\n", p->target->name, p->parent->pid, p->parent->comm, p->pid, p->comm);
1868 + }
1869 +
1870 + found++;
1871 + }
1872 + }
1873 +
1874 + if(unlikely(debug))
1875 + fprintf(stderr, "apps.plugin: TARGET INHERITANCE: merged %d processes\n", found);
1876 + }
1877 +
1878 + // init goes always to default target
1879 + if(all_pids[1])
1880 + all_pids[1]->target = apps_groups_default_target;
1881 +
1882 + // give a default target on all top level processes
1883 + if(unlikely(debug)) loops++;
1884 + for(p = root_of_pids; p ; p = p->next) {
1885 + // if the process is not merged itself
1886 + // then is is a top level process
1887 + if(unlikely(!p->merged && !p->target))
1888 + p->target = apps_groups_default_target;
1889 +
1890 + // make sure all processes have a sortlist
1891 + if(unlikely(!p->sortlist))
1892 + p->sortlist = sortlist++;
1893 + }
1894 +
1895 + if(all_pids[1])
1896 + all_pids[1]->sortlist = sortlist++;
1897 +
1898 + // give a target to all merged child processes
1899 + found = 1;
1900 + while(found) {
1901 + if(unlikely(debug)) loops++;
1902 + found = 0;
1903 + for(p = root_of_pids; p ; p = p->next) {
1904 + if(unlikely(!p->target && p->merged && p->parent && p->parent->target)) {
1905 + p->target = p->parent->target;
1906 + found++;
1907 +
1908 + if(debug || (p->target && p->target->debug))
1909 + fprintf(stderr, "apps.plugin: \t\tTARGET INHERITANCE: %s is inherited by %d (%s) from its parent %d (%s) at phase 2.\n", p->target->name, p->pid, p->comm, p->parent->pid, p->parent->comm);
1910 + }
1911 + }
1912 + }
1913 +
1914 + if(unlikely(debug))
1915 + fprintf(stderr, "apps.plugin: apply_apps_groups_targets_inheritance() made %d loops on the process tree\n", loops);
1916 }
1917
1918 long zero_all_targets(struct target *root) {
1919 - struct target *w;
1920 - long count = 0;
1921 -
1922 - for (w = root; w ; w = w->next) {
1923 - count++;
1924 -
1925 - if(w->fds) freez(w->fds);
1926 - w->fds = NULL;
1927 -
1928 - w->minflt = 0;
1929 - w->majflt = 0;
1930 - w->utime = 0;
1931 - w->stime = 0;
1932 - w->gtime = 0;
1933 - w->cminflt = 0;
1934 - w->cmajflt = 0;
1935 - w->cutime = 0;
1936 - w->cstime = 0;
1937 - w->cgtime = 0;
1938 - w->num_threads = 0;
1939 - w->rss = 0;
1940 - w->processes = 0;
1941 -
1942 - w->statm_size = 0;
1943 - w->statm_resident = 0;
1944 - w->statm_share = 0;
1945 - w->statm_text = 0;
1946 - w->statm_lib = 0;
1947 - w->statm_data = 0;
1948 - w->statm_dirty = 0;
1949 -
1950 - w->io_logical_bytes_read = 0;
1951 - w->io_logical_bytes_written = 0;
1952 - w->io_read_calls = 0;
1953 - w->io_write_calls = 0;
1954 - w->io_storage_bytes_read = 0;
1955 - w->io_storage_bytes_written = 0;
1956 - w->io_cancelled_write_bytes = 0;
1957 - }
1958 -
1959 - return count;
1919 + struct target *w;
1920 + long count = 0;
1921 +
1922 + for (w = root; w ; w = w->next) {
1923 + count++;
1924 +
1925 + if(w->fds) freez(w->fds);
1926 + w->fds = NULL;
1927 +
1928 + w->minflt = 0;
1929 + w->majflt = 0;
1930 + w->utime = 0;
1931 + w->stime = 0;
1932 + w->gtime = 0;
1933 + w->cminflt = 0;
1934 + w->cmajflt = 0;
1935 + w->cutime = 0;
1936 + w->cstime = 0;
1937 + w->cgtime = 0;
1938 + w->num_threads = 0;
1939 + w->rss = 0;
1940 + w->processes = 0;
1941 +
1942 + w->statm_size = 0;
1943 + w->statm_resident = 0;
1944 + w->statm_share = 0;
1945 + w->statm_text = 0;
1946 + w->statm_lib = 0;
1947 + w->statm_data = 0;
1948 + w->statm_dirty = 0;
1949 +
1950 + w->io_logical_bytes_read = 0;
1951 + w->io_logical_bytes_written = 0;
1952 + w->io_read_calls = 0;
1953 + w->io_write_calls = 0;
1954 + w->io_storage_bytes_read = 0;
1955 + w->io_storage_bytes_written = 0;
1956 + w->io_cancelled_write_bytes = 0;
1957 + }
1958 +
1959 + return count;
1960 }
1961
1962 void aggregate_pid_on_target(struct target *w, struct pid_stat *p, struct target *o) {
1963 - (void)o;
1964 -
1965 - if(unlikely(!w->fds))
1966 - w->fds = callocz(sizeof(int), (size_t) all_files_size);
1967 -
1968 - if(likely(p->updated)) {
1969 - w->cutime += p->cutime;
1970 - w->cstime += p->cstime;
1971 - w->cgtime += p->cgtime;
1972 - w->cminflt += p->cminflt;
1973 - w->cmajflt += p->cmajflt;
1974 -
1975 - w->utime += p->utime;
1976 - w->stime += p->stime;
1977 - w->gtime += p->gtime;
1978 - w->minflt += p->minflt;
1979 - w->majflt += p->majflt;
1980 -
1981 - w->rss += p->rss;
1982 -
1983 - w->statm_size += p->statm_size;
1984 - w->statm_resident += p->statm_resident;
1985 - w->statm_share += p->statm_share;
1986 - w->statm_text += p->statm_text;
1987 - w->statm_lib += p->statm_lib;
1988 - w->statm_data += p->statm_data;
1989 - w->statm_dirty += p->statm_dirty;
1990 -
1991 - w->io_logical_bytes_read += p->io_logical_bytes_read;
1992 - w->io_logical_bytes_written += p->io_logical_bytes_written;
1993 - w->io_read_calls += p->io_read_calls;
1994 - w->io_write_calls += p->io_write_calls;
1995 - w->io_storage_bytes_read += p->io_storage_bytes_read;
1996 - w->io_storage_bytes_written += p->io_storage_bytes_written;
1997 - w->io_cancelled_write_bytes += p->io_cancelled_write_bytes;
1998 -
1999 - w->processes++;
2000 - w->num_threads += p->num_threads;
2001 -
2002 - if(likely(w->fds)) {
2003 - int c;
2004 - for(c = 0; c < p->fds_size ;c++) {
2005 - if(p->fds[c] == 0) continue;
2006 -
2007 - if(likely(p->fds[c] < all_files_size)) {
2008 - if(w->fds) w->fds[p->fds[c]]++;
2009 - }
2010 - else
2011 - error("Invalid fd number %d", p->fds[c]);
2012 - }
2013 - }
2014 -
2015 - if(unlikely(debug || w->debug))
2016 - fprintf(stderr, "apps.plugin: \taggregating '%s' pid %d on target '%s' utime=%llu, stime=%llu, gtime=%llu, cutime=%llu, cstime=%llu, cgtime=%llu, minflt=%llu, majflt=%llu, cminflt=%llu, cmajflt=%llu\n", p->comm, p->pid, w->name, p->utime, p->stime, p->gtime, p->cutime, p->cstime, p->cgtime, p->minflt, p->majflt, p->cminflt, p->cmajflt);
2017 - }
1963 + (void)o;
1964 +
1965 + if(unlikely(!w->fds))
1966 + w->fds = callocz(sizeof(int), (size_t) all_files_size);
1967 +
1968 + if(likely(p->updated)) {
1969 + w->cutime += p->cutime;
1970 + w->cstime += p->cstime;
1971 + w->cgtime += p->cgtime;
1972 + w->cminflt += p->cminflt;
1973 + w->cmajflt += p->cmajflt;
1974 +
1975 + w->utime += p->utime;
1976 + w->stime += p->stime;
1977 + w->gtime += p->gtime;
1978 + w->minflt += p->minflt;
1979 + w->majflt += p->majflt;
1980 +
1981 + w->rss += p->rss;
1982 +
1983 + w->statm_size += p->statm_size;
1984 + w->statm_resident += p->statm_resident;
1985 + w->statm_share += p->statm_share;
1986 + w->statm_text += p->statm_text;
1987 + w->statm_lib += p->statm_lib;
1988 + w->statm_data += p->statm_data;
1989 + w->statm_dirty += p->statm_dirty;
1990 +
1991 + w->io_logical_bytes_read += p->io_logical_bytes_read;
1992 + w->io_logical_bytes_written += p->io_logical_bytes_written;
1993 + w->io_read_calls += p->io_read_calls;
1994 + w->io_write_calls += p->io_write_calls;
1995 + w->io_storage_bytes_read += p->io_storage_bytes_read;
1996 + w->io_storage_bytes_written += p->io_storage_bytes_written;
1997 + w->io_cancelled_write_bytes += p->io_cancelled_write_bytes;
1998 +
1999 + w->processes++;
2000 + w->num_threads += p->num_threads;
2001 +
2002 + if(likely(w->fds)) {
2003 + int c;
2004 + for(c = 0; c < p->fds_size ;c++) {
2005 + if(p->fds[c] == 0) continue;
2006 +
2007 + if(likely(p->fds[c] < all_files_size)) {
2008 + if(w->fds) w->fds[p->fds[c]]++;
2009 + }
2010 + else
2011 + error("Invalid fd number %d", p->fds[c]);
2012 + }
2013 + }
2014 +
2015 + if(unlikely(debug || w->debug))
2016 + fprintf(stderr, "apps.plugin: \taggregating '%s' pid %d on target '%s' utime=%llu, stime=%llu, gtime=%llu, cutime=%llu, cstime=%llu, cgtime=%llu, minflt=%llu, majflt=%llu, cminflt=%llu, cmajflt=%llu\n", p->comm, p->pid, w->name, p->utime, p->stime, p->gtime, p->cutime, p->cstime, p->cgtime, p->minflt, p->majflt, p->cminflt, p->cmajflt);
2017 + }
2018 }
2019
2020 void count_targets_fds(struct target *root) {
2021 - int c;
2022 - struct target *w;
2023 -
2024 - for (w = root; w ; w = w->next) {
2025 - if(!w->fds) continue;
2026 -
2027 - w->openfiles = 0;
2028 - w->openpipes = 0;
2029 - w->opensockets = 0;
2030 - w->openinotifies = 0;
2031 - w->openeventfds = 0;
2032 - w->opentimerfds = 0;
2033 - w->opensignalfds = 0;
2034 - w->openeventpolls = 0;
2035 - w->openother = 0;
2036 -
2037 - for(c = 1; c < all_files_size ;c++) {
2038 - if(w->fds[c] > 0)
2039 - switch(all_files[c].type) {
2040 - case FILETYPE_FILE:
2041 - w->openfiles++;
2042 - break;
2043 -
2044 - case FILETYPE_PIPE:
2045 - w->openpipes++;
2046 - break;
2047 -
2048 - case FILETYPE_SOCKET:
2049 - w->opensockets++;
2050 - break;
2051 -
2052 - case FILETYPE_INOTIFY:
2053 - w->openinotifies++;
2054 - break;
2055 -
2056 - case FILETYPE_EVENTFD:
2057 - w->openeventfds++;
2058 - break;
2059 -
2060 - case FILETYPE_TIMERFD:
2061 - w->opentimerfds++;
2062 - break;
2063 -
2064 - case FILETYPE_SIGNALFD:
2065 - w->opensignalfds++;
2066 - break;
2067 -
2068 - case FILETYPE_EVENTPOLL:
2069 - w->openeventpolls++;
2070 - break;
2071 -
2072 - default:
2073 - w->openother++;
2074 - }
2075 - }
2076 -
2077 - freez(w->fds);
2078 - w->fds = NULL;
2079 - }
2021 + int c;
2022 + struct target *w;
2023 +
2024 + for (w = root; w ; w = w->next) {
2025 + if(!w->fds) continue;
2026 +
2027 + w->openfiles = 0;
2028 + w->openpipes = 0;
2029 + w->opensockets = 0;
2030 + w->openinotifies = 0;
2031 + w->openeventfds = 0;
2032 + w->opentimerfds = 0;
2033 + w->opensignalfds = 0;
2034 + w->openeventpolls = 0;
2035 + w->openother = 0;
2036 +
2037 + for(c = 1; c < all_files_size ;c++) {
2038 + if(w->fds[c] > 0)
2039 + switch(all_files[c].type) {
2040 + case FILETYPE_FILE:
2041 + w->openfiles++;
2042 + break;
2043 +
2044 + case FILETYPE_PIPE:
2045 + w->openpipes++;
2046 + break;
2047 +
2048 + case FILETYPE_SOCKET:
2049 + w->opensockets++;
2050 + break;
2051 +
2052 + case FILETYPE_INOTIFY:
2053 + w->openinotifies++;
2054 + break;
2055 +
2056 + case FILETYPE_EVENTFD:
2057 + w->openeventfds++;
2058 + break;
2059 +
2060 + case FILETYPE_TIMERFD:
2061 + w->opentimerfds++;
2062 + break;
2063 +
2064 + case FILETYPE_SIGNALFD:
2065 + w->opensignalfds++;
2066 + break;
2067 +
2068 + case FILETYPE_EVENTPOLL:
2069 + w->openeventpolls++;
2070 + break;
2071 +
2072 + default:
2073 + w->openother++;
2074 + }
2075 + }
2076 +
2077 + freez(w->fds);
2078 + w->fds = NULL;
2079 + }
2080 }
2081
2082 void calculate_netdata_statistics(void) {
2083 - apply_apps_groups_targets_inheritance();
2083 + apply_apps_groups_targets_inheritance();
2084
2085 - zero_all_targets(users_root_target);
2086 - zero_all_targets(groups_root_target);
2087 - apps_groups_targets = zero_all_targets(apps_groups_root_target);
2085 + zero_all_targets(users_root_target);
2086 + zero_all_targets(groups_root_target);
2087 + apps_groups_targets = zero_all_targets(apps_groups_root_target);
2088
2089 - // this has to be done, before the cleanup
2090 - struct pid_stat *p = NULL;
2091 - struct target *w = NULL, *o = NULL;
2089 + // this has to be done, before the cleanup
2090 + struct pid_stat *p = NULL;
2091 + struct target *w = NULL, *o = NULL;
2092
2093 - // concentrate everything on the apps_groups_targets
2094 - for(p = root_of_pids; p ; p = p->next) {
2093 + // concentrate everything on the apps_groups_targets
2094 + for(p = root_of_pids; p ; p = p->next) {
2095
2096 - // --------------------------------------------------------------------
2097 - // apps_groups targets
2098 - if(likely(p->target))
2099 - aggregate_pid_on_target(p->target, p, NULL);
2100 - else
2101 - error("pid %d %s was left without a target!", p->pid, p->comm);
2096 + // --------------------------------------------------------------------
2097 + // apps_groups targets
2098 + if(likely(p->target))
2099 + aggregate_pid_on_target(p->target, p, NULL);
2100 + else
2101 + error("pid %d %s was left without a target!", p->pid, p->comm);
2102
2103
2104 - // --------------------------------------------------------------------
2105 - // user targets
2106 - o = p->user_target;
2107 - if(likely(p->user_target && p->user_target->uid == p->uid))
2108 - w = p->user_target;
2109 - else {
2110 - if(unlikely(debug && p->user_target))
2111 - fprintf(stderr, "apps.plugin: \t\tpid %d (%s) switched user from %u (%s) to %u.\n", p->pid, p->comm, p->user_target->uid, p->user_target->name, p->uid);
2104 + // --------------------------------------------------------------------
2105 + // user targets
2106 + o = p->user_target;
2107 + if(likely(p->user_target && p->user_target->uid == p->uid))
2108 + w = p->user_target;
2109 + else {
2110 + if(unlikely(debug && p->user_target))
2111 + fprintf(stderr, "apps.plugin: \t\tpid %d (%s) switched user from %u (%s) to %u.\n", p->pid, p->comm, p->user_target->uid, p->user_target->name, p->uid);
2112
2113 - w = p->user_target = get_users_target(p->uid);
2114 - }
2113 + w = p->user_target = get_users_target(p->uid);
2114 + }
2115
2116 - if(likely(w))
2117 - aggregate_pid_on_target(w, p, o);
2118 - else
2119 - error("pid %d %s was left without a user target!", p->pid, p->comm);
2116 + if(likely(w))
2117 + aggregate_pid_on_target(w, p, o);
2118 + else
2119 + error("pid %d %s was left without a user target!", p->pid, p->comm);
2120
2121
2122 - // --------------------------------------------------------------------
2123 - // group targets
2124 - o = p->group_target;
2125 - if(likely(p->group_target && p->group_target->gid == p->gid))
2126 - w = p->group_target;
2127 - else {
2128 - if(unlikely(debug && p->group_target))
2129 - fprintf(stderr, "apps.plugin: \t\tpid %d (%s) switched group from %u (%s) to %u.\n", p->pid, p->comm, p->group_target->gid, p->group_target->name, p->gid);
2122 + // --------------------------------------------------------------------
2123 + // group targets
2124 + o = p->group_target;
2125 + if(likely(p->group_target && p->group_target->gid == p->gid))
2126 + w = p->group_target;
2127 + else {
2128 + if(unlikely(debug && p->group_target))
2129 + fprintf(stderr, "apps.plugin: \t\tpid %d (%s) switched group from %u (%s) to %u.\n", p->pid, p->comm, p->group_target->gid, p->group_target->name, p->gid);
2130
2131 - w = p->group_target = get_groups_target(p->gid);
2132 - }
2131 + w = p->group_target = get_groups_target(p->gid);
2132 + }
2133
2134 - if(likely(w))
2135 - aggregate_pid_on_target(w, p, o);
2136 - else
2137 - error("pid %d %s was left without a group target!", p->pid, p->comm);
2134 + if(likely(w))
2135 + aggregate_pid_on_target(w, p, o);
2136 + else
2137 + error("pid %d %s was left without a group target!", p->pid, p->comm);
2138
2139 - }
2139 + }
2140
2141 - count_targets_fds(apps_groups_root_target);
2142 - count_targets_fds(users_root_target);
2143 - count_targets_fds(groups_root_target);
2141 + count_targets_fds(apps_groups_root_target);
2142 + count_targets_fds(users_root_target);
2143 + count_targets_fds(groups_root_target);
2144
2145 - cleanup_exited_pids();
2145 + cleanup_exited_pids();
2146 }
2147
2148 // ----------------------------------------------------------------------------
@@ -2152,383 +2152,383 @@ BUFFER *output = NULL;
2152 int print_calculated_number(char *str, calculated_number value) { (void)str; (void)value; return 0; }
2153
2154 static inline void send_BEGIN(const char *type, const char *id, unsigned long long usec) {
2155 - // fprintf(stdout, "BEGIN %s.%s %llu\n", type, id, usec);
2156 - buffer_strcat(output, "BEGIN ");
2157 - buffer_strcat(output, type);
2158 - buffer_strcat(output, ".");
2159 - buffer_strcat(output, id);
2160 - buffer_strcat(output, " ");
2161 - buffer_print_llu(output, usec);
2162 - buffer_strcat(output, "\n");
2155 + // fprintf(stdout, "BEGIN %s.%s %llu\n", type, id, usec);
2156 + buffer_strcat(output, "BEGIN ");
2157 + buffer_strcat(output, type);
2158 + buffer_strcat(output, ".");
2159 + buffer_strcat(output, id);
2160 + buffer_strcat(output, " ");
2161 + buffer_print_llu(output, usec);
2162 + buffer_strcat(output, "\n");
2163 }
2164
2165 static inline void send_SET(const char *name, unsigned long long value) {
2166 - // fprintf(stdout, "SET %s = %llu\n", name, value);
2167 - buffer_strcat(output, "SET ");
2168 - buffer_strcat(output, name);
2169 - buffer_strcat(output, " = ");
2170 - buffer_print_llu(output, value);
2171 - buffer_strcat(output, "\n");
2166 + // fprintf(stdout, "SET %s = %llu\n", name, value);
2167 + buffer_strcat(output, "SET ");
2168 + buffer_strcat(output, name);
2169 + buffer_strcat(output, " = ");
2170 + buffer_print_llu(output, value);
2171 + buffer_strcat(output, "\n");
2172 }
2173
2174 static inline void send_END(void) {
2175 - // fprintf(stdout, "END\n");
2176 - buffer_strcat(output, "END\n");
2175 + // fprintf(stdout, "END\n");
2176 + buffer_strcat(output, "END\n");
2177 }
2178
2179 double utime_fix_ratio = 1.0, stime_fix_ratio = 1.0, gtime_fix_ratio = 1.0, cutime_fix_ratio = 1.0, cstime_fix_ratio = 1.0, cgtime_fix_ratio = 1.0;
2180 double minflt_fix_ratio = 1.0, majflt_fix_ratio = 1.0, cminflt_fix_ratio = 1.0, cmajflt_fix_ratio = 1.0;
2181
2182 unsigned long long send_resource_usage_to_netdata() {
2183 - static struct timeval last = { 0, 0 };
2184 - static struct rusage me_last;
2185 -
2186 - struct timeval now;
2187 - struct rusage me;
2188 -
2189 - unsigned long long usec;
2190 - unsigned long long cpuuser;
2191 - unsigned long long cpusyst;
2192 -
2193 - if(!last.tv_sec) {
2194 - gettimeofday(&last, NULL);
2195 - getrusage(RUSAGE_SELF, &me_last);
2196 -
2197 - // the first time, give a zero to allow
2198 - // netdata calibrate to the current time
2199 - // usec = update_every * 1000000ULL;
2200 - usec = 0ULL;
2201 - cpuuser = 0;
2202 - cpusyst = 0;
2203 - }
2204 - else {
2205 - gettimeofday(&now, NULL);
2206 - getrusage(RUSAGE_SELF, &me);
2207 -
2208 - usec = usec_dt(&now, &last);
2209 - cpuuser = me.ru_utime.tv_sec * 1000000ULL + me.ru_utime.tv_usec;
2210 - cpusyst = me.ru_stime.tv_sec * 1000000ULL + me.ru_stime.tv_usec;
2211 -
2212 - bcopy(&now, &last, sizeof(struct timeval));
2213 - bcopy(&me, &me_last, sizeof(struct rusage));
2214 - }
2215 -
2216 - buffer_sprintf(output,
2217 - "BEGIN netdata.apps_cpu %llu\n"
2218 - "SET user = %llu\n"
2219 - "SET system = %llu\n"
2220 - "END\n"
2221 - "BEGIN netdata.apps_files %llu\n"
2222 - "SET files = %llu\n"
2223 - "SET pids = %ld\n"
2224 - "SET fds = %d\n"
2225 - "SET targets = %ld\n"
2226 - "END\n"
2227 - "BEGIN netdata.apps_fix %llu\n"
2228 - "SET utime = %llu\n"
2229 - "SET stime = %llu\n"
2230 - "SET gtime = %llu\n"
2231 - "SET minflt = %llu\n"
2232 - "SET majflt = %llu\n"
2233 - "END\n"
2234 - , usec
2235 - , cpuuser
2236 - , cpusyst
2237 - , usec
2238 - , file_counter
2239 - , all_pids_count
2240 - , all_files_len
2241 - , apps_groups_targets
2242 - , usec
2243 - , (unsigned long long)(utime_fix_ratio * 100 * RATES_DETAIL)
2244 - , (unsigned long long)(stime_fix_ratio * 100 * RATES_DETAIL)
2245 - , (unsigned long long)(gtime_fix_ratio * 100 * RATES_DETAIL)
2246 - , (unsigned long long)(minflt_fix_ratio * 100 * RATES_DETAIL)
2247 - , (unsigned long long)(majflt_fix_ratio * 100 * RATES_DETAIL)
2248 - );
2249 -
2250 - if(include_exited_childs)
2251 - buffer_sprintf(output,
2252 - "BEGIN netdata.apps_children_fix %llu\n"
2253 - "SET cutime = %llu\n"
2254 - "SET cstime = %llu\n"
2255 - "SET cgtime = %llu\n"
2256 - "SET cminflt = %llu\n"
2257 - "SET cmajflt = %llu\n"
2258 - "END\n"
2259 - , usec
2260 - , (unsigned long long)(cutime_fix_ratio * 100 * RATES_DETAIL)
2261 - , (unsigned long long)(cstime_fix_ratio * 100 * RATES_DETAIL)
2262 - , (unsigned long long)(cgtime_fix_ratio * 100 * RATES_DETAIL)
2263 - , (unsigned long long)(cminflt_fix_ratio * 100 * RATES_DETAIL)
2264 - , (unsigned long long)(cmajflt_fix_ratio * 100 * RATES_DETAIL)
2265 - );
2266 -
2267 - return usec;
2183 + static struct timeval last = { 0, 0 };
2184 + static struct rusage me_last;
2185 +
2186 + struct timeval now;
2187 + struct rusage me;
2188 +
2189 + unsigned long long usec;
2190 + unsigned long long cpuuser;
2191 + unsigned long long cpusyst;
2192 +
2193 + if(!last.tv_sec) {
2194 + gettimeofday(&last, NULL);
2195 + getrusage(RUSAGE_SELF, &me_last);
2196 +
2197 + // the first time, give a zero to allow
2198 + // netdata calibrate to the current time
2199 + // usec = update_every * 1000000ULL;
2200 + usec = 0ULL;
2201 + cpuuser = 0;
2202 + cpusyst = 0;
2203 + }
2204 + else {
2205 + gettimeofday(&now, NULL);
2206 + getrusage(RUSAGE_SELF, &me);
2207 +
2208 + usec = usec_dt(&now, &last);
2209 + cpuuser = me.ru_utime.tv_sec * 1000000ULL + me.ru_utime.tv_usec;
2210 + cpusyst = me.ru_stime.tv_sec * 1000000ULL + me.ru_stime.tv_usec;
2211 +
2212 + bcopy(&now, &last, sizeof(struct timeval));
2213 + bcopy(&me, &me_last, sizeof(struct rusage));
2214 + }
2215 +
2216 + buffer_sprintf(output,
2217 + "BEGIN netdata.apps_cpu %llu\n"
2218 + "SET user = %llu\n"
2219 + "SET system = %llu\n"
2220 + "END\n"
2221 + "BEGIN netdata.apps_files %llu\n"
2222 + "SET files = %llu\n"
2223 + "SET pids = %ld\n"
2224 + "SET fds = %d\n"
2225 + "SET targets = %ld\n"
2226 + "END\n"
2227 + "BEGIN netdata.apps_fix %llu\n"
2228 + "SET utime = %llu\n"
2229 + "SET stime = %llu\n"
2230 + "SET gtime = %llu\n"
2231 + "SET minflt = %llu\n"
2232 + "SET majflt = %llu\n"
2233 + "END\n"
2234 + , usec
2235 + , cpuuser
2236 + , cpusyst
2237 + , usec
2238 + , file_counter
2239 + , all_pids_count
2240 + , all_files_len
2241 + , apps_groups_targets
2242 + , usec
2243 + , (unsigned long long)(utime_fix_ratio * 100 * RATES_DETAIL)
2244 + , (unsigned long long)(stime_fix_ratio * 100 * RATES_DETAIL)
2245 + , (unsigned long long)(gtime_fix_ratio * 100 * RATES_DETAIL)
2246 + , (unsigned long long)(minflt_fix_ratio * 100 * RATES_DETAIL)
2247 + , (unsigned long long)(majflt_fix_ratio * 100 * RATES_DETAIL)
2248 + );
2249 +
2250 + if(include_exited_childs)
2251 + buffer_sprintf(output,
2252 + "BEGIN netdata.apps_children_fix %llu\n"
2253 + "SET cutime = %llu\n"
2254 + "SET cstime = %llu\n"
2255 + "SET cgtime = %llu\n"
2256 + "SET cminflt = %llu\n"
2257 + "SET cmajflt = %llu\n"
2258 + "END\n"
2259 + , usec
2260 + , (unsigned long long)(cutime_fix_ratio * 100 * RATES_DETAIL)
2261 + , (unsigned long long)(cstime_fix_ratio * 100 * RATES_DETAIL)
2262 + , (unsigned long long)(cgtime_fix_ratio * 100 * RATES_DETAIL)
2263 + , (unsigned long long)(cminflt_fix_ratio * 100 * RATES_DETAIL)
2264 + , (unsigned long long)(cmajflt_fix_ratio * 100 * RATES_DETAIL)
2265 + );
2266 +
2267 + return usec;
2268 }
2269
2270 void normalize_data(struct target *root) {
2271 - struct target *w;
2272 -
2273 - // childs processing introduces spikes
2274 - // here we try to eliminate them by disabling childs processing either for specific dimensions
2275 - // or entirely. Of course, either way, we disable it just a single iteration.
2276 -
2277 - unsigned long long max = processors * hz * RATES_DETAIL;
2278 - unsigned long long utime = 0, cutime = 0, stime = 0, cstime = 0, gtime = 0, cgtime = 0, minflt = 0, cminflt = 0, majflt = 0, cmajflt = 0;
2279 -
2280 - if(global_utime > max) global_utime = max;
2281 - if(global_stime > max) global_stime = max;
2282 - if(global_gtime > max) global_gtime = max;
2283 -
2284 - for(w = root; w ; w = w->next) {
2285 - if(w->target || (!w->processes && !w->exposed)) continue;
2286 -
2287 - utime += w->utime;
2288 - stime += w->stime;
2289 - gtime += w->gtime;
2290 - cutime += w->cutime;
2291 - cstime += w->cstime;
2292 - cgtime += w->cgtime;
2293 -
2294 - minflt += w->minflt;
2295 - majflt += w->majflt;
2296 - cminflt += w->cminflt;
2297 - cmajflt += w->cmajflt;
2298 - }
2299 -
2300 - if((global_utime || global_stime || global_gtime) && (utime || stime || gtime)) {
2301 - if(global_utime + global_stime + global_gtime > utime + cutime + stime + cstime + gtime + cgtime) {
2302 - // everything we collected fits
2303 - utime_fix_ratio =
2304 - stime_fix_ratio =
2305 - gtime_fix_ratio =
2306 - cutime_fix_ratio =
2307 - cstime_fix_ratio =
2308 - cgtime_fix_ratio = 1.0; //(double)(global_utime + global_stime) / (double)(utime + cutime + stime + cstime);
2309 - }
2310 - else if(global_utime + global_stime > utime + stime) {
2311 - // childrens resources are too high
2312 - // lower only the children resources
2313 - utime_fix_ratio =
2314 - stime_fix_ratio =
2315 - gtime_fix_ratio = 1.0;
2316 - cutime_fix_ratio =
2317 - cstime_fix_ratio =
2318 - cgtime_fix_ratio = (double)((global_utime + global_stime) - (utime + stime)) / (double)(cutime + cstime);
2319 - }
2320 - else {
2321 - // even running processes are unrealistic
2322 - // zero the children resources
2323 - // lower the running processes resources
2324 - utime_fix_ratio =
2325 - stime_fix_ratio =
2326 - gtime_fix_ratio = (double)(global_utime + global_stime) / (double)(utime + stime);
2327 - cutime_fix_ratio =
2328 - cstime_fix_ratio =
2329 - cgtime_fix_ratio = 0.0;
2330 - }
2331 - }
2332 - else {
2333 - utime_fix_ratio =
2334 - stime_fix_ratio =
2335 - gtime_fix_ratio =
2336 - cutime_fix_ratio =
2337 - cstime_fix_ratio =
2338 - cgtime_fix_ratio = 0.0;
2339 - }
2340 -
2341 - if(utime_fix_ratio > 1.0) utime_fix_ratio = 1.0;
2342 - if(cutime_fix_ratio > 1.0) cutime_fix_ratio = 1.0;
2343 - if(stime_fix_ratio > 1.0) stime_fix_ratio = 1.0;
2344 - if(cstime_fix_ratio > 1.0) cstime_fix_ratio = 1.0;
2345 - if(gtime_fix_ratio > 1.0) gtime_fix_ratio = 1.0;
2346 - if(cgtime_fix_ratio > 1.0) cgtime_fix_ratio = 1.0;
2347 -
2348 - // if(utime_fix_ratio < 0.0) utime_fix_ratio = 0.0;
2349 - // if(cutime_fix_ratio < 0.0) cutime_fix_ratio = 0.0;
2350 - // if(stime_fix_ratio < 0.0) stime_fix_ratio = 0.0;
2351 - // if(cstime_fix_ratio < 0.0) cstime_fix_ratio = 0.0;
2352 - // if(gtime_fix_ratio < 0.0) gtime_fix_ratio = 0.0;
2353 - // if(cgtime_fix_ratio < 0.0) cgtime_fix_ratio = 0.0;
2354 -
2355 - // FIXME
2356 - // we use cpu time to normalize page faults
2357 - // the problem is that to find the proper max values
2358 - // for page faults we have to parse /proc/vmstat
2359 - // which is quite big to do it again (netdata does it already)
2360 - //
2361 - // a better solution could be to somehow have netdata
2362 - // do this normalization for us
2363 -
2364 - if(utime || stime || gtime)
2365 - majflt_fix_ratio =
2366 - minflt_fix_ratio = (double)(utime * utime_fix_ratio + stime * stime_fix_ratio + gtime * gtime_fix_ratio) / (double)(utime + stime + gtime);
2367 - else
2368 - minflt_fix_ratio =
2369 - majflt_fix_ratio = 1.0;
2370 -
2371 - if(cutime || cstime || cgtime)
2372 - cmajflt_fix_ratio =
2373 - cminflt_fix_ratio = (double)(cutime * cutime_fix_ratio + cstime * cstime_fix_ratio + cgtime * cgtime_fix_ratio) / (double)(cutime + cstime + cgtime);
2374 - else
2375 - cminflt_fix_ratio =
2376 - cmajflt_fix_ratio = 1.0;
2377 -
2378 - // the report
2379 -
2380 - if(unlikely(debug)) {
2381 - fprintf(stderr,
2382 - "SYSTEM: u=%llu s=%llu g=%llu "
2383 - "COLLECTED: u=%llu s=%llu g=%llu cu=%llu cs=%llu cg=%llu "
2384 - "DELTA: u=%lld s=%lld g=%lld "
2385 - "FIX: u=%0.2f s=%0.2f g=%0.2f cu=%0.2f cs=%0.2f cg=%0.2f "
2386 - "FINALLY: u=%llu s=%llu g=%llu cu=%llu cs=%llu cg=%llu "
2387 - "\n"
2388 - , global_utime
2389 - , global_stime
2390 - , global_gtime
2391 - , utime
2392 - , stime
2393 - , gtime
2394 - , cutime
2395 - , cstime
2396 - , cgtime
2397 - , (long long)utime + (long long)cutime - (long long)global_utime
2398 - , (long long)stime + (long long)cstime - (long long)global_stime
2399 - , (long long)gtime + (long long)cgtime - (long long)global_gtime
2400 - , utime_fix_ratio
2401 - , stime_fix_ratio
2402 - , gtime_fix_ratio
2403 - , cutime_fix_ratio
2404 - , cstime_fix_ratio
2405 - , cgtime_fix_ratio
2406 - , (unsigned long long)(utime * utime_fix_ratio)
2407 - , (unsigned long long)(stime * stime_fix_ratio)
2408 - , (unsigned long long)(gtime * gtime_fix_ratio)
2409 - , (unsigned long long)(cutime * cutime_fix_ratio)
2410 - , (unsigned long long)(cstime * cstime_fix_ratio)
2411 - , (unsigned long long)(cgtime * cgtime_fix_ratio)
2412 - );
2413 - }
2271 + struct target *w;
2272 +
2273 + // childs processing introduces spikes
2274 + // here we try to eliminate them by disabling childs processing either for specific dimensions
2275 + // or entirely. Of course, either way, we disable it just a single iteration.
2276 +
2277 + unsigned long long max = processors * hz * RATES_DETAIL;
2278 + unsigned long long utime = 0, cutime = 0, stime = 0, cstime = 0, gtime = 0, cgtime = 0, minflt = 0, cminflt = 0, majflt = 0, cmajflt = 0;
2279 +
2280 + if(global_utime > max) global_utime = max;
2281 + if(global_stime > max) global_stime = max;
2282 + if(global_gtime > max) global_gtime = max;
2283 +
2284 + for(w = root; w ; w = w->next) {
2285 + if(w->target || (!w->processes && !w->exposed)) continue;
2286 +
2287 + utime += w->utime;
2288 + stime += w->stime;
2289 + gtime += w->gtime;
2290 + cutime += w->cutime;
2291 + cstime += w->cstime;
2292 + cgtime += w->cgtime;
2293 +
2294 + minflt += w->minflt;
2295 + majflt += w->majflt;
2296 + cminflt += w->cminflt;
2297 + cmajflt += w->cmajflt;
2298 + }
2299 +
2300 + if((global_utime || global_stime || global_gtime) && (utime || stime || gtime)) {
2301 + if(global_utime + global_stime + global_gtime > utime + cutime + stime + cstime + gtime + cgtime) {
2302 + // everything we collected fits
2303 + utime_fix_ratio =
2304 + stime_fix_ratio =
2305 + gtime_fix_ratio =
2306 + cutime_fix_ratio =
2307 + cstime_fix_ratio =
2308 + cgtime_fix_ratio = 1.0; //(double)(global_utime + global_stime) / (double)(utime + cutime + stime + cstime);
2309 + }
2310 + else if(global_utime + global_stime > utime + stime) {
2311 + // childrens resources are too high
2312 + // lower only the children resources
2313 + utime_fix_ratio =
2314 + stime_fix_ratio =
2315 + gtime_fix_ratio = 1.0;
2316 + cutime_fix_ratio =
2317 + cstime_fix_ratio =
2318 + cgtime_fix_ratio = (double)((global_utime + global_stime) - (utime + stime)) / (double)(cutime + cstime);
2319 + }
2320 + else {
2321 + // even running processes are unrealistic
2322 + // zero the children resources
2323 + // lower the running processes resources
2324 + utime_fix_ratio =
2325 + stime_fix_ratio =
2326 + gtime_fix_ratio = (double)(global_utime + global_stime) / (double)(utime + stime);
2327 + cutime_fix_ratio =
2328 + cstime_fix_ratio =
2329 + cgtime_fix_ratio = 0.0;
2330 + }
2331 + }
2332 + else {
2333 + utime_fix_ratio =
2334 + stime_fix_ratio =
2335 + gtime_fix_ratio =
2336 + cutime_fix_ratio =
2337 + cstime_fix_ratio =
2338 + cgtime_fix_ratio = 0.0;
2339 + }
2340 +
2341 + if(utime_fix_ratio > 1.0) utime_fix_ratio = 1.0;
2342 + if(cutime_fix_ratio > 1.0) cutime_fix_ratio = 1.0;
2343 + if(stime_fix_ratio > 1.0) stime_fix_ratio = 1.0;
2344 + if(cstime_fix_ratio > 1.0) cstime_fix_ratio = 1.0;
2345 + if(gtime_fix_ratio > 1.0) gtime_fix_ratio = 1.0;
2346 + if(cgtime_fix_ratio > 1.0) cgtime_fix_ratio = 1.0;
2347 +
2348 + // if(utime_fix_ratio < 0.0) utime_fix_ratio = 0.0;
2349 + // if(cutime_fix_ratio < 0.0) cutime_fix_ratio = 0.0;
2350 + // if(stime_fix_ratio < 0.0) stime_fix_ratio = 0.0;
2351 + // if(cstime_fix_ratio < 0.0) cstime_fix_ratio = 0.0;
2352 + // if(gtime_fix_ratio < 0.0) gtime_fix_ratio = 0.0;
2353 + // if(cgtime_fix_ratio < 0.0) cgtime_fix_ratio = 0.0;
2354 +
2355 + // FIXME
2356 + // we use cpu time to normalize page faults
2357 + // the problem is that to find the proper max values
2358 + // for page faults we have to parse /proc/vmstat
2359 + // which is quite big to do it again (netdata does it already)
2360 + //
2361 + // a better solution could be to somehow have netdata
2362 + // do this normalization for us
2363 +
2364 + if(utime || stime || gtime)
2365 + majflt_fix_ratio =
2366 + minflt_fix_ratio = (double)(utime * utime_fix_ratio + stime * stime_fix_ratio + gtime * gtime_fix_ratio) / (double)(utime + stime + gtime);
2367 + else
2368 + minflt_fix_ratio =
2369 + majflt_fix_ratio = 1.0;
2370 +
2371 + if(cutime || cstime || cgtime)
2372 + cmajflt_fix_ratio =
2373 + cminflt_fix_ratio = (double)(cutime * cutime_fix_ratio + cstime * cstime_fix_ratio + cgtime * cgtime_fix_ratio) / (double)(cutime + cstime + cgtime);
2374 + else
2375 + cminflt_fix_ratio =
2376 + cmajflt_fix_ratio = 1.0;
2377 +
2378 + // the report
2379 +
2380 + if(unlikely(debug)) {
2381 + fprintf(stderr,
2382 + "SYSTEM: u=%llu s=%llu g=%llu "
2383 + "COLLECTED: u=%llu s=%llu g=%llu cu=%llu cs=%llu cg=%llu "
2384 + "DELTA: u=%lld s=%lld g=%lld "
2385 + "FIX: u=%0.2f s=%0.2f g=%0.2f cu=%0.2f cs=%0.2f cg=%0.2f "
2386 + "FINALLY: u=%llu s=%llu g=%llu cu=%llu cs=%llu cg=%llu "
2387 + "\n"
2388 + , global_utime
2389 + , global_stime
2390 + , global_gtime
2391 + , utime
2392 + , stime
2393 + , gtime
2394 + , cutime
2395 + , cstime
2396 + , cgtime
2397 + , (long long)utime + (long long)cutime - (long long)global_utime
2398 + , (long long)stime + (long long)cstime - (long long)global_stime
2399 + , (long long)gtime + (long long)cgtime - (long long)global_gtime
2400 + , utime_fix_ratio
2401 + , stime_fix_ratio
2402 + , gtime_fix_ratio
2403 + , cutime_fix_ratio
2404 + , cstime_fix_ratio
2405 + , cgtime_fix_ratio
2406 + , (unsigned long long)(utime * utime_fix_ratio)
2407 + , (unsigned long long)(stime * stime_fix_ratio)
2408 + , (unsigned long long)(gtime * gtime_fix_ratio)
2409 + , (unsigned long long)(cutime * cutime_fix_ratio)
2410 + , (unsigned long long)(cstime * cstime_fix_ratio)
2411 + , (unsigned long long)(cgtime * cgtime_fix_ratio)
2412 + );
2413 + }
2414 }
2415
2416 void send_collected_data_to_netdata(struct target *root, const char *type, unsigned long long usec) {
2417 - struct target *w;
2418 -
2419 - send_BEGIN(type, "cpu", usec);
2420 - for (w = root; w ; w = w->next) {
2421 - if(unlikely(w->exposed))
2422 - send_SET(w->name, (unsigned long long)(w->utime * utime_fix_ratio) + (unsigned long long)(w->stime * stime_fix_ratio) + (unsigned long long)(w->gtime * gtime_fix_ratio) + (include_exited_childs?((unsigned long long)(w->cutime * cutime_fix_ratio) + (unsigned long long)(w->cstime * cstime_fix_ratio) + (unsigned long long)(w->cgtime * cgtime_fix_ratio)):0ULL));
2423 - }
2424 - send_END();
2425 -
2426 - send_BEGIN(type, "cpu_user", usec);
2427 - for (w = root; w ; w = w->next) {
2428 - if(unlikely(w->exposed))
2429 - send_SET(w->name, (unsigned long long)(w->utime * utime_fix_ratio) + (include_exited_childs?((unsigned long long)(w->cutime * cutime_fix_ratio)):0ULL));
2430 - }
2431 - send_END();
2432 -
2433 - send_BEGIN(type, "cpu_system", usec);
2434 - for (w = root; w ; w = w->next) {
2435 - if(unlikely(w->exposed))
2436 - send_SET(w->name, (unsigned long long)(w->stime * stime_fix_ratio) + (include_exited_childs?((unsigned long long)(w->cstime * cstime_fix_ratio)):0ULL));
2437 - }
2438 - send_END();
2439 -
2440 - if(show_guest_time) {
2441 - send_BEGIN(type, "cpu_guest", usec);
2442 - for (w = root; w ; w = w->next) {
2443 - if(unlikely(w->exposed))
2444 - send_SET(w->name, (unsigned long long)(w->gtime * gtime_fix_ratio) + (include_exited_childs?((unsigned long long)(w->cgtime * cgtime_fix_ratio)):0ULL));
2445 - }
2446 - send_END();
2447 - }
2448 -
2449 - send_BEGIN(type, "threads", usec);
2450 - for (w = root; w ; w = w->next) {
2451 - if(unlikely(w->exposed))
2452 - send_SET(w->name, w->num_threads);
2453 - }
2454 - send_END();
2455 -
2456 - send_BEGIN(type, "processes", usec);
2457 - for (w = root; w ; w = w->next) {
2458 - if(unlikely(w->exposed))
2459 - send_SET(w->name, w->processes);
2460 - }
2461 - send_END();
2462 -
2463 - send_BEGIN(type, "mem", usec);
2464 - for (w = root; w ; w = w->next) {
2465 - if(unlikely(w->exposed))
2466 - send_SET(w->name, (w->statm_resident > w->statm_share)?(w->statm_resident - w->statm_share):0ULL);
2467 - }
2468 - send_END();
2469 -
2470 - send_BEGIN(type, "minor_faults", usec);
2471 - for (w = root; w ; w = w->next) {
2472 - if(unlikely(w->exposed))
2473 - send_SET(w->name, (unsigned long long)(w->minflt * minflt_fix_ratio) + (include_exited_childs?((unsigned long long)(w->cminflt * cminflt_fix_ratio)):0ULL));
2474 - }
2475 - send_END();
2476 -
2477 - send_BEGIN(type, "major_faults", usec);
2478 - for (w = root; w ; w = w->next) {
2479 - if(unlikely(w->exposed))
2480 - send_SET(w->name, (unsigned long long)(w->majflt * majflt_fix_ratio) + (include_exited_childs?((unsigned long long)(w->cmajflt * cmajflt_fix_ratio)):0ULL));
2481 - }
2482 - send_END();
2483 -
2484 - send_BEGIN(type, "lreads", usec);
2485 - for (w = root; w ; w = w->next) {
2486 - if(unlikely(w->exposed))
2487 - send_SET(w->name, w->io_logical_bytes_read);
2488 - }
2489 - send_END();
2490 -
2491 - send_BEGIN(type, "lwrites", usec);
2492 - for (w = root; w ; w = w->next) {
2493 - if(unlikely(w->exposed))
2494 - send_SET(w->name, w->io_logical_bytes_written);
2495 - }
2496 - send_END();
2497 -
2498 - send_BEGIN(type, "preads", usec);
2499 - for (w = root; w ; w = w->next) {
2500 - if(unlikely(w->exposed))
2501 - send_SET(w->name, w->io_storage_bytes_read);
2502 - }
2503 - send_END();
2504 -
2505 - send_BEGIN(type, "pwrites", usec);
2506 - for (w = root; w ; w = w->next) {
2507 - if(unlikely(w->exposed))
2508 - send_SET(w->name, w->io_storage_bytes_written);
2509 - }
2510 - send_END();
2511 -
2512 - send_BEGIN(type, "files", usec);
2513 - for (w = root; w ; w = w->next) {
2514 - if(unlikely(w->exposed))
2515 - send_SET(w->name, w->openfiles);
2516 - }
2517 - send_END();
2518 -
2519 - send_BEGIN(type, "sockets", usec);
2520 - for (w = root; w ; w = w->next) {
2521 - if(unlikely(w->exposed))
2522 - send_SET(w->name, w->opensockets);
2523 - }
2524 - send_END();
2525 -
2526 - send_BEGIN(type, "pipes", usec);
2527 - for (w = root; w ; w = w->next) {
2528 - if(unlikely(w->exposed))
2529 - send_SET(w->name, w->openpipes);
2530 - }
2531 - send_END();
2417 + struct target *w;
2418 +
2419 + send_BEGIN(type, "cpu", usec);
2420 + for (w = root; w ; w = w->next) {
2421 + if(unlikely(w->exposed))
2422 + send_SET(w->name, (unsigned long long)(w->utime * utime_fix_ratio) + (unsigned long long)(w->stime * stime_fix_ratio) + (unsigned long long)(w->gtime * gtime_fix_ratio) + (include_exited_childs?((unsigned long long)(w->cutime * cutime_fix_ratio) + (unsigned long long)(w->cstime * cstime_fix_ratio) + (unsigned long long)(w->cgtime * cgtime_fix_ratio)):0ULL));
2423 + }
2424 + send_END();
2425 +
2426 + send_BEGIN(type, "cpu_user", usec);
2427 + for (w = root; w ; w = w->next) {
2428 + if(unlikely(w->exposed))
2429 + send_SET(w->name, (unsigned long long)(w->utime * utime_fix_ratio) + (include_exited_childs?((unsigned long long)(w->cutime * cutime_fix_ratio)):0ULL));
2430 + }
2431 + send_END();
2432 +
2433 + send_BEGIN(type, "cpu_system", usec);
2434 + for (w = root; w ; w = w->next) {
2435 + if(unlikely(w->exposed))
2436 + send_SET(w->name, (unsigned long long)(w->stime * stime_fix_ratio) + (include_exited_childs?((unsigned long long)(w->cstime * cstime_fix_ratio)):0ULL));
2437 + }
2438 + send_END();
2439 +
2440 + if(show_guest_time) {
2441 + send_BEGIN(type, "cpu_guest", usec);
2442 + for (w = root; w ; w = w->next) {
2443 + if(unlikely(w->exposed))
2444 + send_SET(w->name, (unsigned long long)(w->gtime * gtime_fix_ratio) + (include_exited_childs?((unsigned long long)(w->cgtime * cgtime_fix_ratio)):0ULL));
2445 + }
2446 + send_END();
2447 + }
2448 +
2449 + send_BEGIN(type, "threads", usec);
2450 + for (w = root; w ; w = w->next) {
2451 + if(unlikely(w->exposed))
2452 + send_SET(w->name, w->num_threads);
2453 + }
2454 + send_END();
2455 +
2456 + send_BEGIN(type, "processes", usec);
2457 + for (w = root; w ; w = w->next) {
2458 + if(unlikely(w->exposed))
2459 + send_SET(w->name, w->processes);
2460 + }
2461 + send_END();
2462 +
2463 + send_BEGIN(type, "mem", usec);
2464 + for (w = root; w ; w = w->next) {
2465 + if(unlikely(w->exposed))
2466 + send_SET(w->name, (w->statm_resident > w->statm_share)?(w->statm_resident - w->statm_share):0ULL);
2467 + }
2468 + send_END();
2469 +
2470 + send_BEGIN(type, "minor_faults", usec);
2471 + for (w = root; w ; w = w->next) {
2472 + if(unlikely(w->exposed))
2473 + send_SET(w->name, (unsigned long long)(w->minflt * minflt_fix_ratio) + (include_exited_childs?((unsigned long long)(w->cminflt * cminflt_fix_ratio)):0ULL));
2474 + }
2475 + send_END();
2476 +
2477 + send_BEGIN(type, "major_faults", usec);
2478 + for (w = root; w ; w = w->next) {
2479 + if(unlikely(w->exposed))
2480 + send_SET(w->name, (unsigned long long)(w->majflt * majflt_fix_ratio) + (include_exited_childs?((unsigned long long)(w->cmajflt * cmajflt_fix_ratio)):0ULL));
2481 + }
2482 + send_END();
2483 +
2484 + send_BEGIN(type, "lreads", usec);
2485 + for (w = root; w ; w = w->next) {
2486 + if(unlikely(w->exposed))
2487 + send_SET(w->name, w->io_logical_bytes_read);
2488 + }
2489 + send_END();
2490 +
2491 + send_BEGIN(type, "lwrites", usec);
2492 + for (w = root; w ; w = w->next) {
2493 + if(unlikely(w->exposed))
2494 + send_SET(w->name, w->io_logical_bytes_written);
2495 + }
2496 + send_END();
2497 +
2498 + send_BEGIN(type, "preads", usec);
2499 + for (w = root; w ; w = w->next) {
2500 + if(unlikely(w->exposed))
2501 + send_SET(w->name, w->io_storage_bytes_read);
2502 + }
2503 + send_END();
2504 +
2505 + send_BEGIN(type, "pwrites", usec);
2506 + for (w = root; w ; w = w->next) {
2507 + if(unlikely(w->exposed))
2508 + send_SET(w->name, w->io_storage_bytes_written);
2509 + }
2510 + send_END();
2511 +
2512 + send_BEGIN(type, "files", usec);
2513 + for (w = root; w ; w = w->next) {
2514 + if(unlikely(w->exposed))
2515 + send_SET(w->name, w->openfiles);
2516 + }
2517 + send_END();
2518 +
2519 + send_BEGIN(type, "sockets", usec);
2520 + for (w = root; w ; w = w->next) {
2521 + if(unlikely(w->exposed))
2522 + send_SET(w->name, w->opensockets);
2523 + }
2524 + send_END();
2525 +
2526 + send_BEGIN(type, "pipes", usec);
2527 + for (w = root; w ; w = w->next) {
2528 + if(unlikely(w->exposed))
2529 + send_SET(w->name, w->openpipes);
2530 + }
2531 + send_END();
2532 }
2533
2534
@@ -2537,121 +2537,121 @@ void send_collected_data_to_netdata(struct target *root, const char *type, unsig
2537
2538 void send_charts_updates_to_netdata(struct target *root, const char *type, const char *title)
2539 {
2540 - struct target *w;
2541 - int newly_added = 0;
2542 -
2543 - for(w = root ; w ; w = w->next) {
2544 - if (w->target) continue;
2545 -
2546 - if (!w->exposed && w->processes) {
2547 - newly_added++;
2548 - w->exposed = 1;
2549 - if (debug || w->debug) fprintf(stderr, "apps.plugin: %s just added - regenerating charts.\n", w->name);
2550 - }
2551 - }
2552 -
2553 - // nothing more to show
2554 - if(!newly_added && show_guest_time == show_guest_time_old) return;
2555 -
2556 - // we have something new to show
2557 - // update the charts
2558 - buffer_sprintf(output, "CHART %s.cpu '' '%s CPU Time (%d%% = %d core%s)' 'cpu time %%' cpu %s.cpu stacked 20001 %d\n", type, title, (processors * 100), processors, (processors>1)?"s":"", type, update_every);
2559 - for (w = root; w ; w = w->next) {
2560 - if(unlikely(w->exposed))
2561 - buffer_sprintf(output, "DIMENSION %s '' absolute 1 %llu %s\n", w->name, hz * RATES_DETAIL / 100, w->hidden ? "hidden" : "");
2562 - }
2563 -
2564 - buffer_sprintf(output, "CHART %s.mem '' '%s Dedicated Memory (w/o shared)' 'MB' mem %s.mem stacked 20003 %d\n", type, title, type, update_every);
2565 - for (w = root; w ; w = w->next) {
2566 - if(unlikely(w->exposed))
2567 - buffer_sprintf(output, "DIMENSION %s '' absolute %ld %ld\n", w->name, sysconf(_SC_PAGESIZE), 1024L*1024L);
2568 - }
2569 -
2570 - buffer_sprintf(output, "CHART %s.threads '' '%s Threads' 'threads' processes %s.threads stacked 20005 %d\n", type, title, type, update_every);
2571 - for (w = root; w ; w = w->next) {
2572 - if(unlikely(w->exposed))
2573 - buffer_sprintf(output, "DIMENSION %s '' absolute 1 1\n", w->name);
2574 - }
2575 -
2576 - buffer_sprintf(output, "CHART %s.processes '' '%s Processes' 'processes' processes %s.processes stacked 20004 %d\n", type, title, type, update_every);
2577 - for (w = root; w ; w = w->next) {
2578 - if(unlikely(w->exposed))
2579 - buffer_sprintf(output, "DIMENSION %s '' absolute 1 1\n", w->name);
2580 - }
2581 -
2582 - buffer_sprintf(output, "CHART %s.cpu_user '' '%s CPU User Time (%d%% = %d core%s)' 'cpu time %%' cpu %s.cpu_user stacked 20020 %d\n", type, title, (processors * 100), processors, (processors>1)?"s":"", type, update_every);
2583 - for (w = root; w ; w = w->next) {
2584 - if(unlikely(w->exposed))
2585 - buffer_sprintf(output, "DIMENSION %s '' absolute 1 %llu\n", w->name, hz * RATES_DETAIL / 100LLU);
2586 - }
2587 -
2588 - buffer_sprintf(output, "CHART %s.cpu_system '' '%s CPU System Time (%d%% = %d core%s)' 'cpu time %%' cpu %s.cpu_system stacked 20021 %d\n", type, title, (processors * 100), processors, (processors>1)?"s":"", type, update_every);
2589 - for (w = root; w ; w = w->next) {
2590 - if(unlikely(w->exposed))
2591 - buffer_sprintf(output, "DIMENSION %s '' absolute 1 %llu\n", w->name, hz * RATES_DETAIL / 100LLU);
2592 - }
2593 -
2594 - if(show_guest_time) {
2595 - buffer_sprintf(output, "CHART %s.cpu_guest '' '%s CPU Guest Time (%d%% = %d core%s)' 'cpu time %%' cpu %s.cpu_system stacked 20022 %d\n", type, title, (processors * 100), processors, (processors > 1) ? "s" : "", type, update_every);
2596 - for (w = root; w; w = w->next) {
2597 - if(unlikely(w->exposed))
2598 - buffer_sprintf(output, "DIMENSION %s '' absolute 1 %llu\n", w->name, hz * RATES_DETAIL / 100LLU);
2599 - }
2600 - }
2601 -
2602 - buffer_sprintf(output, "CHART %s.major_faults '' '%s Major Page Faults (swap read)' 'page faults/s' swap %s.major_faults stacked 20010 %d\n", type, title, type, update_every);
2603 - for (w = root; w ; w = w->next) {
2604 - if(unlikely(w->exposed))
2605 - buffer_sprintf(output, "DIMENSION %s '' absolute 1 %llu\n", w->name, RATES_DETAIL);
2606 - }
2607 -
2608 - buffer_sprintf(output, "CHART %s.minor_faults '' '%s Minor Page Faults' 'page faults/s' mem %s.minor_faults stacked 20011 %d\n", type, title, type, update_every);
2609 - for (w = root; w ; w = w->next) {
2610 - if(unlikely(w->exposed))
2611 - buffer_sprintf(output, "DIMENSION %s '' absolute 1 %llu\n", w->name, RATES_DETAIL);
2612 - }
2613 -
2614 - buffer_sprintf(output, "CHART %s.lreads '' '%s Disk Logical Reads' 'kilobytes/s' disk %s.lreads stacked 20042 %d\n", type, title, type, update_every);
2615 - for (w = root; w ; w = w->next) {
2616 - if(unlikely(w->exposed))
2617 - buffer_sprintf(output, "DIMENSION %s '' absolute 1 %llu\n", w->name, 1024LLU * RATES_DETAIL);
2618 - }
2619 -
2620 - buffer_sprintf(output, "CHART %s.lwrites '' '%s I/O Logical Writes' 'kilobytes/s' disk %s.lwrites stacked 20042 %d\n", type, title, type, update_every);
2621 - for (w = root; w ; w = w->next) {
2622 - if(unlikely(w->exposed))
2623 - buffer_sprintf(output, "DIMENSION %s '' absolute 1 %llu\n", w->name, 1024LLU * RATES_DETAIL);
2624 - }
2625 -
2626 - buffer_sprintf(output, "CHART %s.preads '' '%s Disk Reads' 'kilobytes/s' disk %s.preads stacked 20002 %d\n", type, title, type, update_every);
2627 - for (w = root; w ; w = w->next) {
2628 - if(unlikely(w->exposed))
2629 - buffer_sprintf(output, "DIMENSION %s '' absolute 1 %llu\n", w->name, 1024LLU * RATES_DETAIL);
2630 - }
2631 -
2632 - buffer_sprintf(output, "CHART %s.pwrites '' '%s Disk Writes' 'kilobytes/s' disk %s.pwrites stacked 20002 %d\n", type, title, type, update_every);
2633 - for (w = root; w ; w = w->next) {
2634 - if(unlikely(w->exposed))
2635 - buffer_sprintf(output, "DIMENSION %s '' absolute 1 %llu\n", w->name, 1024LLU * RATES_DETAIL);
2636 - }
2637 -
2638 - buffer_sprintf(output, "CHART %s.files '' '%s Open Files' 'open files' disk %s.files stacked 20050 %d\n", type, title, type, update_every);
2639 - for (w = root; w ; w = w->next) {
2640 - if(unlikely(w->exposed))
2641 - buffer_sprintf(output, "DIMENSION %s '' absolute 1 1\n", w->name);
2642 - }
2643 -
2644 - buffer_sprintf(output, "CHART %s.sockets '' '%s Open Sockets' 'open sockets' net %s.sockets stacked 20051 %d\n", type, title, type, update_every);
2645 - for (w = root; w ; w = w->next) {
2646 - if(unlikely(w->exposed))
2647 - buffer_sprintf(output, "DIMENSION %s '' absolute 1 1\n", w->name);
2648 - }
2649 -
2650 - buffer_sprintf(output, "CHART %s.pipes '' '%s Pipes' 'open pipes' processes %s.pipes stacked 20053 %d\n", type, title, type, update_every);
2651 - for (w = root; w ; w = w->next) {
2652 - if(unlikely(w->exposed))
2653 - buffer_sprintf(output, "DIMENSION %s '' absolute 1 1\n", w->name);
2654 - }
2540 + struct target *w;
2541 + int newly_added = 0;
2542 +
2543 + for(w = root ; w ; w = w->next) {
2544 + if (w->target) continue;
2545 +
2546 + if (!w->exposed && w->processes) {
2547 + newly_added++;
2548 + w->exposed = 1;
2549 + if (debug || w->debug) fprintf(stderr, "apps.plugin: %s just added - regenerating charts.\n", w->name);
2550 + }
2551 + }
2552 +
2553 + // nothing more to show
2554 + if(!newly_added && show_guest_time == show_guest_time_old) return;
2555 +
2556 + // we have something new to show
2557 + // update the charts
2558 + buffer_sprintf(output, "CHART %s.cpu '' '%s CPU Time (%d%% = %d core%s)' 'cpu time %%' cpu %s.cpu stacked 20001 %d\n", type, title, (processors * 100), processors, (processors>1)?"s":"", type, update_every);
2559 + for (w = root; w ; w = w->next) {
2560 + if(unlikely(w->exposed))
2561 + buffer_sprintf(output, "DIMENSION %s '' absolute 1 %llu %s\n", w->name, hz * RATES_DETAIL / 100, w->hidden ? "hidden" : "");
2562 + }
2563 +
2564 + buffer_sprintf(output, "CHART %s.mem '' '%s Dedicated Memory (w/o shared)' 'MB' mem %s.mem stacked 20003 %d\n", type, title, type, update_every);
2565 + for (w = root; w ; w = w->next) {
2566 + if(unlikely(w->exposed))
2567 + buffer_sprintf(output, "DIMENSION %s '' absolute %ld %ld\n", w->name, sysconf(_SC_PAGESIZE), 1024L*1024L);
2568 + }
2569 +
2570 + buffer_sprintf(output, "CHART %s.threads '' '%s Threads' 'threads' processes %s.threads stacked 20005 %d\n", type, title, type, update_every);
2571 + for (w = root; w ; w = w->next) {
2572 + if(unlikely(w->exposed))
2573 + buffer_sprintf(output, "DIMENSION %s '' absolute 1 1\n", w->name);
2574 + }
2575 +
2576 + buffer_sprintf(output, "CHART %s.processes '' '%s Processes' 'processes' processes %s.processes stacked 20004 %d\n", type, title, type, update_every);
2577 + for (w = root; w ; w = w->next) {
2578 + if(unlikely(w->exposed))
2579 + buffer_sprintf(output, "DIMENSION %s '' absolute 1 1\n", w->name);
2580 + }
2581 +
2582 + buffer_sprintf(output, "CHART %s.cpu_user '' '%s CPU User Time (%d%% = %d core%s)' 'cpu time %%' cpu %s.cpu_user stacked 20020 %d\n", type, title, (processors * 100), processors, (processors>1)?"s":"", type, update_every);
2583 + for (w = root; w ; w = w->next) {
2584 + if(unlikely(w->exposed))
2585 + buffer_sprintf(output, "DIMENSION %s '' absolute 1 %llu\n", w->name, hz * RATES_DETAIL / 100LLU);
2586 + }
2587 +
2588 + buffer_sprintf(output, "CHART %s.cpu_system '' '%s CPU System Time (%d%% = %d core%s)' 'cpu time %%' cpu %s.cpu_system stacked 20021 %d\n", type, title, (processors * 100), processors, (processors>1)?"s":"", type, update_every);
2589 + for (w = root; w ; w = w->next) {
2590 + if(unlikely(w->exposed))
2591 + buffer_sprintf(output, "DIMENSION %s '' absolute 1 %llu\n", w->name, hz * RATES_DETAIL / 100LLU);
2592 + }
2593 +
2594 + if(show_guest_time) {
2595 + buffer_sprintf(output, "CHART %s.cpu_guest '' '%s CPU Guest Time (%d%% = %d core%s)' 'cpu time %%' cpu %s.cpu_system stacked 20022 %d\n", type, title, (processors * 100), processors, (processors > 1) ? "s" : "", type, update_every);
2596 + for (w = root; w; w = w->next) {
2597 + if(unlikely(w->exposed))
2598 + buffer_sprintf(output, "DIMENSION %s '' absolute 1 %llu\n", w->name, hz * RATES_DETAIL / 100LLU);
2599 + }
2600 + }
2601 +
2602 + buffer_sprintf(output, "CHART %s.major_faults '' '%s Major Page Faults (swap read)' 'page faults/s' swap %s.major_faults stacked 20010 %d\n", type, title, type, update_every);
2603 + for (w = root; w ; w = w->next) {
2604 + if(unlikely(w->exposed))
2605 + buffer_sprintf(output, "DIMENSION %s '' absolute 1 %llu\n", w->name, RATES_DETAIL);
2606 + }
2607 +
2608 + buffer_sprintf(output, "CHART %s.minor_faults '' '%s Minor Page Faults' 'page faults/s' mem %s.minor_faults stacked 20011 %d\n", type, title, type, update_every);
2609 + for (w = root; w ; w = w->next) {
2610 + if(unlikely(w->exposed))
2611 + buffer_sprintf(output, "DIMENSION %s '' absolute 1 %llu\n", w->name, RATES_DETAIL);
2612 + }
2613 +
2614 + buffer_sprintf(output, "CHART %s.lreads '' '%s Disk Logical Reads' 'kilobytes/s' disk %s.lreads stacked 20042 %d\n", type, title, type, update_every);
2615 + for (w = root; w ; w = w->next) {
2616 + if(unlikely(w->exposed))
2617 + buffer_sprintf(output, "DIMENSION %s '' absolute 1 %llu\n", w->name, 1024LLU * RATES_DETAIL);
2618 + }
2619 +
2620 + buffer_sprintf(output, "CHART %s.lwrites '' '%s I/O Logical Writes' 'kilobytes/s' disk %s.lwrites stacked 20042 %d\n", type, title, type, update_every);
2621 + for (w = root; w ; w = w->next) {
2622 + if(unlikely(w->exposed))
2623 + buffer_sprintf(output, "DIMENSION %s '' absolute 1 %llu\n", w->name, 1024LLU * RATES_DETAIL);
2624 + }
2625 +
2626 + buffer_sprintf(output, "CHART %s.preads '' '%s Disk Reads' 'kilobytes/s' disk %s.preads stacked 20002 %d\n", type, title, type, update_every);
2627 + for (w = root; w ; w = w->next) {
2628 + if(unlikely(w->exposed))
2629 + buffer_sprintf(output, "DIMENSION %s '' absolute 1 %llu\n", w->name, 1024LLU * RATES_DETAIL);
2630 + }
2631 +
2632 + buffer_sprintf(output, "CHART %s.pwrites '' '%s Disk Writes' 'kilobytes/s' disk %s.pwrites stacked 20002 %d\n", type, title, type, update_every);
2633 + for (w = root; w ; w = w->next) {
2634 + if(unlikely(w->exposed))
2635 + buffer_sprintf(output, "DIMENSION %s '' absolute 1 %llu\n", w->name, 1024LLU * RATES_DETAIL);
2636 + }
2637 +
2638 + buffer_sprintf(output, "CHART %s.files '' '%s Open Files' 'open files' disk %s.files stacked 20050 %d\n", type, title, type, update_every);
2639 + for (w = root; w ; w = w->next) {
2640 + if(unlikely(w->exposed))
2641 + buffer_sprintf(output, "DIMENSION %s '' absolute 1 1\n", w->name);
2642 + }
2643 +
2644 + buffer_sprintf(output, "CHART %s.sockets '' '%s Open Sockets' 'open sockets' net %s.sockets stacked 20051 %d\n", type, title, type, update_every);
2645 + for (w = root; w ; w = w->next) {
2646 + if(unlikely(w->exposed))
2647 + buffer_sprintf(output, "DIMENSION %s '' absolute 1 1\n", w->name);
2648 + }
2649 +
2650 + buffer_sprintf(output, "CHART %s.pipes '' '%s Pipes' 'open pipes' processes %s.pipes stacked 20053 %d\n", type, title, type, update_every);
2651 + for (w = root; w ; w = w->next) {
2652 + if(unlikely(w->exposed))
2653 + buffer_sprintf(output, "DIMENSION %s '' absolute 1 1\n", w->name);
2654 + }
2655 }
2656
2657
@@ -2660,33 +2660,33 @@ void send_charts_updates_to_netdata(struct target *root, const char *type, const
2660
2661 void parse_args(int argc, char **argv)
2662 {
2663 - int i, freq = 0;
2664 - char *name = NULL;
2665 -
2666 - for(i = 1; i < argc; i++) {
2667 - if(!freq) {
2668 - int n = atoi(argv[i]);
2669 - if(n > 0) {
2670 - freq = n;
2671 - continue;
2672 - }
2673 - }
2674 -
2675 - if(strcmp("debug", argv[i]) == 0) {
2676 - debug = 1;
2677 - // debug_flags = 0xffffffff;
2678 - continue;
2679 - }
2680 -
2681 - if(strcmp("no-childs", argv[i]) == 0 || strcmp("without-childs", argv[i]) == 0) {
2682 - include_exited_childs = 0;
2683 - continue;
2684 - }
2685 -
2686 - if(strcmp("with-childs", argv[i]) == 0) {
2687 - include_exited_childs = 1;
2688 - continue;
2689 - }
2663 + int i, freq = 0;
2664 + char *name = NULL;
2665 +
2666 + for(i = 1; i < argc; i++) {
2667 + if(!freq) {
2668 + int n = atoi(argv[i]);
2669 + if(n > 0) {
2670 + freq = n;
2671 + continue;
2672 + }
2673 + }
2674 +
2675 + if(strcmp("debug", argv[i]) == 0) {
2676 + debug = 1;
2677 + // debug_flags = 0xffffffff;
2678 + continue;
2679 + }
2680 +
2681 + if(strcmp("no-childs", argv[i]) == 0 || strcmp("without-childs", argv[i]) == 0) {
2682 + include_exited_childs = 0;
2683 + continue;
2684 + }
2685 +
2686 + if(strcmp("with-childs", argv[i]) == 0) {
2687 + include_exited_childs = 1;
2688 + continue;
2689 + }
2690
2691 if(strcmp("with-guest", argv[i]) == 0) {
2692 enable_guest_charts = 1;
@@ -2698,7 +2698,7 @@ void parse_args(int argc, char **argv)
2698 continue;
2699 }
2700
2701 - if(strcmp("-h", argv[i]) == 0 || strcmp("--help", argv[i]) == 0) {
2701 + if(strcmp("-h", argv[i]) == 0 || strcmp("--help", argv[i]) == 0) {
2702 fprintf(stderr,
2703 "apps.plugin\n"
2704 "(C) 2016 Costa Tsaousis"
@@ -2728,161 +2728,161 @@ void parse_args(int argc, char **argv)
2728 }
2729
2730 if(!name) {
2731 - name = argv[i];
2732 - continue;
2733 - }
2731 + name = argv[i];
2732 + continue;
2733 + }
2734
2735 - error("Cannot understand option %s", argv[i]);
2736 - exit(1);
2737 - }
2735 + error("Cannot understand option %s", argv[i]);
2736 + exit(1);
2737 + }
2738
2739 - if(freq > 0) update_every = freq;
2740 - if(!name) name = "groups";
2739 + if(freq > 0) update_every = freq;
2740 + if(!name) name = "groups";
2741
2742 - if(read_apps_groups_conf(name)) {
2743 - error("Cannot read process groups %s", name);
2744 - exit(1);
2745 - }
2742 + if(read_apps_groups_conf(name)) {
2743 + error("Cannot read process groups %s", name);
2744 + exit(1);
2745 + }
2746 }
2747
2748 int main(int argc, char **argv)
2749 {
2750 - // debug_flags = D_PROCFILE;
2750 + // debug_flags = D_PROCFILE;
2751
2752 - // set the name for logging
2753 - program_name = "apps.plugin";
2752 + // set the name for logging
2753 + program_name = "apps.plugin";
2754
2755 - // disable syslog for apps.plugin
2756 - error_log_syslog = 0;
2755 + // disable syslog for apps.plugin
2756 + error_log_syslog = 0;
2757
2758 - // set errors flood protection to 100 logs per hour
2759 - error_log_errors_per_period = 100;
2760 - error_log_throttle_period = 3600;
2758 + // set errors flood protection to 100 logs per hour
2759 + error_log_errors_per_period = 100;
2760 + error_log_throttle_period = 3600;
2761
2762 - host_prefix = getenv("NETDATA_HOST_PREFIX");
2763 - if(host_prefix == NULL) {
2764 - info("NETDATA_HOST_PREFIX is not passed from netdata");
2765 - host_prefix = "";
2766 - }
2767 - else info("Found NETDATA_HOST_PREFIX='%s'", host_prefix);
2762 + host_prefix = getenv("NETDATA_HOST_PREFIX");
2763 + if(host_prefix == NULL) {
2764 + info("NETDATA_HOST_PREFIX is not passed from netdata");
2765 + host_prefix = "";
2766 + }
2767 + else info("Found NETDATA_HOST_PREFIX='%s'", host_prefix);
2768
2769 - config_dir = getenv("NETDATA_CONFIG_DIR");
2770 - if(config_dir == NULL) {
2771 - info("NETDATA_CONFIG_DIR is not passed from netdata");
2772 - config_dir = CONFIG_DIR;
2773 - }
2774 - else info("Found NETDATA_CONFIG_DIR='%s'", config_dir);
2769 + config_dir = getenv("NETDATA_CONFIG_DIR");
2770 + if(config_dir == NULL) {
2771 + info("NETDATA_CONFIG_DIR is not passed from netdata");
2772 + config_dir = CONFIG_DIR;
2773 + }
2774 + else info("Found NETDATA_CONFIG_DIR='%s'", config_dir);
2775
2776 #ifdef NETDATA_INTERNAL_CHECKS
2777 - if(debug_flags != 0) {
2778 - struct rlimit rl = { RLIM_INFINITY, RLIM_INFINITY };
2779 - if(setrlimit(RLIMIT_CORE, &rl) != 0)
2780 - info("Cannot request unlimited core dumps for debugging... Proceeding anyway...");
2781 - prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
2782 - }
2777 + if(debug_flags != 0) {
2778 + struct rlimit rl = { RLIM_INFINITY, RLIM_INFINITY };
2779 + if(setrlimit(RLIMIT_CORE, &rl) != 0)
2780 + info("Cannot request unlimited core dumps for debugging... Proceeding anyway...");
2781 + prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
2782 + }
2783 #endif /* NETDATA_INTERNAL_CHECKS */
2784
2785 - procfile_adaptive_initial_allocation = 1;
2786 -
2787 - time_t started_t = time(NULL);
2788 - time_t current_t;
2789 - get_HZ();
2790 - pid_max = get_system_pid_max();
2791 - processors = get_system_cpus();
2792 -
2793 - parse_args(argc, argv);
2794 -
2795 - all_pids_sortlist = callocz(sizeof(pid_t), (size_t)pid_max);
2796 - all_pids = callocz(sizeof(struct pid_stat *), (size_t) pid_max);
2797 -
2798 - output = buffer_create(1024);
2799 - buffer_sprintf(output,
2800 - "CHART netdata.apps_cpu '' 'Apps Plugin CPU' 'milliseconds/s' apps.plugin netdata.apps_cpu stacked 140000 %1$d\n"
2801 - "DIMENSION user '' incremental 1 1000\n"
2802 - "DIMENSION system '' incremental 1 1000\n"
2803 - "CHART netdata.apps_files '' 'Apps Plugin Files' 'files/s' apps.plugin netdata.apps_files line 140001 %1$d\n"
2804 - "DIMENSION files '' incremental 1 1\n"
2805 - "DIMENSION pids '' absolute 1 1\n"
2806 - "DIMENSION fds '' absolute 1 1\n"
2807 - "DIMENSION targets '' absolute 1 1\n"
2808 - "CHART netdata.apps_fix '' 'Apps Plugin Normalization Ratios' 'percentage' apps.plugin netdata.apps_fix line 140002 %1$d\n"
2809 - "DIMENSION utime '' absolute 1 %2$llu\n"
2810 - "DIMENSION stime '' absolute 1 %2$llu\n"
2811 - "DIMENSION gtime '' absolute 1 %2$llu\n"
2812 - "DIMENSION minflt '' absolute 1 %2$llu\n"
2813 - "DIMENSION majflt '' absolute 1 %2$llu\n"
2814 - , update_every
2815 - , RATES_DETAIL
2816 - );
2817 -
2818 - if(include_exited_childs)
2819 - buffer_sprintf(output,
2820 - "CHART netdata.apps_children_fix '' 'Apps Plugin Exited Children Normalization Ratios' 'percentage' apps.plugin netdata.apps_children_fix line 140003 %1$d\n"
2821 - "DIMENSION cutime '' absolute 1 %2$llu\n"
2822 - "DIMENSION cstime '' absolute 1 %2$llu\n"
2823 - "DIMENSION cgtime '' absolute 1 %2$llu\n"
2824 - "DIMENSION cminflt '' absolute 1 %2$llu\n"
2825 - "DIMENSION cmajflt '' absolute 1 %2$llu\n"
2826 - , update_every
2827 - , RATES_DETAIL
2828 - );
2785 + procfile_adaptive_initial_allocation = 1;
2786 +
2787 + time_t started_t = time(NULL);
2788 + time_t current_t;
2789 + get_HZ();
2790 + pid_max = get_system_pid_max();
2791 + processors = get_system_cpus();
2792 +
2793 + parse_args(argc, argv);
2794 +
2795 + all_pids_sortlist = callocz(sizeof(pid_t), (size_t)pid_max);
2796 + all_pids = callocz(sizeof(struct pid_stat *), (size_t) pid_max);
2797 +
2798 + output = buffer_create(1024);
2799 + buffer_sprintf(output,
2800 + "CHART netdata.apps_cpu '' 'Apps Plugin CPU' 'milliseconds/s' apps.plugin netdata.apps_cpu stacked 140000 %1$d\n"
2801 + "DIMENSION user '' incremental 1 1000\n"
2802 + "DIMENSION system '' incremental 1 1000\n"
2803 + "CHART netdata.apps_files '' 'Apps Plugin Files' 'files/s' apps.plugin netdata.apps_files line 140001 %1$d\n"
2804 + "DIMENSION files '' incremental 1 1\n"
2805 + "DIMENSION pids '' absolute 1 1\n"
2806 + "DIMENSION fds '' absolute 1 1\n"
2807 + "DIMENSION targets '' absolute 1 1\n"
2808 + "CHART netdata.apps_fix '' 'Apps Plugin Normalization Ratios' 'percentage' apps.plugin netdata.apps_fix line 140002 %1$d\n"
2809 + "DIMENSION utime '' absolute 1 %2$llu\n"
2810 + "DIMENSION stime '' absolute 1 %2$llu\n"
2811 + "DIMENSION gtime '' absolute 1 %2$llu\n"
2812 + "DIMENSION minflt '' absolute 1 %2$llu\n"
2813 + "DIMENSION majflt '' absolute 1 %2$llu\n"
2814 + , update_every
2815 + , RATES_DETAIL
2816 + );
2817 +
2818 + if(include_exited_childs)
2819 + buffer_sprintf(output,
2820 + "CHART netdata.apps_children_fix '' 'Apps Plugin Exited Children Normalization Ratios' 'percentage' apps.plugin netdata.apps_children_fix line 140003 %1$d\n"
2821 + "DIMENSION cutime '' absolute 1 %2$llu\n"
2822 + "DIMENSION cstime '' absolute 1 %2$llu\n"
2823 + "DIMENSION cgtime '' absolute 1 %2$llu\n"
2824 + "DIMENSION cminflt '' absolute 1 %2$llu\n"
2825 + "DIMENSION cmajflt '' absolute 1 %2$llu\n"
2826 + , update_every
2827 + , RATES_DETAIL
2828 + );
2829
2830 #ifndef PROFILING_MODE
2831 - unsigned long long sunext = (time(NULL) - (time(NULL) % update_every) + update_every) * 1000000ULL;
2832 - unsigned long long sunow;
2831 + unsigned long long sunext = (time(NULL) - (time(NULL) % update_every) + update_every) * 1000000ULL;

This file is too large to show in full.

src/avl.c
+27 -27
@@ -15,7 +15,7 @@
15
16
17 /* Search |tree| for an item matching |item|, and return it if found.
18 - Otherwise return |NULL|. */
18 + Otherwise return |NULL|. */
19 avl *avl_search(avl_tree *tree, avl *item) {
20 avl *p;
21
@@ -36,8 +36,8 @@ avl *avl_search(avl_tree *tree, avl *item) {
36 }
37
38 /* Inserts |item| into |tree| and returns a pointer to |item|'s address.
39 - If a duplicate item is found in the tree,
40 - returns a pointer to the duplicate without inserting |item|.
39 + If a duplicate item is found in the tree,
40 + returns a pointer to the duplicate without inserting |item|.
41 */
42 avl *avl_insert(avl_tree *tree, avl *item) {
43 avl *y, *z; /* Top node to update balance factor, and parent. */
@@ -134,7 +134,7 @@ avl *avl_insert(avl_tree *tree, avl *item) {
134 }
135
136 /* Deletes from |tree| and returns an item matching |item|.
137 - Returns a null pointer if no matching item found. */
137 + Returns a null pointer if no matching item found. */
138 avl *avl_remove(avl_tree *tree, avl *item) {
139 /* Stack of nodes. */
140 avl *pa[AVL_MAX_HEIGHT]; /* Nodes. */
@@ -283,9 +283,9 @@ avl *avl_remove(avl_tree *tree, avl *item) {
283 void avl_read_lock(avl_tree_lock *t) {
284 #ifndef AVL_WITHOUT_PTHREADS
285 #ifdef AVL_LOCK_WITH_MUTEX
286 - pthread_mutex_lock(&t->mutex);
286 + pthread_mutex_lock(&t->mutex);
287 #else
288 - pthread_rwlock_rdlock(&t->rwlock);
288 + pthread_rwlock_rdlock(&t->rwlock);
289 #endif
290 #endif /* AVL_WITHOUT_PTHREADS */
291 }
@@ -293,9 +293,9 @@ void avl_read_lock(avl_tree_lock *t) {
293 void avl_write_lock(avl_tree_lock *t) {
294 #ifndef AVL_WITHOUT_PTHREADS
295 #ifdef AVL_LOCK_WITH_MUTEX
296 - pthread_mutex_lock(&t->mutex);
296 + pthread_mutex_lock(&t->mutex);
297 #else
298 - pthread_rwlock_wrlock(&t->rwlock);
298 + pthread_rwlock_wrlock(&t->rwlock);
299 #endif
300 #endif /* AVL_WITHOUT_PTHREADS */
301 }
@@ -303,9 +303,9 @@ void avl_write_lock(avl_tree_lock *t) {
303 void avl_unlock(avl_tree_lock *t) {
304 #ifndef AVL_WITHOUT_PTHREADS
305 #ifdef AVL_LOCK_WITH_MUTEX
306 - pthread_mutex_unlock(&t->mutex);
306 + pthread_mutex_unlock(&t->mutex);
307 #else
308 - pthread_rwlock_unlock(&t->rwlock);
308 + pthread_rwlock_unlock(&t->rwlock);
309 #endif
310 #endif /* AVL_WITHOUT_PTHREADS */
311 }
@@ -313,42 +313,42 @@ void avl_unlock(avl_tree_lock *t) {
313 /* ------------------------------------------------------------------------- */
314
315 void avl_init_lock(avl_tree_lock *t, int (*compar)(void *a, void *b)) {
316 - avl_init(&t->avl_tree, compar);
316 + avl_init(&t->avl_tree, compar);
317
318 #ifndef AVL_WITHOUT_PTHREADS
319 - int lock;
319 + int lock;
320
321 #ifdef AVL_LOCK_WITH_MUTEX
322 - lock = pthread_mutex_init(&t->mutex, NULL);
322 + lock = pthread_mutex_init(&t->mutex, NULL);
323 #else
324 - lock = pthread_rwlock_init(&t->rwlock, NULL);
324 + lock = pthread_rwlock_init(&t->rwlock, NULL);
325 #endif
326
327 - if(lock != 0)
328 - fatal("Failed to initialize AVL mutex/rwlock, error: %d", lock);
327 + if(lock != 0)
328 + fatal("Failed to initialize AVL mutex/rwlock, error: %d", lock);
329
330 #endif /* AVL_WITHOUT_PTHREADS */
331 }
332
333 avl *avl_search_lock(avl_tree_lock *t, avl *a) {
334 - avl_read_lock(t);
335 - avl *ret = avl_search(&t->avl_tree, a);
336 - avl_unlock(t);
337 - return ret;
334 + avl_read_lock(t);
335 + avl *ret = avl_search(&t->avl_tree, a);
336 + avl_unlock(t);
337 + return ret;
338 }
339
340 avl * avl_remove_lock(avl_tree_lock *t, avl *a) {
341 - avl_write_lock(t);
342 - avl *ret = avl_remove(&t->avl_tree, a);
343 - avl_unlock(t);
344 - return ret;
341 + avl_write_lock(t);
342 + avl *ret = avl_remove(&t->avl_tree, a);
343 + avl_unlock(t);
344 + return ret;
345 }
346
347 avl *avl_insert_lock(avl_tree_lock *t, avl *a) {
348 - avl_write_lock(t);
348 + avl_write_lock(t);
349 avl * ret = avl_insert(&t->avl_tree, a);
350 - avl_unlock(t);
351 - return ret;
350 + avl_unlock(t);
351 + return ret;
352 }
353
354 void avl_init(avl_tree *t, int (*compar)(void *a, void *b)) {
src/avl.h
+5 -5
@@ -32,18 +32,18 @@ typedef struct avl {
32
33 /* An AVL tree */
34 typedef struct avl_tree {
35 - avl *root;
36 - int (*compar)(void *a, void *b);
35 + avl *root;
36 + int (*compar)(void *a, void *b);
37 } avl_tree;
38
39 typedef struct avl_tree_lock {
40 - avl_tree avl_tree;
40 + avl_tree avl_tree;
41
42 #ifndef AVL_WITHOUT_PTHREADS
43 #ifdef AVL_LOCK_WITH_MUTEX
44 - pthread_mutex_t mutex;
44 + pthread_mutex_t mutex;
45 #else /* AVL_LOCK_WITH_MUTEX */
46 - pthread_rwlock_t rwlock;
46 + pthread_rwlock_t rwlock;
47 #endif /* AVL_LOCK_WITH_MUTEX */
48 #endif /* AVL_WITHOUT_PTHREADS */
49 } avl_tree_lock;
src/common.c
+28 -28
@@ -642,15 +642,15 @@ void netdata_fix_chart_id(char *s) {
642 // http://stackoverflow.com/questions/7666509/hash-function-for-string
643 uint32_t simple_hash(const char *name)
644 {
645 - const char *s = name;
646 - uint32_t hash = 5381;
647 - int i;
645 + const char *s = name;
646 + uint32_t hash = 5381;
647 + int i;
648
649 - while((i = *s++)) hash = ((hash << 5) + hash) + i;
649 + while((i = *s++)) hash = ((hash << 5) + hash) + i;
650
651 - // fprintf(stderr, "HASH: %lu %s\n", hash, name);
651 + // fprintf(stderr, "HASH: %lu %s\n", hash, name);
652
653 - return hash;
653 + return hash;
654 }
655 */
656
@@ -694,22 +694,22 @@ uint32_t simple_uhash(const char *name) {
694 // http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx
695 // one at a time hash
696 uint32_t simple_hash(const char *name) {
697 - unsigned char *s = (unsigned char *)name;
698 - uint32_t h = 0;
697 + unsigned char *s = (unsigned char *)name;
698 + uint32_t h = 0;
699
700 - while(*s) {
701 - h += *s++;
702 - h += (h << 10);
703 - h ^= (h >> 6);
704 - }
700 + while(*s) {
701 + h += *s++;
702 + h += (h << 10);
703 + h ^= (h >> 6);
704 + }
705
706 - h += (h << 3);
707 - h ^= (h >> 11);
708 - h += (h << 15);
706 + h += (h << 3);
707 + h ^= (h >> 11);
708 + h += (h << 15);
709
710 - // fprintf(stderr, "HASH: %u = %s\n", h, name);
710 + // fprintf(stderr, "HASH: %u = %s\n", h, name);
711
712 - return h;
712 + return h;
713 }
714 */
715
@@ -782,16 +782,16 @@ void *mymmap(const char *filename, size_t size, int flags, int ksm) {
782 #ifdef MADV_MERGEABLE
783 } else {
784 /*
785 - // test - load the file into memory
786 - mem = calloc(1, size);
787 - if(mem) {
788 - if(lseek(fd, 0, SEEK_SET) == 0) {
789 - if(read(fd, mem, size) != (ssize_t)size)
790 - error("Cannot read from file '%s'", filename);
791 - }
792 - else
793 - error("Cannot seek to beginning of file '%s'.", filename);
794 - }
785 + // test - load the file into memory
786 + mem = calloc(1, size);
787 + if(mem) {
788 + if(lseek(fd, 0, SEEK_SET) == 0) {
789 + if(read(fd, mem, size) != (ssize_t)size)
790 + error("Cannot read from file '%s'", filename);
791 + }
792 + else
793 + error("Cannot seek to beginning of file '%s'.", filename);
794 + }
795 */
796 mem = mmap(NULL, size, PROT_READ | PROT_WRITE, flags | MAP_ANONYMOUS, -1, 0);
797 if (mem != MAP_FAILED) {
src/daemon.c
+168 -168
@@ -23,195 +23,195 @@ void sig_handler_logrotate(int signo)
23
24 void sig_handler_save(int signo)
25 {
26 - if(signo) {
26 + if(signo) {
27 error_log_limit_reset();
28 - info("Received signal %d to save the database...", signo);
29 - rrdset_save_all();
30 - }
28 + info("Received signal %d to save the database...", signo);
29 + rrdset_save_all();
30 + }
31 }
32
33 static void chown_open_file(int fd, uid_t uid, gid_t gid) {
34 - if(fd == -1) return;
34 + if(fd == -1) return;
35
36 - struct stat buf;
36 + struct stat buf;
37
38 - if(fstat(fd, &buf) == -1) {
39 - error("Cannot fstat() fd %d", fd);
40 - return;
41 - }
38 + if(fstat(fd, &buf) == -1) {
39 + error("Cannot fstat() fd %d", fd);
40 + return;
41 + }
42
43 - if((buf.st_uid != uid || buf.st_gid != gid) && S_ISREG(buf.st_mode)) {
44 - if(fchown(fd, uid, gid) == -1)
45 - error("Cannot fchown() fd %d.", fd);
46 - }
43 + if((buf.st_uid != uid || buf.st_gid != gid) && S_ISREG(buf.st_mode)) {
44 + if(fchown(fd, uid, gid) == -1)
45 + error("Cannot fchown() fd %d.", fd);
46 + }
47 }
48
49 int become_user(const char *username, int pid_fd)
50 {
51 - struct passwd *pw = getpwnam(username);
52 - if(!pw) {
53 - error("User %s is not present.", username);
54 - return -1;
55 - }
56 -
57 - uid_t uid = pw->pw_uid;
58 - gid_t gid = pw->pw_gid;
59 -
60 - int ngroups = (int)sysconf(_SC_NGROUPS_MAX);
61 - gid_t *supplementary_groups = NULL;
62 - if(ngroups) {
63 - supplementary_groups = mallocz(sizeof(gid_t) * ngroups);
64 - if(getgrouplist(username, gid, supplementary_groups, &ngroups) == -1) {
65 - error("Cannot get supplementary groups of user '%s'.", username);
66 - freez(supplementary_groups);
67 - supplementary_groups = NULL;
68 - ngroups = 0;
69 - }
70 - }
71 -
72 - chown_open_file(STDOUT_FILENO, uid, gid);
73 - chown_open_file(STDERR_FILENO, uid, gid);
74 - chown_open_file(stdaccess_fd, uid, gid);
75 - chown_open_file(pid_fd, uid, gid);
76 -
77 - if(supplementary_groups && ngroups) {
78 - if(setgroups(ngroups, supplementary_groups) == -1)
79 - error("Cannot set supplementary groups for user '%s'", username);
80 -
81 - freez(supplementary_groups);
82 - supplementary_groups = NULL;
83 - ngroups = 0;
84 - }
85 -
86 - if(setresgid(gid, gid, gid) != 0) {
87 - error("Cannot switch to user's %s group (gid: %u).", username, gid);
88 - return -1;
89 - }
90 -
91 - if(setresuid(uid, uid, uid) != 0) {
92 - error("Cannot switch to user %s (uid: %u).", username, uid);
93 - return -1;
94 - }
95 -
96 - if(setgid(gid) != 0) {
97 - error("Cannot switch to user's %s group (gid: %u).", username, gid);
98 - return -1;
99 - }
100 - if(setegid(gid) != 0) {
101 - error("Cannot effectively switch to user's %s group (gid: %u).", username, gid);
102 - return -1;
103 - }
104 - if(setuid(uid) != 0) {
105 - error("Cannot switch to user %s (uid: %u).", username, uid);
106 - return -1;
107 - }
108 - if(seteuid(uid) != 0) {
109 - error("Cannot effectively switch to user %s (uid: %u).", username, uid);
110 - return -1;
111 - }
112 -
113 - return(0);
51 + struct passwd *pw = getpwnam(username);
52 + if(!pw) {
53 + error("User %s is not present.", username);
54 + return -1;
55 + }
56 +
57 + uid_t uid = pw->pw_uid;
58 + gid_t gid = pw->pw_gid;
59 +
60 + int ngroups = (int)sysconf(_SC_NGROUPS_MAX);
61 + gid_t *supplementary_groups = NULL;
62 + if(ngroups) {
63 + supplementary_groups = mallocz(sizeof(gid_t) * ngroups);
64 + if(getgrouplist(username, gid, supplementary_groups, &ngroups) == -1) {
65 + error("Cannot get supplementary groups of user '%s'.", username);
66 + freez(supplementary_groups);
67 + supplementary_groups = NULL;
68 + ngroups = 0;
69 + }
70 + }
71 +
72 + chown_open_file(STDOUT_FILENO, uid, gid);
73 + chown_open_file(STDERR_FILENO, uid, gid);
74 + chown_open_file(stdaccess_fd, uid, gid);
75 + chown_open_file(pid_fd, uid, gid);
76 +
77 + if(supplementary_groups && ngroups) {
78 + if(setgroups(ngroups, supplementary_groups) == -1)
79 + error("Cannot set supplementary groups for user '%s'", username);
80 +
81 + freez(supplementary_groups);
82 + supplementary_groups = NULL;
83 + ngroups = 0;
84 + }
85 +
86 + if(setresgid(gid, gid, gid) != 0) {
87 + error("Cannot switch to user's %s group (gid: %u).", username, gid);
88 + return -1;
89 + }
90 +
91 + if(setresuid(uid, uid, uid) != 0) {
92 + error("Cannot switch to user %s (uid: %u).", username, uid);
93 + return -1;
94 + }
95 +
96 + if(setgid(gid) != 0) {
97 + error("Cannot switch to user's %s group (gid: %u).", username, gid);
98 + return -1;
99 + }
100 + if(setegid(gid) != 0) {
101 + error("Cannot effectively switch to user's %s group (gid: %u).", username, gid);
102 + return -1;
103 + }
104 + if(setuid(uid) != 0) {
105 + error("Cannot switch to user %s (uid: %u).", username, uid);
106 + return -1;
107 + }
108 + if(seteuid(uid) != 0) {
109 + error("Cannot effectively switch to user %s (uid: %u).", username, uid);
110 + return -1;
111 + }
112 +
113 + return(0);
114 }
115
116 void oom_score_adj(int score) {
117 - int done = 0;
118 - int fd = open("/proc/self/oom_score_adj", O_WRONLY);
119 - if(fd != -1) {
120 - char buf[10 + 1];
121 - ssize_t len = snprintfz(buf, 10, "%d", score);
122 - if(write(fd, buf, len) == len) done = 1;
123 - close(fd);
124 - }
125 -
126 - if(!done)
127 - error("Cannot adjust my Out-Of-Memory score to %d.", score);
128 - else
129 - info("Adjusted my Out-Of-Memory score to %d.", score);
117 + int done = 0;
118 + int fd = open("/proc/self/oom_score_adj", O_WRONLY);
119 + if(fd != -1) {
120 + char buf[10 + 1];
121 + ssize_t len = snprintfz(buf, 10, "%d", score);
122 + if(write(fd, buf, len) == len) done = 1;
123 + close(fd);
124 + }
125 +
126 + if(!done)
127 + error("Cannot adjust my Out-Of-Memory score to %d.", score);
128 + else
129 + info("Adjusted my Out-Of-Memory score to %d.", score);
130 }
131
132 int sched_setscheduler_idle(void) {
133 - const struct sched_param param = {
134 - .sched_priority = 0
135 - };
133 + const struct sched_param param = {
134 + .sched_priority = 0
135 + };
136
137 - int i = sched_setscheduler(0, SCHED_IDLE, &param);
138 - if(i != 0)
139 - error("Cannot adjust my scheduling priority to IDLE.");
140 - else
141 - info("Adjusted my scheduling priority to IDLE.");
137 + int i = sched_setscheduler(0, SCHED_IDLE, &param);
138 + if(i != 0)
139 + error("Cannot adjust my scheduling priority to IDLE.");
140 + else
141 + info("Adjusted my scheduling priority to IDLE.");
142
143 - return i;
143 + return i;
144 }
145
146 int become_daemon(int dont_fork, const char *user)
147 {
148 - if(!dont_fork) {
149 - int i = fork();
150 - if(i == -1) {
151 - perror("cannot fork");
152 - exit(1);
153 - }
154 - if(i != 0) {
155 - exit(0); // the parent
156 - }
157 -
158 - // become session leader
159 - if (setsid() < 0) {
160 - perror("Cannot become session leader.");
161 - exit(2);
162 - }
163 -
164 - // fork() again
165 - i = fork();
166 - if(i == -1) {
167 - perror("cannot fork");
168 - exit(1);
169 - }
170 - if(i != 0) {
171 - exit(0); // the parent
172 - }
173 - }
174 -
175 - // generate our pid file
176 - int pidfd = -1;
177 - if(pidfile[0]) {
178 - pidfd = open(pidfile, O_WRONLY | O_CREAT, 0644);
179 - if(pidfd >= 0) {
180 - if(ftruncate(pidfd, 0) != 0)
181 - error("Cannot truncate pidfile '%s'.", pidfile);
182 -
183 - char b[100];
184 - sprintf(b, "%d\n", getpid());
185 - ssize_t i = write(pidfd, b, strlen(b));
186 - if(i <= 0)
187 - error("Cannot write pidfile '%s'.", pidfile);
188 - }
189 - else error("Failed to open pidfile '%s'.", pidfile);
190 - }
191 -
192 - // Set new file permissions
193 - umask(0002);
194 -
195 - // adjust my Out-Of-Memory score
196 - oom_score_adj(1000);
197 -
198 - // never become a problem
199 - if(sched_setscheduler_idle() != 0) {
200 - if(nice(19) == -1) error("Cannot lower my CPU priority.");
201 - else info("Set my nice value to 19.");
202 - }
203 -
204 - if(user && *user) {
205 - if(become_user(user, pidfd) != 0) {
206 - error("Cannot become user '%s'. Continuing as we are.", user);
207 - }
208 - else info("Successfully became user '%s'.", user);
209 - }
210 -
211 - if(pidfd != -1) {
212 - close(pidfd);
213 - pidfd = -1;
214 - }
215 -
216 - return(0);
148 + if(!dont_fork) {
149 + int i = fork();
150 + if(i == -1) {
151 + perror("cannot fork");
152 + exit(1);
153 + }
154 + if(i != 0) {
155 + exit(0); // the parent
156 + }
157 +
158 + // become session leader
159 + if (setsid() < 0) {
160 + perror("Cannot become session leader.");
161 + exit(2);
162 + }
163 +
164 + // fork() again
165 + i = fork();
166 + if(i == -1) {
167 + perror("cannot fork");
168 + exit(1);
169 + }
170 + if(i != 0) {
171 + exit(0); // the parent
172 + }
173 + }
174 +
175 + // generate our pid file
176 + int pidfd = -1;
177 + if(pidfile[0]) {
178 + pidfd = open(pidfile, O_WRONLY | O_CREAT, 0644);
179 + if(pidfd >= 0) {
180 + if(ftruncate(pidfd, 0) != 0)
181 + error("Cannot truncate pidfile '%s'.", pidfile);
182 +
183 + char b[100];
184 + sprintf(b, "%d\n", getpid());
185 + ssize_t i = write(pidfd, b, strlen(b));
186 + if(i <= 0)
187 + error("Cannot write pidfile '%s'.", pidfile);
188 + }
189 + else error("Failed to open pidfile '%s'.", pidfile);
190 + }
191 +
192 + // Set new file permissions
193 + umask(0002);
194 +
195 + // adjust my Out-Of-Memory score
196 + oom_score_adj(1000);
197 +
198 + // never become a problem
199 + if(sched_setscheduler_idle() != 0) {
200 + if(nice(19) == -1) error("Cannot lower my CPU priority.");
201 + else info("Set my nice value to 19.");
202 + }
203 +
204 + if(user && *user) {
205 + if(become_user(user, pidfd) != 0) {
206 + error("Cannot become user '%s'. Continuing as we are.", user);
207 + }
208 + else info("Successfully became user '%s'.", user);
209 + }
210 +
211 + if(pidfd != -1) {
212 + close(pidfd);
213 + pidfd = -1;
214 + }
215 +
216 + return(0);
217 }
src/dictionary.c
+157 -157
@@ -4,24 +4,24 @@
4 // dictionary statistics
5
6 static inline void NETDATA_DICTIONARY_STATS_INSERTS_PLUS1(DICTIONARY *dict) {
7 - if(likely(dict->stats))
8 - dict->stats->inserts++;
7 + if(likely(dict->stats))
8 + dict->stats->inserts++;
9 }
10 static inline void NETDATA_DICTIONARY_STATS_DELETES_PLUS1(DICTIONARY *dict) {
11 - if(likely(dict->stats))
12 - dict->stats->deletes++;
11 + if(likely(dict->stats))
12 + dict->stats->deletes++;
13 }
14 static inline void NETDATA_DICTIONARY_STATS_SEARCHES_PLUS1(DICTIONARY *dict) {
15 - if(likely(dict->stats))
16 - dict->stats->searches++;
15 + if(likely(dict->stats))
16 + dict->stats->searches++;
17 }
18 static inline void NETDATA_DICTIONARY_STATS_ENTRIES_PLUS1(DICTIONARY *dict) {
19 - if(likely(dict->stats))
20 - dict->stats->entries++;
19 + if(likely(dict->stats))
20 + dict->stats->entries++;
21 }
22 static inline void NETDATA_DICTIONARY_STATS_ENTRIES_MINUS1(DICTIONARY *dict) {
23 - if(likely(dict->stats))
24 - dict->stats->entries--;
23 + if(likely(dict->stats))
24 + dict->stats->entries--;
25 }
26
27
@@ -29,24 +29,24 @@ static inline void NETDATA_DICTIONARY_STATS_ENTRIES_MINUS1(DICTIONARY *dict) {
29 // dictionary locks
30
31 static inline void dictionary_read_lock(DICTIONARY *dict) {
32 - if(likely(dict->rwlock)) {
33 - // debug(D_DICTIONARY, "Dictionary READ lock");
34 - pthread_rwlock_rdlock(dict->rwlock);
35 - }
32 + if(likely(dict->rwlock)) {
33 + // debug(D_DICTIONARY, "Dictionary READ lock");
34 + pthread_rwlock_rdlock(dict->rwlock);
35 + }
36 }
37
38 static inline void dictionary_write_lock(DICTIONARY *dict) {
39 - if(likely(dict->rwlock)) {
40 - // debug(D_DICTIONARY, "Dictionary WRITE lock");
41 - pthread_rwlock_wrlock(dict->rwlock);
42 - }
39 + if(likely(dict->rwlock)) {
40 + // debug(D_DICTIONARY, "Dictionary WRITE lock");
41 + pthread_rwlock_wrlock(dict->rwlock);
42 + }
43 }
44
45 static inline void dictionary_unlock(DICTIONARY *dict) {
46 - if(likely(dict->rwlock)) {
47 - // debug(D_DICTIONARY, "Dictionary UNLOCK lock");
48 - pthread_rwlock_unlock(dict->rwlock);
49 - }
46 + if(likely(dict->rwlock)) {
47 + // debug(D_DICTIONARY, "Dictionary UNLOCK lock");
48 + pthread_rwlock_unlock(dict->rwlock);
49 + }
50 }
51
52
@@ -54,196 +54,196 @@ static inline void dictionary_unlock(DICTIONARY *dict) {
54 // avl index
55
56 static int name_value_compare(void* a, void* b) {
57 - if(((NAME_VALUE *)a)->hash < ((NAME_VALUE *)b)->hash) return -1;
58 - else if(((NAME_VALUE *)a)->hash > ((NAME_VALUE *)b)->hash) return 1;
59 - else return strcmp(((NAME_VALUE *)a)->name, ((NAME_VALUE *)b)->name);
57 + if(((NAME_VALUE *)a)->hash < ((NAME_VALUE *)b)->hash) return -1;
58 + else if(((NAME_VALUE *)a)->hash > ((NAME_VALUE *)b)->hash) return 1;
59 + else return strcmp(((NAME_VALUE *)a)->name, ((NAME_VALUE *)b)->name);
60 }
61
62 #define dictionary_name_value_index_add_nolock(dict, nv) do { NETDATA_DICTIONARY_STATS_INSERTS_PLUS1(dict); avl_insert(&((dict)->values_index), (avl *)(nv)); } while(0)
63 #define dictionary_name_value_index_del_nolock(dict, nv) do { NETDATA_DICTIONARY_STATS_DELETES_PLUS1(dict); avl_remove(&(dict->values_index), (avl *)(nv)); } while(0)
64
65 static inline NAME_VALUE *dictionary_name_value_index_find_nolock(DICTIONARY *dict, const char *name, uint32_t hash) {
66 - NAME_VALUE tmp;
67 - tmp.hash = (hash)?hash:simple_hash(name);
68 - tmp.name = (char *)name;
66 + NAME_VALUE tmp;
67 + tmp.hash = (hash)?hash:simple_hash(name);
68 + tmp.name = (char *)name;
69
70 - NETDATA_DICTIONARY_STATS_SEARCHES_PLUS1(dict);
71 - return (NAME_VALUE *)avl_search(&(dict->values_index), (avl *) &tmp);
70 + NETDATA_DICTIONARY_STATS_SEARCHES_PLUS1(dict);
71 + return (NAME_VALUE *)avl_search(&(dict->values_index), (avl *) &tmp);
72 }
73
74 // ----------------------------------------------------------------------------
75 // internal methods
76
77 static NAME_VALUE *dictionary_name_value_create_nolock(DICTIONARY *dict, const char *name, void *value, size_t value_len, uint32_t hash) {
78 - debug(D_DICTIONARY, "Creating name value entry for name '%s'.", name);
78 + debug(D_DICTIONARY, "Creating name value entry for name '%s'.", name);
79
80 - NAME_VALUE *nv = callocz(1, sizeof(NAME_VALUE));
80 + NAME_VALUE *nv = callocz(1, sizeof(NAME_VALUE));
81
82 - if(dict->flags & DICTIONARY_FLAG_NAME_LINK_DONT_CLONE)
83 - nv->name = (char *)name;
84 - else {
85 - nv->name = strdupz(name);
86 - }
82 + if(dict->flags & DICTIONARY_FLAG_NAME_LINK_DONT_CLONE)
83 + nv->name = (char *)name;
84 + else {
85 + nv->name = strdupz(name);
86 + }
87
88 - nv->hash = (hash)?hash:simple_hash(nv->name);
88 + nv->hash = (hash)?hash:simple_hash(nv->name);
89
90 - if(dict->flags & DICTIONARY_FLAG_VALUE_LINK_DONT_CLONE)
91 - nv->value = value;
92 - else {
93 - nv->value = mallocz(value_len);
94 - memcpy(nv->value, value, value_len);
95 - }
90 + if(dict->flags & DICTIONARY_FLAG_VALUE_LINK_DONT_CLONE)
91 + nv->value = value;
92 + else {
93 + nv->value = mallocz(value_len);
94 + memcpy(nv->value, value, value_len);
95 + }
96
97 - // index it
98 - dictionary_name_value_index_add_nolock(dict, nv);
99 - NETDATA_DICTIONARY_STATS_ENTRIES_PLUS1(dict);
97 + // index it
98 + dictionary_name_value_index_add_nolock(dict, nv);
99 + NETDATA_DICTIONARY_STATS_ENTRIES_PLUS1(dict);
100
101 - return nv;
101 + return nv;
102 }
103
104 static void dictionary_name_value_destroy_nolock(DICTIONARY *dict, NAME_VALUE *nv) {
105 - debug(D_DICTIONARY, "Destroying name value entry for name '%s'.", nv->name);
105 + debug(D_DICTIONARY, "Destroying name value entry for name '%s'.", nv->name);
106
107 - dictionary_name_value_index_del_nolock(dict, nv);
107 + dictionary_name_value_index_del_nolock(dict, nv);
108
109 - NETDATA_DICTIONARY_STATS_ENTRIES_MINUS1(dict);
109 + NETDATA_DICTIONARY_STATS_ENTRIES_MINUS1(dict);
110
111 - if(!(dict->flags & DICTIONARY_FLAG_VALUE_LINK_DONT_CLONE)) {
112 - debug(D_REGISTRY, "Dictionary freeing value of '%s'", nv->name);
113 - freez(nv->value);
114 - }
111 + if(!(dict->flags & DICTIONARY_FLAG_VALUE_LINK_DONT_CLONE)) {
112 + debug(D_REGISTRY, "Dictionary freeing value of '%s'", nv->name);
113 + freez(nv->value);
114 + }
115
116 - if(!(dict->flags & DICTIONARY_FLAG_NAME_LINK_DONT_CLONE)) {
117 - debug(D_REGISTRY, "Dictionary freeing name '%s'", nv->name);
118 - freez(nv->name);
119 - }
116 + if(!(dict->flags & DICTIONARY_FLAG_NAME_LINK_DONT_CLONE)) {
117 + debug(D_REGISTRY, "Dictionary freeing name '%s'", nv->name);
118 + freez(nv->name);
119 + }
120
121 - freez(nv);
121 + freez(nv);
122 }
123
124 // ----------------------------------------------------------------------------
125 // API - basic methods
126
127 DICTIONARY *dictionary_create(uint8_t flags) {
128 - debug(D_DICTIONARY, "Creating dictionary.");
128 + debug(D_DICTIONARY, "Creating dictionary.");
129
130 - DICTIONARY *dict = callocz(1, sizeof(DICTIONARY));
130 + DICTIONARY *dict = callocz(1, sizeof(DICTIONARY));
131
132 - if(flags & DICTIONARY_FLAG_WITH_STATISTICS)
133 - dict->stats = callocz(1, sizeof(struct dictionary_stats));
132 + if(flags & DICTIONARY_FLAG_WITH_STATISTICS)
133 + dict->stats = callocz(1, sizeof(struct dictionary_stats));
134
135 - if(!(flags & DICTIONARY_FLAG_SINGLE_THREADED)) {
136 - dict->rwlock = callocz(1, sizeof(pthread_rwlock_t));
137 - pthread_rwlock_init(dict->rwlock, NULL);
138 - }
135 + if(!(flags & DICTIONARY_FLAG_SINGLE_THREADED)) {
136 + dict->rwlock = callocz(1, sizeof(pthread_rwlock_t));
137 + pthread_rwlock_init(dict->rwlock, NULL);
138 + }
139
140 - avl_init(&dict->values_index, name_value_compare);
141 - dict->flags = flags;
140 + avl_init(&dict->values_index, name_value_compare);
141 + dict->flags = flags;
142
143 - return dict;
143 + return dict;
144 }
145
146 void dictionary_destroy(DICTIONARY *dict) {
147 - debug(D_DICTIONARY, "Destroying dictionary.");
147 + debug(D_DICTIONARY, "Destroying dictionary.");
148
149 - dictionary_write_lock(dict);
149 + dictionary_write_lock(dict);
150
151 - while(dict->values_index.root)
152 - dictionary_name_value_destroy_nolock(dict, (NAME_VALUE *)dict->values_index.root);
151 + while(dict->values_index.root)
152 + dictionary_name_value_destroy_nolock(dict, (NAME_VALUE *)dict->values_index.root);
153
154 - dictionary_unlock(dict);
154 + dictionary_unlock(dict);
155
156 - if(dict->stats)
157 - freez(dict->stats);
156 + if(dict->stats)
157 + freez(dict->stats);
158
159 - if(dict->rwlock)
160 - freez(dict->rwlock);
159 + if(dict->rwlock)
160 + freez(dict->rwlock);
161
162 - freez(dict);
162 + freez(dict);
163 }
164
165 // ----------------------------------------------------------------------------
166
167 void *dictionary_set(DICTIONARY *dict, const char *name, void *value, size_t value_len) {
168 - debug(D_DICTIONARY, "SET dictionary entry with name '%s'.", name);
168 + debug(D_DICTIONARY, "SET dictionary entry with name '%s'.", name);
169
170 - uint32_t hash = simple_hash(name);
170 + uint32_t hash = simple_hash(name);
171
172 - dictionary_write_lock(dict);
172 + dictionary_write_lock(dict);
173
174 - NAME_VALUE *nv = dictionary_name_value_index_find_nolock(dict, name, hash);
175 - if(unlikely(!nv)) {
176 - debug(D_DICTIONARY, "Dictionary entry with name '%s' not found. Creating a new one.", name);
174 + NAME_VALUE *nv = dictionary_name_value_index_find_nolock(dict, name, hash);
175 + if(unlikely(!nv)) {
176 + debug(D_DICTIONARY, "Dictionary entry with name '%s' not found. Creating a new one.", name);
177
178 - nv = dictionary_name_value_create_nolock(dict, name, value, value_len, hash);
179 - if(unlikely(!nv))
180 - fatal("Cannot create name_value.");
181 - }
182 - else {
183 - debug(D_DICTIONARY, "Dictionary entry with name '%s' found. Changing its value.", name);
178 + nv = dictionary_name_value_create_nolock(dict, name, value, value_len, hash);
179 + if(unlikely(!nv))
180 + fatal("Cannot create name_value.");
181 + }
182 + else {
183 + debug(D_DICTIONARY, "Dictionary entry with name '%s' found. Changing its value.", name);
184
185 - if(dict->flags & DICTIONARY_FLAG_VALUE_LINK_DONT_CLONE) {
186 - debug(D_REGISTRY, "Dictionary: linking value to '%s'", name);
187 - nv->value = value;
188 - }
189 - else {
190 - debug(D_REGISTRY, "Dictionary: cloning value to '%s'", name);
185 + if(dict->flags & DICTIONARY_FLAG_VALUE_LINK_DONT_CLONE) {
186 + debug(D_REGISTRY, "Dictionary: linking value to '%s'", name);
187 + nv->value = value;
188 + }
189 + else {
190 + debug(D_REGISTRY, "Dictionary: cloning value to '%s'", name);
191
192 - // copy the new value without breaking
193 - // any other thread accessing the same entry
194 - void *new = mallocz(value_len),
195 - *old = nv->value;
192 + // copy the new value without breaking
193 + // any other thread accessing the same entry
194 + void *new = mallocz(value_len),
195 + *old = nv->value;
196
197 - memcpy(new, value, value_len);
198 - nv->value = new;
197 + memcpy(new, value, value_len);
198 + nv->value = new;
199
200 - debug(D_REGISTRY, "Dictionary: freeing old value of '%s'", name);
201 - freez(old);
202 - }
203 - }
200 + debug(D_REGISTRY, "Dictionary: freeing old value of '%s'", name);
201 + freez(old);
202 + }
203 + }
204
205 - dictionary_unlock(dict);
205 + dictionary_unlock(dict);
206
207 - return nv->value;
207 + return nv->value;
208 }
209
210 void *dictionary_get(DICTIONARY *dict, const char *name) {
211 - debug(D_DICTIONARY, "GET dictionary entry with name '%s'.", name);
211 + debug(D_DICTIONARY, "GET dictionary entry with name '%s'.", name);
212
213 - dictionary_read_lock(dict);
214 - NAME_VALUE *nv = dictionary_name_value_index_find_nolock(dict, name, 0);
215 - dictionary_unlock(dict);
213 + dictionary_read_lock(dict);
214 + NAME_VALUE *nv = dictionary_name_value_index_find_nolock(dict, name, 0);
215 + dictionary_unlock(dict);
216
217 - if(unlikely(!nv)) {
218 - debug(D_DICTIONARY, "Not found dictionary entry with name '%s'.", name);
219 - return NULL;
220 - }
217 + if(unlikely(!nv)) {
218 + debug(D_DICTIONARY, "Not found dictionary entry with name '%s'.", name);
219 + return NULL;
220 + }
221
222 - debug(D_DICTIONARY, "Found dictionary entry with name '%s'.", name);
223 - return nv->value;
222 + debug(D_DICTIONARY, "Found dictionary entry with name '%s'.", name);
223 + return nv->value;
224 }
225
226 int dictionary_del(DICTIONARY *dict, const char *name) {
227 - int ret;
227 + int ret;
228
229 - debug(D_DICTIONARY, "DEL dictionary entry with name '%s'.", name);
229 + debug(D_DICTIONARY, "DEL dictionary entry with name '%s'.", name);
230
231 - dictionary_write_lock(dict);
231 + dictionary_write_lock(dict);
232
233 - NAME_VALUE *nv = dictionary_name_value_index_find_nolock(dict, name, 0);
234 - if(unlikely(!nv)) {
235 - debug(D_DICTIONARY, "Not found dictionary entry with name '%s'.", name);
236 - ret = -1;
237 - }
238 - else {
239 - debug(D_DICTIONARY, "Found dictionary entry with name '%s'.", name);
240 - dictionary_name_value_destroy_nolock(dict, nv);
241 - ret = 0;
242 - }
233 + NAME_VALUE *nv = dictionary_name_value_index_find_nolock(dict, name, 0);
234 + if(unlikely(!nv)) {
235 + debug(D_DICTIONARY, "Not found dictionary entry with name '%s'.", name);
236 + ret = -1;
237 + }
238 + else {
239 + debug(D_DICTIONARY, "Found dictionary entry with name '%s'.", name);
240 + dictionary_name_value_destroy_nolock(dict, nv);
241 + ret = 0;
242 + }
243
244 - dictionary_unlock(dict);
244 + dictionary_unlock(dict);
245
246 - return ret;
246 + return ret;
247 }
248
249
@@ -253,36 +253,36 @@ int dictionary_del(DICTIONARY *dict, const char *name) {
253 // do not user other dictionary calls while walking the dictionary - deadlock!
254
255 static int dictionary_walker(avl *a, int (*callback)(void *entry, void *data), void *data) {
256 - int total = 0, ret = 0;
256 + int total = 0, ret = 0;
257
258 - if(a->avl_link[0]) {
259 - ret = dictionary_walker(a->avl_link[0], callback, data);
260 - if(ret < 0) return ret;
261 - total += ret;
262 - }
258 + if(a->avl_link[0]) {
259 + ret = dictionary_walker(a->avl_link[0], callback, data);
260 + if(ret < 0) return ret;
261 + total += ret;
262 + }
263
264 - ret = callback(((NAME_VALUE *)a)->value, data);
265 - if(ret < 0) return ret;
266 - total += ret;
264 + ret = callback(((NAME_VALUE *)a)->value, data);
265 + if(ret < 0) return ret;
266 + total += ret;
267
268 - if(a->avl_link[1]) {
269 - ret = dictionary_walker(a->avl_link[1], callback, data);
270 - if (ret < 0) return ret;
271 - total += ret;
272 - }
268 + if(a->avl_link[1]) {
269 + ret = dictionary_walker(a->avl_link[1], callback, data);
270 + if (ret < 0) return ret;
271 + total += ret;
272 + }
273
274 - return total;
274 + return total;
275 }
276
277 int dictionary_get_all(DICTIONARY *dict, int (*callback)(void *entry, void *data), void *data) {
278 - int ret = 0;
278 + int ret = 0;
279
280 - dictionary_read_lock(dict);
280 + dictionary_read_lock(dict);
281
282 - if(likely(dict->values_index.root))
283 - ret = dictionary_walker(dict->values_index.root, callback, data);
282 + if(likely(dict->values_index.root))
283 + ret = dictionary_walker(dict->values_index.root, callback, data);
284
285 - dictionary_unlock(dict);
285 + dictionary_unlock(dict);
286
287 - return ret;
287 + return ret;
288 }
src/dictionary.h
+18 -18
@@ -2,36 +2,36 @@
2 #define NETDATA_DICTIONARY_H 1
3
4 struct dictionary_stats {
5 - unsigned long long inserts;
6 - unsigned long long deletes;
7 - unsigned long long searches;
8 - unsigned long long entries;
5 + unsigned long long inserts;
6 + unsigned long long deletes;
7 + unsigned long long searches;
8 + unsigned long long entries;
9 };
10
11 typedef struct name_value {
12 - avl avl; // the index - this has to be first!
12 + avl avl; // the index - this has to be first!
13
14 - uint32_t hash; // a simple hash to speed up searching
15 - // we first compare hashes, and only if the hashes are equal we do string comparisons
14 + uint32_t hash; // a simple hash to speed up searching
15 + // we first compare hashes, and only if the hashes are equal we do string comparisons
16
17 - char *name;
18 - void *value;
17 + char *name;
18 + void *value;
19 } NAME_VALUE;
20
21 typedef struct dictionary {
22 - avl_tree values_index;
22 + avl_tree values_index;
23
24 - uint8_t flags;
24 + uint8_t flags;
25
26 - struct dictionary_stats *stats;
27 - pthread_rwlock_t *rwlock;
26 + struct dictionary_stats *stats;
27 + pthread_rwlock_t *rwlock;
28 } DICTIONARY;
29
30 -#define DICTIONARY_FLAG_DEFAULT 0x00000000
31 -#define DICTIONARY_FLAG_SINGLE_THREADED 0x00000001
32 -#define DICTIONARY_FLAG_VALUE_LINK_DONT_CLONE 0x00000002
33 -#define DICTIONARY_FLAG_NAME_LINK_DONT_CLONE 0x00000004
34 -#define DICTIONARY_FLAG_WITH_STATISTICS 0x00000008
30 +#define DICTIONARY_FLAG_DEFAULT 0x00000000
31 +#define DICTIONARY_FLAG_SINGLE_THREADED 0x00000001
32 +#define DICTIONARY_FLAG_VALUE_LINK_DONT_CLONE 0x00000002
33 +#define DICTIONARY_FLAG_NAME_LINK_DONT_CLONE 0x00000004
34 +#define DICTIONARY_FLAG_WITH_STATISTICS 0x00000008
35
36 extern DICTIONARY *dictionary_create(uint8_t flags);
37 extern void dictionary_destroy(DICTIONARY *dict);
src/global_statistics.h
+5 -5
@@ -7,13 +7,13 @@
7 struct global_statistics {
8 volatile uint16_t connected_clients;
9
10 - volatile uint64_t web_requests;
10 + volatile uint64_t web_requests;
11 volatile uint64_t web_usec;
12 volatile uint64_t web_usec_max;
13 - volatile uint64_t bytes_received;
14 - volatile uint64_t bytes_sent;
15 - volatile uint64_t content_size;
16 - volatile uint64_t compressed_content_size;
13 + volatile uint64_t bytes_received;
14 + volatile uint64_t bytes_sent;
15 + volatile uint64_t content_size;
16 + volatile uint64_t compressed_content_size;
17 };
18
19 extern volatile struct global_statistics global_statistics;
src/log.c
+170 -170
@@ -5,7 +5,7 @@ unsigned long long debug_flags = DEBUG;
5
6 int access_log_syslog = 1;
7 int error_log_syslog = 1;
8 -int output_log_syslog = 1; // debug log
8 +int output_log_syslog = 1; // debug log
9
10 int stdaccess_fd = -1;
11 FILE *stdaccess = NULL;
@@ -124,79 +124,79 @@ time_t error_log_throttle_period = 1200;
124 unsigned long error_log_errors_per_period = 200;
125
126 int error_log_limit(int reset) {
127 - static time_t start = 0;
128 - static unsigned long counter = 0, prevented = 0;
129 -
130 - // do not throttle if the period is 0
131 - if(error_log_throttle_period == 0)
132 - return 0;
133 -
134 - // prevent all logs if the errors per period is 0
135 - if(error_log_errors_per_period == 0)
136 - return 1;
137 -
138 - time_t now = time(NULL);
139 - if(!start) start = now;
140 -
141 - if(reset) {
142 - if(prevented) {
143 - log_date(stderr);
144 - fprintf(stderr, "%s: Resetting logging for process '%s' (prevented %lu logs in the last %ld seconds).\n"
145 - , program_name
146 - , program_name
147 - , prevented
148 - , now - start
149 - );
150 - }
151 -
152 - start = now;
153 - counter = 0;
154 - prevented = 0;
155 - }
156 -
157 - // detect if we log too much
158 - counter++;
159 -
160 - if(now - start > error_log_throttle_period) {
161 - if(prevented) {
162 - log_date(stderr);
163 - fprintf(stderr, "%s: Resuming logging from process '%s' (prevented %lu logs in the last %ld seconds).\n"
164 - , program_name
165 - , program_name
166 - , prevented
167 - , error_log_throttle_period
168 - );
169 - }
170 -
171 - // restart the period accounting
172 - start = now;
173 - counter = 1;
174 - prevented = 0;
175 -
176 - // log this error
177 - return 0;
178 - }
179 -
180 - if(counter > error_log_errors_per_period) {
181 - if(!prevented) {
182 - log_date(stderr);
183 - fprintf(stderr, "%s: Too many logs (%lu logs in %ld seconds, threshold is set to %lu logs in %ld seconds). Preventing more logs from process '%s' for %ld seconds.\n"
184 - , program_name
185 - , counter
186 - , now - start
187 - , error_log_errors_per_period
188 - , error_log_throttle_period
189 - , program_name
190 - , start + error_log_throttle_period - now);
191 - }
192 -
193 - prevented++;
194 -
195 - // prevent logging this error
196 - return 1;
197 - }
198 -
199 - return 0;
127 + static time_t start = 0;
128 + static unsigned long counter = 0, prevented = 0;
129 +
130 + // do not throttle if the period is 0
131 + if(error_log_throttle_period == 0)
132 + return 0;
133 +
134 + // prevent all logs if the errors per period is 0
135 + if(error_log_errors_per_period == 0)
136 + return 1;
137 +
138 + time_t now = time(NULL);
139 + if(!start) start = now;
140 +
141 + if(reset) {
142 + if(prevented) {
143 + log_date(stderr);
144 + fprintf(stderr, "%s: Resetting logging for process '%s' (prevented %lu logs in the last %ld seconds).\n"
145 + , program_name
146 + , program_name
147 + , prevented
148 + , now - start
149 + );
150 + }
151 +
152 + start = now;
153 + counter = 0;
154 + prevented = 0;
155 + }
156 +
157 + // detect if we log too much
158 + counter++;
159 +
160 + if(now - start > error_log_throttle_period) {
161 + if(prevented) {
162 + log_date(stderr);
163 + fprintf(stderr, "%s: Resuming logging from process '%s' (prevented %lu logs in the last %ld seconds).\n"
164 + , program_name
165 + , program_name
166 + , prevented
167 + , error_log_throttle_period
168 + );
169 + }
170 +
171 + // restart the period accounting
172 + start = now;
173 + counter = 1;
174 + prevented = 0;
175 +
176 + // log this error
177 + return 0;
178 + }
179 +
180 + if(counter > error_log_errors_per_period) {
181 + if(!prevented) {
182 + log_date(stderr);
183 + fprintf(stderr, "%s: Too many logs (%lu logs in %ld seconds, threshold is set to %lu logs in %ld seconds). Preventing more logs from process '%s' for %ld seconds.\n"
184 + , program_name
185 + , counter
186 + , now - start
187 + , error_log_errors_per_period
188 + , error_log_throttle_period
189 + , program_name
190 + , start + error_log_throttle_period - now);
191 + }
192 +
193 + prevented++;
194 +
195 + // prevent logging this error
196 + return 1;
197 + }
198 +
199 + return 0;
200 }
201
202 // ----------------------------------------------------------------------------
@@ -208,17 +208,17 @@ int error_log_limit(int reset) {
208
209 void log_date(FILE *out)
210 {
211 - char outstr[24];
212 - time_t t;
213 - struct tm *tmp, tmbuf;
211 + char outstr[24];
212 + time_t t;
213 + struct tm *tmp, tmbuf;
214
215 - t = time(NULL);
216 - tmp = localtime_r(&t, &tmbuf);
215 + t = time(NULL);
216 + tmp = localtime_r(&t, &tmbuf);
217
218 - if (tmp == NULL) return;
219 - if (unlikely(strftime(outstr, sizeof(outstr), "%y-%m-%d %H:%M:%S", tmp) == 0)) return;
218 + if (tmp == NULL) return;
219 + if (unlikely(strftime(outstr, sizeof(outstr), "%y-%m-%d %H:%M:%S", tmp) == 0)) return;
220
221 - fprintf(out, "%s: ", outstr);
221 + fprintf(out, "%s: ", outstr);
222 }
223
224 // ----------------------------------------------------------------------------
@@ -226,22 +226,22 @@ void log_date(FILE *out)
226
227 void debug_int( const char *file, const char *function, const unsigned long line, const char *fmt, ... )
228 {
229 - va_list args;
230 -
231 - log_date(stdout);
232 - va_start( args, fmt );
233 - printf("DEBUG (%04lu@%-10.10s:%-15.15s): %s: ", line, file, function, program_name);
234 - vprintf(fmt, args);
235 - va_end( args );
236 - putchar('\n');
237 -
238 - if(output_log_syslog) {
239 - va_start( args, fmt );
240 - vsyslog(LOG_ERR, fmt, args );
241 - va_end( args );
242 - }
243 -
244 - fflush(stdout);
229 + va_list args;
230 +
231 + log_date(stdout);
232 + va_start( args, fmt );
233 + printf("DEBUG (%04lu@%-10.10s:%-15.15s): %s: ", line, file, function, program_name);
234 + vprintf(fmt, args);
235 + va_end( args );
236 + putchar('\n');
237 +
238 + if(output_log_syslog) {
239 + va_start( args, fmt );
240 + vsyslog(LOG_ERR, fmt, args );
241 + va_end( args );
242 + }
243 +
244 + fflush(stdout);
245 }
246
247 // ----------------------------------------------------------------------------
@@ -249,26 +249,26 @@ void debug_int( const char *file, const char *function, const unsigned long line
249
250 void info_int( const char *file, const char *function, const unsigned long line, const char *fmt, ... )
251 {
252 - va_list args;
252 + va_list args;
253
254 - // prevent logging too much
255 - if(error_log_limit(0)) return;
254 + // prevent logging too much
255 + if(error_log_limit(0)) return;
256
257 - log_date(stderr);
257 + log_date(stderr);
258
259 - va_start( args, fmt );
260 - if(debug_flags) fprintf(stderr, "INFO (%04lu@%-10.10s:%-15.15s): %s: ", line, file, function, program_name);
261 - else fprintf(stderr, "INFO: %s: ", program_name);
262 - vfprintf( stderr, fmt, args );
263 - va_end( args );
259 + va_start( args, fmt );
260 + if(debug_flags) fprintf(stderr, "INFO (%04lu@%-10.10s:%-15.15s): %s: ", line, file, function, program_name);
261 + else fprintf(stderr, "INFO: %s: ", program_name);
262 + vfprintf( stderr, fmt, args );
263 + va_end( args );
264
265 - fputc('\n', stderr);
265 + fputc('\n', stderr);
266
267 - if(error_log_syslog) {
268 - va_start( args, fmt );
269 - vsyslog(LOG_INFO, fmt, args );
270 - va_end( args );
271 - }
267 + if(error_log_syslog) {
268 + va_start( args, fmt );
269 + vsyslog(LOG_INFO, fmt, args );
270 + va_end( args );
271 + }
272 }
273
274 // ----------------------------------------------------------------------------
@@ -276,56 +276,56 @@ void info_int( const char *file, const char *function, const unsigned long line,
276
277 void error_int( const char *prefix, const char *file, const char *function, const unsigned long line, const char *fmt, ... )
278 {
279 - va_list args;
280 -
281 - // prevent logging too much
282 - if(error_log_limit(0)) return;
283 -
284 - log_date(stderr);
285 -
286 - va_start( args, fmt );
287 - if(debug_flags) fprintf(stderr, "%s (%04lu@%-10.10s:%-15.15s): %s: ", prefix, line, file, function, program_name);
288 - else fprintf(stderr, "%s: %s: ", prefix, program_name);
289 - vfprintf( stderr, fmt, args );
290 - va_end( args );
291 -
292 - if(errno) {
293 - char buf[1024];
294 - fprintf(stderr, " (errno %d, %s)\n", errno, strerror_r(errno, buf, 1023));
295 - errno = 0;
296 - }
297 - else
298 - fputc('\n', stderr);
299 -
300 - if(error_log_syslog) {
301 - va_start( args, fmt );
302 - vsyslog(LOG_ERR, fmt, args );
303 - va_end( args );
304 - }
279 + va_list args;
280 +
281 + // prevent logging too much
282 + if(error_log_limit(0)) return;
283 +
284 + log_date(stderr);
285 +
286 + va_start( args, fmt );
287 + if(debug_flags) fprintf(stderr, "%s (%04lu@%-10.10s:%-15.15s): %s: ", prefix, line, file, function, program_name);
288 + else fprintf(stderr, "%s: %s: ", prefix, program_name);
289 + vfprintf( stderr, fmt, args );
290 + va_end( args );
291 +
292 + if(errno) {
293 + char buf[1024];
294 + fprintf(stderr, " (errno %d, %s)\n", errno, strerror_r(errno, buf, 1023));
295 + errno = 0;
296 + }
297 + else
298 + fputc('\n', stderr);
299 +
300 + if(error_log_syslog) {
301 + va_start( args, fmt );
302 + vsyslog(LOG_ERR, fmt, args );
303 + va_end( args );
304 + }
305 }
306
307 void fatal_int( const char *file, const char *function, const unsigned long line, const char *fmt, ... )
308 {
309 - va_list args;
309 + va_list args;
310
311 - log_date(stderr);
311 + log_date(stderr);
312
313 - va_start( args, fmt );
314 - if(debug_flags) fprintf(stderr, "FATAL (%04lu@%-10.10s:%-15.15s): %s: ", line, file, function, program_name);
315 - else fprintf(stderr, "FATAL: %s: ", program_name);
316 - vfprintf( stderr, fmt, args );
317 - va_end( args );
313 + va_start( args, fmt );
314 + if(debug_flags) fprintf(stderr, "FATAL (%04lu@%-10.10s:%-15.15s): %s: ", line, file, function, program_name);
315 + else fprintf(stderr, "FATAL: %s: ", program_name);
316 + vfprintf( stderr, fmt, args );
317 + va_end( args );
318
319 - perror(" # ");
320 - fputc('\n', stderr);
319 + perror(" # ");
320 + fputc('\n', stderr);
321
322 - if(error_log_syslog) {
323 - va_start( args, fmt );
324 - vsyslog(LOG_CRIT, fmt, args );
325 - va_end( args );
326 - }
322 + if(error_log_syslog) {
323 + va_start( args, fmt );
324 + vsyslog(LOG_CRIT, fmt, args );
325 + va_end( args );
326 + }
327
328 - netdata_cleanup_and_exit(1);
328 + netdata_cleanup_and_exit(1);
329 }
330
331 // ----------------------------------------------------------------------------
@@ -333,21 +333,21 @@ void fatal_int( const char *file, const char *function, const unsigned long line
333
334 void log_access( const char *fmt, ... )
335 {
336 - va_list args;
337 -
338 - if(stdaccess) {
339 - log_date(stdaccess);
340 -
341 - va_start( args, fmt );
342 - vfprintf( stdaccess, fmt, args );
343 - va_end( args );
344 - fputc('\n', stdaccess);
345 - }
346 -
347 - if(access_log_syslog) {
348 - va_start( args, fmt );
349 - vsyslog(LOG_INFO, fmt, args );
350 - va_end( args );
351 - }
336 + va_list args;
337 +
338 + if(stdaccess) {
339 + log_date(stdaccess);
340 +
341 + va_start( args, fmt );
342 + vfprintf( stdaccess, fmt, args );
343 + va_end( args );
344 + fputc('\n', stdaccess);
345 + }
346 +
347 + if(access_log_syslog) {
348 + va_start( args, fmt );
349 + vsyslog(LOG_INFO, fmt, args );
350 + va_end( args );
351 + }
352 }
353
src/log.h
+13 -13
@@ -1,14 +1,14 @@
1 #ifndef NETDATA_LOG_H
2 #define NETDATA_LOG_H 1
3
4 -#define D_WEB_BUFFER 0x00000001
5 -#define D_WEB_CLIENT 0x00000002
6 -#define D_LISTENER 0x00000004
7 -#define D_WEB_DATA 0x00000008
8 -#define D_OPTIONS 0x00000010
4 +#define D_WEB_BUFFER 0x00000001
5 +#define D_WEB_CLIENT 0x00000002
6 +#define D_LISTENER 0x00000004
7 +#define D_WEB_DATA 0x00000008
8 +#define D_OPTIONS 0x00000010
9 #define D_PROCNETDEV_LOOP 0x00000020
10 -#define D_RRD_STATS 0x00000040
11 -#define D_WEB_CLIENT_ACCESS 0x00000080
10 +#define D_RRD_STATS 0x00000040
11 +#define D_WEB_CLIENT_ACCESS 0x00000080
12 #define D_TC_LOOP 0x00000100
13 #define D_DEFLATE 0x00000200
14 #define D_CONFIG 0x00000400
@@ -16,13 +16,13 @@
16 #define D_CHILDS 0x00001000
17 #define D_EXIT 0x00002000
18 #define D_CHECKS 0x00004000
19 -#define D_NFACCT_LOOP 0x00008000
20 -#define D_PROCFILE 0x00010000
21 -#define D_RRD_CALLS 0x00020000
22 -#define D_DICTIONARY 0x00040000
23 -#define D_MEMORY 0x00080000
19 +#define D_NFACCT_LOOP 0x00008000
20 +#define D_PROCFILE 0x00010000
21 +#define D_RRD_CALLS 0x00020000
22 +#define D_DICTIONARY 0x00040000
23 +#define D_MEMORY 0x00080000
24 #define D_CGROUP 0x00100000
25 -#define D_REGISTRY 0x00200000
25 +#define D_REGISTRY 0x00200000
26 #define D_VARIABLES 0x00400000
27
28 //#define DEBUG (D_WEB_CLIENT_ACCESS|D_LISTENER|D_RRD_STATS)
src/main.h
+9 -9
@@ -7,15 +7,15 @@ extern volatile sig_atomic_t netdata_exit;
7 * This struct contains information about command line options.
8 */
9 struct option_def {
10 - /** The option character */
11 - const char val;
12 - /** The name of the long option. */
13 - const char *description;
14 - /** Short descripton what the option does */
15 - /** Name of the argument displayed in SYNOPSIS */
16 - const char *arg_name;
17 - /** Default value if not set */
18 - const char *default_value;
10 + /** The option character */
11 + const char val;
12 + /** The name of the long option. */
13 + const char *description;
14 + /** Short descripton what the option does */
15 + /** Name of the argument displayed in SYNOPSIS */
16 + const char *arg_name;
17 + /** Default value if not set */
18 + const char *default_value;
19 };
20
21 /**
src/plugin_checks.c
+58 -58
@@ -2,83 +2,83 @@
2
3 void *checks_main(void *ptr)
4 {
5 - if(ptr) { ; }
5 + if(ptr) { ; }
6
7 - info("CHECKS thread created with task id %d", gettid());
7 + info("CHECKS thread created with task id %d", gettid());
8
9 - if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
10 - error("Cannot set pthread cancel type to DEFERRED.");
9 + if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
10 + error("Cannot set pthread cancel type to DEFERRED.");
11
12 - if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
13 - error("Cannot set pthread cancel state to ENABLE.");
12 + if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
13 + error("Cannot set pthread cancel state to ENABLE.");
14
15 - unsigned long long usec = 0, susec = rrd_update_every * 1000000ULL, loop_usec = 0, total_susec = 0;
16 - struct timeval now, last, loop;
15 + unsigned long long usec = 0, susec = rrd_update_every * 1000000ULL, loop_usec = 0, total_susec = 0;
16 + struct timeval now, last, loop;
17
18 - RRDSET *check1, *check2, *check3, *apps_cpu = NULL;
18 + RRDSET *check1, *check2, *check3, *apps_cpu = NULL;
19
20 - check1 = rrdset_create("netdata", "check1", NULL, "netdata", NULL, "Caller gives microseconds", "a million !", 99999, rrd_update_every, RRDSET_TYPE_LINE);
21 - rrddim_add(check1, "absolute", NULL, -1, 1, RRDDIM_ABSOLUTE);
22 - rrddim_add(check1, "incremental", NULL, 1, 1, RRDDIM_INCREMENTAL);
20 + check1 = rrdset_create("netdata", "check1", NULL, "netdata", NULL, "Caller gives microseconds", "a million !", 99999, rrd_update_every, RRDSET_TYPE_LINE);
21 + rrddim_add(check1, "absolute", NULL, -1, 1, RRDDIM_ABSOLUTE);
22 + rrddim_add(check1, "incremental", NULL, 1, 1, RRDDIM_INCREMENTAL);
23
24 - check2 = rrdset_create("netdata", "check2", NULL, "netdata", NULL, "Netdata calcs microseconds", "a million !", 99999, rrd_update_every, RRDSET_TYPE_LINE);
25 - rrddim_add(check2, "absolute", NULL, -1, 1, RRDDIM_ABSOLUTE);
26 - rrddim_add(check2, "incremental", NULL, 1, 1, RRDDIM_INCREMENTAL);
24 + check2 = rrdset_create("netdata", "check2", NULL, "netdata", NULL, "Netdata calcs microseconds", "a million !", 99999, rrd_update_every, RRDSET_TYPE_LINE);
25 + rrddim_add(check2, "absolute", NULL, -1, 1, RRDDIM_ABSOLUTE);
26 + rrddim_add(check2, "incremental", NULL, 1, 1, RRDDIM_INCREMENTAL);
27
28 - check3 = rrdset_create("netdata", "checkdt", NULL, "netdata", NULL, "Clock difference", "microseconds diff", 99999, rrd_update_every, RRDSET_TYPE_LINE);
29 - rrddim_add(check3, "caller", NULL, 1, 1, RRDDIM_ABSOLUTE);
30 - rrddim_add(check3, "netdata", NULL, 1, 1, RRDDIM_ABSOLUTE);
31 - rrddim_add(check3, "apps.plugin", NULL, 1, 1, RRDDIM_ABSOLUTE);
28 + check3 = rrdset_create("netdata", "checkdt", NULL, "netdata", NULL, "Clock difference", "microseconds diff", 99999, rrd_update_every, RRDSET_TYPE_LINE);
29 + rrddim_add(check3, "caller", NULL, 1, 1, RRDDIM_ABSOLUTE);
30 + rrddim_add(check3, "netdata", NULL, 1, 1, RRDDIM_ABSOLUTE);
31 + rrddim_add(check3, "apps.plugin", NULL, 1, 1, RRDDIM_ABSOLUTE);
32
33 - gettimeofday(&last, NULL);
34 - while(1) {
35 - usleep(susec);
33 + gettimeofday(&last, NULL);
34 + while(1) {
35 + usleep(susec);
36
37 - // find the time to sleep in order to wait exactly update_every seconds
38 - gettimeofday(&now, NULL);
39 - loop_usec = usec_dt(&now, &last);
40 - usec = loop_usec - susec;
41 - debug(D_PROCNETDEV_LOOP, "CHECK: last loop took %llu usec (worked for %llu, sleeped for %llu).", loop_usec, usec, susec);
37 + // find the time to sleep in order to wait exactly update_every seconds
38 + gettimeofday(&now, NULL);
39 + loop_usec = usec_dt(&now, &last);
40 + usec = loop_usec - susec;
41 + debug(D_PROCNETDEV_LOOP, "CHECK: last loop took %llu usec (worked for %llu, sleeped for %llu).", loop_usec, usec, susec);
42
43 - if(usec < (rrd_update_every * 1000000ULL / 2ULL)) susec = (rrd_update_every * 1000000ULL) - usec;
44 - else susec = rrd_update_every * 1000000ULL / 2ULL;
43 + if(usec < (rrd_update_every * 1000000ULL / 2ULL)) susec = (rrd_update_every * 1000000ULL) - usec;
44 + else susec = rrd_update_every * 1000000ULL / 2ULL;
45
46 - // --------------------------------------------------------------------
47 - // Calculate loop time
46 + // --------------------------------------------------------------------
47 + // Calculate loop time
48
49 - last.tv_sec = now.tv_sec;
50 - last.tv_usec = now.tv_usec;
51 - total_susec += loop_usec;
49 + last.tv_sec = now.tv_sec;
50 + last.tv_usec = now.tv_usec;
51 + total_susec += loop_usec;
52
53 - // --------------------------------------------------------------------
54 - // check chart 1
53 + // --------------------------------------------------------------------
54 + // check chart 1
55
56 - if(check1->counter_done) rrdset_next_usec(check1, loop_usec);
57 - rrddim_set(check1, "absolute", 1000000);
58 - rrddim_set(check1, "incremental", total_susec);
59 - rrdset_done(check1);
56 + if(check1->counter_done) rrdset_next_usec(check1, loop_usec);
57 + rrddim_set(check1, "absolute", 1000000);
58 + rrddim_set(check1, "incremental", total_susec);
59 + rrdset_done(check1);
60
61 - // --------------------------------------------------------------------
62 - // check chart 2
61 + // --------------------------------------------------------------------
62 + // check chart 2
63
64 - if(check2->counter_done) rrdset_next(check2);
65 - rrddim_set(check2, "absolute", 1000000);
66 - rrddim_set(check2, "incremental", total_susec);
67 - rrdset_done(check2);
64 + if(check2->counter_done) rrdset_next(check2);
65 + rrddim_set(check2, "absolute", 1000000);
66 + rrddim_set(check2, "incremental", total_susec);
67 + rrdset_done(check2);
68
69 - // --------------------------------------------------------------------
70 - // check chart 3
69 + // --------------------------------------------------------------------
70 + // check chart 3
71
72 - if(!apps_cpu) apps_cpu = rrdset_find("apps.cpu");
73 - if(check3->counter_done) rrdset_next_usec(check3, loop_usec);
74 - gettimeofday(&loop, NULL);
75 - rrddim_set(check3, "caller", (long long) usec_dt(&loop, &check1->last_collected_time));
76 - rrddim_set(check3, "netdata", (long long) usec_dt(&loop, &check2->last_collected_time));
77 - if(apps_cpu) rrddim_set(check3, "apps.plugin", (long long) usec_dt(&loop, &apps_cpu->last_collected_time));
78 - rrdset_done(check3);
79 - }
72 + if(!apps_cpu) apps_cpu = rrdset_find("apps.cpu");
73 + if(check3->counter_done) rrdset_next_usec(check3, loop_usec);
74 + gettimeofday(&loop, NULL);
75 + rrddim_set(check3, "caller", (long long) usec_dt(&loop, &check1->last_collected_time));
76 + rrddim_set(check3, "netdata", (long long) usec_dt(&loop, &check2->last_collected_time));
77 + if(apps_cpu) rrddim_set(check3, "apps.plugin", (long long) usec_dt(&loop, &apps_cpu->last_collected_time));
78 + rrdset_done(check3);
79 + }
80
81 - pthread_exit(NULL);
82 - return NULL;
81 + pthread_exit(NULL);
82 + return NULL;
83 }
84
src/plugin_idlejitter.c
+35 -35
@@ -4,51 +4,51 @@
4
5 void *cpuidlejitter_main(void *ptr)
6 {
7 - if(ptr) { ; }
7 + if(ptr) { ; }
8
9 - info("CPU Idle Jitter thread created with task id %d", gettid());
9 + info("CPU Idle Jitter thread created with task id %d", gettid());
10
11 - if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
12 - error("Cannot set pthread cancel type to DEFERRED.");
11 + if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
12 + error("Cannot set pthread cancel type to DEFERRED.");
13
14 - if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
15 - error("Cannot set pthread cancel state to ENABLE.");
14 + if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
15 + error("Cannot set pthread cancel state to ENABLE.");
16
17 - int sleep_ms = (int) config_get_number("plugin:idlejitter", "loop time in ms", CPU_IDLEJITTER_SLEEP_TIME_MS);
18 - if(sleep_ms <= 0) {
19 - config_set_number("plugin:idlejitter", "loop time in ms", CPU_IDLEJITTER_SLEEP_TIME_MS);
20 - sleep_ms = CPU_IDLEJITTER_SLEEP_TIME_MS;
21 - }
17 + int sleep_ms = (int) config_get_number("plugin:idlejitter", "loop time in ms", CPU_IDLEJITTER_SLEEP_TIME_MS);
18 + if(sleep_ms <= 0) {
19 + config_set_number("plugin:idlejitter", "loop time in ms", CPU_IDLEJITTER_SLEEP_TIME_MS);
20 + sleep_ms = CPU_IDLEJITTER_SLEEP_TIME_MS;
21 + }
22
23 - RRDSET *st = rrdset_find("system.idlejitter");
24 - if(!st) {
25 - st = rrdset_create("system", "idlejitter", NULL, "processes", NULL, "CPU Idle Jitter", "microseconds lost/s", 9999, rrd_update_every, RRDSET_TYPE_LINE);
26 - rrddim_add(st, "jitter", NULL, 1, 1, RRDDIM_ABSOLUTE);
27 - }
23 + RRDSET *st = rrdset_find("system.idlejitter");
24 + if(!st) {
25 + st = rrdset_create("system", "idlejitter", NULL, "processes", NULL, "CPU Idle Jitter", "microseconds lost/s", 9999, rrd_update_every, RRDSET_TYPE_LINE);
26 + rrddim_add(st, "jitter", NULL, 1, 1, RRDDIM_ABSOLUTE);
27 + }
28
29 - struct timeval before, after;
30 - unsigned long long counter;
31 - for(counter = 0; 1 ;counter++) {
32 - unsigned long long usec = 0, susec = 0;
29 + struct timeval before, after;
30 + unsigned long long counter;
31 + for(counter = 0; 1 ;counter++) {
32 + unsigned long long usec = 0, susec = 0;
33
34 - while(susec < (rrd_update_every * 1000000ULL)) {
34 + while(susec < (rrd_update_every * 1000000ULL)) {
35
36 - gettimeofday(&before, NULL);
37 - usleep(sleep_ms * 1000);
38 - gettimeofday(&after, NULL);
36 + gettimeofday(&before, NULL);
37 + usleep(sleep_ms * 1000);
38 + gettimeofday(&after, NULL);
39
40 - // calculate the time it took for a full loop
41 - usec = usec_dt(&after, &before);
42 - susec += usec;
43 - }
44 - usec -= (sleep_ms * 1000);
40 + // calculate the time it took for a full loop
41 + usec = usec_dt(&after, &before);
42 + susec += usec;
43 + }
44 + usec -= (sleep_ms * 1000);
45
46 - if(counter) rrdset_next(st);
47 - rrddim_set(st, "jitter", usec);
48 - rrdset_done(st);
49 - }
46 + if(counter) rrdset_next(st);
47 + rrddim_set(st, "jitter", usec);
48 + rrdset_done(st);
49 + }
50
51 - pthread_exit(NULL);
52 - return NULL;
51 + pthread_exit(NULL);
52 + return NULL;
53 }
54
src/plugin_nfacct.c
+145 -145
@@ -5,198 +5,198 @@
5 #include "common.h"
6
7 struct mynfacct {
8 - const char *name;
9 - uint64_t pkts;
10 - uint64_t bytes;
11 - struct nfacct *nfacct;
8 + const char *name;
9 + uint64_t pkts;
10 + uint64_t bytes;
11 + struct nfacct *nfacct;
12 };
13
14 struct nfacct_list {
15 - int size;
16 - int len;
17 - struct mynfacct data[];
15 + int size;
16 + int len;
17 + struct mynfacct data[];
18 } *nfacct_list = NULL;
19
20 static int nfacct_callback(const struct nlmsghdr *nlh, void *data) {
21 - if(data) {};
22 -
23 - if(!nfacct_list || nfacct_list->len == nfacct_list->size) {
24 - int size = (nfacct_list) ? nfacct_list->size : 0;
25 - int len = (nfacct_list) ? nfacct_list->len : 0;
26 - size++;
27 -
28 - info("nfacct.plugin: increasing nfacct_list to size %d", size);
29 -
30 - nfacct_list = realloc(nfacct_list, sizeof(struct nfacct_list) + (sizeof(struct mynfacct) * size));
31 - if(!nfacct_list) {
32 - error("nfacct.plugin: cannot allocate nfacct_list.");
33 - return MNL_CB_OK;
34 - }
35 -
36 - nfacct_list->data[len].nfacct = nfacct_alloc();
37 - if(!nfacct_list->data[size - 1].nfacct) {
38 - error("nfacct.plugin: nfacct_alloc() failed.");
39 - free(nfacct_list);
40 - nfacct_list = NULL;
41 - return MNL_CB_OK;
42 - }
43 -
44 - nfacct_list->size = size;
45 - nfacct_list->len = len;
46 - }
47 -
48 - if(nfacct_nlmsg_parse_payload(nlh, nfacct_list->data[nfacct_list->len].nfacct) < 0) {
49 - error("nfacct.plugin: nfacct_nlmsg_parse_payload() failed.");
50 - return MNL_CB_OK;
51 - }
52 -
53 - nfacct_list->data[nfacct_list->len].name = nfacct_attr_get_str(nfacct_list->data[nfacct_list->len].nfacct, NFACCT_ATTR_NAME);
54 - nfacct_list->data[nfacct_list->len].pkts = nfacct_attr_get_u64(nfacct_list->data[nfacct_list->len].nfacct, NFACCT_ATTR_PKTS);
55 - nfacct_list->data[nfacct_list->len].bytes = nfacct_attr_get_u64(nfacct_list->data[nfacct_list->len].nfacct, NFACCT_ATTR_BYTES);
56 -
57 - nfacct_list->len++;
58 - return MNL_CB_OK;
21 + if(data) {};
22 +
23 + if(!nfacct_list || nfacct_list->len == nfacct_list->size) {
24 + int size = (nfacct_list) ? nfacct_list->size : 0;
25 + int len = (nfacct_list) ? nfacct_list->len : 0;
26 + size++;
27 +
28 + info("nfacct.plugin: increasing nfacct_list to size %d", size);
29 +
30 + nfacct_list = realloc(nfacct_list, sizeof(struct nfacct_list) + (sizeof(struct mynfacct) * size));
31 + if(!nfacct_list) {
32 + error("nfacct.plugin: cannot allocate nfacct_list.");
33 + return MNL_CB_OK;
34 + }
35 +
36 + nfacct_list->data[len].nfacct = nfacct_alloc();
37 + if(!nfacct_list->data[size - 1].nfacct) {
38 + error("nfacct.plugin: nfacct_alloc() failed.");
39 + free(nfacct_list);
40 + nfacct_list = NULL;
41 + return MNL_CB_OK;
42 + }
43 +
44 + nfacct_list->size = size;
45 + nfacct_list->len = len;
46 + }
47 +
48 + if(nfacct_nlmsg_parse_payload(nlh, nfacct_list->data[nfacct_list->len].nfacct) < 0) {
49 + error("nfacct.plugin: nfacct_nlmsg_parse_payload() failed.");
50 + return MNL_CB_OK;
51 + }
52 +
53 + nfacct_list->data[nfacct_list->len].name = nfacct_attr_get_str(nfacct_list->data[nfacct_list->len].nfacct, NFACCT_ATTR_NAME);
54 + nfacct_list->data[nfacct_list->len].pkts = nfacct_attr_get_u64(nfacct_list->data[nfacct_list->len].nfacct, NFACCT_ATTR_PKTS);
55 + nfacct_list->data[nfacct_list->len].bytes = nfacct_attr_get_u64(nfacct_list->data[nfacct_list->len].nfacct, NFACCT_ATTR_BYTES);
56 +
57 + nfacct_list->len++;
58 + return MNL_CB_OK;
59 }
60
61 void *nfacct_main(void *ptr) {
62 - if(ptr) { ; }
62 + if(ptr) { ; }
63
64 - info("NFACCT thread created with task id %d", gettid());
64 + info("NFACCT thread created with task id %d", gettid());
65
66 - if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
67 - error("nfacct.plugin: Cannot set pthread cancel type to DEFERRED.");
66 + if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
67 + error("nfacct.plugin: Cannot set pthread cancel type to DEFERRED.");
68
69 - if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
70 - error("nfacct.plugin: Cannot set pthread cancel state to ENABLE.");
69 + if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
70 + error("nfacct.plugin: Cannot set pthread cancel state to ENABLE.");
71
72 - char buf[MNL_SOCKET_BUFFER_SIZE];
73 - struct mnl_socket *nl = NULL;
74 - struct nlmsghdr *nlh = NULL;
75 - unsigned int seq = 0, portid = 0;
72 + char buf[MNL_SOCKET_BUFFER_SIZE];
73 + struct mnl_socket *nl = NULL;
74 + struct nlmsghdr *nlh = NULL;
75 + unsigned int seq = 0, portid = 0;
76
77 - seq = time(NULL) - 1;
77 + seq = time(NULL) - 1;
78
79 - nl = mnl_socket_open(NETLINK_NETFILTER);
80 - if(!nl) {
81 - error("nfacct.plugin: mnl_socket_open() failed");
82 - pthread_exit(NULL);
83 - return NULL;
84 - }
79 + nl = mnl_socket_open(NETLINK_NETFILTER);
80 + if(!nl) {
81 + error("nfacct.plugin: mnl_socket_open() failed");
82 + pthread_exit(NULL);
83 + return NULL;
84 + }
85
86 - if(mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
87 - mnl_socket_close(nl);
88 - error("nfacct.plugin: mnl_socket_bind() failed");
89 - pthread_exit(NULL);
90 - return NULL;
91 - }
92 - portid = mnl_socket_get_portid(nl);
86 + if(mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
87 + mnl_socket_close(nl);
88 + error("nfacct.plugin: mnl_socket_bind() failed");
89 + pthread_exit(NULL);
90 + return NULL;
91 + }
92 + portid = mnl_socket_get_portid(nl);
93
94 - // ------------------------------------------------------------------------
94 + // ------------------------------------------------------------------------
95
96 - struct timeval last, now;
97 - unsigned long long usec = 0, susec = 0;
98 - RRDSET *st = NULL;
96 + struct timeval last, now;
97 + unsigned long long usec = 0, susec = 0;
98 + RRDSET *st = NULL;
99
100 - gettimeofday(&last, NULL);
100 + gettimeofday(&last, NULL);
101
102 - // ------------------------------------------------------------------------
102 + // ------------------------------------------------------------------------
103
104 - while(1) {
105 - if(unlikely(netdata_exit)) break;
104 + while(1) {
105 + if(unlikely(netdata_exit)) break;
106
107 - seq++;
107 + seq++;
108
109 - nlh = nfacct_nlmsg_build_hdr(buf, NFNL_MSG_ACCT_GET, NLM_F_DUMP, seq);
110 - if(!nlh) {
111 - mnl_socket_close(nl);
112 - error("nfacct.plugin: nfacct_nlmsg_build_hdr() failed");
113 - pthread_exit(NULL);
114 - return NULL;
115 - }
109 + nlh = nfacct_nlmsg_build_hdr(buf, NFNL_MSG_ACCT_GET, NLM_F_DUMP, seq);
110 + if(!nlh) {
111 + mnl_socket_close(nl);
112 + error("nfacct.plugin: nfacct_nlmsg_build_hdr() failed");
113 + pthread_exit(NULL);
114 + return NULL;
115 + }
116
117 - if(mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
118 - error("nfacct.plugin: mnl_socket_send");
119 - pthread_exit(NULL);
120 - return NULL;
121 - }
117 + if(mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
118 + error("nfacct.plugin: mnl_socket_send");
119 + pthread_exit(NULL);
120 + return NULL;
121 + }
122
123 - if(nfacct_list) nfacct_list->len = 0;
123 + if(nfacct_list) nfacct_list->len = 0;
124
125 - int ret;
126 - while((ret = mnl_socket_recvfrom(nl, buf, sizeof(buf))) > 0) {
127 - if((ret = mnl_cb_run(buf, ret, seq, portid, nfacct_callback, NULL)) <= 0) break;
128 - }
125 + int ret;
126 + while((ret = mnl_socket_recvfrom(nl, buf, sizeof(buf))) > 0) {
127 + if((ret = mnl_cb_run(buf, ret, seq, portid, nfacct_callback, NULL)) <= 0) break;
128 + }
129
130 - if (ret == -1) {
131 - error("nfacct.plugin: error communicating with kernel.");
132 - pthread_exit(NULL);
133 - return NULL;
134 - }
130 + if (ret == -1) {
131 + error("nfacct.plugin: error communicating with kernel.");
132 + pthread_exit(NULL);
133 + return NULL;
134 + }
135
136 - // --------------------------------------------------------------------
136 + // --------------------------------------------------------------------
137
138 - gettimeofday(&now, NULL);
139 - usec = usecdiff(&now, &last) - susec;
140 - debug(D_NFACCT_LOOP, "nfacct.plugin: last loop took %llu usec (worked for %llu, sleeped for %llu).", usec + susec, usec, susec);
138 + gettimeofday(&now, NULL);
139 + usec = usecdiff(&now, &last) - susec;
140 + debug(D_NFACCT_LOOP, "nfacct.plugin: last loop took %llu usec (worked for %llu, sleeped for %llu).", usec + susec, usec, susec);
141
142 - if(usec < (rrd_update_every * 1000000ULL / 2ULL)) susec = (rrd_update_every * 1000000ULL) - usec;
143 - else susec = rrd_update_every * 1000000ULL / 2ULL;
142 + if(usec < (rrd_update_every * 1000000ULL / 2ULL)) susec = (rrd_update_every * 1000000ULL) - usec;
143 + else susec = rrd_update_every * 1000000ULL / 2ULL;
144
145
146 - // --------------------------------------------------------------------
146 + // --------------------------------------------------------------------
147
148 - if(nfacct_list && nfacct_list->len) {
149 - int i;
148 + if(nfacct_list && nfacct_list->len) {
149 + int i;
150
151 - st = rrdset_find_bytype("netfilter", "nfacct_packets");
152 - if(!st) {
153 - st = rrdset_create("netfilter", "nfacct_packets", NULL, "nfacct", NULL, "Netfilter Accounting Packets", "packets/s", 1006, rrd_update_every, RRDSET_TYPE_STACKED);
151 + st = rrdset_find_bytype("netfilter", "nfacct_packets");
152 + if(!st) {
153 + st = rrdset_create("netfilter", "nfacct_packets", NULL, "nfacct", NULL, "Netfilter Accounting Packets", "packets/s", 1006, rrd_update_every, RRDSET_TYPE_STACKED);
154
155 - for(i = 0; i < nfacct_list->len ; i++)
156 - rrddim_add(st, nfacct_list->data[i].name, NULL, 1, rrd_update_every, RRDDIM_INCREMENTAL);
157 - }
158 - else rrdset_next(st);
155 + for(i = 0; i < nfacct_list->len ; i++)
156 + rrddim_add(st, nfacct_list->data[i].name, NULL, 1, rrd_update_every, RRDDIM_INCREMENTAL);
157 + }
158 + else rrdset_next(st);
159
160 - for(i = 0; i < nfacct_list->len ; i++) {
161 - RRDDIM *rd = rrddim_find(st, nfacct_list->data[i].name);
160 + for(i = 0; i < nfacct_list->len ; i++) {
161 + RRDDIM *rd = rrddim_find(st, nfacct_list->data[i].name);
162
163 - if(!rd) rd = rrddim_add(st, nfacct_list->data[i].name, NULL, 1, rrd_update_every, RRDDIM_INCREMENTAL);
164 - if(rd) rrddim_set_by_pointer(st, rd, nfacct_list->data[i].pkts);
165 - }
163 + if(!rd) rd = rrddim_add(st, nfacct_list->data[i].name, NULL, 1, rrd_update_every, RRDDIM_INCREMENTAL);
164 + if(rd) rrddim_set_by_pointer(st, rd, nfacct_list->data[i].pkts);
165 + }
166
167 - rrdset_done(st);
167 + rrdset_done(st);
168
169 - // ----------------------------------------------------------------
169 + // ----------------------------------------------------------------
170
171 - st = rrdset_find_bytype("netfilter", "nfacct_bytes");
172 - if(!st) {
173 - st = rrdset_create("netfilter", "nfacct_bytes", NULL, "nfacct", NULL, "Netfilter Accounting Bandwidth", "kilobytes/s", 1007, rrd_update_every, RRDSET_TYPE_STACKED);
171 + st = rrdset_find_bytype("netfilter", "nfacct_bytes");
172 + if(!st) {
173 + st = rrdset_create("netfilter", "nfacct_bytes", NULL, "nfacct", NULL, "Netfilter Accounting Bandwidth", "kilobytes/s", 1007, rrd_update_every, RRDSET_TYPE_STACKED);
174
175 - for(i = 0; i < nfacct_list->len ; i++)
176 - rrddim_add(st, nfacct_list->data[i].name, NULL, 1, 1000 * rrd_update_every, RRDDIM_INCREMENTAL);
177 - }
178 - else rrdset_next(st);
175 + for(i = 0; i < nfacct_list->len ; i++)
176 + rrddim_add(st, nfacct_list->data[i].name, NULL, 1, 1000 * rrd_update_every, RRDDIM_INCREMENTAL);
177 + }
178 + else rrdset_next(st);
179
180 - for(i = 0; i < nfacct_list->len ; i++) {
181 - RRDDIM *rd = rrddim_find(st, nfacct_list->data[i].name);
180 + for(i = 0; i < nfacct_list->len ; i++) {
181 + RRDDIM *rd = rrddim_find(st, nfacct_list->data[i].name);
182
183 - if(!rd) rd = rrddim_add(st, nfacct_list->data[i].name, NULL, 1, 1000 * rrd_update_every, RRDDIM_INCREMENTAL);
184 - if(rd) rrddim_set_by_pointer(st, rd, nfacct_list->data[i].bytes);
185 - }
183 + if(!rd) rd = rrddim_add(st, nfacct_list->data[i].name, NULL, 1, 1000 * rrd_update_every, RRDDIM_INCREMENTAL);
184 + if(rd) rrddim_set_by_pointer(st, rd, nfacct_list->data[i].bytes);
185 + }
186
187 - rrdset_done(st);
188 - }
187 + rrdset_done(st);
188 + }
189
190 - // --------------------------------------------------------------------
190 + // --------------------------------------------------------------------
191
192 - usleep(susec);
192 + usleep(susec);
193
194 - // copy current to last
195 - bcopy(&now, &last, sizeof(struct timeval));
196 - }
194 + // copy current to last
195 + bcopy(&now, &last, sizeof(struct timeval));
196 + }
197
198 - mnl_socket_close(nl);
199 - pthread_exit(NULL);
200 - return NULL;
198 + mnl_socket_close(nl);
199 + pthread_exit(NULL);
200 + return NULL;
201 }
202 #endif
src/plugin_proc.c
+219 -219
@@ -2,225 +2,225 @@
2
3 void *proc_main(void *ptr)
4 {
5 - (void)ptr;
6 -
7 - info("PROC Plugin thread created with task id %d", gettid());
8 -
9 - if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
10 - error("Cannot set pthread cancel type to DEFERRED.");
11 -
12 - if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
13 - error("Cannot set pthread cancel state to ENABLE.");
14 -
15 - // disable (by default) various interface that are not needed
16 - config_get_boolean("plugin:proc:/proc/net/dev:lo", "enabled", 0);
17 - config_get_boolean("plugin:proc:/proc/net/dev:fireqos_monitor", "enabled", 0);
18 -
19 - // when ZERO, attempt to do it
20 - int vdo_proc_net_dev = !config_get_boolean("plugin:proc", "/proc/net/dev", 1);
21 - int vdo_proc_diskstats = !config_get_boolean("plugin:proc", "/proc/diskstats", 1);
22 - int vdo_proc_net_snmp = !config_get_boolean("plugin:proc", "/proc/net/snmp", 1);
23 - int vdo_proc_net_snmp6 = !config_get_boolean("plugin:proc", "/proc/net/snmp6", 1);
24 - int vdo_proc_net_netstat = !config_get_boolean("plugin:proc", "/proc/net/netstat", 1);
25 - int vdo_proc_net_stat_conntrack = !config_get_boolean("plugin:proc", "/proc/net/stat/conntrack", 1);
26 - int vdo_proc_net_ip_vs_stats = !config_get_boolean("plugin:proc", "/proc/net/ip_vs/stats", 1);
27 - int vdo_proc_net_stat_synproxy = !config_get_boolean("plugin:proc", "/proc/net/stat/synproxy", 1);
28 - int vdo_proc_stat = !config_get_boolean("plugin:proc", "/proc/stat", 1);
29 - int vdo_proc_meminfo = !config_get_boolean("plugin:proc", "/proc/meminfo", 1);
30 - int vdo_proc_vmstat = !config_get_boolean("plugin:proc", "/proc/vmstat", 1);
31 - int vdo_proc_net_rpc_nfsd = !config_get_boolean("plugin:proc", "/proc/net/rpc/nfsd", 1);
32 - int vdo_proc_sys_kernel_random_entropy_avail = !config_get_boolean("plugin:proc", "/proc/sys/kernel/random/entropy_avail", 1);
33 - int vdo_proc_interrupts = !config_get_boolean("plugin:proc", "/proc/interrupts", 1);
34 - int vdo_proc_softirqs = !config_get_boolean("plugin:proc", "/proc/softirqs", 1);
35 - int vdo_proc_loadavg = !config_get_boolean("plugin:proc", "/proc/loadavg", 1);
36 - int vdo_sys_kernel_mm_ksm = !config_get_boolean("plugin:proc", "/sys/kernel/mm/ksm", 1);
37 - int vdo_cpu_netdata = !config_get_boolean("plugin:proc", "netdata server resources", 1);
38 -
39 - // keep track of the time each module was called
40 - unsigned long long sutime_proc_net_dev = 0ULL;
41 - unsigned long long sutime_proc_diskstats = 0ULL;
42 - unsigned long long sutime_proc_net_snmp = 0ULL;
43 - unsigned long long sutime_proc_net_snmp6 = 0ULL;
44 - unsigned long long sutime_proc_net_netstat = 0ULL;
45 - unsigned long long sutime_proc_net_stat_conntrack = 0ULL;
46 - unsigned long long sutime_proc_net_ip_vs_stats = 0ULL;
47 - unsigned long long sutime_proc_net_stat_synproxy = 0ULL;
48 - unsigned long long sutime_proc_stat = 0ULL;
49 - unsigned long long sutime_proc_meminfo = 0ULL;
50 - unsigned long long sutime_proc_vmstat = 0ULL;
51 - unsigned long long sutime_proc_net_rpc_nfsd = 0ULL;
52 - unsigned long long sutime_proc_sys_kernel_random_entropy_avail = 0ULL;
53 - unsigned long long sutime_proc_interrupts = 0ULL;
54 - unsigned long long sutime_proc_softirqs = 0ULL;
55 - unsigned long long sutime_proc_loadavg = 0ULL;
56 - unsigned long long sutime_sys_kernel_mm_ksm = 0ULL;
57 -
58 - // the next time we will run - aligned properly
59 - unsigned long long sunext = (time(NULL) - (time(NULL) % rrd_update_every) + rrd_update_every) * 1000000ULL;
60 - unsigned long long sunow;
61 -
62 - for(;1;) {
63 - if(unlikely(netdata_exit)) break;
64 -
65 - // delay until it is our time to run
66 - while((sunow = time_usec()) < sunext)
67 - sleep_usec(sunext - sunow);
68 -
69 - // find the next time we need to run
70 - while(time_usec() > sunext)
71 - sunext += rrd_update_every * 1000000ULL;
72 -
73 - if(unlikely(netdata_exit)) break;
74 -
75 - // BEGIN -- the job to be done
76 -
77 - if(!vdo_sys_kernel_mm_ksm) {
78 - debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_sys_kernel_mm_ksm().");
79 -
80 - sunow = time_usec();
81 - vdo_sys_kernel_mm_ksm = do_sys_kernel_mm_ksm(rrd_update_every, (sutime_sys_kernel_mm_ksm > 0)?sunow - sutime_sys_kernel_mm_ksm:0ULL);
82 - sutime_sys_kernel_mm_ksm = sunow;
83 - }
84 - if(unlikely(netdata_exit)) break;
85 -
86 - if(!vdo_proc_loadavg) {
87 - debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_loadavg().");
88 - sunow = time_usec();
89 - vdo_proc_loadavg = do_proc_loadavg(rrd_update_every, (sutime_proc_loadavg > 0)?sunow - sutime_proc_loadavg:0ULL);
90 - sutime_proc_loadavg = sunow;
91 - }
92 - if(unlikely(netdata_exit)) break;
93 -
94 - if(!vdo_proc_interrupts) {
95 - debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_interrupts().");
96 - sunow = time_usec();
97 - vdo_proc_interrupts = do_proc_interrupts(rrd_update_every, (sutime_proc_interrupts > 0)?sunow - sutime_proc_interrupts:0ULL);
98 - sutime_proc_interrupts = sunow;
99 - }
100 - if(unlikely(netdata_exit)) break;
101 -
102 - if(!vdo_proc_softirqs) {
103 - debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_softirqs().");
104 - sunow = time_usec();
105 - vdo_proc_softirqs = do_proc_softirqs(rrd_update_every, (sutime_proc_softirqs > 0)?sunow - sutime_proc_softirqs:0ULL);
106 - sutime_proc_softirqs = sunow;
107 - }
108 - if(unlikely(netdata_exit)) break;
109 -
110 - if(!vdo_proc_sys_kernel_random_entropy_avail) {
111 - debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_sys_kernel_random_entropy_avail().");
112 - sunow = time_usec();
113 - vdo_proc_sys_kernel_random_entropy_avail = do_proc_sys_kernel_random_entropy_avail(rrd_update_every, (sutime_proc_sys_kernel_random_entropy_avail > 0)?sunow - sutime_proc_sys_kernel_random_entropy_avail:0ULL);
114 - sutime_proc_sys_kernel_random_entropy_avail = sunow;
115 - }
116 - if(unlikely(netdata_exit)) break;
117 -
118 - if(!vdo_proc_net_dev) {
119 - debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_net_dev().");
120 - sunow = time_usec();
121 - vdo_proc_net_dev = do_proc_net_dev(rrd_update_every, (sutime_proc_net_dev > 0)?sunow - sutime_proc_net_dev:0ULL);
122 - sutime_proc_net_dev = sunow;
123 - }
124 - if(unlikely(netdata_exit)) break;
125 -
126 - if(!vdo_proc_diskstats) {
127 - debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_diskstats().");
128 - sunow = time_usec();
129 - vdo_proc_diskstats = do_proc_diskstats(rrd_update_every, (sutime_proc_diskstats > 0)?sunow - sutime_proc_diskstats:0ULL);
130 - sutime_proc_diskstats = sunow;
131 - }
132 - if(unlikely(netdata_exit)) break;
133 -
134 - if(!vdo_proc_net_snmp) {
135 - debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_net_snmp().");
136 - sunow = time_usec();
137 - vdo_proc_net_snmp = do_proc_net_snmp(rrd_update_every, (sutime_proc_net_snmp > 0)?sunow - sutime_proc_net_snmp:0ULL);
138 - sutime_proc_net_snmp = sunow;
139 - }
140 - if(unlikely(netdata_exit)) break;
141 -
142 - if(!vdo_proc_net_snmp6) {
143 - debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_net_snmp6().");
144 - sunow = time_usec();
145 - vdo_proc_net_snmp6 = do_proc_net_snmp6(rrd_update_every, (sutime_proc_net_snmp6 > 0)?sunow - sutime_proc_net_snmp6:0ULL);
146 - sutime_proc_net_snmp6 = sunow;
147 - }
148 - if(unlikely(netdata_exit)) break;
149 -
150 - if(!vdo_proc_net_netstat) {
151 - debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_net_netstat().");
152 - sunow = time_usec();
153 - vdo_proc_net_netstat = do_proc_net_netstat(rrd_update_every, (sutime_proc_net_netstat > 0)?sunow - sutime_proc_net_netstat:0ULL);
154 - sutime_proc_net_netstat = sunow;
155 - }
156 - if(unlikely(netdata_exit)) break;
157 -
158 - if(!vdo_proc_net_stat_conntrack) {
159 - debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_net_stat_conntrack().");
160 - sunow = time_usec();
161 - vdo_proc_net_stat_conntrack = do_proc_net_stat_conntrack(rrd_update_every, (sutime_proc_net_stat_conntrack > 0)?sunow - sutime_proc_net_stat_conntrack:0ULL);
162 - sutime_proc_net_stat_conntrack = sunow;
163 - }
164 - if(unlikely(netdata_exit)) break;
165 -
166 - if(!vdo_proc_net_ip_vs_stats) {
167 - debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling vdo_proc_net_ip_vs_stats().");
168 - sunow = time_usec();
169 - vdo_proc_net_ip_vs_stats = do_proc_net_ip_vs_stats(rrd_update_every, (sutime_proc_net_ip_vs_stats > 0)?sunow - sutime_proc_net_ip_vs_stats:0ULL);
170 - sutime_proc_net_ip_vs_stats = sunow;
171 - }
172 - if(unlikely(netdata_exit)) break;
173 -
174 - if(!vdo_proc_net_stat_synproxy) {
175 - debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling vdo_proc_net_stat_synproxy().");
176 - sunow = time_usec();
177 - vdo_proc_net_stat_synproxy = do_proc_net_stat_synproxy(rrd_update_every, (sutime_proc_net_stat_synproxy > 0)?sunow - sutime_proc_net_stat_synproxy:0ULL);
178 - sutime_proc_net_stat_synproxy = sunow;
179 - }
180 - if(unlikely(netdata_exit)) break;
181 -
182 - if(!vdo_proc_stat) {
183 - debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_stat().");
184 - sunow = time_usec();
185 - vdo_proc_stat = do_proc_stat(rrd_update_every, (sutime_proc_stat > 0)?sunow - sutime_proc_stat:0ULL);
186 - sutime_proc_stat = sunow;
187 - }
188 - if(unlikely(netdata_exit)) break;
189 -
190 - if(!vdo_proc_meminfo) {
191 - debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling vdo_proc_meminfo().");
192 - sunow = time_usec();
193 - vdo_proc_meminfo = do_proc_meminfo(rrd_update_every, (sutime_proc_meminfo > 0)?sunow - sutime_proc_meminfo:0ULL);
194 - sutime_proc_meminfo = sunow;
195 - }
196 - if(unlikely(netdata_exit)) break;
197 -
198 - if(!vdo_proc_vmstat) {
199 - debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling vdo_proc_vmstat().");
200 - sunow = time_usec();
201 - vdo_proc_vmstat = do_proc_vmstat(rrd_update_every, (sutime_proc_vmstat > 0)?sunow - sutime_proc_vmstat:0ULL);
202 - sutime_proc_vmstat = sunow;
203 - }
204 - if(unlikely(netdata_exit)) break;
205 -
206 - if(!vdo_proc_net_rpc_nfsd) {
207 - debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_net_rpc_nfsd().");
208 - sunow = time_usec();
209 - vdo_proc_net_rpc_nfsd = do_proc_net_rpc_nfsd(rrd_update_every, (sutime_proc_net_rpc_nfsd > 0)?sunow - sutime_proc_net_rpc_nfsd:0ULL);
210 - sutime_proc_net_rpc_nfsd = sunow;
211 - }
212 - if(unlikely(netdata_exit)) break;
213 -
214 - // END -- the job is done
215 -
216 - // --------------------------------------------------------------------
217 -
218 - if(!vdo_cpu_netdata) {
5 + (void)ptr;
6 +
7 + info("PROC Plugin thread created with task id %d", gettid());
8 +
9 + if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
10 + error("Cannot set pthread cancel type to DEFERRED.");
11 +
12 + if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
13 + error("Cannot set pthread cancel state to ENABLE.");
14 +
15 + // disable (by default) various interface that are not needed
16 + config_get_boolean("plugin:proc:/proc/net/dev:lo", "enabled", 0);
17 + config_get_boolean("plugin:proc:/proc/net/dev:fireqos_monitor", "enabled", 0);
18 +
19 + // when ZERO, attempt to do it
20 + int vdo_proc_net_dev = !config_get_boolean("plugin:proc", "/proc/net/dev", 1);
21 + int vdo_proc_diskstats = !config_get_boolean("plugin:proc", "/proc/diskstats", 1);
22 + int vdo_proc_net_snmp = !config_get_boolean("plugin:proc", "/proc/net/snmp", 1);
23 + int vdo_proc_net_snmp6 = !config_get_boolean("plugin:proc", "/proc/net/snmp6", 1);
24 + int vdo_proc_net_netstat = !config_get_boolean("plugin:proc", "/proc/net/netstat", 1);
25 + int vdo_proc_net_stat_conntrack = !config_get_boolean("plugin:proc", "/proc/net/stat/conntrack", 1);
26 + int vdo_proc_net_ip_vs_stats = !config_get_boolean("plugin:proc", "/proc/net/ip_vs/stats", 1);
27 + int vdo_proc_net_stat_synproxy = !config_get_boolean("plugin:proc", "/proc/net/stat/synproxy", 1);
28 + int vdo_proc_stat = !config_get_boolean("plugin:proc", "/proc/stat", 1);
29 + int vdo_proc_meminfo = !config_get_boolean("plugin:proc", "/proc/meminfo", 1);
30 + int vdo_proc_vmstat = !config_get_boolean("plugin:proc", "/proc/vmstat", 1);
31 + int vdo_proc_net_rpc_nfsd = !config_get_boolean("plugin:proc", "/proc/net/rpc/nfsd", 1);
32 + int vdo_proc_sys_kernel_random_entropy_avail = !config_get_boolean("plugin:proc", "/proc/sys/kernel/random/entropy_avail", 1);
33 + int vdo_proc_interrupts = !config_get_boolean("plugin:proc", "/proc/interrupts", 1);
34 + int vdo_proc_softirqs = !config_get_boolean("plugin:proc", "/proc/softirqs", 1);
35 + int vdo_proc_loadavg = !config_get_boolean("plugin:proc", "/proc/loadavg", 1);
36 + int vdo_sys_kernel_mm_ksm = !config_get_boolean("plugin:proc", "/sys/kernel/mm/ksm", 1);
37 + int vdo_cpu_netdata = !config_get_boolean("plugin:proc", "netdata server resources", 1);
38 +
39 + // keep track of the time each module was called
40 + unsigned long long sutime_proc_net_dev = 0ULL;
41 + unsigned long long sutime_proc_diskstats = 0ULL;
42 + unsigned long long sutime_proc_net_snmp = 0ULL;
43 + unsigned long long sutime_proc_net_snmp6 = 0ULL;
44 + unsigned long long sutime_proc_net_netstat = 0ULL;
45 + unsigned long long sutime_proc_net_stat_conntrack = 0ULL;
46 + unsigned long long sutime_proc_net_ip_vs_stats = 0ULL;
47 + unsigned long long sutime_proc_net_stat_synproxy = 0ULL;
48 + unsigned long long sutime_proc_stat = 0ULL;
49 + unsigned long long sutime_proc_meminfo = 0ULL;
50 + unsigned long long sutime_proc_vmstat = 0ULL;
51 + unsigned long long sutime_proc_net_rpc_nfsd = 0ULL;
52 + unsigned long long sutime_proc_sys_kernel_random_entropy_avail = 0ULL;
53 + unsigned long long sutime_proc_interrupts = 0ULL;
54 + unsigned long long sutime_proc_softirqs = 0ULL;
55 + unsigned long long sutime_proc_loadavg = 0ULL;
56 + unsigned long long sutime_sys_kernel_mm_ksm = 0ULL;
57 +
58 + // the next time we will run - aligned properly
59 + unsigned long long sunext = (time(NULL) - (time(NULL) % rrd_update_every) + rrd_update_every) * 1000000ULL;
60 + unsigned long long sunow;
61 +
62 + for(;1;) {
63 + if(unlikely(netdata_exit)) break;
64 +
65 + // delay until it is our time to run
66 + while((sunow = time_usec()) < sunext)
67 + sleep_usec(sunext - sunow);
68 +
69 + // find the next time we need to run
70 + while(time_usec() > sunext)
71 + sunext += rrd_update_every * 1000000ULL;
72 +
73 + if(unlikely(netdata_exit)) break;
74 +
75 + // BEGIN -- the job to be done
76 +
77 + if(!vdo_sys_kernel_mm_ksm) {
78 + debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_sys_kernel_mm_ksm().");
79 +
80 + sunow = time_usec();
81 + vdo_sys_kernel_mm_ksm = do_sys_kernel_mm_ksm(rrd_update_every, (sutime_sys_kernel_mm_ksm > 0)?sunow - sutime_sys_kernel_mm_ksm:0ULL);
82 + sutime_sys_kernel_mm_ksm = sunow;
83 + }
84 + if(unlikely(netdata_exit)) break;
85 +
86 + if(!vdo_proc_loadavg) {
87 + debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_loadavg().");
88 + sunow = time_usec();
89 + vdo_proc_loadavg = do_proc_loadavg(rrd_update_every, (sutime_proc_loadavg > 0)?sunow - sutime_proc_loadavg:0ULL);
90 + sutime_proc_loadavg = sunow;
91 + }
92 + if(unlikely(netdata_exit)) break;
93 +
94 + if(!vdo_proc_interrupts) {
95 + debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_interrupts().");
96 + sunow = time_usec();
97 + vdo_proc_interrupts = do_proc_interrupts(rrd_update_every, (sutime_proc_interrupts > 0)?sunow - sutime_proc_interrupts:0ULL);
98 + sutime_proc_interrupts = sunow;
99 + }
100 + if(unlikely(netdata_exit)) break;
101 +
102 + if(!vdo_proc_softirqs) {
103 + debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_softirqs().");
104 + sunow = time_usec();
105 + vdo_proc_softirqs = do_proc_softirqs(rrd_update_every, (sutime_proc_softirqs > 0)?sunow - sutime_proc_softirqs:0ULL);
106 + sutime_proc_softirqs = sunow;
107 + }
108 + if(unlikely(netdata_exit)) break;
109 +
110 + if(!vdo_proc_sys_kernel_random_entropy_avail) {
111 + debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_sys_kernel_random_entropy_avail().");
112 + sunow = time_usec();
113 + vdo_proc_sys_kernel_random_entropy_avail = do_proc_sys_kernel_random_entropy_avail(rrd_update_every, (sutime_proc_sys_kernel_random_entropy_avail > 0)?sunow - sutime_proc_sys_kernel_random_entropy_avail:0ULL);
114 + sutime_proc_sys_kernel_random_entropy_avail = sunow;
115 + }
116 + if(unlikely(netdata_exit)) break;
117 +
118 + if(!vdo_proc_net_dev) {
119 + debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_net_dev().");
120 + sunow = time_usec();
121 + vdo_proc_net_dev = do_proc_net_dev(rrd_update_every, (sutime_proc_net_dev > 0)?sunow - sutime_proc_net_dev:0ULL);
122 + sutime_proc_net_dev = sunow;
123 + }
124 + if(unlikely(netdata_exit)) break;
125 +
126 + if(!vdo_proc_diskstats) {
127 + debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_diskstats().");
128 + sunow = time_usec();
129 + vdo_proc_diskstats = do_proc_diskstats(rrd_update_every, (sutime_proc_diskstats > 0)?sunow - sutime_proc_diskstats:0ULL);
130 + sutime_proc_diskstats = sunow;
131 + }
132 + if(unlikely(netdata_exit)) break;
133 +
134 + if(!vdo_proc_net_snmp) {
135 + debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_net_snmp().");
136 + sunow = time_usec();
137 + vdo_proc_net_snmp = do_proc_net_snmp(rrd_update_every, (sutime_proc_net_snmp > 0)?sunow - sutime_proc_net_snmp:0ULL);
138 + sutime_proc_net_snmp = sunow;
139 + }
140 + if(unlikely(netdata_exit)) break;
141 +
142 + if(!vdo_proc_net_snmp6) {
143 + debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_net_snmp6().");
144 + sunow = time_usec();
145 + vdo_proc_net_snmp6 = do_proc_net_snmp6(rrd_update_every, (sutime_proc_net_snmp6 > 0)?sunow - sutime_proc_net_snmp6:0ULL);
146 + sutime_proc_net_snmp6 = sunow;
147 + }
148 + if(unlikely(netdata_exit)) break;
149 +
150 + if(!vdo_proc_net_netstat) {
151 + debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_net_netstat().");
152 + sunow = time_usec();
153 + vdo_proc_net_netstat = do_proc_net_netstat(rrd_update_every, (sutime_proc_net_netstat > 0)?sunow - sutime_proc_net_netstat:0ULL);
154 + sutime_proc_net_netstat = sunow;
155 + }
156 + if(unlikely(netdata_exit)) break;
157 +
158 + if(!vdo_proc_net_stat_conntrack) {
159 + debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_net_stat_conntrack().");
160 + sunow = time_usec();
161 + vdo_proc_net_stat_conntrack = do_proc_net_stat_conntrack(rrd_update_every, (sutime_proc_net_stat_conntrack > 0)?sunow - sutime_proc_net_stat_conntrack:0ULL);
162 + sutime_proc_net_stat_conntrack = sunow;
163 + }
164 + if(unlikely(netdata_exit)) break;
165 +
166 + if(!vdo_proc_net_ip_vs_stats) {
167 + debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling vdo_proc_net_ip_vs_stats().");
168 + sunow = time_usec();
169 + vdo_proc_net_ip_vs_stats = do_proc_net_ip_vs_stats(rrd_update_every, (sutime_proc_net_ip_vs_stats > 0)?sunow - sutime_proc_net_ip_vs_stats:0ULL);
170 + sutime_proc_net_ip_vs_stats = sunow;
171 + }
172 + if(unlikely(netdata_exit)) break;
173 +
174 + if(!vdo_proc_net_stat_synproxy) {
175 + debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling vdo_proc_net_stat_synproxy().");
176 + sunow = time_usec();
177 + vdo_proc_net_stat_synproxy = do_proc_net_stat_synproxy(rrd_update_every, (sutime_proc_net_stat_synproxy > 0)?sunow - sutime_proc_net_stat_synproxy:0ULL);
178 + sutime_proc_net_stat_synproxy = sunow;
179 + }
180 + if(unlikely(netdata_exit)) break;
181 +
182 + if(!vdo_proc_stat) {
183 + debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_stat().");
184 + sunow = time_usec();
185 + vdo_proc_stat = do_proc_stat(rrd_update_every, (sutime_proc_stat > 0)?sunow - sutime_proc_stat:0ULL);
186 + sutime_proc_stat = sunow;
187 + }
188 + if(unlikely(netdata_exit)) break;
189 +
190 + if(!vdo_proc_meminfo) {
191 + debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling vdo_proc_meminfo().");
192 + sunow = time_usec();
193 + vdo_proc_meminfo = do_proc_meminfo(rrd_update_every, (sutime_proc_meminfo > 0)?sunow - sutime_proc_meminfo:0ULL);
194 + sutime_proc_meminfo = sunow;
195 + }
196 + if(unlikely(netdata_exit)) break;
197 +
198 + if(!vdo_proc_vmstat) {
199 + debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling vdo_proc_vmstat().");
200 + sunow = time_usec();
201 + vdo_proc_vmstat = do_proc_vmstat(rrd_update_every, (sutime_proc_vmstat > 0)?sunow - sutime_proc_vmstat:0ULL);
202 + sutime_proc_vmstat = sunow;
203 + }
204 + if(unlikely(netdata_exit)) break;
205 +
206 + if(!vdo_proc_net_rpc_nfsd) {
207 + debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_net_rpc_nfsd().");
208 + sunow = time_usec();
209 + vdo_proc_net_rpc_nfsd = do_proc_net_rpc_nfsd(rrd_update_every, (sutime_proc_net_rpc_nfsd > 0)?sunow - sutime_proc_net_rpc_nfsd:0ULL);
210 + sutime_proc_net_rpc_nfsd = sunow;
211 + }
212 + if(unlikely(netdata_exit)) break;
213 +
214 + // END -- the job is done
215 +
216 + // --------------------------------------------------------------------
217 +
218 + if(!vdo_cpu_netdata) {
219 global_statistics_charts();
220 - registry_statistics();
221 - }
222 - }
220 + registry_statistics();
221 + }
222 + }
223
224 - pthread_exit(NULL);
225 - return NULL;
224 + pthread_exit(NULL);
225 + return NULL;
226 }
src/plugin_tc.c
+731 -731
@@ -1,7 +1,7 @@
1 #include "common.h"
2
3 -#define RRD_TYPE_TC "tc"
4 -#define RRD_TYPE_TC_LEN strlen(RRD_TYPE_TC)
3 +#define RRD_TYPE_TC "tc"
4 +#define RRD_TYPE_TC_LEN strlen(RRD_TYPE_TC)
5
6 // ----------------------------------------------------------------------------
7 // /sbin/tc processor
@@ -10,71 +10,71 @@
10 #define TC_LINE_MAX 1024
11
12 struct tc_class {
13 - avl avl;
14 -
15 - char *id;
16 - uint32_t hash;
17 -
18 - char *name;
19 -
20 - char *leafid;
21 - uint32_t leaf_hash;
22 -
23 - char *parentid;
24 - uint32_t parent_hash;
25 -
26 - char hasparent;
27 - char isleaf;
28 - unsigned long long bytes;
29 - unsigned long long packets;
30 - unsigned long long dropped;
31 - unsigned long long overlimits;
32 - unsigned long long requeues;
33 - unsigned long long lended;
34 - unsigned long long borrowed;
35 - unsigned long long giants;
36 - unsigned long long tokens;
37 - unsigned long long ctokens;
38 -
39 - RRDDIM *rd_bytes;
40 - RRDDIM *rd_packets;
41 - RRDDIM *rd_dropped;
42 -
43 - char name_updated;
44 - char updated; // updated bytes
45 - int seen; // seen in the tc list (even without bytes)
46 -
47 - struct tc_class *next;
48 - struct tc_class *prev;
13 + avl avl;
14 +
15 + char *id;
16 + uint32_t hash;
17 +
18 + char *name;
19 +
20 + char *leafid;
21 + uint32_t leaf_hash;
22 +
23 + char *parentid;
24 + uint32_t parent_hash;
25 +
26 + char hasparent;
27 + char isleaf;
28 + unsigned long long bytes;
29 + unsigned long long packets;
30 + unsigned long long dropped;
31 + unsigned long long overlimits;
32 + unsigned long long requeues;
33 + unsigned long long lended;
34 + unsigned long long borrowed;
35 + unsigned long long giants;
36 + unsigned long long tokens;
37 + unsigned long long ctokens;
38 +
39 + RRDDIM *rd_bytes;
40 + RRDDIM *rd_packets;
41 + RRDDIM *rd_dropped;
42 +
43 + char name_updated;
44 + char updated; // updated bytes
45 + int seen; // seen in the tc list (even without bytes)
46 +
47 + struct tc_class *next;
48 + struct tc_class *prev;
49 };
50
51 struct tc_device {
52 - avl avl;
52 + avl avl;
53
54 - char *id;
55 - uint32_t hash;
54 + char *id;
55 + uint32_t hash;
56
57 - char *name;
58 - char *family;
57 + char *name;
58 + char *family;
59
60 - char name_updated;
61 - char family_updated;
60 + char name_updated;
61 + char family_updated;
62
63 - char enabled;
64 - char enabled_bytes;
65 - char enabled_packets;
66 - char enabled_dropped;
63 + char enabled;
64 + char enabled_bytes;
65 + char enabled_packets;
66 + char enabled_dropped;
67
68 - RRDSET *st_bytes;
69 - RRDSET *st_packets;
70 - RRDSET *st_dropped;
68 + RRDSET *st_bytes;
69 + RRDSET *st_packets;
70 + RRDSET *st_dropped;
71
72 - avl_tree classes_index;
72 + avl_tree classes_index;
73
74 - struct tc_class *classes;
74 + struct tc_class *classes;
75
76 - struct tc_device *next;
77 - struct tc_device *prev;
76 + struct tc_device *next;
77 + struct tc_device *prev;
78 };
79
80
@@ -84,25 +84,25 @@ struct tc_device *tc_device_root = NULL;
84 // tc_device index
85
86 static int tc_device_compare(void* a, void* b) {
87 - if(((struct tc_device *)a)->hash < ((struct tc_device *)b)->hash) return -1;
88 - else if(((struct tc_device *)a)->hash > ((struct tc_device *)b)->hash) return 1;
89 - else return strcmp(((struct tc_device *)a)->id, ((struct tc_device *)b)->id);
87 + if(((struct tc_device *)a)->hash < ((struct tc_device *)b)->hash) return -1;
88 + else if(((struct tc_device *)a)->hash > ((struct tc_device *)b)->hash) return 1;
89 + else return strcmp(((struct tc_device *)a)->id, ((struct tc_device *)b)->id);
90 }
91
92 avl_tree tc_device_root_index = {
93 - NULL,
94 - tc_device_compare
93 + NULL,
94 + tc_device_compare
95 };
96
97 #define tc_device_index_add(st) avl_insert(&tc_device_root_index, (avl *)(st))
98 #define tc_device_index_del(st) avl_remove(&tc_device_root_index, (avl *)(st))
99
100 static inline struct tc_device *tc_device_index_find(const char *id, uint32_t hash) {
101 - struct tc_device tmp;
102 - tmp.id = (char *)id;
103 - tmp.hash = (hash)?hash:simple_hash(tmp.id);
101 + struct tc_device tmp;
102 + tmp.id = (char *)id;
103 + tmp.hash = (hash)?hash:simple_hash(tmp.id);
104
105 - return (struct tc_device *)avl_search(&(tc_device_root_index), (avl *)&tmp);
105 + return (struct tc_device *)avl_search(&(tc_device_root_index), (avl *)&tmp);
106 }
107
108
@@ -110,764 +110,764 @@ static inline struct tc_device *tc_device_index_find(const char *id, uint32_t ha
110 // tc_class index
111
112 static int tc_class_compare(void* a, void* b) {
113 - if(((struct tc_class *)a)->hash < ((struct tc_class *)b)->hash) return -1;
114 - else if(((struct tc_class *)a)->hash > ((struct tc_class *)b)->hash) return 1;
115 - else return strcmp(((struct tc_class *)a)->id, ((struct tc_class *)b)->id);
113 + if(((struct tc_class *)a)->hash < ((struct tc_class *)b)->hash) return -1;
114 + else if(((struct tc_class *)a)->hash > ((struct tc_class *)b)->hash) return 1;
115 + else return strcmp(((struct tc_class *)a)->id, ((struct tc_class *)b)->id);
116 }
117
118 #define tc_class_index_add(st, rd) avl_insert(&((st)->classes_index), (avl *)(rd))
119 #define tc_class_index_del(st, rd) avl_remove(&((st)->classes_index), (avl *)(rd))
120
121 static inline struct tc_class *tc_class_index_find(struct tc_device *st, const char *id, uint32_t hash) {
122 - struct tc_class tmp;
123 - tmp.id = (char *)id;
124 - tmp.hash = (hash)?hash:simple_hash(tmp.id);
122 + struct tc_class tmp;
123 + tmp.id = (char *)id;
124 + tmp.hash = (hash)?hash:simple_hash(tmp.id);
125
126 - return (struct tc_class *)avl_search(&(st->classes_index), (avl *) &tmp);
126 + return (struct tc_class *)avl_search(&(st->classes_index), (avl *) &tmp);
127 }
128
129 // ----------------------------------------------------------------------------
130
131 static inline void tc_class_free(struct tc_device *n, struct tc_class *c) {
132 - debug(D_TC_LOOP, "Removing from device '%s' class '%s', parentid '%s', leafid '%s', seen=%d", n->id, c->id, c->parentid?c->parentid:"", c->leafid?c->leafid:"", c->seen);
133 -
134 - if(c->next) c->next->prev = c->prev;
135 - if(c->prev) c->prev->next = c->next;
136 - if(n->classes == c) {
137 - if(c->next) n->classes = c->next;
138 - else n->classes = c->prev;
139 - }
140 -
141 - tc_class_index_del(n, c);
142 -
143 - freez(c->id);
144 - freez(c->name);
145 - freez(c->leafid);
146 - freez(c->parentid);
147 - freez(c);
132 + debug(D_TC_LOOP, "Removing from device '%s' class '%s', parentid '%s', leafid '%s', seen=%d", n->id, c->id, c->parentid?c->parentid:"", c->leafid?c->leafid:"", c->seen);
133 +
134 + if(c->next) c->next->prev = c->prev;
135 + if(c->prev) c->prev->next = c->next;
136 + if(n->classes == c) {
137 + if(c->next) n->classes = c->next;
138 + else n->classes = c->prev;
139 + }
140 +
141 + tc_class_index_del(n, c);
142 +
143 + freez(c->id);
144 + freez(c->name);
145 + freez(c->leafid);
146 + freez(c->parentid);
147 + freez(c);
148 }
149
150 static inline void tc_device_classes_cleanup(struct tc_device *d) {
151 - static int cleanup_every = 999;
152 -
153 - if(unlikely(cleanup_every > 0)) {
154 - cleanup_every = (int) config_get_number("plugin:tc", "cleanup unused classes every", 60);
155 - if(cleanup_every < 0) cleanup_every = -cleanup_every;
156 - }
157 -
158 - d->name_updated = 0;
159 - d->family_updated = 0;
160 -
161 - struct tc_class *c = d->classes;
162 - while(c) {
163 - if(unlikely(cleanup_every > 0 && c->seen >= cleanup_every)) {
164 - struct tc_class *nc = c->next;
165 - tc_class_free(d, c);
166 - c = nc;
167 - }
168 - else {
169 - c->updated = 0;
170 - c->name_updated = 0;
171 -
172 - c = c->next;
173 - }
174 - }
151 + static int cleanup_every = 999;
152 +
153 + if(unlikely(cleanup_every > 0)) {
154 + cleanup_every = (int) config_get_number("plugin:tc", "cleanup unused classes every", 60);
155 + if(cleanup_every < 0) cleanup_every = -cleanup_every;
156 + }
157 +
158 + d->name_updated = 0;
159 + d->family_updated = 0;
160 +
161 + struct tc_class *c = d->classes;
162 + while(c) {
163 + if(unlikely(cleanup_every > 0 && c->seen >= cleanup_every)) {
164 + struct tc_class *nc = c->next;
165 + tc_class_free(d, c);
166 + c = nc;
167 + }
168 + else {
169 + c->updated = 0;
170 + c->name_updated = 0;
171 +
172 + c = c->next;
173 + }
174 + }
175 }
176
177 static inline void tc_device_commit(struct tc_device *d) {
178 - static int enable_new_interfaces = -1, enable_bytes = -1, enable_packets = -1, enable_dropped = -1;
179 -
180 - if(unlikely(enable_new_interfaces == -1)) {
181 - enable_new_interfaces = config_get_boolean_ondemand("plugin:tc", "enable new interfaces detected at runtime", CONFIG_ONDEMAND_YES);
182 - enable_bytes = config_get_boolean_ondemand("plugin:tc", "enable traffic charts for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
183 - enable_packets = config_get_boolean_ondemand("plugin:tc", "enable packets charts for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
184 - enable_dropped = config_get_boolean_ondemand("plugin:tc", "enable dropped charts for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
185 - }
186 -
187 - // we only need to add leaf classes
188 - struct tc_class *c, *x;
189 - unsigned long long bytes_sum = 0, packets_sum = 0, dropped_sum = 0;
190 - int active_classes = 0;
191 -
192 - // set all classes
193 - for(c = d->classes ; c ; c = c->next) {
194 - c->isleaf = 1;
195 - c->hasparent = 0;
196 - }
197 -
198 - // mark the classes as leafs and parents
199 - for(c = d->classes ; c ; c = c->next) {
200 - if(unlikely(!c->updated)) continue;
201 -
202 - for(x = d->classes ; x ; x = x->next) {
203 - if(unlikely(!x->updated)) continue;
204 -
205 - if(unlikely(c == x)) continue;
206 -
207 - if(x->parentid && (
208 - ( c->hash == x->parent_hash && strcmp(c->id, x->parentid) == 0) ||
209 - (c->leafid && c->leaf_hash == x->parent_hash && strcmp(c->leafid, x->parentid) == 0))) {
210 - // debug(D_TC_LOOP, "TC: In device '%s', class '%s' (leafid: '%s') has as leaf class '%s' (parentid: '%s').", d->name?d->name:d->id, c->name?c->name:c->id, c->leafid?c->leafid:c->id, x->name?x->name:x->id, x->parentid?x->parentid:x->id);
211 - c->isleaf = 0;
212 - x->hasparent = 1;
213 - }
214 - }
215 - }
216 -
217 - // debugging:
218 - /*
219 - for ( c = d->classes ; c ; c = c->next) {
220 - if(c->isleaf && c->hasparent) debug(D_TC_LOOP, "TC: Device %s, class %s, OK", d->name, c->id);
221 - else debug(D_TC_LOOP, "TC: Device %s, class %s, IGNORE (isleaf: %d, hasparent: %d, parent: %s)", d->name, c->id, c->isleaf, c->hasparent, c->parentid);
222 - }
223 - */
224 -
225 - // we need at least a class
226 - for(c = d->classes ; c ; c = c->next) {
227 - // debug(D_TC_LOOP, "TC: Device '%s', class '%s', isLeaf=%d, HasParent=%d, Seen=%d", d->name?d->name:d->id, c->name?c->name:c->id, c->isleaf, c->hasparent, c->seen);
228 - if(!c->updated) continue;
229 - if(c->isleaf && c->hasparent) {
230 - active_classes++;
231 - bytes_sum += c->bytes;
232 - packets_sum += c->packets;
233 - dropped_sum += c->dropped;
234 - }
235 - }
236 -
237 - if(unlikely(!active_classes)) {
238 - debug(D_TC_LOOP, "TC: Ignoring TC device '%s'. No leaf classes.", d->name?d->name:d->id);
239 - tc_device_classes_cleanup(d);
240 - return;
241 - }
242 -
243 - if(unlikely(d->enabled == -1)) {
244 - char var_name[CONFIG_MAX_NAME + 1];
245 - snprintfz(var_name, CONFIG_MAX_NAME, "qos for %s", d->id);
246 - d->enabled = config_get_boolean_ondemand("plugin:tc", var_name, enable_new_interfaces);
247 -
248 - snprintfz(var_name, CONFIG_MAX_NAME, "traffic chart for %s", d->id);
249 - d->enabled_bytes = config_get_boolean_ondemand("plugin:tc", var_name, enable_bytes);
250 -
251 - snprintfz(var_name, CONFIG_MAX_NAME, "packets chart for %s", d->id);
252 - d->enabled_packets = config_get_boolean_ondemand("plugin:tc", var_name, enable_packets);
253 -
254 - snprintfz(var_name, CONFIG_MAX_NAME, "dropped packets chart for %s", d->id);
255 - d->enabled_dropped = config_get_boolean_ondemand("plugin:tc", var_name, enable_dropped);
256 - }
257 -
258 - if(likely(d->enabled)) {
259 - // --------------------------------------------------------------------
260 - // bytes
261 -
262 - if(d->enabled_bytes == CONFIG_ONDEMAND_YES || (d->enabled_bytes == CONFIG_ONDEMAND_ONDEMAND && bytes_sum)) {
263 - d->enabled_bytes = CONFIG_ONDEMAND_YES;
264 -
265 - if(unlikely(!d->st_bytes)) {
266 - d->st_bytes = rrdset_find_bytype(RRD_TYPE_TC, d->id);
267 - if(unlikely(!d->st_bytes)) {
268 - debug(D_TC_LOOP, "TC: Creating new chart for device '%s'", d->name?d->name:d->id);
269 - d->st_bytes = rrdset_create(RRD_TYPE_TC, d->id, d->name?d->name:d->id, d->family?d->family:d->id, RRD_TYPE_TC ".qos", "Class Usage", "kilobits/s", 7000, rrd_update_every, RRDSET_TYPE_STACKED);
270 - }
271 - }
272 - else {
273 - debug(D_TC_LOOP, "TC: Updating chart for device '%s'", d->name?d->name:d->id);
274 - rrdset_next_plugins(d->st_bytes);
275 -
276 - if(unlikely(d->name_updated && d->name && strcmp(d->id, d->name) != 0)) {
277 - rrdset_set_name(d->st_bytes, d->name);
278 - d->name_updated = 0;
279 - }
280 -
281 - // FIXME
282 - // update the family
283 - }
284 -
285 - for(c = d->classes ; c ; c = c->next) {
286 - if(unlikely(!c->updated)) continue;
287 -
288 - if(c->isleaf && c->hasparent) {
289 - c->seen++;
290 -
291 - if(unlikely(!c->rd_bytes)) {
292 - c->rd_bytes = rrddim_find(d->st_bytes, c->id);
293 - if(unlikely(!c->rd_bytes)) {
294 - debug(D_TC_LOOP, "TC: Adding to chart '%s', dimension '%s' (name: '%s')", d->st_bytes->id, c->id, c->name);
295 -
296 - // new class, we have to add it
297 - c->rd_bytes = rrddim_add(d->st_bytes, c->id, c->name?c->name:c->id, 8, 1024, RRDDIM_INCREMENTAL);
298 - }
299 - else debug(D_TC_LOOP, "TC: Updating chart '%s', dimension '%s'", d->st_bytes->id, c->id);
300 - }
301 -
302 - rrddim_set_by_pointer(d->st_bytes, c->rd_bytes, c->bytes);
303 -
304 - // if it has a name, different to the id
305 - if(unlikely(c->name_updated && c->name && strcmp(c->id, c->name) != 0)) {
306 - // update the rrd dimension with the new name
307 - debug(D_TC_LOOP, "TC: Setting chart '%s', dimension '%s' name to '%s'", d->st_bytes->id, c->rd_bytes->id, c->name);
308 - rrddim_set_name(d->st_bytes, c->rd_bytes, c->name);
309 - }
310 - }
311 - }
312 - rrdset_done(d->st_bytes);
313 - }
314 -
315 - // --------------------------------------------------------------------
316 - // packets
317 -
318 - if(d->enabled_packets == CONFIG_ONDEMAND_YES || (d->enabled_packets == CONFIG_ONDEMAND_ONDEMAND && packets_sum)) {
319 - d->enabled_packets = CONFIG_ONDEMAND_YES;
320 -
321 - if(unlikely(!d->st_packets)) {
322 - char id[RRD_ID_LENGTH_MAX + 1];
323 - char name[RRD_ID_LENGTH_MAX + 1];
324 - snprintfz(id, RRD_ID_LENGTH_MAX, "%s_packets", d->id);
325 - snprintfz(name, RRD_ID_LENGTH_MAX, "%s_packets", d->name?d->name:d->id);
326 -
327 - d->st_packets = rrdset_find_bytype(RRD_TYPE_TC, id);
328 - if(unlikely(!d->st_packets)) {
329 - debug(D_TC_LOOP, "TC: Creating new _packets chart for device '%s'", d->name?d->name:d->id);
330 - d->st_packets = rrdset_create(RRD_TYPE_TC, id, name, d->family?d->family:d->id, RRD_TYPE_TC ".qos_packets", "Class Packets", "packets/s", 7010, rrd_update_every, RRDSET_TYPE_STACKED);
331 - }
332 - }
333 - else {
334 - debug(D_TC_LOOP, "TC: Updating _packets chart for device '%s'", d->name?d->name:d->id);
335 - rrdset_next_plugins(d->st_packets);
336 -
337 - // FIXME
338 - // update the family
339 - }
340 -
341 - for(c = d->classes ; c ; c = c->next) {
342 - if(unlikely(!c->updated)) continue;
343 -
344 - if(c->isleaf && c->hasparent) {
345 - if(unlikely(!c->rd_packets)) {
346 - c->rd_packets = rrddim_find(d->st_packets, c->id);
347 - if(unlikely(!c->rd_packets)) {
348 - debug(D_TC_LOOP, "TC: Adding to chart '%s', dimension '%s' (name: '%s')", d->st_packets->id, c->id, c->name);
349 -
350 - // new class, we have to add it
351 - c->rd_packets = rrddim_add(d->st_packets, c->id, c->name?c->name:c->id, 1, 1, RRDDIM_INCREMENTAL);
352 - }
353 - else debug(D_TC_LOOP, "TC: Updating chart '%s', dimension '%s'", d->st_packets->id, c->id);
354 - }
355 -
356 - rrddim_set_by_pointer(d->st_packets, c->rd_packets, c->packets);
357 -
358 - // if it has a name, different to the id
359 - if(unlikely(c->name_updated && c->name && strcmp(c->id, c->name) != 0)) {
360 - // update the rrd dimension with the new name
361 - debug(D_TC_LOOP, "TC: Setting chart '%s', dimension '%s' name to '%s'", d->st_packets->id, c->rd_packets->id, c->name);
362 - rrddim_set_name(d->st_packets, c->rd_packets, c->name);
363 - }
364 - }
365 - }
366 - rrdset_done(d->st_packets);
367 - }
368 -
369 - // --------------------------------------------------------------------
370 - // dropped
371 -
372 - if(d->enabled_dropped == CONFIG_ONDEMAND_YES || (d->enabled_dropped == CONFIG_ONDEMAND_ONDEMAND && dropped_sum)) {
373 - d->enabled_dropped = CONFIG_ONDEMAND_YES;
374 -
375 - if(unlikely(!d->st_dropped)) {
376 - char id[RRD_ID_LENGTH_MAX + 1];
377 - char name[RRD_ID_LENGTH_MAX + 1];
378 - snprintfz(id, RRD_ID_LENGTH_MAX, "%s_dropped", d->id);
379 - snprintfz(name, RRD_ID_LENGTH_MAX, "%s_dropped", d->name?d->name:d->id);
380 -
381 - d->st_dropped = rrdset_find_bytype(RRD_TYPE_TC, id);
382 - if(unlikely(!d->st_dropped)) {
383 - debug(D_TC_LOOP, "TC: Creating new _dropped chart for device '%s'", d->name?d->name:d->id);
384 - d->st_dropped = rrdset_create(RRD_TYPE_TC, id, name, d->family?d->family:d->id, RRD_TYPE_TC ".qos_dropped", "Class Dropped Packets", "packets/s", 7020, rrd_update_every, RRDSET_TYPE_STACKED);
385 - }
386 - }
387 - else {
388 - debug(D_TC_LOOP, "TC: Updating _dropped chart for device '%s'", d->name?d->name:d->id);
389 - rrdset_next_plugins(d->st_dropped);
390 -
391 - // FIXME
392 - // update the family
393 - }
394 -
395 - for(c = d->classes ; c ; c = c->next) {
396 - if(unlikely(!c->updated)) continue;
397 -
398 - if(c->isleaf && c->hasparent) {
399 - if(unlikely(!c->rd_dropped)) {
400 - c->rd_dropped = rrddim_find(d->st_dropped, c->id);
401 - if(unlikely(!c->rd_dropped)) {
402 - debug(D_TC_LOOP, "TC: Adding to chart '%s', dimension '%s' (name: '%s')", d->st_dropped->id, c->id, c->name);
403 -
404 - // new class, we have to add it
405 - c->rd_dropped = rrddim_add(d->st_dropped, c->id, c->name?c->name:c->id, 1, 1, RRDDIM_INCREMENTAL);
406 - }
407 - else debug(D_TC_LOOP, "TC: Updating chart '%s', dimension '%s'", d->st_dropped->id, c->id);
408 - }
409 -
410 - rrddim_set_by_pointer(d->st_dropped, c->rd_dropped, c->dropped);
411 -
412 - // if it has a name, different to the id
413 - if(unlikely(c->name_updated && c->name && strcmp(c->id, c->name) != 0)) {
414 - // update the rrd dimension with the new name
415 - debug(D_TC_LOOP, "TC: Setting chart '%s', dimension '%s' name to '%s'", d->st_dropped->id, c->rd_dropped->id, c->name);
416 - rrddim_set_name(d->st_dropped, c->rd_dropped, c->name);
417 - }
418 - }
419 - }
420 - rrdset_done(d->st_dropped);
421 - }
422 - }
423 -
424 - tc_device_classes_cleanup(d);
178 + static int enable_new_interfaces = -1, enable_bytes = -1, enable_packets = -1, enable_dropped = -1;
179 +
180 + if(unlikely(enable_new_interfaces == -1)) {
181 + enable_new_interfaces = config_get_boolean_ondemand("plugin:tc", "enable new interfaces detected at runtime", CONFIG_ONDEMAND_YES);
182 + enable_bytes = config_get_boolean_ondemand("plugin:tc", "enable traffic charts for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
183 + enable_packets = config_get_boolean_ondemand("plugin:tc", "enable packets charts for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
184 + enable_dropped = config_get_boolean_ondemand("plugin:tc", "enable dropped charts for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
185 + }
186 +
187 + // we only need to add leaf classes
188 + struct tc_class *c, *x;
189 + unsigned long long bytes_sum = 0, packets_sum = 0, dropped_sum = 0;
190 + int active_classes = 0;
191 +
192 + // set all classes
193 + for(c = d->classes ; c ; c = c->next) {
194 + c->isleaf = 1;
195 + c->hasparent = 0;
196 + }
197 +
198 + // mark the classes as leafs and parents
199 + for(c = d->classes ; c ; c = c->next) {
200 + if(unlikely(!c->updated)) continue;
201 +
202 + for(x = d->classes ; x ; x = x->next) {
203 + if(unlikely(!x->updated)) continue;
204 +
205 + if(unlikely(c == x)) continue;
206 +
207 + if(x->parentid && (
208 + ( c->hash == x->parent_hash && strcmp(c->id, x->parentid) == 0) ||
209 + (c->leafid && c->leaf_hash == x->parent_hash && strcmp(c->leafid, x->parentid) == 0))) {
210 + // debug(D_TC_LOOP, "TC: In device '%s', class '%s' (leafid: '%s') has as leaf class '%s' (parentid: '%s').", d->name?d->name:d->id, c->name?c->name:c->id, c->leafid?c->leafid:c->id, x->name?x->name:x->id, x->parentid?x->parentid:x->id);
211 + c->isleaf = 0;
212 + x->hasparent = 1;
213 + }
214 + }
215 + }
216 +
217 + // debugging:
218 + /*
219 + for ( c = d->classes ; c ; c = c->next) {
220 + if(c->isleaf && c->hasparent) debug(D_TC_LOOP, "TC: Device %s, class %s, OK", d->name, c->id);
221 + else debug(D_TC_LOOP, "TC: Device %s, class %s, IGNORE (isleaf: %d, hasparent: %d, parent: %s)", d->name, c->id, c->isleaf, c->hasparent, c->parentid);
222 + }
223 + */
224 +
225 + // we need at least a class
226 + for(c = d->classes ; c ; c = c->next) {
227 + // debug(D_TC_LOOP, "TC: Device '%s', class '%s', isLeaf=%d, HasParent=%d, Seen=%d", d->name?d->name:d->id, c->name?c->name:c->id, c->isleaf, c->hasparent, c->seen);
228 + if(!c->updated) continue;
229 + if(c->isleaf && c->hasparent) {
230 + active_classes++;
231 + bytes_sum += c->bytes;
232 + packets_sum += c->packets;
233 + dropped_sum += c->dropped;
234 + }
235 + }
236 +
237 + if(unlikely(!active_classes)) {
238 + debug(D_TC_LOOP, "TC: Ignoring TC device '%s'. No leaf classes.", d->name?d->name:d->id);
239 + tc_device_classes_cleanup(d);
240 + return;
241 + }
242 +
243 + if(unlikely(d->enabled == -1)) {
244 + char var_name[CONFIG_MAX_NAME + 1];
245 + snprintfz(var_name, CONFIG_MAX_NAME, "qos for %s", d->id);
246 + d->enabled = config_get_boolean_ondemand("plugin:tc", var_name, enable_new_interfaces);
247 +
248 + snprintfz(var_name, CONFIG_MAX_NAME, "traffic chart for %s", d->id);
249 + d->enabled_bytes = config_get_boolean_ondemand("plugin:tc", var_name, enable_bytes);
250 +
251 + snprintfz(var_name, CONFIG_MAX_NAME, "packets chart for %s", d->id);
252 + d->enabled_packets = config_get_boolean_ondemand("plugin:tc", var_name, enable_packets);
253 +
254 + snprintfz(var_name, CONFIG_MAX_NAME, "dropped packets chart for %s", d->id);
255 + d->enabled_dropped = config_get_boolean_ondemand("plugin:tc", var_name, enable_dropped);
256 + }
257 +
258 + if(likely(d->enabled)) {
259 + // --------------------------------------------------------------------
260 + // bytes
261 +
262 + if(d->enabled_bytes == CONFIG_ONDEMAND_YES || (d->enabled_bytes == CONFIG_ONDEMAND_ONDEMAND && bytes_sum)) {
263 + d->enabled_bytes = CONFIG_ONDEMAND_YES;
264 +
265 + if(unlikely(!d->st_bytes)) {
266 + d->st_bytes = rrdset_find_bytype(RRD_TYPE_TC, d->id);
267 + if(unlikely(!d->st_bytes)) {
268 + debug(D_TC_LOOP, "TC: Creating new chart for device '%s'", d->name?d->name:d->id);
269 + d->st_bytes = rrdset_create(RRD_TYPE_TC, d->id, d->name?d->name:d->id, d->family?d->family:d->id, RRD_TYPE_TC ".qos", "Class Usage", "kilobits/s", 7000, rrd_update_every, RRDSET_TYPE_STACKED);
270 + }
271 + }
272 + else {
273 + debug(D_TC_LOOP, "TC: Updating chart for device '%s'", d->name?d->name:d->id);
274 + rrdset_next_plugins(d->st_bytes);
275 +
276 + if(unlikely(d->name_updated && d->name && strcmp(d->id, d->name) != 0)) {
277 + rrdset_set_name(d->st_bytes, d->name);
278 + d->name_updated = 0;
279 + }
280 +
281 + // FIXME
282 + // update the family
283 + }
284 +
285 + for(c = d->classes ; c ; c = c->next) {
286 + if(unlikely(!c->updated)) continue;
287 +
288 + if(c->isleaf && c->hasparent) {
289 + c->seen++;
290 +
291 + if(unlikely(!c->rd_bytes)) {
292 + c->rd_bytes = rrddim_find(d->st_bytes, c->id);
293 + if(unlikely(!c->rd_bytes)) {
294 + debug(D_TC_LOOP, "TC: Adding to chart '%s', dimension '%s' (name: '%s')", d->st_bytes->id, c->id, c->name);
295 +
296 + // new class, we have to add it
297 + c->rd_bytes = rrddim_add(d->st_bytes, c->id, c->name?c->name:c->id, 8, 1024, RRDDIM_INCREMENTAL);
298 + }
299 + else debug(D_TC_LOOP, "TC: Updating chart '%s', dimension '%s'", d->st_bytes->id, c->id);
300 + }
301 +
302 + rrddim_set_by_pointer(d->st_bytes, c->rd_bytes, c->bytes);
303 +
304 + // if it has a name, different to the id
305 + if(unlikely(c->name_updated && c->name && strcmp(c->id, c->name) != 0)) {
306 + // update the rrd dimension with the new name
307 + debug(D_TC_LOOP, "TC: Setting chart '%s', dimension '%s' name to '%s'", d->st_bytes->id, c->rd_bytes->id, c->name);
308 + rrddim_set_name(d->st_bytes, c->rd_bytes, c->name);
309 + }
310 + }
311 + }
312 + rrdset_done(d->st_bytes);
313 + }
314 +
315 + // --------------------------------------------------------------------
316 + // packets
317 +
318 + if(d->enabled_packets == CONFIG_ONDEMAND_YES || (d->enabled_packets == CONFIG_ONDEMAND_ONDEMAND && packets_sum)) {
319 + d->enabled_packets = CONFIG_ONDEMAND_YES;
320 +
321 + if(unlikely(!d->st_packets)) {
322 + char id[RRD_ID_LENGTH_MAX + 1];
323 + char name[RRD_ID_LENGTH_MAX + 1];
324 + snprintfz(id, RRD_ID_LENGTH_MAX, "%s_packets", d->id);
325 + snprintfz(name, RRD_ID_LENGTH_MAX, "%s_packets", d->name?d->name:d->id);
326 +
327 + d->st_packets = rrdset_find_bytype(RRD_TYPE_TC, id);
328 + if(unlikely(!d->st_packets)) {
329 + debug(D_TC_LOOP, "TC: Creating new _packets chart for device '%s'", d->name?d->name:d->id);
330 + d->st_packets = rrdset_create(RRD_TYPE_TC, id, name, d->family?d->family:d->id, RRD_TYPE_TC ".qos_packets", "Class Packets", "packets/s", 7010, rrd_update_every, RRDSET_TYPE_STACKED);
331 + }
332 + }
333 + else {
334 + debug(D_TC_LOOP, "TC: Updating _packets chart for device '%s'", d->name?d->name:d->id);
335 + rrdset_next_plugins(d->st_packets);
336 +
337 + // FIXME
338 + // update the family
339 + }
340 +
341 + for(c = d->classes ; c ; c = c->next) {
342 + if(unlikely(!c->updated)) continue;
343 +
344 + if(c->isleaf && c->hasparent) {
345 + if(unlikely(!c->rd_packets)) {
346 + c->rd_packets = rrddim_find(d->st_packets, c->id);
347 + if(unlikely(!c->rd_packets)) {
348 + debug(D_TC_LOOP, "TC: Adding to chart '%s', dimension '%s' (name: '%s')", d->st_packets->id, c->id, c->name);
349 +
350 + // new class, we have to add it
351 + c->rd_packets = rrddim_add(d->st_packets, c->id, c->name?c->name:c->id, 1, 1, RRDDIM_INCREMENTAL);
352 + }
353 + else debug(D_TC_LOOP, "TC: Updating chart '%s', dimension '%s'", d->st_packets->id, c->id);
354 + }
355 +
356 + rrddim_set_by_pointer(d->st_packets, c->rd_packets, c->packets);
357 +
358 + // if it has a name, different to the id
359 + if(unlikely(c->name_updated && c->name && strcmp(c->id, c->name) != 0)) {
360 + // update the rrd dimension with the new name
361 + debug(D_TC_LOOP, "TC: Setting chart '%s', dimension '%s' name to '%s'", d->st_packets->id, c->rd_packets->id, c->name);
362 + rrddim_set_name(d->st_packets, c->rd_packets, c->name);
363 + }
364 + }
365 + }
366 + rrdset_done(d->st_packets);
367 + }
368 +
369 + // --------------------------------------------------------------------
370 + // dropped
371 +
372 + if(d->enabled_dropped == CONFIG_ONDEMAND_YES || (d->enabled_dropped == CONFIG_ONDEMAND_ONDEMAND && dropped_sum)) {
373 + d->enabled_dropped = CONFIG_ONDEMAND_YES;
374 +
375 + if(unlikely(!d->st_dropped)) {
376 + char id[RRD_ID_LENGTH_MAX + 1];
377 + char name[RRD_ID_LENGTH_MAX + 1];
378 + snprintfz(id, RRD_ID_LENGTH_MAX, "%s_dropped", d->id);
379 + snprintfz(name, RRD_ID_LENGTH_MAX, "%s_dropped", d->name?d->name:d->id);
380 +
381 + d->st_dropped = rrdset_find_bytype(RRD_TYPE_TC, id);
382 + if(unlikely(!d->st_dropped)) {
383 + debug(D_TC_LOOP, "TC: Creating new _dropped chart for device '%s'", d->name?d->name:d->id);
384 + d->st_dropped = rrdset_create(RRD_TYPE_TC, id, name, d->family?d->family:d->id, RRD_TYPE_TC ".qos_dropped", "Class Dropped Packets", "packets/s", 7020, rrd_update_every, RRDSET_TYPE_STACKED);
385 + }
386 + }
387 + else {
388 + debug(D_TC_LOOP, "TC: Updating _dropped chart for device '%s'", d->name?d->name:d->id);
389 + rrdset_next_plugins(d->st_dropped);
390 +
391 + // FIXME
392 + // update the family
393 + }
394 +
395 + for(c = d->classes ; c ; c = c->next) {
396 + if(unlikely(!c->updated)) continue;
397 +
398 + if(c->isleaf && c->hasparent) {
399 + if(unlikely(!c->rd_dropped)) {
400 + c->rd_dropped = rrddim_find(d->st_dropped, c->id);
401 + if(unlikely(!c->rd_dropped)) {
402 + debug(D_TC_LOOP, "TC: Adding to chart '%s', dimension '%s' (name: '%s')", d->st_dropped->id, c->id, c->name);
403 +
404 + // new class, we have to add it
405 + c->rd_dropped = rrddim_add(d->st_dropped, c->id, c->name?c->name:c->id, 1, 1, RRDDIM_INCREMENTAL);
406 + }
407 + else debug(D_TC_LOOP, "TC: Updating chart '%s', dimension '%s'", d->st_dropped->id, c->id);
408 + }
409 +
410 + rrddim_set_by_pointer(d->st_dropped, c->rd_dropped, c->dropped);
411 +
412 + // if it has a name, different to the id
413 + if(unlikely(c->name_updated && c->name && strcmp(c->id, c->name) != 0)) {
414 + // update the rrd dimension with the new name
415 + debug(D_TC_LOOP, "TC: Setting chart '%s', dimension '%s' name to '%s'", d->st_dropped->id, c->rd_dropped->id, c->name);
416 + rrddim_set_name(d->st_dropped, c->rd_dropped, c->name);
417 + }
418 + }
419 + }
420 + rrdset_done(d->st_dropped);
421 + }
422 + }
423 +
424 + tc_device_classes_cleanup(d);
425 }
426
427 static inline void tc_device_set_class_name(struct tc_device *d, char *id, char *name)
428 {
429 - struct tc_class *c = tc_class_index_find(d, id, 0);
430 - if(likely(c)) {
431 - freez(c->name);
432 - c->name = NULL;
433 -
434 - if(likely(name && *name && strcmp(c->id, name) != 0)) {
435 - debug(D_TC_LOOP, "TC: Setting device '%s', class '%s' name to '%s'", d->id, id, name);
436 - c->name = strdupz(name);
437 - c->name_updated = 1;
438 - }
439 - }
429 + struct tc_class *c = tc_class_index_find(d, id, 0);
430 + if(likely(c)) {
431 + freez(c->name);
432 + c->name = NULL;
433 +
434 + if(likely(name && *name && strcmp(c->id, name) != 0)) {
435 + debug(D_TC_LOOP, "TC: Setting device '%s', class '%s' name to '%s'", d->id, id, name);
436 + c->name = strdupz(name);
437 + c->name_updated = 1;
438 + }
439 + }
440 }
441
442 static inline void tc_device_set_device_name(struct tc_device *d, char *name) {
443 - freez(d->name);
444 - d->name = NULL;
445 -
446 - if(likely(name && *name && strcmp(d->id, name) != 0)) {
447 - debug(D_TC_LOOP, "TC: Setting device '%s' name to '%s'", d->id, name);
448 - d->name = strdupz(name);
449 - d->name_updated = 1;
450 - }
443 + freez(d->name);
444 + d->name = NULL;
445 +
446 + if(likely(name && *name && strcmp(d->id, name) != 0)) {
447 + debug(D_TC_LOOP, "TC: Setting device '%s' name to '%s'", d->id, name);
448 + d->name = strdupz(name);
449 + d->name_updated = 1;
450 + }
451 }
452
453 static inline void tc_device_set_device_family(struct tc_device *d, char *family) {
454 - freez(d->family);
455 - d->family = NULL;
456 -
457 - if(likely(family && *family && strcmp(d->id, family) != 0)) {
458 - debug(D_TC_LOOP, "TC: Setting device '%s' family to '%s'", d->id, family);
459 - d->family = strdupz(family);
460 - d->family_updated = 1;
461 - }
462 - // no need for null termination - it is already null
454 + freez(d->family);
455 + d->family = NULL;
456 +
457 + if(likely(family && *family && strcmp(d->id, family) != 0)) {
458 + debug(D_TC_LOOP, "TC: Setting device '%s' family to '%s'", d->id, family);
459 + d->family = strdupz(family);
460 + d->family_updated = 1;
461 + }
462 + // no need for null termination - it is already null
463 }
464
465 static inline struct tc_device *tc_device_create(char *id)
466 {
467 - struct tc_device *d = tc_device_index_find(id, 0);
467 + struct tc_device *d = tc_device_index_find(id, 0);
468
469 - if(!d) {
470 - debug(D_TC_LOOP, "TC: Creating device '%s'", id);
469 + if(!d) {
470 + debug(D_TC_LOOP, "TC: Creating device '%s'", id);
471
472 - d = callocz(1, sizeof(struct tc_device));
472 + d = callocz(1, sizeof(struct tc_device));
473
474 - d->id = strdupz(id);
475 - d->hash = simple_hash(d->id);
476 - d->enabled = -1;
474 + d->id = strdupz(id);
475 + d->hash = simple_hash(d->id);
476 + d->enabled = -1;
477
478 - avl_init(&d->classes_index, tc_class_compare);
479 - tc_device_index_add(d);
478 + avl_init(&d->classes_index, tc_class_compare);
479 + tc_device_index_add(d);
480
481 - if(!tc_device_root) {
482 - tc_device_root = d;
483 - }
484 - else {
485 - d->next = tc_device_root;
486 - tc_device_root->prev = d;
487 - tc_device_root = d;
488 - }
489 - }
481 + if(!tc_device_root) {
482 + tc_device_root = d;
483 + }
484 + else {
485 + d->next = tc_device_root;
486 + tc_device_root->prev = d;
487 + tc_device_root = d;
488 + }
489 + }
490
491 - return(d);
491 + return(d);
492 }
493
494 static inline struct tc_class *tc_class_add(struct tc_device *n, char *id, char *parentid, char *leafid)
495 {
496 - struct tc_class *c = tc_class_index_find(n, id, 0);
496 + struct tc_class *c = tc_class_index_find(n, id, 0);
497
498 - if(!c) {
499 - debug(D_TC_LOOP, "TC: Creating in device '%s', class id '%s', parentid '%s', leafid '%s'", n->id, id, parentid?parentid:"", leafid?leafid:"");
498 + if(!c) {
499 + debug(D_TC_LOOP, "TC: Creating in device '%s', class id '%s', parentid '%s', leafid '%s'", n->id, id, parentid?parentid:"", leafid?leafid:"");
500
501 - c = callocz(1, sizeof(struct tc_class));
501 + c = callocz(1, sizeof(struct tc_class));
502
503 - if(n->classes) n->classes->prev = c;
504 - c->next = n->classes;
505 - n->classes = c;
503 + if(n->classes) n->classes->prev = c;
504 + c->next = n->classes;
505 + n->classes = c;
506
507 - c->id = strdupz(id);
508 - c->hash = simple_hash(c->id);
507 + c->id = strdupz(id);
508 + c->hash = simple_hash(c->id);
509
510 - if(parentid && *parentid) {
511 - c->parentid = strdupz(parentid);
512 - c->parent_hash = simple_hash(c->parentid);
513 - }
510 + if(parentid && *parentid) {
511 + c->parentid = strdupz(parentid);
512 + c->parent_hash = simple_hash(c->parentid);
513 + }
514
515 - if(leafid && *leafid) {
516 - c->leafid = strdupz(leafid);
517 - c->leaf_hash = simple_hash(c->leafid);
518 - }
515 + if(leafid && *leafid) {
516 + c->leafid = strdupz(leafid);
517 + c->leaf_hash = simple_hash(c->leafid);
518 + }
519
520 - tc_class_index_add(n, c);
521 - }
520 + tc_class_index_add(n, c);
521 + }
522
523 - c->seen = 1;
523 + c->seen = 1;
524
525 - return(c);
525 + return(c);
526 }
527
528 static inline void tc_device_free(struct tc_device *n)
529 {
530 - if(n->next) n->next->prev = n->prev;
531 - if(n->prev) n->prev->next = n->next;
532 - if(tc_device_root == n) {
533 - if(n->next) tc_device_root = n->next;
534 - else tc_device_root = n->prev;
535 - }
530 + if(n->next) n->next->prev = n->prev;
531 + if(n->prev) n->prev->next = n->next;
532 + if(tc_device_root == n) {
533 + if(n->next) tc_device_root = n->next;
534 + else tc_device_root = n->prev;
535 + }
536
537 - tc_device_index_del(n);
537 + tc_device_index_del(n);
538
539 - while(n->classes) tc_class_free(n, n->classes);
539 + while(n->classes) tc_class_free(n, n->classes);
540
541 - freez(n->id);
542 - freez(n->name);
543 - freez(n->family);
544 - freez(n);
541 + freez(n->id);
542 + freez(n->name);
543 + freez(n->family);
544 + freez(n);
545 }
546
547 static inline void tc_device_free_all()
548 {
549 - while(tc_device_root)
550 - tc_device_free(tc_device_root);
549 + while(tc_device_root)
550 + tc_device_free(tc_device_root);
551 }
552
553 #define MAX_WORDS 20
554
555 static inline int tc_space(char c) {
556 - switch(c) {
557 - case ' ':
558 - case '\t':
559 - case '\r':
560 - case '\n':
561 - return 1;
562 -
563 - default:
564 - return 0;
565 - }
556 + switch(c) {
557 + case ' ':
558 + case '\t':
559 + case '\r':
560 + case '\n':
561 + return 1;
562 +
563 + default:
564 + return 0;
565 + }
566 }
567
568 static inline void tc_split_words(char *str, char **words, int max_words) {
569 - char *s = str;
570 - int i = 0;
569 + char *s = str;
570 + int i = 0;
571
572 - // skip all white space
573 - while(tc_space(*s)) s++;
572 + // skip all white space
573 + while(tc_space(*s)) s++;
574
575 - // store the first word
576 - words[i++] = s;
575 + // store the first word
576 + words[i++] = s;
577
578 - // while we have something
579 - while(*s) {
580 - // if it is a space
581 - if(unlikely(tc_space(*s))) {
578 + // while we have something
579 + while(*s) {
580 + // if it is a space
581 + if(unlikely(tc_space(*s))) {
582
583 - // terminate the word
584 - *s++ = '\0';
583 + // terminate the word
584 + *s++ = '\0';
585
586 - // skip all white space
587 - while(tc_space(*s)) s++;
586 + // skip all white space
587 + while(tc_space(*s)) s++;
588
589 - // if we reached the end, stop
590 - if(!*s) break;
589 + // if we reached the end, stop
590 + if(!*s) break;
591
592 - // store the next word
593 - if(i < max_words) words[i++] = s;
594 - else break;
595 - }
596 - else s++;
597 - }
592 + // store the next word
593 + if(i < max_words) words[i++] = s;
594 + else break;
595 + }
596 + else s++;
597 + }
598
599 - // terminate the words
600 - while(i < max_words) words[i++] = NULL;
599 + // terminate the words
600 + while(i < max_words) words[i++] = NULL;
601 }
602
603 pid_t tc_child_pid = 0;
604 void *tc_main(void *ptr) {
605 - (void)ptr;
605 + (void)ptr;
606
607 - info("TC thread created with task id %d", gettid());
607 + info("TC thread created with task id %d", gettid());
608
609 - if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
610 - error("Cannot set pthread cancel type to DEFERRED.");
609 + if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
610 + error("Cannot set pthread cancel type to DEFERRED.");
611
612 - if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
613 - error("Cannot set pthread cancel state to ENABLE.");
612 + if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
613 + error("Cannot set pthread cancel state to ENABLE.");
614
615 - struct rusage thread;
616 - RRDSET *stcpu = NULL, *sttime = NULL;
615 + struct rusage thread;
616 + RRDSET *stcpu = NULL, *sttime = NULL;
617
618 - char buffer[TC_LINE_MAX+1] = "";
619 - char *words[MAX_WORDS] = { NULL };
618 + char buffer[TC_LINE_MAX+1] = "";
619 + char *words[MAX_WORDS] = { NULL };
620
621 - uint32_t BEGIN_HASH = simple_hash("BEGIN");
622 - uint32_t END_HASH = simple_hash("END");
623 - uint32_t CLASS_HASH = simple_hash("class");
624 - uint32_t SENT_HASH = simple_hash("Sent");
625 - uint32_t LENDED_HASH = simple_hash("lended:");
626 - uint32_t TOKENS_HASH = simple_hash("tokens:");
627 - uint32_t SETDEVICENAME_HASH = simple_hash("SETDEVICENAME");
628 - uint32_t SETDEVICEGROUP_HASH = simple_hash("SETDEVICEGROUP");
629 - uint32_t SETCLASSNAME_HASH = simple_hash("SETCLASSNAME");
630 - uint32_t WORKTIME_HASH = simple_hash("WORKTIME");
621 + uint32_t BEGIN_HASH = simple_hash("BEGIN");
622 + uint32_t END_HASH = simple_hash("END");
623 + uint32_t CLASS_HASH = simple_hash("class");
624 + uint32_t SENT_HASH = simple_hash("Sent");
625 + uint32_t LENDED_HASH = simple_hash("lended:");
626 + uint32_t TOKENS_HASH = simple_hash("tokens:");
627 + uint32_t SETDEVICENAME_HASH = simple_hash("SETDEVICENAME");
628 + uint32_t SETDEVICEGROUP_HASH = simple_hash("SETDEVICEGROUP");
629 + uint32_t SETCLASSNAME_HASH = simple_hash("SETCLASSNAME");
630 + uint32_t WORKTIME_HASH = simple_hash("WORKTIME");
631 #ifdef DETACH_PLUGINS_FROM_NETDATA
632 - uint32_t MYPID_HASH = simple_hash("MYPID");
632 + uint32_t MYPID_HASH = simple_hash("MYPID");
633 #endif
634 - uint32_t first_hash;
635 -
636 - snprintfz(buffer, TC_LINE_MAX, "%s/tc-qos-helper.sh", config_get("plugins", "plugins directory", PLUGINS_DIR));
637 - char *tc_script = config_get("plugin:tc", "script to run to get tc values", buffer);
638 -
639 - for(;1;) {
640 - if(unlikely(netdata_exit)) break;
641 -
642 - FILE *fp;
643 - struct tc_device *device = NULL;
644 - struct tc_class *class = NULL;
645 -
646 - snprintfz(buffer, TC_LINE_MAX, "exec %s %d", tc_script, rrd_update_every);
647 - debug(D_TC_LOOP, "executing '%s'", buffer);
648 -
649 - fp = mypopen(buffer, &tc_child_pid);
650 - if(unlikely(!fp)) {
651 - error("TC: Cannot popen(\"%s\", \"r\").", buffer);
652 - pthread_exit(NULL);
653 - return NULL;
654 - }
655 -
656 - while(fgets(buffer, TC_LINE_MAX, fp) != NULL) {
657 - if(unlikely(netdata_exit)) break;
658 -
659 - buffer[TC_LINE_MAX] = '\0';
660 - // debug(D_TC_LOOP, "TC: read '%s'", buffer);
661 -
662 - tc_split_words(buffer, words, MAX_WORDS);
663 -
664 - if(unlikely(!words[0] || !*words[0])) {
665 - // debug(D_TC_LOOP, "empty line");
666 - continue;
667 - }
668 - // else debug(D_TC_LOOP, "First word is '%s'", words[0]);
669 -
670 - first_hash = simple_hash(words[0]);
671 -
672 - if(unlikely(device && first_hash == CLASS_HASH && strcmp(words[0], "class") == 0)) {
673 - // debug(D_TC_LOOP, "CLASS line on class id='%s', parent='%s', parentid='%s', leaf='%s', leafid='%s'", words[2], words[3], words[4], words[5], words[6]);
674 -
675 - // words[1] : class type
676 - // words[2] : N:XX
677 - // words[3] : parent or root
678 - if(likely(words[1] && words[2] && words[3] && (strcmp(words[3], "parent") == 0 || strcmp(words[3], "root") == 0))) {
679 - //char *type = words[1]; // the class: htb, fq_codel, etc
680 -
681 - // we are only interested for HTB classes
682 - //if(strcmp(type, "htb") != 0) continue;
683 -
684 - char *id = words[2]; // the class major:minor
685 - char *parent = words[3]; // 'parent' or 'root'
686 - char *parentid = words[4]; // the parent's id
687 - char *leaf = words[5]; // 'leaf'
688 - char *leafid = words[6]; // leafid
689 -
690 - if(strcmp(parent, "root") == 0) {
691 - parentid = NULL;
692 - leafid = NULL;
693 - }
694 - else if(!leaf || strcmp(leaf, "leaf") != 0)
695 - leafid = NULL;
696 -
697 - char leafbuf[20 + 1] = "";
698 - if(leafid && leafid[strlen(leafid) - 1] == ':') {
699 - strncpyz(leafbuf, leafid, 20 - 1);
700 - strcat(leafbuf, "1");
701 - leafid = leafbuf;
702 - }
703 -
704 - class = tc_class_add(device, id, parentid, leafid);
705 - }
706 - else {
707 - // clear the last class
708 - class = NULL;
709 - }
710 - }
711 - else if(unlikely(first_hash == END_HASH && strcmp(words[0], "END") == 0)) {
712 - // debug(D_TC_LOOP, "END line");
713 -
714 - if(likely(device)) {
715 - if(pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL) != 0)
716 - error("Cannot set pthread cancel state to DISABLE.");
717 -
718 - tc_device_commit(device);
719 - // tc_device_free(device);
720 -
721 - if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
722 - error("Cannot set pthread cancel state to ENABLE.");
723 - }
724 -
725 - device = NULL;
726 - class = NULL;
727 - }
728 - else if(unlikely(first_hash == BEGIN_HASH && strcmp(words[0], "BEGIN") == 0)) {
729 - // debug(D_TC_LOOP, "BEGIN line on device '%s'", words[1]);
730 -
731 - if(likely(words[1] && *words[1])) {
732 - device = tc_device_create(words[1]);
733 - }
734 - else {
735 - // tc_device_free(device);
736 - device = NULL;
737 - }
738 -
739 - class = NULL;
740 - }
741 - else if(unlikely(device && class && first_hash == SENT_HASH && strcmp(words[0], "Sent") == 0)) {
742 - // debug(D_TC_LOOP, "SENT line '%s'", words[1]);
743 - if(likely(words[1] && *words[1])) {
744 - class->bytes = strtoull(words[1], NULL, 10);
745 - class->updated = 1;
746 - }
747 - else {
748 - class->updated = 0;
749 - }
750 -
751 - if(likely(words[3] && *words[3]))
752 - class->packets = strtoull(words[3], NULL, 10);
753 -
754 - if(likely(words[6] && *words[6]))
755 - class->dropped = strtoull(words[6], NULL, 10);
756 -
757 - if(likely(words[8] && *words[8]))
758 - class->overlimits = strtoull(words[8], NULL, 10);
759 -
760 - if(likely(words[10] && *words[10]))
761 - class->requeues = strtoull(words[8], NULL, 10);
762 - }
763 - else if(unlikely(device && class && class->updated && first_hash == LENDED_HASH && strcmp(words[0], "lended:") == 0)) {
764 - // debug(D_TC_LOOP, "LENDED line '%s'", words[1]);
765 - if(likely(words[1] && *words[1]))
766 - class->lended = strtoull(words[1], NULL, 10);
767 -
768 - if(likely(words[3] && *words[3]))
769 - class->borrowed = strtoull(words[3], NULL, 10);
770 -
771 - if(likely(words[5] && *words[5]))
772 - class->giants = strtoull(words[5], NULL, 10);
773 - }
774 - else if(unlikely(device && class && class->updated && first_hash == TOKENS_HASH && strcmp(words[0], "tokens:") == 0)) {
775 - // debug(D_TC_LOOP, "TOKENS line '%s'", words[1]);
776 - if(likely(words[1] && *words[1]))
777 - class->tokens = strtoull(words[1], NULL, 10);
778 -
779 - if(likely(words[3] && *words[3]))
780 - class->ctokens = strtoull(words[3], NULL, 10);
781 - }
782 - else if(unlikely(device && first_hash == SETDEVICENAME_HASH && strcmp(words[0], "SETDEVICENAME") == 0)) {
783 - // debug(D_TC_LOOP, "SETDEVICENAME line '%s'", words[1]);
784 - if(likely(words[1] && *words[1]))
785 - tc_device_set_device_name(device, words[1]);
786 - }
787 - else if(unlikely(device && first_hash == SETDEVICEGROUP_HASH && strcmp(words[0], "SETDEVICEGROUP") == 0)) {
788 - // debug(D_TC_LOOP, "SETDEVICEGROUP line '%s'", words[1]);
789 - if(likely(words[1] && *words[1]))
790 - tc_device_set_device_family(device, words[1]);
791 - }
792 - else if(unlikely(device && first_hash == SETCLASSNAME_HASH && strcmp(words[0], "SETCLASSNAME") == 0)) {
793 - // debug(D_TC_LOOP, "SETCLASSNAME line '%s' '%s'", words[1], words[2]);
794 - char *id = words[1];
795 - char *path = words[2];
796 - if(likely(id && *id && path && *path))
797 - tc_device_set_class_name(device, id, path);
798 - }
799 - else if(unlikely(first_hash == WORKTIME_HASH && strcmp(words[0], "WORKTIME") == 0)) {
800 - // debug(D_TC_LOOP, "WORKTIME line '%s' '%s'", words[1], words[2]);
801 - getrusage(RUSAGE_THREAD, &thread);
802 -
803 - if(unlikely(!stcpu)) stcpu = rrdset_find("netdata.plugin_tc_cpu");
804 - if(unlikely(!stcpu)) {
805 - stcpu = rrdset_create("netdata", "plugin_tc_cpu", NULL, "tc.helper", NULL, "NetData TC CPU usage", "milliseconds/s", 135000, rrd_update_every, RRDSET_TYPE_STACKED);
806 - rrddim_add(stcpu, "user", NULL, 1, 1000, RRDDIM_INCREMENTAL);
807 - rrddim_add(stcpu, "system", NULL, 1, 1000, RRDDIM_INCREMENTAL);
808 - }
809 - else rrdset_next(stcpu);
810 -
811 - rrddim_set(stcpu, "user" , thread.ru_utime.tv_sec * 1000000ULL + thread.ru_utime.tv_usec);
812 - rrddim_set(stcpu, "system", thread.ru_stime.tv_sec * 1000000ULL + thread.ru_stime.tv_usec);
813 - rrdset_done(stcpu);
814 -
815 - if(unlikely(!sttime)) stcpu = rrdset_find("netdata.plugin_tc_time");
816 - if(unlikely(!sttime)) {
817 - sttime = rrdset_create("netdata", "plugin_tc_time", NULL, "tc.helper", NULL, "NetData TC script execution", "milliseconds/run", 135001, rrd_update_every, RRDSET_TYPE_AREA);
818 - rrddim_add(sttime, "run_time", "run time", 1, 1, RRDDIM_ABSOLUTE);
819 - }
820 - else rrdset_next(sttime);
821 -
822 - rrddim_set(sttime, "run_time", atoll(words[1]));
823 - rrdset_done(sttime);
824 -
825 - }
634 + uint32_t first_hash;
635 +
636 + snprintfz(buffer, TC_LINE_MAX, "%s/tc-qos-helper.sh", config_get("plugins", "plugins directory", PLUGINS_DIR));
637 + char *tc_script = config_get("plugin:tc", "script to run to get tc values", buffer);
638 +
639 + for(;1;) {
640 + if(unlikely(netdata_exit)) break;
641 +
642 + FILE *fp;
643 + struct tc_device *device = NULL;
644 + struct tc_class *class = NULL;
645 +
646 + snprintfz(buffer, TC_LINE_MAX, "exec %s %d", tc_script, rrd_update_every);
647 + debug(D_TC_LOOP, "executing '%s'", buffer);
648 +
649 + fp = mypopen(buffer, &tc_child_pid);
650 + if(unlikely(!fp)) {
651 + error("TC: Cannot popen(\"%s\", \"r\").", buffer);
652 + pthread_exit(NULL);
653 + return NULL;
654 + }
655 +
656 + while(fgets(buffer, TC_LINE_MAX, fp) != NULL) {
657 + if(unlikely(netdata_exit)) break;
658 +
659 + buffer[TC_LINE_MAX] = '\0';
660 + // debug(D_TC_LOOP, "TC: read '%s'", buffer);
661 +
662 + tc_split_words(buffer, words, MAX_WORDS);
663 +
664 + if(unlikely(!words[0] || !*words[0])) {
665 + // debug(D_TC_LOOP, "empty line");
666 + continue;
667 + }
668 + // else debug(D_TC_LOOP, "First word is '%s'", words[0]);
669 +
670 + first_hash = simple_hash(words[0]);
671 +
672 + if(unlikely(device && first_hash == CLASS_HASH && strcmp(words[0], "class") == 0)) {
673 + // debug(D_TC_LOOP, "CLASS line on class id='%s', parent='%s', parentid='%s', leaf='%s', leafid='%s'", words[2], words[3], words[4], words[5], words[6]);
674 +
675 + // words[1] : class type
676 + // words[2] : N:XX
677 + // words[3] : parent or root
678 + if(likely(words[1] && words[2] && words[3] && (strcmp(words[3], "parent") == 0 || strcmp(words[3], "root") == 0))) {
679 + //char *type = words[1]; // the class: htb, fq_codel, etc
680 +
681 + // we are only interested for HTB classes
682 + //if(strcmp(type, "htb") != 0) continue;
683 +
684 + char *id = words[2]; // the class major:minor
685 + char *parent = words[3]; // 'parent' or 'root'
686 + char *parentid = words[4]; // the parent's id
687 + char *leaf = words[5]; // 'leaf'
688 + char *leafid = words[6]; // leafid
689 +
690 + if(strcmp(parent, "root") == 0) {
691 + parentid = NULL;
692 + leafid = NULL;
693 + }
694 + else if(!leaf || strcmp(leaf, "leaf") != 0)
695 + leafid = NULL;
696 +
697 + char leafbuf[20 + 1] = "";
698 + if(leafid && leafid[strlen(leafid) - 1] == ':') {
699 + strncpyz(leafbuf, leafid, 20 - 1);
700 + strcat(leafbuf, "1");
701 + leafid = leafbuf;
702 + }
703 +
704 + class = tc_class_add(device, id, parentid, leafid);
705 + }
706 + else {
707 + // clear the last class
708 + class = NULL;
709 + }
710 + }
711 + else if(unlikely(first_hash == END_HASH && strcmp(words[0], "END") == 0)) {
712 + // debug(D_TC_LOOP, "END line");
713 +
714 + if(likely(device)) {
715 + if(pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL) != 0)
716 + error("Cannot set pthread cancel state to DISABLE.");
717 +
718 + tc_device_commit(device);
719 + // tc_device_free(device);
720 +
721 + if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
722 + error("Cannot set pthread cancel state to ENABLE.");
723 + }
724 +
725 + device = NULL;
726 + class = NULL;
727 + }
728 + else if(unlikely(first_hash == BEGIN_HASH && strcmp(words[0], "BEGIN") == 0)) {
729 + // debug(D_TC_LOOP, "BEGIN line on device '%s'", words[1]);
730 +
731 + if(likely(words[1] && *words[1])) {
732 + device = tc_device_create(words[1]);
733 + }
734 + else {
735 + // tc_device_free(device);
736 + device = NULL;
737 + }
738 +
739 + class = NULL;
740 + }
741 + else if(unlikely(device && class && first_hash == SENT_HASH && strcmp(words[0], "Sent") == 0)) {
742 + // debug(D_TC_LOOP, "SENT line '%s'", words[1]);
743 + if(likely(words[1] && *words[1])) {
744 + class->bytes = strtoull(words[1], NULL, 10);
745 + class->updated = 1;
746 + }
747 + else {
748 + class->updated = 0;
749 + }
750 +
751 + if(likely(words[3] && *words[3]))
752 + class->packets = strtoull(words[3], NULL, 10);
753 +
754 + if(likely(words[6] && *words[6]))
755 + class->dropped = strtoull(words[6], NULL, 10);
756 +
757 + if(likely(words[8] && *words[8]))
758 + class->overlimits = strtoull(words[8], NULL, 10);
759 +
760 + if(likely(words[10] && *words[10]))
761 + class->requeues = strtoull(words[8], NULL, 10);
762 + }
763 + else if(unlikely(device && class && class->updated && first_hash == LENDED_HASH && strcmp(words[0], "lended:") == 0)) {
764 + // debug(D_TC_LOOP, "LENDED line '%s'", words[1]);
765 + if(likely(words[1] && *words[1]))
766 + class->lended = strtoull(words[1], NULL, 10);
767 +
768 + if(likely(words[3] && *words[3]))
769 + class->borrowed = strtoull(words[3], NULL, 10);
770 +
771 + if(likely(words[5] && *words[5]))
772 + class->giants = strtoull(words[5], NULL, 10);
773 + }
774 + else if(unlikely(device && class && class->updated && first_hash == TOKENS_HASH && strcmp(words[0], "tokens:") == 0)) {
775 + // debug(D_TC_LOOP, "TOKENS line '%s'", words[1]);
776 + if(likely(words[1] && *words[1]))
777 + class->tokens = strtoull(words[1], NULL, 10);
778 +
779 + if(likely(words[3] && *words[3]))
780 + class->ctokens = strtoull(words[3], NULL, 10);
781 + }
782 + else if(unlikely(device && first_hash == SETDEVICENAME_HASH && strcmp(words[0], "SETDEVICENAME") == 0)) {
783 + // debug(D_TC_LOOP, "SETDEVICENAME line '%s'", words[1]);
784 + if(likely(words[1] && *words[1]))
785 + tc_device_set_device_name(device, words[1]);
786 + }
787 + else if(unlikely(device && first_hash == SETDEVICEGROUP_HASH && strcmp(words[0], "SETDEVICEGROUP") == 0)) {
788 + // debug(D_TC_LOOP, "SETDEVICEGROUP line '%s'", words[1]);
789 + if(likely(words[1] && *words[1]))
790 + tc_device_set_device_family(device, words[1]);
791 + }
792 + else if(unlikely(device && first_hash == SETCLASSNAME_HASH && strcmp(words[0], "SETCLASSNAME") == 0)) {
793 + // debug(D_TC_LOOP, "SETCLASSNAME line '%s' '%s'", words[1], words[2]);
794 + char *id = words[1];
795 + char *path = words[2];
796 + if(likely(id && *id && path && *path))
797 + tc_device_set_class_name(device, id, path);
798 + }
799 + else if(unlikely(first_hash == WORKTIME_HASH && strcmp(words[0], "WORKTIME") == 0)) {
800 + // debug(D_TC_LOOP, "WORKTIME line '%s' '%s'", words[1], words[2]);
801 + getrusage(RUSAGE_THREAD, &thread);
802 +
803 + if(unlikely(!stcpu)) stcpu = rrdset_find("netdata.plugin_tc_cpu");
804 + if(unlikely(!stcpu)) {
805 + stcpu = rrdset_create("netdata", "plugin_tc_cpu", NULL, "tc.helper", NULL, "NetData TC CPU usage", "milliseconds/s", 135000, rrd_update_every, RRDSET_TYPE_STACKED);
806 + rrddim_add(stcpu, "user", NULL, 1, 1000, RRDDIM_INCREMENTAL);
807 + rrddim_add(stcpu, "system", NULL, 1, 1000, RRDDIM_INCREMENTAL);
808 + }
809 + else rrdset_next(stcpu);
810 +
811 + rrddim_set(stcpu, "user" , thread.ru_utime.tv_sec * 1000000ULL + thread.ru_utime.tv_usec);
812 + rrddim_set(stcpu, "system", thread.ru_stime.tv_sec * 1000000ULL + thread.ru_stime.tv_usec);
813 + rrdset_done(stcpu);
814 +
815 + if(unlikely(!sttime)) stcpu = rrdset_find("netdata.plugin_tc_time");
816 + if(unlikely(!sttime)) {
817 + sttime = rrdset_create("netdata", "plugin_tc_time", NULL, "tc.helper", NULL, "NetData TC script execution", "milliseconds/run", 135001, rrd_update_every, RRDSET_TYPE_AREA);
818 + rrddim_add(sttime, "run_time", "run time", 1, 1, RRDDIM_ABSOLUTE);
819 + }
820 + else rrdset_next(sttime);
821 +
822 + rrddim_set(sttime, "run_time", atoll(words[1]));
823 + rrdset_done(sttime);
824 +
825 + }
826 #ifdef DETACH_PLUGINS_FROM_NETDATA
827 - else if(unlikely(first_hash == MYPID_HASH && (strcmp(words[0], "MYPID") == 0))) {
828 - // debug(D_TC_LOOP, "MYPID line '%s'", words[1]);
829 - char *id = words[1];
830 - pid_t pid = atol(id);
827 + else if(unlikely(first_hash == MYPID_HASH && (strcmp(words[0], "MYPID") == 0))) {
828 + // debug(D_TC_LOOP, "MYPID line '%s'", words[1]);
829 + char *id = words[1];
830 + pid_t pid = atol(id);
831
832 - if(likely(pid)) tc_child_pid = pid;
832 + if(likely(pid)) tc_child_pid = pid;
833
834 - debug(D_TC_LOOP, "TC: Child PID is %d.", tc_child_pid);
835 - }
834 + debug(D_TC_LOOP, "TC: Child PID is %d.", tc_child_pid);
835 + }
836 #endif
837 - //else {
838 - // debug(D_TC_LOOP, "IGNORED line");
839 - //}
840 - }
841 -
842 - // fgets() failed or loop broke
843 - int code = mypclose(fp, tc_child_pid);
844 - tc_child_pid = 0;
845 -
846 - if(unlikely(device)) {
847 - // tc_device_free(device);
848 - device = NULL;
849 - class = NULL;
850 - }
851 -
852 - if(unlikely(netdata_exit)) {
853 - tc_device_free_all();
854 - pthread_exit(NULL);
855 - return NULL;
856 - }
857 -
858 - if(code == 1 || code == 127) {
859 - // 1 = DISABLE
860 - // 127 = cannot even run it
861 - error("TC: tc-qos-helper.sh exited with code %d. Disabling it.", code);
862 -
863 - tc_device_free_all();
864 - pthread_exit(NULL);
865 - return NULL;
866 - }
867 -
868 - sleep((unsigned int) rrd_update_every);
869 - }
870 -
871 - pthread_exit(NULL);
872 - return NULL;
837 + //else {
838 + // debug(D_TC_LOOP, "IGNORED line");
839 + //}
840 + }
841 +
842 + // fgets() failed or loop broke
843 + int code = mypclose(fp, tc_child_pid);
844 + tc_child_pid = 0;
845 +
846 + if(unlikely(device)) {
847 + // tc_device_free(device);
848 + device = NULL;
849 + class = NULL;
850 + }
851 +
852 + if(unlikely(netdata_exit)) {
853 + tc_device_free_all();
854 + pthread_exit(NULL);
855 + return NULL;
856 + }
857 +
858 + if(code == 1 || code == 127) {
859 + // 1 = DISABLE
860 + // 127 = cannot even run it
861 + error("TC: tc-qos-helper.sh exited with code %d. Disabling it.", code);
862 +
863 + tc_device_free_all();
864 + pthread_exit(NULL);
865 + return NULL;
866 + }
867 +
868 + sleep((unsigned int) rrd_update_every);
869 + }
870 +
871 + pthread_exit(NULL);
872 + return NULL;
873 }
src/plugins_d.c
+517 -517
@@ -5,544 +5,544 @@ struct plugind *pluginsd_root = NULL;
5 #define MAX_WORDS 20
6
7 static inline int pluginsd_space(char c) {
8 - switch(c) {
9 - case ' ':
10 - case '\t':
11 - case '\r':
12 - case '\n':
13 - case '=':
14 - return 1;
15 -
16 - default:
17 - return 0;
18 - }
8 + switch(c) {
9 + case ' ':
10 + case '\t':
11 + case '\r':
12 + case '\n':
13 + case '=':
14 + return 1;
15 +
16 + default:
17 + return 0;
18 + }
19 }
20
21 static int pluginsd_split_words(char *str, char **words, int max_words) {
22 - char *s = str, quote = 0;
23 - int i = 0, j;
24 -
25 - // skip all white space
26 - while(unlikely(pluginsd_space(*s))) s++;
27 -
28 - // check for quote
29 - if(unlikely(*s == '\'' || *s == '"')) {
30 - quote = *s; // remember the quote
31 - s++; // skip the quote
32 - }
33 -
34 - // store the first word
35 - words[i++] = s;
36 -
37 - // while we have something
38 - while(likely(*s)) {
39 - // if it is escape
40 - if(unlikely(*s == '\\' && s[1])) {
41 - s += 2;
42 - continue;
43 - }
44 -
45 - // if it is quote
46 - else if(unlikely(*s == quote)) {
47 - quote = 0;
48 - *s = ' ';
49 - continue;
50 - }
51 -
52 - // if it is a space
53 - else if(unlikely(quote == 0 && pluginsd_space(*s))) {
54 -
55 - // terminate the word
56 - *s++ = '\0';
57 -
58 - // skip all white space
59 - while(likely(pluginsd_space(*s))) s++;
60 -
61 - // check for quote
62 - if(unlikely(*s == '\'' || *s == '"')) {
63 - quote = *s; // remember the quote
64 - s++; // skip the quote
65 - }
66 -
67 - // if we reached the end, stop
68 - if(unlikely(!*s)) break;
69 -
70 - // store the next word
71 - if(likely(i < max_words)) words[i++] = s;
72 - else break;
73 - }
74 -
75 - // anything else
76 - else s++;
77 - }
78 -
79 - // terminate the words
80 - j = i;
81 - while(likely(j < max_words)) words[j++] = NULL;
82 -
83 - return i;
22 + char *s = str, quote = 0;
23 + int i = 0, j;
24 +
25 + // skip all white space
26 + while(unlikely(pluginsd_space(*s))) s++;
27 +
28 + // check for quote
29 + if(unlikely(*s == '\'' || *s == '"')) {
30 + quote = *s; // remember the quote
31 + s++; // skip the quote
32 + }
33 +
34 + // store the first word
35 + words[i++] = s;
36 +
37 + // while we have something
38 + while(likely(*s)) {
39 + // if it is escape
40 + if(unlikely(*s == '\\' && s[1])) {
41 + s += 2;
42 + continue;
43 + }
44 +
45 + // if it is quote
46 + else if(unlikely(*s == quote)) {
47 + quote = 0;
48 + *s = ' ';
49 + continue;
50 + }
51 +
52 + // if it is a space
53 + else if(unlikely(quote == 0 && pluginsd_space(*s))) {
54 +
55 + // terminate the word
56 + *s++ = '\0';
57 +
58 + // skip all white space
59 + while(likely(pluginsd_space(*s))) s++;
60 +
61 + // check for quote
62 + if(unlikely(*s == '\'' || *s == '"')) {
63 + quote = *s; // remember the quote
64 + s++; // skip the quote
65 + }
66 +
67 + // if we reached the end, stop
68 + if(unlikely(!*s)) break;
69 +
70 + // store the next word
71 + if(likely(i < max_words)) words[i++] = s;
72 + else break;
73 + }
74 +
75 + // anything else
76 + else s++;
77 + }
78 +
79 + // terminate the words
80 + j = i;
81 + while(likely(j < max_words)) words[j++] = NULL;
82 +
83 + return i;
84 }
85
86
87 void *pluginsd_worker_thread(void *arg)
88 {
89 - struct plugind *cd = (struct plugind *)arg;
90 - char line[PLUGINSD_LINE_MAX + 1];
89 + struct plugind *cd = (struct plugind *)arg;
90 + char line[PLUGINSD_LINE_MAX + 1];
91
92 #ifdef DETACH_PLUGINS_FROM_NETDATA
93 - unsigned long long usec = 0, susec = 0;
94 - struct timeval last = {0, 0} , now = {0, 0};
93 + unsigned long long usec = 0, susec = 0;
94 + struct timeval last = {0, 0} , now = {0, 0};
95 #endif
96
97 - char *words[MAX_WORDS] = { NULL };
98 - uint32_t SET_HASH = simple_hash("SET");
99 - uint32_t BEGIN_HASH = simple_hash("BEGIN");
100 - uint32_t END_HASH = simple_hash("END");
101 - uint32_t FLUSH_HASH = simple_hash("FLUSH");
102 - uint32_t CHART_HASH = simple_hash("CHART");
103 - uint32_t DIMENSION_HASH = simple_hash("DIMENSION");
104 - uint32_t DISABLE_HASH = simple_hash("DISABLE");
97 + char *words[MAX_WORDS] = { NULL };
98 + uint32_t SET_HASH = simple_hash("SET");
99 + uint32_t BEGIN_HASH = simple_hash("BEGIN");
100 + uint32_t END_HASH = simple_hash("END");
101 + uint32_t FLUSH_HASH = simple_hash("FLUSH");
102 + uint32_t CHART_HASH = simple_hash("CHART");
103 + uint32_t DIMENSION_HASH = simple_hash("DIMENSION");
104 + uint32_t DISABLE_HASH = simple_hash("DISABLE");
105 #ifdef DETACH_PLUGINS_FROM_NETDATA
106 - uint32_t MYPID_HASH = simple_hash("MYPID");
107 - uint32_t STOPPING_WAKE_ME_UP_PLEASE_HASH = simple_hash("STOPPING_WAKE_ME_UP_PLEASE");
106 + uint32_t MYPID_HASH = simple_hash("MYPID");
107 + uint32_t STOPPING_WAKE_ME_UP_PLEASE_HASH = simple_hash("STOPPING_WAKE_ME_UP_PLEASE");
108 #endif
109
110 - size_t count = 0;
111 -
112 - while(likely(1)) {
113 - if(unlikely(netdata_exit)) break;
114 -
115 - FILE *fp = mypopen(cd->cmd, &cd->pid);
116 - if(unlikely(!fp)) {
117 - error("Cannot popen(\"%s\", \"r\").", cd->cmd);
118 - break;
119 - }
120 -
121 - info("PLUGINSD: '%s' running on pid %d", cd->fullfilename, cd->pid);
122 -
123 - RRDSET *st = NULL;
124 - char *s;
125 - uint32_t hash;
126 -
127 - while(likely(fgets(line, PLUGINSD_LINE_MAX, fp) != NULL)) {
128 - if(unlikely(netdata_exit)) break;
129 -
130 - line[PLUGINSD_LINE_MAX] = '\0';
131 -
132 - // debug(D_PLUGINSD, "PLUGINSD: %s: %s", cd->filename, line);
133 -
134 - int w = pluginsd_split_words(line, words, MAX_WORDS);
135 - s = words[0];
136 - if(unlikely(!s || !*s || !w)) {
137 - // debug(D_PLUGINSD, "PLUGINSD: empty line");
138 - continue;
139 - }
140 -
141 - // debug(D_PLUGINSD, "PLUGINSD: words 0='%s' 1='%s' 2='%s' 3='%s' 4='%s' 5='%s' 6='%s' 7='%s' 8='%s' 9='%s'", words[0], words[1], words[2], words[3], words[4], words[5], words[6], words[7], words[8], words[9]);
142 -
143 - hash = simple_hash(s);
144 -
145 - if(likely(hash == SET_HASH && !strcmp(s, "SET"))) {
146 - char *dimension = words[1];
147 - char *value = words[2];
148 -
149 - if(unlikely(!dimension || !*dimension)) {
150 - error("PLUGINSD: '%s' is requesting a SET on chart '%s', without a dimension. Disabling it.", cd->fullfilename, st->id);
151 - cd->enabled = 0;
152 - killpid(cd->pid, SIGTERM);
153 - break;
154 - }
155 -
156 - if(unlikely(!value || !*value)) value = NULL;
157 -
158 - if(unlikely(!st)) {
159 - error("PLUGINSD: '%s' is requesting a SET on dimension %s with value %s, without a BEGIN. Disabling it.", cd->fullfilename, dimension, value?value:"<nothing>");
160 - cd->enabled = 0;
161 - killpid(cd->pid, SIGTERM);
162 - break;
163 - }
164 -
165 - if(unlikely(st->debug)) debug(D_PLUGINSD, "PLUGINSD: '%s' is setting dimension %s/%s to %s", cd->fullfilename, st->id, dimension, value?value:"<nothing>");
166 -
167 - if(value) rrddim_set(st, dimension, strtoll(value, NULL, 0));
168 - }
169 - else if(likely(hash == BEGIN_HASH && !strcmp(s, "BEGIN"))) {
170 - char *id = words[1];
171 - char *microseconds_txt = words[2];
172 -
173 - if(unlikely(!id)) {
174 - error("PLUGINSD: '%s' is requesting a BEGIN without a chart id. Disabling it.", cd->fullfilename);
175 - cd->enabled = 0;
176 - killpid(cd->pid, SIGTERM);
177 - break;
178 - }
179 -
180 - st = rrdset_find(id);
181 - if(unlikely(!st)) {
182 - error("PLUGINSD: '%s' is requesting a BEGIN on chart '%s', which does not exist. Disabling it.", cd->fullfilename, id);
183 - cd->enabled = 0;
184 - killpid(cd->pid, SIGTERM);
185 - break;
186 - }
187 -
188 - if(likely(st->counter_done)) {
189 - unsigned long long microseconds = 0;
190 - if(microseconds_txt && *microseconds_txt) microseconds = strtoull(microseconds_txt, NULL, 10);
191 - if(microseconds) rrdset_next_usec(st, microseconds);
192 - else rrdset_next_plugins(st);
193 - }
194 - }
195 - else if(likely(hash == END_HASH && !strcmp(s, "END"))) {
196 - if(unlikely(!st)) {
197 - error("PLUGINSD: '%s' is requesting an END, without a BEGIN. Disabling it.", cd->fullfilename);
198 - cd->enabled = 0;
199 - killpid(cd->pid, SIGTERM);
200 - break;
201 - }
202 -
203 - if(unlikely(st->debug)) debug(D_PLUGINSD, "PLUGINSD: '%s' is requesting an END on chart %s", cd->fullfilename, st->id);
204 -
205 - rrdset_done(st);
206 - st = NULL;
207 -
208 - count++;
209 - }
210 - else if(likely(hash == FLUSH_HASH && !strcmp(s, "FLUSH"))) {
211 - debug(D_PLUGINSD, "PLUGINSD: '%s' is requesting a FLUSH", cd->fullfilename);
212 - st = NULL;
213 - }
214 - else if(likely(hash == CHART_HASH && !strcmp(s, "CHART"))) {
215 - int noname = 0;
216 - st = NULL;
217 -
218 - if((words[1]) != NULL && (words[2]) != NULL && strcmp(words[1], words[2]) == 0)
219 - noname = 1;
220 -
221 - char *type = words[1];
222 - char *id = NULL;
223 - if(likely(type)) {
224 - id = strchr(type, '.');
225 - if(likely(id)) { *id = '\0'; id++; }
226 - }
227 - char *name = words[2];
228 - char *title = words[3];
229 - char *units = words[4];
230 - char *family = words[5];
231 - char *context = words[6];
232 - char *chart = words[7];
233 - char *priority_s = words[8];
234 - char *update_every_s = words[9];
235 -
236 - if(unlikely(!type || !*type || !id || !*id)) {
237 - error("PLUGINSD: '%s' is requesting a CHART, without a type.id. Disabling it.", cd->fullfilename);
238 - cd->enabled = 0;
239 - killpid(cd->pid, SIGTERM);
240 - break;
241 - }
242 -
243 - int priority = 1000;
244 - if(likely(priority_s)) priority = atoi(priority_s);
245 -
246 - int update_every = cd->update_every;
247 - if(likely(update_every_s)) update_every = atoi(update_every_s);
248 - if(unlikely(!update_every)) update_every = cd->update_every;
249 -
250 - int chart_type = RRDSET_TYPE_LINE;
251 - if(unlikely(chart)) chart_type = rrdset_type_id(chart);
252 -
253 - if(unlikely(noname || !name || !*name || strcasecmp(name, "NULL") == 0 || strcasecmp(name, "(NULL)") == 0)) name = NULL;
254 - if(unlikely(!family || !*family)) family = NULL;
255 - if(unlikely(!context || !*context)) context = NULL;
256 -
257 - st = rrdset_find_bytype(type, id);
258 - if(unlikely(!st)) {
259 - debug(D_PLUGINSD, "PLUGINSD: Creating chart type='%s', id='%s', name='%s', family='%s', context='%s', chart='%s', priority=%d, update_every=%d"
260 - , type, id
261 - , name?name:""
262 - , family?family:""
263 - , context?context:""
264 - , rrdset_type_name(chart_type)
265 - , priority
266 - , update_every
267 - );
268 -
269 - st = rrdset_create(type, id, name, family, context, title, units, priority, update_every, chart_type);
270 - cd->update_every = update_every;
271 - }
272 - else debug(D_PLUGINSD, "PLUGINSD: Chart '%s' already exists. Not adding it again.", st->id);
273 - }
274 - else if(likely(hash == DIMENSION_HASH && !strcmp(s, "DIMENSION"))) {
275 - char *id = words[1];
276 - char *name = words[2];
277 - char *algorithm = words[3];
278 - char *multiplier_s = words[4];
279 - char *divisor_s = words[5];
280 - char *options = words[6];
281 -
282 - if(unlikely(!id || !*id)) {
283 - error("PLUGINSD: '%s' is requesting a DIMENSION, without an id. Disabling it.", cd->fullfilename);
284 - cd->enabled = 0;
285 - killpid(cd->pid, SIGTERM);
286 - break;
287 - }
288 -
289 - if(unlikely(!st)) {
290 - error("PLUGINSD: '%s' is requesting a DIMENSION, without a CHART. Disabling it.", cd->fullfilename);
291 - cd->enabled = 0;
292 - killpid(cd->pid, SIGTERM);
293 - break;
294 - }
295 -
296 - long multiplier = 1;
297 - if(multiplier_s && *multiplier_s) multiplier = strtol(multiplier_s, NULL, 0);
298 - if(unlikely(!multiplier)) multiplier = 1;
299 -
300 - long divisor = 1;
301 - if(likely(divisor_s && *divisor_s)) divisor = strtol(divisor_s, NULL, 0);
302 - if(unlikely(!divisor)) divisor = 1;
303 -
304 - if(unlikely(!algorithm || !*algorithm)) algorithm = "absolute";
305 -
306 - if(unlikely(st->debug)) debug(D_PLUGINSD, "PLUGINSD: Creating dimension in chart %s, id='%s', name='%s', algorithm='%s', multiplier=%ld, divisor=%ld, hidden='%s'"
307 - , st->id
308 - , id
309 - , name?name:""
310 - , rrddim_algorithm_name(rrddim_algorithm_id(algorithm))
311 - , multiplier
312 - , divisor
313 - , options?options:""
314 - );
315 -
316 - RRDDIM *rd = rrddim_find(st, id);
317 - if(unlikely(!rd)) {
318 - rd = rrddim_add(st, id, name, multiplier, divisor, rrddim_algorithm_id(algorithm));
319 - rd->flags = 0x00000000;
320 - if(options && *options) {
321 - if(strstr(options, "hidden") != NULL) rd->flags |= RRDDIM_FLAG_HIDDEN;
322 - if(strstr(options, "noreset") != NULL) rd->flags |= RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS;
323 - if(strstr(options, "nooverflow") != NULL) rd->flags |= RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS;
324 - }
325 - }
326 - else if(unlikely(st->debug)) debug(D_PLUGINSD, "PLUGINSD: dimension %s/%s already exists. Not adding it again.", st->id, id);
327 - }
328 - else if(unlikely(hash == DISABLE_HASH && !strcmp(s, "DISABLE"))) {
329 - error("PLUGINSD: '%s' called DISABLE. Disabling it.", cd->fullfilename);
330 - cd->enabled = 0;
331 - killpid(cd->pid, SIGTERM);
332 - break;
333 - }
110 + size_t count = 0;
111 +
112 + while(likely(1)) {
113 + if(unlikely(netdata_exit)) break;
114 +
115 + FILE *fp = mypopen(cd->cmd, &cd->pid);
116 + if(unlikely(!fp)) {
117 + error("Cannot popen(\"%s\", \"r\").", cd->cmd);
118 + break;
119 + }
120 +
121 + info("PLUGINSD: '%s' running on pid %d", cd->fullfilename, cd->pid);
122 +
123 + RRDSET *st = NULL;
124 + char *s;
125 + uint32_t hash;
126 +
127 + while(likely(fgets(line, PLUGINSD_LINE_MAX, fp) != NULL)) {
128 + if(unlikely(netdata_exit)) break;
129 +
130 + line[PLUGINSD_LINE_MAX] = '\0';
131 +
132 + // debug(D_PLUGINSD, "PLUGINSD: %s: %s", cd->filename, line);
133 +
134 + int w = pluginsd_split_words(line, words, MAX_WORDS);
135 + s = words[0];
136 + if(unlikely(!s || !*s || !w)) {
137 + // debug(D_PLUGINSD, "PLUGINSD: empty line");
138 + continue;
139 + }
140 +
141 + // debug(D_PLUGINSD, "PLUGINSD: words 0='%s' 1='%s' 2='%s' 3='%s' 4='%s' 5='%s' 6='%s' 7='%s' 8='%s' 9='%s'", words[0], words[1], words[2], words[3], words[4], words[5], words[6], words[7], words[8], words[9]);
142 +
143 + hash = simple_hash(s);
144 +
145 + if(likely(hash == SET_HASH && !strcmp(s, "SET"))) {
146 + char *dimension = words[1];
147 + char *value = words[2];
148 +
149 + if(unlikely(!dimension || !*dimension)) {
150 + error("PLUGINSD: '%s' is requesting a SET on chart '%s', without a dimension. Disabling it.", cd->fullfilename, st->id);
151 + cd->enabled = 0;
152 + killpid(cd->pid, SIGTERM);
153 + break;
154 + }
155 +
156 + if(unlikely(!value || !*value)) value = NULL;
157 +
158 + if(unlikely(!st)) {
159 + error("PLUGINSD: '%s' is requesting a SET on dimension %s with value %s, without a BEGIN. Disabling it.", cd->fullfilename, dimension, value?value:"<nothing>");
160 + cd->enabled = 0;
161 + killpid(cd->pid, SIGTERM);
162 + break;
163 + }
164 +
165 + if(unlikely(st->debug)) debug(D_PLUGINSD, "PLUGINSD: '%s' is setting dimension %s/%s to %s", cd->fullfilename, st->id, dimension, value?value:"<nothing>");
166 +
167 + if(value) rrddim_set(st, dimension, strtoll(value, NULL, 0));
168 + }
169 + else if(likely(hash == BEGIN_HASH && !strcmp(s, "BEGIN"))) {
170 + char *id = words[1];
171 + char *microseconds_txt = words[2];
172 +
173 + if(unlikely(!id)) {
174 + error("PLUGINSD: '%s' is requesting a BEGIN without a chart id. Disabling it.", cd->fullfilename);
175 + cd->enabled = 0;
176 + killpid(cd->pid, SIGTERM);
177 + break;
178 + }
179 +
180 + st = rrdset_find(id);
181 + if(unlikely(!st)) {
182 + error("PLUGINSD: '%s' is requesting a BEGIN on chart '%s', which does not exist. Disabling it.", cd->fullfilename, id);
183 + cd->enabled = 0;
184 + killpid(cd->pid, SIGTERM);
185 + break;
186 + }
187 +
188 + if(likely(st->counter_done)) {
189 + unsigned long long microseconds = 0;
190 + if(microseconds_txt && *microseconds_txt) microseconds = strtoull(microseconds_txt, NULL, 10);
191 + if(microseconds) rrdset_next_usec(st, microseconds);
192 + else rrdset_next_plugins(st);
193 + }
194 + }
195 + else if(likely(hash == END_HASH && !strcmp(s, "END"))) {
196 + if(unlikely(!st)) {
197 + error("PLUGINSD: '%s' is requesting an END, without a BEGIN. Disabling it.", cd->fullfilename);
198 + cd->enabled = 0;
199 + killpid(cd->pid, SIGTERM);
200 + break;
201 + }
202 +
203 + if(unlikely(st->debug)) debug(D_PLUGINSD, "PLUGINSD: '%s' is requesting an END on chart %s", cd->fullfilename, st->id);
204 +
205 + rrdset_done(st);
206 + st = NULL;
207 +
208 + count++;
209 + }
210 + else if(likely(hash == FLUSH_HASH && !strcmp(s, "FLUSH"))) {
211 + debug(D_PLUGINSD, "PLUGINSD: '%s' is requesting a FLUSH", cd->fullfilename);
212 + st = NULL;
213 + }
214 + else if(likely(hash == CHART_HASH && !strcmp(s, "CHART"))) {
215 + int noname = 0;
216 + st = NULL;
217 +
218 + if((words[1]) != NULL && (words[2]) != NULL && strcmp(words[1], words[2]) == 0)
219 + noname = 1;
220 +
221 + char *type = words[1];
222 + char *id = NULL;
223 + if(likely(type)) {
224 + id = strchr(type, '.');
225 + if(likely(id)) { *id = '\0'; id++; }
226 + }
227 + char *name = words[2];
228 + char *title = words[3];
229 + char *units = words[4];
230 + char *family = words[5];
231 + char *context = words[6];
232 + char *chart = words[7];
233 + char *priority_s = words[8];
234 + char *update_every_s = words[9];
235 +
236 + if(unlikely(!type || !*type || !id || !*id)) {
237 + error("PLUGINSD: '%s' is requesting a CHART, without a type.id. Disabling it.", cd->fullfilename);
238 + cd->enabled = 0;
239 + killpid(cd->pid, SIGTERM);
240 + break;
241 + }
242 +
243 + int priority = 1000;
244 + if(likely(priority_s)) priority = atoi(priority_s);
245 +
246 + int update_every = cd->update_every;
247 + if(likely(update_every_s)) update_every = atoi(update_every_s);
248 + if(unlikely(!update_every)) update_every = cd->update_every;
249 +
250 + int chart_type = RRDSET_TYPE_LINE;
251 + if(unlikely(chart)) chart_type = rrdset_type_id(chart);
252 +
253 + if(unlikely(noname || !name || !*name || strcasecmp(name, "NULL") == 0 || strcasecmp(name, "(NULL)") == 0)) name = NULL;
254 + if(unlikely(!family || !*family)) family = NULL;
255 + if(unlikely(!context || !*context)) context = NULL;
256 +
257 + st = rrdset_find_bytype(type, id);
258 + if(unlikely(!st)) {
259 + debug(D_PLUGINSD, "PLUGINSD: Creating chart type='%s', id='%s', name='%s', family='%s', context='%s', chart='%s', priority=%d, update_every=%d"
260 + , type, id
261 + , name?name:""
262 + , family?family:""
263 + , context?context:""
264 + , rrdset_type_name(chart_type)
265 + , priority
266 + , update_every
267 + );
268 +
269 + st = rrdset_create(type, id, name, family, context, title, units, priority, update_every, chart_type);
270 + cd->update_every = update_every;
271 + }
272 + else debug(D_PLUGINSD, "PLUGINSD: Chart '%s' already exists. Not adding it again.", st->id);
273 + }
274 + else if(likely(hash == DIMENSION_HASH && !strcmp(s, "DIMENSION"))) {
275 + char *id = words[1];
276 + char *name = words[2];
277 + char *algorithm = words[3];
278 + char *multiplier_s = words[4];
279 + char *divisor_s = words[5];
280 + char *options = words[6];
281 +
282 + if(unlikely(!id || !*id)) {
283 + error("PLUGINSD: '%s' is requesting a DIMENSION, without an id. Disabling it.", cd->fullfilename);
284 + cd->enabled = 0;
285 + killpid(cd->pid, SIGTERM);
286 + break;
287 + }
288 +
289 + if(unlikely(!st)) {
290 + error("PLUGINSD: '%s' is requesting a DIMENSION, without a CHART. Disabling it.", cd->fullfilename);
291 + cd->enabled = 0;
292 + killpid(cd->pid, SIGTERM);
293 + break;
294 + }
295 +
296 + long multiplier = 1;
297 + if(multiplier_s && *multiplier_s) multiplier = strtol(multiplier_s, NULL, 0);
298 + if(unlikely(!multiplier)) multiplier = 1;
299 +
300 + long divisor = 1;
301 + if(likely(divisor_s && *divisor_s)) divisor = strtol(divisor_s, NULL, 0);
302 + if(unlikely(!divisor)) divisor = 1;
303 +
304 + if(unlikely(!algorithm || !*algorithm)) algorithm = "absolute";
305 +
306 + if(unlikely(st->debug)) debug(D_PLUGINSD, "PLUGINSD: Creating dimension in chart %s, id='%s', name='%s', algorithm='%s', multiplier=%ld, divisor=%ld, hidden='%s'"
307 + , st->id
308 + , id
309 + , name?name:""
310 + , rrddim_algorithm_name(rrddim_algorithm_id(algorithm))
311 + , multiplier
312 + , divisor
313 + , options?options:""
314 + );
315 +
316 + RRDDIM *rd = rrddim_find(st, id);
317 + if(unlikely(!rd)) {
318 + rd = rrddim_add(st, id, name, multiplier, divisor, rrddim_algorithm_id(algorithm));
319 + rd->flags = 0x00000000;
320 + if(options && *options) {
321 + if(strstr(options, "hidden") != NULL) rd->flags |= RRDDIM_FLAG_HIDDEN;
322 + if(strstr(options, "noreset") != NULL) rd->flags |= RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS;
323 + if(strstr(options, "nooverflow") != NULL) rd->flags |= RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS;
324 + }
325 + }
326 + else if(unlikely(st->debug)) debug(D_PLUGINSD, "PLUGINSD: dimension %s/%s already exists. Not adding it again.", st->id, id);
327 + }
328 + else if(unlikely(hash == DISABLE_HASH && !strcmp(s, "DISABLE"))) {
329 + error("PLUGINSD: '%s' called DISABLE. Disabling it.", cd->fullfilename);
330 + cd->enabled = 0;
331 + killpid(cd->pid, SIGTERM);
332 + break;
333 + }
334 #ifdef DETACH_PLUGINS_FROM_NETDATA
335 - else if(likely(hash == MYPID_HASH && !strcmp(s, "MYPID"))) {
336 - char *pid_s = words[1];
337 - pid_t pid = strtod(pid_s, NULL, 0);
338 -
339 - if(likely(pid)) cd->pid = pid;
340 - debug(D_PLUGINSD, "PLUGINSD: %s is on pid %d", cd->id, cd->pid);
341 - }
342 - else if(likely(hash == STOPPING_WAKE_ME_UP_PLEASE_HASH && !strcmp(s, "STOPPING_WAKE_ME_UP_PLEASE"))) {
343 - error("PLUGINSD: '%s' (pid %d) called STOPPING_WAKE_ME_UP_PLEASE.", cd->fullfilename, cd->pid);
344 -
345 - gettimeofday(&now, NULL);
346 - if(unlikely(!usec && !susec)) {
347 - // our first run
348 - susec = cd->rrd_update_every * 1000000ULL;
349 - }
350 - else {
351 - // second+ run
352 - usec = usecdiff(&now, &last) - susec;
353 - error("PLUGINSD: %s last loop took %llu usec (worked for %llu, sleeped for %llu).\n", cd->fullfilename, usec + susec, usec, susec);
354 - if(unlikely(usec < (rrd_update_every * 1000000ULL / 2ULL))) susec = (rrd_update_every * 1000000ULL) - usec;
355 - else susec = rrd_update_every * 1000000ULL / 2ULL;
356 - }
357 -
358 - error("PLUGINSD: %s sleeping for %llu. Will kill with SIGCONT pid %d to wake it up.\n", cd->fullfilename, susec, cd->pid);
359 - usleep(susec);
360 - killpid(cd->pid, SIGCONT);
361 - bcopy(&now, &last, sizeof(struct timeval));
362 - break;
363 - }
335 + else if(likely(hash == MYPID_HASH && !strcmp(s, "MYPID"))) {
336 + char *pid_s = words[1];
337 + pid_t pid = strtod(pid_s, NULL, 0);
338 +
339 + if(likely(pid)) cd->pid = pid;
340 + debug(D_PLUGINSD, "PLUGINSD: %s is on pid %d", cd->id, cd->pid);
341 + }
342 + else if(likely(hash == STOPPING_WAKE_ME_UP_PLEASE_HASH && !strcmp(s, "STOPPING_WAKE_ME_UP_PLEASE"))) {
343 + error("PLUGINSD: '%s' (pid %d) called STOPPING_WAKE_ME_UP_PLEASE.", cd->fullfilename, cd->pid);
344 +
345 + gettimeofday(&now, NULL);
346 + if(unlikely(!usec && !susec)) {
347 + // our first run
348 + susec = cd->rrd_update_every * 1000000ULL;
349 + }
350 + else {
351 + // second+ run
352 + usec = usecdiff(&now, &last) - susec;
353 + error("PLUGINSD: %s last loop took %llu usec (worked for %llu, sleeped for %llu).\n", cd->fullfilename, usec + susec, usec, susec);
354 + if(unlikely(usec < (rrd_update_every * 1000000ULL / 2ULL))) susec = (rrd_update_every * 1000000ULL) - usec;
355 + else susec = rrd_update_every * 1000000ULL / 2ULL;
356 + }
357 +
358 + error("PLUGINSD: %s sleeping for %llu. Will kill with SIGCONT pid %d to wake it up.\n", cd->fullfilename, susec, cd->pid);
359 + usleep(susec);
360 + killpid(cd->pid, SIGCONT);
361 + bcopy(&now, &last, sizeof(struct timeval));
362 + break;
363 + }
364 #endif
365 - else {
366 - error("PLUGINSD: '%s' is sending command '%s' which is not known by netdata. Disabling it.", cd->fullfilename, s);
367 - cd->enabled = 0;
368 - killpid(cd->pid, SIGTERM);
369 - break;
370 - }
371 - }
372 - if(likely(count)) {
373 - cd->successful_collections += count;
374 - cd->serial_failures = 0;
375 - }
376 - else
377 - cd->serial_failures++;
378 -
379 - info("PLUGINSD: '%s' on pid %d stopped after %zu successful data collections (ENDs).", cd->fullfilename, cd->pid, count);
380 -
381 - // get the return code
382 - int code = mypclose(fp, cd->pid);
383 -
384 - if(netdata_exit) {
385 - cd->pid = 0;
386 - cd->enabled = 0;
387 - cd->obsolete = 1;
388 - pthread_exit(NULL);
389 - return NULL;
390 - }
391 -
392 - if(code != 0) {
393 - // the plugin reports failure
394 -
395 - if(likely(!cd->successful_collections)) {
396 - // nothing collected - disable it
397 - error("PLUGINSD: '%s' exited with error code %d. Disabling it.", cd->fullfilename, code);
398 - cd->enabled = 0;
399 - }
400 - else {
401 - // we have collected something
402 -
403 - if(likely(cd->serial_failures <= 10)) {
404 - error("PLUGINSD: '%s' exited with error code %d, but has given useful output in the past (%zu times). Waiting a bit before starting it again.", cd->fullfilename, code, cd->successful_collections);
405 - sleep((unsigned int) (cd->update_every * 10));
406 - }
407 - else {
408 - error("PLUGINSD: '%s' exited with error code %d, but has given useful output in the past (%zu times). We tried %zu times to restart it, but it failed to generate data. Disabling it.", cd->fullfilename, code, cd->successful_collections, cd->serial_failures);
409 - cd->enabled = 0;
410 - }
411 - }
412 - }
413 - else {
414 - // the plugin reports success
415 -
416 - if(unlikely(!cd->successful_collections)) {
417 - // we have collected nothing so far
418 -
419 - if(likely(cd->serial_failures <= 10)) {
420 - error("PLUGINSD: '%s' (pid %d) does not generate useful output but it reports success (exits with 0). Waiting a bit before starting it again.", cd->fullfilename, cd->pid);
421 - sleep((unsigned int) (cd->update_every * 10));
422 - }
423 - else {
424 - error("PLUGINSD: '%s' (pid %d) does not generate useful output, although it reports success (exits with 0), but we have tried %zu times to collect something. Disabling it.", cd->fullfilename, cd->pid, cd->serial_failures);
425 - cd->enabled = 0;
426 - }
427 - }
428 - else
429 - sleep((unsigned int) cd->update_every);
430 - }
431 - cd->pid = 0;
432 -
433 - if(unlikely(!cd->enabled))
434 - break;
435 - }
436 -
437 - cd->obsolete = 1;
438 - pthread_exit(NULL);
439 - return NULL;
365 + else {
366 + error("PLUGINSD: '%s' is sending command '%s' which is not known by netdata. Disabling it.", cd->fullfilename, s);
367 + cd->enabled = 0;
368 + killpid(cd->pid, SIGTERM);
369 + break;
370 + }
371 + }
372 + if(likely(count)) {
373 + cd->successful_collections += count;
374 + cd->serial_failures = 0;
375 + }
376 + else
377 + cd->serial_failures++;
378 +
379 + info("PLUGINSD: '%s' on pid %d stopped after %zu successful data collections (ENDs).", cd->fullfilename, cd->pid, count);
380 +
381 + // get the return code
382 + int code = mypclose(fp, cd->pid);
383 +
384 + if(netdata_exit) {
385 + cd->pid = 0;
386 + cd->enabled = 0;
387 + cd->obsolete = 1;
388 + pthread_exit(NULL);
389 + return NULL;
390 + }
391 +
392 + if(code != 0) {
393 + // the plugin reports failure
394 +
395 + if(likely(!cd->successful_collections)) {
396 + // nothing collected - disable it
397 + error("PLUGINSD: '%s' exited with error code %d. Disabling it.", cd->fullfilename, code);
398 + cd->enabled = 0;
399 + }
400 + else {
401 + // we have collected something
402 +
403 + if(likely(cd->serial_failures <= 10)) {
404 + error("PLUGINSD: '%s' exited with error code %d, but has given useful output in the past (%zu times). Waiting a bit before starting it again.", cd->fullfilename, code, cd->successful_collections);
405 + sleep((unsigned int) (cd->update_every * 10));
406 + }
407 + else {
408 + error("PLUGINSD: '%s' exited with error code %d, but has given useful output in the past (%zu times). We tried %zu times to restart it, but it failed to generate data. Disabling it.", cd->fullfilename, code, cd->successful_collections, cd->serial_failures);
409 + cd->enabled = 0;
410 + }
411 + }
412 + }
413 + else {
414 + // the plugin reports success
415 +
416 + if(unlikely(!cd->successful_collections)) {
417 + // we have collected nothing so far
418 +
419 + if(likely(cd->serial_failures <= 10)) {
420 + error("PLUGINSD: '%s' (pid %d) does not generate useful output but it reports success (exits with 0). Waiting a bit before starting it again.", cd->fullfilename, cd->pid);
421 + sleep((unsigned int) (cd->update_every * 10));
422 + }
423 + else {
424 + error("PLUGINSD: '%s' (pid %d) does not generate useful output, although it reports success (exits with 0), but we have tried %zu times to collect something. Disabling it.", cd->fullfilename, cd->pid, cd->serial_failures);
425 + cd->enabled = 0;
426 + }
427 + }
428 + else
429 + sleep((unsigned int) cd->update_every);
430 + }
431 + cd->pid = 0;
432 +
433 + if(unlikely(!cd->enabled))
434 + break;
435 + }
436 +
437 + cd->obsolete = 1;
438 + pthread_exit(NULL);
439 + return NULL;
440 }
441
442 void *pluginsd_main(void *ptr)
443 {
444 - if(ptr) { ; }
444 + if(ptr) { ; }
445
446 - info("PLUGINS.D thread created with task id %d", gettid());
447 -
448 - if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
449 - error("Cannot set pthread cancel type to DEFERRED.");
450 -
451 - if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
452 - error("Cannot set pthread cancel state to ENABLE.");
453 -
454 - char *dir_name = config_get("plugins", "plugins directory", PLUGINS_DIR);
455 - int automatic_run = config_get_boolean("plugins", "enable running new plugins", 1);
456 - int scan_frequency = (int) config_get_number("plugins", "check for new plugins every", 60);
457 - DIR *dir = NULL;
458 - struct dirent *file = NULL;
459 - struct plugind *cd;
460 -
461 - // enable the apps plugin by default
462 - // config_get_boolean("plugins", "apps", 1);
463 -
464 - if(scan_frequency < 1) scan_frequency = 1;
465 -
466 - while(likely(1)) {
467 - if(unlikely(netdata_exit)) break;
468 -
469 - dir = opendir(dir_name);
470 - if(unlikely(!dir)) {
471 - error("Cannot open directory '%s'.", dir_name);
472 - pthread_exit(NULL);
473 - return NULL;
474 - }
475 -
476 - while(likely((file = readdir(dir)))) {
477 - if(unlikely(netdata_exit)) break;
478 -
479 - debug(D_PLUGINSD, "PLUGINSD: Examining file '%s'", file->d_name);
480 -
481 - if(unlikely(strcmp(file->d_name, ".") == 0 || strcmp(file->d_name, "..") == 0)) continue;
482 -
483 - int len = (int) strlen(file->d_name);
484 - if(unlikely(len <= (int)PLUGINSD_FILE_SUFFIX_LEN)) continue;
485 - if(unlikely(strcmp(PLUGINSD_FILE_SUFFIX, &file->d_name[len - (int)PLUGINSD_FILE_SUFFIX_LEN]) != 0)) {
486 - debug(D_PLUGINSD, "PLUGINSD: File '%s' does not end in '%s'.", file->d_name, PLUGINSD_FILE_SUFFIX);
487 - continue;
488 - }
489 -
490 - char pluginname[CONFIG_MAX_NAME + 1];
491 - snprintfz(pluginname, CONFIG_MAX_NAME, "%.*s", (int)(len - PLUGINSD_FILE_SUFFIX_LEN), file->d_name);
492 - int enabled = config_get_boolean("plugins", pluginname, automatic_run);
493 -
494 - if(unlikely(!enabled)) {
495 - debug(D_PLUGINSD, "PLUGINSD: plugin '%s' is not enabled", file->d_name);
496 - continue;
497 - }
498 -
499 - // check if it runs already
500 - for(cd = pluginsd_root ; likely(cd) ; cd = cd->next) {
501 - if(unlikely(strcmp(cd->filename, file->d_name) == 0)) break;
502 - }
503 - if(likely(cd && !cd->obsolete)) {
504 - debug(D_PLUGINSD, "PLUGINSD: plugin '%s' is already running", cd->filename);
505 - continue;
506 - }
507 -
508 - // it is not running
509 - // allocate a new one, or use the obsolete one
510 - if(unlikely(!cd)) {
511 - cd = callocz(sizeof(struct plugind), 1);
512 -
513 - snprintfz(cd->id, CONFIG_MAX_NAME, "plugin:%s", pluginname);
514 -
515 - strncpyz(cd->filename, file->d_name, FILENAME_MAX);
516 - snprintfz(cd->fullfilename, FILENAME_MAX, "%s/%s", dir_name, cd->filename);
517 -
518 - cd->enabled = enabled;
519 - cd->update_every = (int) config_get_number(cd->id, "update every", rrd_update_every);
520 - cd->started_t = time(NULL);
521 -
522 - char *def = "";
523 - snprintfz(cd->cmd, PLUGINSD_CMD_MAX, "exec %s %d %s", cd->fullfilename, cd->update_every, config_get(cd->id, "command options", def));
524 -
525 - // link it
526 - if(likely(pluginsd_root)) cd->next = pluginsd_root;
527 - pluginsd_root = cd;
528 - }
529 - cd->obsolete = 0;
530 -
531 - if(unlikely(!cd->enabled)) continue;
532 -
533 - // spawn a new thread for it
534 - if(unlikely(pthread_create(&cd->thread, NULL, pluginsd_worker_thread, cd) != 0)) {
535 - error("PLUGINSD: failed to create new thread for plugin '%s'.", cd->filename);
536 - cd->obsolete = 1;
537 - }
538 - else if(unlikely(pthread_detach(cd->thread) != 0))
539 - error("PLUGINSD: Cannot request detach of newly created thread for plugin '%s'.", cd->filename);
540 - }
541 -
542 - closedir(dir);
543 - sleep((unsigned int) scan_frequency);
544 - }
446 + info("PLUGINS.D thread created with task id %d", gettid());
447 +
448 + if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
449 + error("Cannot set pthread cancel type to DEFERRED.");
450 +
451 + if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
452 + error("Cannot set pthread cancel state to ENABLE.");
453 +
454 + char *dir_name = config_get("plugins", "plugins directory", PLUGINS_DIR);
455 + int automatic_run = config_get_boolean("plugins", "enable running new plugins", 1);
456 + int scan_frequency = (int) config_get_number("plugins", "check for new plugins every", 60);
457 + DIR *dir = NULL;
458 + struct dirent *file = NULL;
459 + struct plugind *cd;
460 +
461 + // enable the apps plugin by default
462 + // config_get_boolean("plugins", "apps", 1);
463 +
464 + if(scan_frequency < 1) scan_frequency = 1;
465 +
466 + while(likely(1)) {
467 + if(unlikely(netdata_exit)) break;
468 +
469 + dir = opendir(dir_name);
470 + if(unlikely(!dir)) {
471 + error("Cannot open directory '%s'.", dir_name);
472 + pthread_exit(NULL);
473 + return NULL;
474 + }
475 +
476 + while(likely((file = readdir(dir)))) {
477 + if(unlikely(netdata_exit)) break;
478 +
479 + debug(D_PLUGINSD, "PLUGINSD: Examining file '%s'", file->d_name);
480 +
481 + if(unlikely(strcmp(file->d_name, ".") == 0 || strcmp(file->d_name, "..") == 0)) continue;
482 +
483 + int len = (int) strlen(file->d_name);
484 + if(unlikely(len <= (int)PLUGINSD_FILE_SUFFIX_LEN)) continue;
485 + if(unlikely(strcmp(PLUGINSD_FILE_SUFFIX, &file->d_name[len - (int)PLUGINSD_FILE_SUFFIX_LEN]) != 0)) {
486 + debug(D_PLUGINSD, "PLUGINSD: File '%s' does not end in '%s'.", file->d_name, PLUGINSD_FILE_SUFFIX);
487 + continue;
488 + }
489 +
490 + char pluginname[CONFIG_MAX_NAME + 1];
491 + snprintfz(pluginname, CONFIG_MAX_NAME, "%.*s", (int)(len - PLUGINSD_FILE_SUFFIX_LEN), file->d_name);
492 + int enabled = config_get_boolean("plugins", pluginname, automatic_run);
493 +
494 + if(unlikely(!enabled)) {
495 + debug(D_PLUGINSD, "PLUGINSD: plugin '%s' is not enabled", file->d_name);
496 + continue;
497 + }
498 +
499 + // check if it runs already
500 + for(cd = pluginsd_root ; likely(cd) ; cd = cd->next) {
501 + if(unlikely(strcmp(cd->filename, file->d_name) == 0)) break;
502 + }
503 + if(likely(cd && !cd->obsolete)) {
504 + debug(D_PLUGINSD, "PLUGINSD: plugin '%s' is already running", cd->filename);
505 + continue;
506 + }
507 +
508 + // it is not running
509 + // allocate a new one, or use the obsolete one
510 + if(unlikely(!cd)) {
511 + cd = callocz(sizeof(struct plugind), 1);
512 +
513 + snprintfz(cd->id, CONFIG_MAX_NAME, "plugin:%s", pluginname);
514 +
515 + strncpyz(cd->filename, file->d_name, FILENAME_MAX);
516 + snprintfz(cd->fullfilename, FILENAME_MAX, "%s/%s", dir_name, cd->filename);
517 +
518 + cd->enabled = enabled;
519 + cd->update_every = (int) config_get_number(cd->id, "update every", rrd_update_every);
520 + cd->started_t = time(NULL);
521 +
522 + char *def = "";
523 + snprintfz(cd->cmd, PLUGINSD_CMD_MAX, "exec %s %d %s", cd->fullfilename, cd->update_every, config_get(cd->id, "command options", def));
524 +
525 + // link it
526 + if(likely(pluginsd_root)) cd->next = pluginsd_root;
527 + pluginsd_root = cd;
528 + }
529 + cd->obsolete = 0;
530 +
531 + if(unlikely(!cd->enabled)) continue;
532 +
533 + // spawn a new thread for it
534 + if(unlikely(pthread_create(&cd->thread, NULL, pluginsd_worker_thread, cd) != 0)) {
535 + error("PLUGINSD: failed to create new thread for plugin '%s'.", cd->filename);
536 + cd->obsolete = 1;
537 + }
538 + else if(unlikely(pthread_detach(cd->thread) != 0))
539 + error("PLUGINSD: Cannot request detach of newly created thread for plugin '%s'.", cd->filename);
540 + }
541 +
542 + closedir(dir);
543 + sleep((unsigned int) scan_frequency);
544 + }
545
546 - pthread_exit(NULL);
547 - return NULL;
546 + pthread_exit(NULL);
547 + return NULL;
548 }
src/plugins_d.h
+15 -15
@@ -7,28 +7,28 @@
7 #define PLUGINSD_LINE_MAX 1024
8
9 struct plugind {
10 - char id[CONFIG_MAX_NAME+1]; // config node id
10 + char id[CONFIG_MAX_NAME+1]; // config node id
11
12 - char filename[FILENAME_MAX+1]; // just the filename
13 - char fullfilename[FILENAME_MAX+1]; // with path
14 - char cmd[PLUGINSD_CMD_MAX+1]; // the command that is executes
12 + char filename[FILENAME_MAX+1]; // just the filename
13 + char fullfilename[FILENAME_MAX+1]; // with path
14 + char cmd[PLUGINSD_CMD_MAX+1]; // the command that is executes
15
16 - pid_t pid;
17 - pthread_t thread;
16 + pid_t pid;
17 + pthread_t thread;
18
19 - size_t successful_collections; // the number of times we have seen
20 - // values collected from this plugin
19 + size_t successful_collections; // the number of times we have seen
20 + // values collected from this plugin
21
22 - size_t serial_failures; // the number of times the plugin started
23 - // without collecting values
22 + size_t serial_failures; // the number of times the plugin started
23 + // without collecting values
24
25 - int update_every; // the plugin default data collection frequency
26 - int obsolete; // do not touch this structure after setting this to 1
27 - int enabled; // if this is enabled or not
25 + int update_every; // the plugin default data collection frequency
26 + int obsolete; // do not touch this structure after setting this to 1
27 + int enabled; // if this is enabled or not
28
29 - time_t started_t;
29 + time_t started_t;
30
31 - struct plugind *next;
31 + struct plugind *next;
32 };
33
34 extern struct plugind *pluginsd_root;
src/popen.c
+152 -152
@@ -2,42 +2,42 @@
2
3 /*
4 struct mypopen {
5 - pid_t pid;
6 - FILE *fp;
7 - struct mypopen *next;
8 - struct mypopen *prev;
5 + pid_t pid;
6 + FILE *fp;
7 + struct mypopen *next;
8 + struct mypopen *prev;
9 };
10
11 static struct mypopen *mypopen_root = NULL;
12
13 static void mypopen_add(FILE *fp, pid_t *pid) {
14 - struct mypopen *mp = malloc(sizeof(struct mypopen));
15 - if(!mp) {
16 - fatal("Cannot allocate %zu bytes", sizeof(struct mypopen))
17 - return;
18 - }
19 -
20 - mp->fp = fp;
21 - mp->pid = pid;
22 - mp->next = popen_root;
23 - mp->prev = NULL;
24 - if(mypopen_root) mypopen_root->prev = mp;
25 - mypopen_root = mp;
14 + struct mypopen *mp = malloc(sizeof(struct mypopen));
15 + if(!mp) {
16 + fatal("Cannot allocate %zu bytes", sizeof(struct mypopen))
17 + return;
18 + }
19 +
20 + mp->fp = fp;
21 + mp->pid = pid;
22 + mp->next = popen_root;
23 + mp->prev = NULL;
24 + if(mypopen_root) mypopen_root->prev = mp;
25 + mypopen_root = mp;
26 }
27
28 static void mypopen_del(FILE *fp) {
29 - struct mypopen *mp;
30 -
31 - for(mp = mypopen_root; mp; mp = mp->next)
32 - if(mp->fd == fp) break;
33 -
34 - if(!mp) error("Cannot find mypopen() file pointer in open childs.");
35 - else {
36 - if(mp->next) mp->next->prev = mp->prev;
37 - if(mp->prev) mp->prev->next = mp->next;
38 - if(mypopen_root == mp) mypopen_root = mp->next;
39 - free(mp);
40 - }
29 + struct mypopen *mp;
30 +
31 + for(mp = mypopen_root; mp; mp = mp->next)
32 + if(mp->fd == fp) break;
33 +
34 + if(!mp) error("Cannot find mypopen() file pointer in open childs.");
35 + else {
36 + if(mp->next) mp->next->prev = mp->prev;
37 + if(mp->prev) mp->prev->next = mp->next;
38 + if(mypopen_root == mp) mypopen_root = mp->next;
39 + free(mp);
40 + }
41 }
42 */
43 #define PIPE_READ 0
@@ -45,141 +45,141 @@ static void mypopen_del(FILE *fp) {
45
46 FILE *mypopen(const char *command, pid_t *pidptr)
47 {
48 - int pipefd[2];
49 -
50 - if(pipe(pipefd) == -1) return NULL;
51 -
52 - int pid = fork();
53 - if(pid == -1) {
54 - close(pipefd[PIPE_READ]);
55 - close(pipefd[PIPE_WRITE]);
56 - return NULL;
57 - }
58 - if(pid != 0) {
59 - // the parent
60 - *pidptr = pid;
61 - close(pipefd[PIPE_WRITE]);
62 - FILE *fp = fdopen(pipefd[PIPE_READ], "r");
63 - /*mypopen_add(fp, pid);*/
64 - return(fp);
65 - }
66 - // the child
67 -
68 - // close all files
69 - int i;
70 - for(i = (int) (sysconf(_SC_OPEN_MAX) - 1); i > 0; i--)
71 - if(i != STDIN_FILENO && i != STDERR_FILENO && i != pipefd[PIPE_WRITE]) close(i);
72 -
73 - // move the pipe to stdout
74 - if(pipefd[PIPE_WRITE] != STDOUT_FILENO) {
75 - dup2(pipefd[PIPE_WRITE], STDOUT_FILENO);
76 - close(pipefd[PIPE_WRITE]);
77 - }
48 + int pipefd[2];
49 +
50 + if(pipe(pipefd) == -1) return NULL;
51 +
52 + int pid = fork();
53 + if(pid == -1) {
54 + close(pipefd[PIPE_READ]);
55 + close(pipefd[PIPE_WRITE]);
56 + return NULL;
57 + }
58 + if(pid != 0) {
59 + // the parent
60 + *pidptr = pid;
61 + close(pipefd[PIPE_WRITE]);
62 + FILE *fp = fdopen(pipefd[PIPE_READ], "r");
63 + /*mypopen_add(fp, pid);*/
64 + return(fp);
65 + }
66 + // the child
67 +
68 + // close all files
69 + int i;
70 + for(i = (int) (sysconf(_SC_OPEN_MAX) - 1); i > 0; i--)
71 + if(i != STDIN_FILENO && i != STDERR_FILENO && i != pipefd[PIPE_WRITE]) close(i);
72 +
73 + // move the pipe to stdout
74 + if(pipefd[PIPE_WRITE] != STDOUT_FILENO) {
75 + dup2(pipefd[PIPE_WRITE], STDOUT_FILENO);
76 + close(pipefd[PIPE_WRITE]);
77 + }
78
79 #ifdef DETACH_PLUGINS_FROM_NETDATA
80 - // this was an attempt to detach the child and use the suspend mode charts.d
81 - // unfortunatelly it does not work as expected.
80 + // this was an attempt to detach the child and use the suspend mode charts.d
81 + // unfortunatelly it does not work as expected.
82
83 - // fork again to become session leader
84 - pid = fork();
85 - if(pid == -1)
86 - error("pre-execution of command '%s' on pid %d: Cannot fork 2nd time.", command, getpid());
83 + // fork again to become session leader
84 + pid = fork();
85 + if(pid == -1)
86 + error("pre-execution of command '%s' on pid %d: Cannot fork 2nd time.", command, getpid());
87
88 - if(pid != 0) {
89 - // the parent
90 - exit(0);
91 - }
88 + if(pid != 0) {
89 + // the parent
90 + exit(0);
91 + }
92
93 - // set a new process group id for just this child
94 - if( setpgid(0, 0) != 0 )
95 - error("pre-execution of command '%s' on pid %d: Cannot set a new process group.", command, getpid());
93 + // set a new process group id for just this child
94 + if( setpgid(0, 0) != 0 )
95 + error("pre-execution of command '%s' on pid %d: Cannot set a new process group.", command, getpid());
96
97 - if( getpgid(0) != getpid() )
98 - error("pre-execution of command '%s' on pid %d: Cannot set a new process group. Process group set is incorrect. Expected %d, found %d", command, getpid(), getpid(), getpgid(0));
97 + if( getpgid(0) != getpid() )
98 + error("pre-execution of command '%s' on pid %d: Cannot set a new process group. Process group set is incorrect. Expected %d, found %d", command, getpid(), getpid(), getpgid(0));
99
100 - if( setsid() != 0 )
101 - error("pre-execution of command '%s' on pid %d: Cannot set session id.", command, getpid());
100 + if( setsid() != 0 )
101 + error("pre-execution of command '%s' on pid %d: Cannot set session id.", command, getpid());
102
103 - fprintf(stdout, "MYPID %d\n", getpid());
104 - fflush(NULL);
103 + fprintf(stdout, "MYPID %d\n", getpid());
104 + fflush(NULL);
105 #endif
106
107 - // reset all signals
108 - {
109 - sigset_t sigset;
110 - sigfillset(&sigset);
111 -
112 - if(pthread_sigmask(SIG_UNBLOCK, &sigset, NULL) == -1)
113 - error("pre-execution of command '%s' on pid %d: could not unblock signals for threads.", command, getpid());
114 -
115 - // We only need to reset ignored signals.
116 - // Signals with signal handlers are reset by default.
117 - struct sigaction sa;
118 - sigemptyset(&sa.sa_mask);
119 - sa.sa_handler = SIG_DFL;
120 - sa.sa_flags = 0;
121 -
122 - if(sigaction(SIGUSR1, &sa, NULL) == -1)
123 - error("pre-execution of command '%s' on pid %d: failed to set default signal handler for SIGUSR1.", command, getpid());
124 -
125 - if(sigaction(SIGPIPE, &sa, NULL) == -1)
126 - error("pre-execution of command '%s' on pid %d: failed to set default signal handler for SIGPIPE.", command, getpid());
127 - }
128 -
129 -
130 - info("executing command: '%s' on pid %d.", command, getpid());
131 - execl("/bin/sh", "sh", "-c", command, NULL);
132 - exit(1);
107 + // reset all signals
108 + {
109 + sigset_t sigset;
110 + sigfillset(&sigset);
111 +
112 + if(pthread_sigmask(SIG_UNBLOCK, &sigset, NULL) == -1)
113 + error("pre-execution of command '%s' on pid %d: could not unblock signals for threads.", command, getpid());
114 +
115 + // We only need to reset ignored signals.
116 + // Signals with signal handlers are reset by default.
117 + struct sigaction sa;
118 + sigemptyset(&sa.sa_mask);
119 + sa.sa_handler = SIG_DFL;
120 + sa.sa_flags = 0;
121 +
122 + if(sigaction(SIGUSR1, &sa, NULL) == -1)
123 + error("pre-execution of command '%s' on pid %d: failed to set default signal handler for SIGUSR1.", command, getpid());
124 +
125 + if(sigaction(SIGPIPE, &sa, NULL) == -1)
126 + error("pre-execution of command '%s' on pid %d: failed to set default signal handler for SIGPIPE.", command, getpid());
127 + }
128 +
129 +
130 + info("executing command: '%s' on pid %d.", command, getpid());
131 + execl("/bin/sh", "sh", "-c", command, NULL);
132 + exit(1);
133 }
134
135 int mypclose(FILE *fp, pid_t pid) {
136 - debug(D_EXIT, "Request to mypclose() on pid %d", pid);
137 -
138 - /*mypopen_del(fp);*/
139 - fclose(fp);
140 -
141 - siginfo_t info;
142 - if(waitid(P_PID, (id_t) pid, &info, WEXITED) != -1) {
143 - switch(info.si_code) {
144 - case CLD_EXITED:
145 - if(info.si_status)
146 - error("child pid %d exited with code %d.", info.si_pid, info.si_status);
147 - return(info.si_status);
148 - break;
149 -
150 - case CLD_KILLED:
151 - error("child pid %d killed by signal %d.", info.si_pid, info.si_status);
152 - return(-1);
153 - break;
154 -
155 - case CLD_DUMPED:
156 - error("child pid %d core dumped by signal %d.", info.si_pid, info.si_status);
157 - return(-2);
158 - break;
159 -
160 - case CLD_STOPPED:
161 - error("child pid %d stopped by signal %d.", info.si_pid, info.si_status);
162 - return(0);
163 - break;
164 -
165 - case CLD_TRAPPED:
166 - error("child pid %d trapped by signal %d.", info.si_pid, info.si_status);
167 - return(-4);
168 - break;
169 -
170 - case CLD_CONTINUED:
171 - error("child pid %d continued by signal %d.", info.si_pid, info.si_status);
172 - return(0);
173 - break;
174 -
175 - default:
176 - error("child pid %d gave us a SIGCHLD with code %d and status %d.", info.si_pid, info.si_code, info.si_status);
177 - return(-5);
178 - break;
179 - }
180 - }
181 - else
182 - error("Cannot waitid() for pid %d", pid);
183 -
184 - return 0;
136 + debug(D_EXIT, "Request to mypclose() on pid %d", pid);
137 +
138 + /*mypopen_del(fp);*/
139 + fclose(fp);
140 +
141 + siginfo_t info;
142 + if(waitid(P_PID, (id_t) pid, &info, WEXITED) != -1) {
143 + switch(info.si_code) {
144 + case CLD_EXITED:
145 + if(info.si_status)
146 + error("child pid %d exited with code %d.", info.si_pid, info.si_status);
147 + return(info.si_status);
148 + break;
149 +
150 + case CLD_KILLED:
151 + error("child pid %d killed by signal %d.", info.si_pid, info.si_status);
152 + return(-1);
153 + break;
154 +
155 + case CLD_DUMPED:
156 + error("child pid %d core dumped by signal %d.", info.si_pid, info.si_status);
157 + return(-2);
158 + break;
159 +
160 + case CLD_STOPPED:
161 + error("child pid %d stopped by signal %d.", info.si_pid, info.si_status);
162 + return(0);
163 + break;
164 +
165 + case CLD_TRAPPED:
166 + error("child pid %d trapped by signal %d.", info.si_pid, info.si_status);
167 + return(-4);
168 + break;
169 +
170 + case CLD_CONTINUED:
171 + error("child pid %d continued by signal %d.", info.si_pid, info.si_status);
172 + return(0);
173 + break;
174 +
175 + default:
176 + error("child pid %d gave us a SIGCHLD with code %d and status %d.", info.si_pid, info.si_code, info.si_status);
177 + return(-5);
178 + break;
179 + }
180 + }
181 + else
182 + error("Cannot waitid() for pid %d", pid);
183 +
184 + return 0;
185 }
src/proc_diskstats.c
+678 -678
@@ -7,694 +7,694 @@
7 #define DISK_TYPE_CONTAINER 3
8
9 static struct disk {
10 - char *disk; // the name of the disk (sda, sdb, etc)
11 - unsigned long major;
12 - unsigned long minor;
13 - int sector_size;
14 - int type;
15 - char *mount_point;
16 -
17 - // disk options caching
18 - int configured;
19 - int do_io;
20 - int do_ops;
21 - int do_mops;
22 - int do_iotime;
23 - int do_qops;
24 - int do_util;
25 - int do_backlog;
26 - int do_space;
27 - int do_inodes;
28 -
29 - struct disk *next;
10 + char *disk; // the name of the disk (sda, sdb, etc)
11 + unsigned long major;
12 + unsigned long minor;
13 + int sector_size;
14 + int type;
15 + char *mount_point;
16 +
17 + // disk options caching
18 + int configured;
19 + int do_io;
20 + int do_ops;
21 + int do_mops;
22 + int do_iotime;
23 + int do_qops;
24 + int do_util;
25 + int do_backlog;
26 + int do_space;
27 + int do_inodes;
28 +
29 + struct disk *next;
30 } *disk_root = NULL;
31
32 static struct mountinfo *disk_mountinfo_root = NULL;
33
34 static struct disk *get_disk(unsigned long major, unsigned long minor, char *disk) {
35 - static char path_to_get_hw_sector_size[FILENAME_MAX + 1] = "";
36 - static char path_to_get_hw_sector_size_partitions[FILENAME_MAX + 1] = "";
37 - static char path_find_block_device[FILENAME_MAX + 1] = "";
38 - struct disk *d;
39 -
40 - // search for it in our RAM list.
41 - // this is sequential, but since we just walk through
42 - // and the number of disks / partitions in a system
43 - // should not be that many, it should be acceptable
44 - for(d = disk_root; d ; d = d->next)
45 - if(unlikely(d->major == major && d->minor == minor))
46 - break;
47 -
48 - // if we found it, return it
49 - if(likely(d))
50 - return d;
51 -
52 - // not found
53 - // create a new disk structure
54 - d = (struct disk *)mallocz(sizeof(struct disk));
55 -
56 - d->disk = strdupz(disk);
57 - d->major = major;
58 - d->minor = minor;
59 - d->type = DISK_TYPE_PHYSICAL; // Default type. Changed later if not correct.
60 - d->configured = 0;
61 - d->sector_size = 512; // the default, will be changed below
62 - d->next = NULL;
63 -
64 - // append it to the list
65 - if(!disk_root)
66 - disk_root = d;
67 - else {
68 - struct disk *last;
69 - for(last = disk_root; last->next ;last = last->next);
70 - last->next = d;
71 - }
72 -
73 - // ------------------------------------------------------------------------
74 - // find the type of the device
75 -
76 - char buffer[FILENAME_MAX + 1];
77 -
78 - // get the default path for finding info about the block device
79 - if(unlikely(!path_find_block_device[0])) {
80 - snprintfz(buffer, FILENAME_MAX, "%s%s", global_host_prefix, "/sys/dev/block/%lu:%lu/%s");
81 - snprintfz(path_find_block_device, FILENAME_MAX, "%s", config_get("plugin:proc:/proc/diskstats", "path to get block device infos", buffer));
82 - }
83 -
84 - // find if it is a partition
85 - // by checking if /sys/dev/block/MAJOR:MINOR/partition is readable.
86 - snprintfz(buffer, FILENAME_MAX, path_find_block_device, major, minor, "partition");
87 - if(access(buffer, R_OK) == 0) {
88 - d->type = DISK_TYPE_PARTITION;
89 - } else {
90 - // find if it is a container
91 - // by checking if /sys/dev/block/MAJOR:MINOR/slaves has entries
92 - snprintfz(buffer, FILENAME_MAX, path_find_block_device, major, minor, "slaves/");
93 - DIR *dirp = opendir(buffer);
94 - if (dirp != NULL) {
95 - struct dirent *dp;
96 - while( (dp = readdir(dirp)) ) {
97 - // . and .. are also files in empty folders.
98 - if(strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0) {
99 - continue;
100 - }
101 -
102 - d->type = DISK_TYPE_CONTAINER;
103 -
104 - // Stop the loop after we found one file.
105 - break;
106 - }
107 - if(closedir(dirp) == -1)
108 - error("Unable to close dir %s", buffer);
109 - }
110 - }
111 -
112 - // ------------------------------------------------------------------------
113 - // check if we can find its mount point
114 -
115 - // mountinfo_find() can be called with NULL disk_mountinfo_root
116 - struct mountinfo *mi = mountinfo_find(disk_mountinfo_root, d->major, d->minor);
117 - if(unlikely(!mi)) {
118 - // mountinfo_free() can be called with NULL disk_mountinfo_root
119 - mountinfo_free(disk_mountinfo_root);
120 -
121 - // re-read mountinfo in case something changed
122 - disk_mountinfo_root = mountinfo_read();
123 -
124 - // search again for this disk
125 - mi = mountinfo_find(disk_mountinfo_root, d->major, d->minor);
126 - }
127 -
128 - if(mi)
129 - d->mount_point = strdupz(mi->mount_point);
130 - // no need to check for NULL
131 - else
132 - d->mount_point = NULL;
133 -
134 - // ------------------------------------------------------------------------
135 - // find the disk sector size
136 -
137 - if(!path_to_get_hw_sector_size[0]) {
138 - snprintfz(buffer, FILENAME_MAX, "%s%s", global_host_prefix, "/sys/block/%s/queue/hw_sector_size");
139 - snprintfz(path_to_get_hw_sector_size, FILENAME_MAX, "%s", config_get("plugin:proc:/proc/diskstats", "path to get h/w sector size", buffer));
140 - }
141 - if(!path_to_get_hw_sector_size_partitions[0]) {
142 - snprintfz(buffer, FILENAME_MAX, "%s%s", global_host_prefix, "/sys/dev/block/%lu:%lu/subsystem/%s/../queue/hw_sector_size");
143 - snprintfz(path_to_get_hw_sector_size_partitions, FILENAME_MAX, "%s", config_get("plugin:proc:/proc/diskstats", "path to get h/w sector size for partitions", buffer));
144 - }
145 -
146 - {
147 - char tf[FILENAME_MAX + 1], *t;
148 - strncpyz(tf, d->disk, FILENAME_MAX);
149 -
150 - // replace all / with !
151 - for(t = tf; *t ;t++)
152 - if(*t == '/') *t = '!';
153 -
154 - if(d->type == DISK_TYPE_PARTITION)
155 - snprintfz(buffer, FILENAME_MAX, path_to_get_hw_sector_size_partitions, d->major, d->minor, tf);
156 - else
157 - snprintfz(buffer, FILENAME_MAX, path_to_get_hw_sector_size, tf);
158 -
159 - FILE *fpss = fopen(buffer, "r");
160 - if(fpss) {
161 - char buffer2[1024 + 1];
162 - char *tmp = fgets(buffer2, 1024, fpss);
163 -
164 - if(tmp) {
165 - d->sector_size = atoi(tmp);
166 - if(d->sector_size <= 0) {
167 - error("Invalid sector size %d for device %s in %s. Assuming 512.", d->sector_size, d->disk, buffer);
168 - d->sector_size = 512;
169 - }
170 - }
171 - else error("Cannot read data for sector size for device %s from %s. Assuming 512.", d->disk, buffer);
172 -
173 - fclose(fpss);
174 - }
175 - else error("Cannot read sector size for device %s from %s. Assuming 512.", d->disk, buffer);
176 - }
177 -
178 - return d;
35 + static char path_to_get_hw_sector_size[FILENAME_MAX + 1] = "";
36 + static char path_to_get_hw_sector_size_partitions[FILENAME_MAX + 1] = "";
37 + static char path_find_block_device[FILENAME_MAX + 1] = "";
38 + struct disk *d;
39 +
40 + // search for it in our RAM list.
41 + // this is sequential, but since we just walk through
42 + // and the number of disks / partitions in a system
43 + // should not be that many, it should be acceptable
44 + for(d = disk_root; d ; d = d->next)
45 + if(unlikely(d->major == major && d->minor == minor))
46 + break;
47 +
48 + // if we found it, return it
49 + if(likely(d))
50 + return d;
51 +
52 + // not found
53 + // create a new disk structure
54 + d = (struct disk *)mallocz(sizeof(struct disk));
55 +
56 + d->disk = strdupz(disk);
57 + d->major = major;
58 + d->minor = minor;
59 + d->type = DISK_TYPE_PHYSICAL; // Default type. Changed later if not correct.
60 + d->configured = 0;
61 + d->sector_size = 512; // the default, will be changed below
62 + d->next = NULL;
63 +
64 + // append it to the list
65 + if(!disk_root)
66 + disk_root = d;
67 + else {
68 + struct disk *last;
69 + for(last = disk_root; last->next ;last = last->next);
70 + last->next = d;
71 + }
72 +
73 + // ------------------------------------------------------------------------
74 + // find the type of the device
75 +
76 + char buffer[FILENAME_MAX + 1];
77 +
78 + // get the default path for finding info about the block device
79 + if(unlikely(!path_find_block_device[0])) {
80 + snprintfz(buffer, FILENAME_MAX, "%s%s", global_host_prefix, "/sys/dev/block/%lu:%lu/%s");
81 + snprintfz(path_find_block_device, FILENAME_MAX, "%s", config_get("plugin:proc:/proc/diskstats", "path to get block device infos", buffer));
82 + }
83 +
84 + // find if it is a partition
85 + // by checking if /sys/dev/block/MAJOR:MINOR/partition is readable.
86 + snprintfz(buffer, FILENAME_MAX, path_find_block_device, major, minor, "partition");
87 + if(access(buffer, R_OK) == 0) {
88 + d->type = DISK_TYPE_PARTITION;
89 + } else {
90 + // find if it is a container
91 + // by checking if /sys/dev/block/MAJOR:MINOR/slaves has entries
92 + snprintfz(buffer, FILENAME_MAX, path_find_block_device, major, minor, "slaves/");
93 + DIR *dirp = opendir(buffer);
94 + if (dirp != NULL) {
95 + struct dirent *dp;
96 + while( (dp = readdir(dirp)) ) {
97 + // . and .. are also files in empty folders.
98 + if(strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0) {
99 + continue;
100 + }
101 +
102 + d->type = DISK_TYPE_CONTAINER;
103 +
104 + // Stop the loop after we found one file.
105 + break;
106 + }
107 + if(closedir(dirp) == -1)
108 + error("Unable to close dir %s", buffer);
109 + }
110 + }
111 +
112 + // ------------------------------------------------------------------------
113 + // check if we can find its mount point
114 +
115 + // mountinfo_find() can be called with NULL disk_mountinfo_root
116 + struct mountinfo *mi = mountinfo_find(disk_mountinfo_root, d->major, d->minor);
117 + if(unlikely(!mi)) {
118 + // mountinfo_free() can be called with NULL disk_mountinfo_root
119 + mountinfo_free(disk_mountinfo_root);
120 +
121 + // re-read mountinfo in case something changed
122 + disk_mountinfo_root = mountinfo_read();
123 +
124 + // search again for this disk
125 + mi = mountinfo_find(disk_mountinfo_root, d->major, d->minor);
126 + }
127 +
128 + if(mi)
129 + d->mount_point = strdupz(mi->mount_point);
130 + // no need to check for NULL
131 + else
132 + d->mount_point = NULL;
133 +
134 + // ------------------------------------------------------------------------
135 + // find the disk sector size
136 +
137 + if(!path_to_get_hw_sector_size[0]) {
138 + snprintfz(buffer, FILENAME_MAX, "%s%s", global_host_prefix, "/sys/block/%s/queue/hw_sector_size");
139 + snprintfz(path_to_get_hw_sector_size, FILENAME_MAX, "%s", config_get("plugin:proc:/proc/diskstats", "path to get h/w sector size", buffer));
140 + }
141 + if(!path_to_get_hw_sector_size_partitions[0]) {
142 + snprintfz(buffer, FILENAME_MAX, "%s%s", global_host_prefix, "/sys/dev/block/%lu:%lu/subsystem/%s/../queue/hw_sector_size");
143 + snprintfz(path_to_get_hw_sector_size_partitions, FILENAME_MAX, "%s", config_get("plugin:proc:/proc/diskstats", "path to get h/w sector size for partitions", buffer));
144 + }
145 +
146 + {
147 + char tf[FILENAME_MAX + 1], *t;
148 + strncpyz(tf, d->disk, FILENAME_MAX);
149 +
150 + // replace all / with !
151 + for(t = tf; *t ;t++)
152 + if(*t == '/') *t = '!';
153 +
154 + if(d->type == DISK_TYPE_PARTITION)
155 + snprintfz(buffer, FILENAME_MAX, path_to_get_hw_sector_size_partitions, d->major, d->minor, tf);
156 + else
157 + snprintfz(buffer, FILENAME_MAX, path_to_get_hw_sector_size, tf);
158 +
159 + FILE *fpss = fopen(buffer, "r");
160 + if(fpss) {
161 + char buffer2[1024 + 1];
162 + char *tmp = fgets(buffer2, 1024, fpss);
163 +
164 + if(tmp) {
165 + d->sector_size = atoi(tmp);
166 + if(d->sector_size <= 0) {
167 + error("Invalid sector size %d for device %s in %s. Assuming 512.", d->sector_size, d->disk, buffer);
168 + d->sector_size = 512;
169 + }
170 + }
171 + else error("Cannot read data for sector size for device %s from %s. Assuming 512.", d->disk, buffer);
172 +
173 + fclose(fpss);
174 + }
175 + else error("Cannot read sector size for device %s from %s. Assuming 512.", d->disk, buffer);
176 + }
177 +
178 + return d;
179 }
180
181 static inline int select_positive_option(int option1, int option2) {
182 - if(option1 == CONFIG_ONDEMAND_YES || option2 == CONFIG_ONDEMAND_YES)
183 - return CONFIG_ONDEMAND_YES;
184 - else if(option1 == CONFIG_ONDEMAND_ONDEMAND || option2 == CONFIG_ONDEMAND_ONDEMAND)
185 - return CONFIG_ONDEMAND_ONDEMAND;
182 + if(option1 == CONFIG_ONDEMAND_YES || option2 == CONFIG_ONDEMAND_YES)
183 + return CONFIG_ONDEMAND_YES;
184 + else if(option1 == CONFIG_ONDEMAND_ONDEMAND || option2 == CONFIG_ONDEMAND_ONDEMAND)
185 + return CONFIG_ONDEMAND_ONDEMAND;
186
187 - return CONFIG_ONDEMAND_NO;
187 + return CONFIG_ONDEMAND_NO;
188 }
189
190 int do_proc_diskstats(int update_every, unsigned long long dt) {
191 - static procfile *ff = NULL;
192 - static struct statvfs buff_statvfs;
193 - static struct stat buff_stat;
194 - static int global_enable_new_disks_detected_at_runtime = CONFIG_ONDEMAND_YES,
195 - global_enable_performance_for_physical_disks = CONFIG_ONDEMAND_ONDEMAND,
196 - global_enable_performance_for_virtual_disks = CONFIG_ONDEMAND_NO,
197 - global_enable_performance_for_partitions = CONFIG_ONDEMAND_NO,
198 - global_enable_performance_for_mountpoints = CONFIG_ONDEMAND_NO,
199 - global_enable_performance_for_virtual_mountpoints = CONFIG_ONDEMAND_ONDEMAND,
200 - global_enable_space_for_mountpoints = CONFIG_ONDEMAND_ONDEMAND,
201 - global_do_io = CONFIG_ONDEMAND_ONDEMAND,
202 - global_do_ops = CONFIG_ONDEMAND_ONDEMAND,
203 - global_do_mops = CONFIG_ONDEMAND_ONDEMAND,
204 - global_do_iotime = CONFIG_ONDEMAND_ONDEMAND,
205 - global_do_qops = CONFIG_ONDEMAND_ONDEMAND,
206 - global_do_util = CONFIG_ONDEMAND_ONDEMAND,
207 - global_do_backlog = CONFIG_ONDEMAND_ONDEMAND,
208 - global_do_space = CONFIG_ONDEMAND_ONDEMAND,
209 - global_do_inodes = CONFIG_ONDEMAND_ONDEMAND,
210 - globals_initialized = 0;
211 -
212 - if(unlikely(!globals_initialized)) {
213 - global_enable_new_disks_detected_at_runtime = config_get_boolean("plugin:proc:/proc/diskstats", "enable new disks detected at runtime", global_enable_new_disks_detected_at_runtime);
214 -
215 - global_enable_performance_for_physical_disks = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "performance metrics for physical disks", global_enable_performance_for_physical_disks);
216 - global_enable_performance_for_virtual_disks = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "performance metrics for virtual disks", global_enable_performance_for_virtual_disks);
217 - global_enable_performance_for_partitions = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "performance metrics for partitions", global_enable_performance_for_partitions);
218 - global_enable_performance_for_mountpoints = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "performance metrics for mounted filesystems", global_enable_performance_for_mountpoints);
219 - global_enable_performance_for_virtual_mountpoints = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "performance metrics for mounted virtual disks", global_enable_performance_for_virtual_mountpoints);
220 - global_enable_space_for_mountpoints = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "space metrics for mounted filesystems", global_enable_space_for_mountpoints);
221 -
222 - global_do_io = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "bandwidth for all disks", global_do_io);
223 - global_do_ops = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "operations for all disks", global_do_ops);
224 - global_do_mops = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "merged operations for all disks", global_do_mops);
225 - global_do_iotime = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "i/o time for all disks", global_do_iotime);
226 - global_do_qops = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "queued operations for all disks", global_do_qops);
227 - global_do_util = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "utilization percentage for all disks", global_do_util);
228 - global_do_backlog = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "backlog for all disks", global_do_backlog);
229 - global_do_space = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "space usage for all disks", global_do_space);
230 - global_do_inodes = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "inodes usage for all disks", global_do_inodes);
231 -
232 - globals_initialized = 1;
233 - }
234 -
235 - if(!ff) {
236 - char filename[FILENAME_MAX + 1];
237 - snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/diskstats");
238 - ff = procfile_open(config_get("plugin:proc:/proc/diskstats", "filename to monitor", filename), " \t", PROCFILE_FLAG_DEFAULT);
239 - }
240 - if(!ff) return 1;
241 -
242 - ff = procfile_readall(ff);
243 - if(!ff) return 0; // we return 0, so that we will retry to open it next time
244 -
245 - uint32_t lines = procfile_lines(ff), l;
246 - uint32_t words;
247 -
248 - for(l = 0; l < lines ;l++) {
249 - // --------------------------------------------------------------------------
250 - // Read parameters
251 -
252 - char *disk;
253 - unsigned long long major = 0, minor = 0,
254 - reads = 0, mreads = 0, readsectors = 0, readms = 0,
255 - writes = 0, mwrites = 0, writesectors = 0, writems = 0,
256 - queued_ios = 0, busy_ms = 0, backlog_ms = 0,
257 - space_avail = 0, space_avail_root = 0, space_used = 0,
258 - inodes_avail = 0, inodes_avail_root = 0, inodes_used = 0;
259 -
260 - unsigned long long last_reads = 0, last_readsectors = 0, last_readms = 0,
261 - last_writes = 0, last_writesectors = 0, last_writems = 0,
262 - last_busy_ms = 0;
263 -
264 - words = procfile_linewords(ff, l);
265 - if(words < 14) continue;
266 -
267 - major = strtoull(procfile_lineword(ff, l, 0), NULL, 10);
268 - minor = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
269 - disk = procfile_lineword(ff, l, 2);
270 -
271 - // # of reads completed # of writes completed
272 - // This is the total number of reads or writes completed successfully.
273 - reads = strtoull(procfile_lineword(ff, l, 3), NULL, 10); // rd_ios
274 - writes = strtoull(procfile_lineword(ff, l, 7), NULL, 10); // wr_ios
275 -
276 - // # of reads merged # of writes merged
277 - // Reads and writes which are adjacent to each other may be merged for
278 - // efficiency. Thus two 4K reads may become one 8K read before it is
279 - // ultimately handed to the disk, and so it will be counted (and queued)
280 - mreads = strtoull(procfile_lineword(ff, l, 4), NULL, 10); // rd_merges_or_rd_sec
281 - mwrites = strtoull(procfile_lineword(ff, l, 8), NULL, 10); // wr_merges
282 -
283 - // # of sectors read # of sectors written
284 - // This is the total number of sectors read or written successfully.
285 - readsectors = strtoull(procfile_lineword(ff, l, 5), NULL, 10); // rd_sec_or_wr_ios
286 - writesectors = strtoull(procfile_lineword(ff, l, 9), NULL, 10); // wr_sec
287 -
288 - // # of milliseconds spent reading # of milliseconds spent writing
289 - // This is the total number of milliseconds spent by all reads or writes (as
290 - // measured from __make_request() to end_that_request_last()).
291 - readms = strtoull(procfile_lineword(ff, l, 6), NULL, 10); // rd_ticks_or_wr_sec
292 - writems = strtoull(procfile_lineword(ff, l, 10), NULL, 10); // wr_ticks
293 -
294 - // # of I/Os currently in progress
295 - // The only field that should go to zero. Incremented as requests are
296 - // given to appropriate struct request_queue and decremented as they finish.
297 - queued_ios = strtoull(procfile_lineword(ff, l, 11), NULL, 10); // ios_pgr
298 -
299 - // # of milliseconds spent doing I/Os
300 - // This field increases so long as field queued_ios is nonzero.
301 - busy_ms = strtoull(procfile_lineword(ff, l, 12), NULL, 10); // tot_ticks
302 -
303 - // weighted # of milliseconds spent doing I/Os
304 - // This field is incremented at each I/O start, I/O completion, I/O
305 - // merge, or read of these stats by the number of I/Os in progress
306 - // (field queued_ios) times the number of milliseconds spent doing I/O since the
307 - // last update of this field. This can provide an easy measure of both
308 - // I/O completion time and the backlog that may be accumulating.
309 - backlog_ms = strtoull(procfile_lineword(ff, l, 13), NULL, 10); // rq_ticks
310 -
311 -
312 - // --------------------------------------------------------------------------
313 - // remove slashes from disk names
314 - char *s;
315 - for(s = disk; *s ;s++)
316 - if(*s == '/') *s = '_';
317 -
318 - // --------------------------------------------------------------------------
319 - // get a disk structure for the disk
320 -
321 - struct disk *d = get_disk(major, minor, disk);
322 -
323 -
324 - // --------------------------------------------------------------------------
325 - // Set its family based on mount point
326 -
327 - char *family = d->mount_point;
328 - if(!family) family = disk;
329 -
330 -
331 - // --------------------------------------------------------------------------
332 - // Check the configuration for the device
333 -
334 - if(unlikely(!d->configured)) {
335 - char var_name[4096 + 1];
336 - snprintfz(var_name, 4096, "plugin:proc:/proc/diskstats:%s", disk);
337 -
338 - int def_enable = config_get_boolean_ondemand(var_name, "enable", global_enable_new_disks_detected_at_runtime);
339 - if(def_enable == CONFIG_ONDEMAND_NO) {
340 - // the user does not want any metrics for this disk
341 - d->do_io = CONFIG_ONDEMAND_NO;
342 - d->do_ops = CONFIG_ONDEMAND_NO;
343 - d->do_mops = CONFIG_ONDEMAND_NO;
344 - d->do_iotime = CONFIG_ONDEMAND_NO;
345 - d->do_qops = CONFIG_ONDEMAND_NO;
346 - d->do_util = CONFIG_ONDEMAND_NO;
347 - d->do_backlog = CONFIG_ONDEMAND_NO;
348 - d->do_space = CONFIG_ONDEMAND_NO;
349 - d->do_inodes = CONFIG_ONDEMAND_NO;
350 - }
351 - else {
352 - // this disk is enabled
353 - // check its direct settings
354 -
355 - int def_performance = CONFIG_ONDEMAND_ONDEMAND;
356 - int def_space = (d->mount_point)?CONFIG_ONDEMAND_ONDEMAND:CONFIG_ONDEMAND_NO;
357 -
358 - // since this is 'on demand' we can figure the performance settings
359 - // based on the type of disk
360 -
361 - switch(d->type) {
362 - case DISK_TYPE_PHYSICAL:
363 - def_performance = global_enable_performance_for_physical_disks;
364 - break;
365 -
366 - case DISK_TYPE_PARTITION:
367 - def_performance = global_enable_performance_for_partitions;
368 - break;
369 -
370 - case DISK_TYPE_CONTAINER:
371 - def_performance = global_enable_performance_for_virtual_disks;
372 -
373 - if(d->mount_point)
374 - def_performance = select_positive_option(def_performance, global_enable_performance_for_virtual_mountpoints);
375 -
376 - break;
377 - }
378 -
379 - if(d->mount_point)
380 - def_performance = select_positive_option(def_performance, global_enable_performance_for_mountpoints);
381 -
382 - // ------------------------------------------------------------
383 - // now we have def_performance and def_space
384 - // to work further
385 -
386 - // def_performance
387 - // check the user configuration (this will also show our 'on demand' decision)
388 - def_performance = config_get_boolean_ondemand(var_name, "enable performance metrics", def_performance);
389 -
390 - int ddo_io = CONFIG_ONDEMAND_NO,
391 - ddo_ops = CONFIG_ONDEMAND_NO,
392 - ddo_mops = CONFIG_ONDEMAND_NO,
393 - ddo_iotime = CONFIG_ONDEMAND_NO,
394 - ddo_qops = CONFIG_ONDEMAND_NO,
395 - ddo_util = CONFIG_ONDEMAND_NO,
396 - ddo_backlog = CONFIG_ONDEMAND_NO;
397 -
398 - // we enable individual performance charts only when def_performance is not disabled
399 - if(def_performance != CONFIG_ONDEMAND_NO) {
400 - ddo_io = global_do_io,
401 - ddo_ops = global_do_ops,
402 - ddo_mops = global_do_mops,
403 - ddo_iotime = global_do_iotime,
404 - ddo_qops = global_do_qops,
405 - ddo_util = global_do_util,
406 - ddo_backlog = global_do_backlog;
407 - }
408 -
409 - d->do_io = config_get_boolean_ondemand(var_name, "bandwidth", ddo_io);
410 - d->do_ops = config_get_boolean_ondemand(var_name, "operations", ddo_ops);
411 - d->do_mops = config_get_boolean_ondemand(var_name, "merged operations", ddo_mops);
412 - d->do_iotime = config_get_boolean_ondemand(var_name, "i/o time", ddo_iotime);
413 - d->do_qops = config_get_boolean_ondemand(var_name, "queued operations", ddo_qops);
414 - d->do_util = config_get_boolean_ondemand(var_name, "utilization percentage", ddo_util);
415 - d->do_backlog = config_get_boolean_ondemand(var_name, "backlog", ddo_backlog);
416 -
417 - // def_space
418 - if(d->mount_point) {
419 - // check the user configuration (this will also show our 'on demand' decision)
420 - def_space = config_get_boolean_ondemand(var_name, "enable space metrics", def_space);
421 -
422 - int ddo_space = def_space,
423 - ddo_inodes = def_space;
424 -
425 - d->do_space = config_get_boolean_ondemand(var_name, "space usage", ddo_space);
426 - d->do_inodes = config_get_boolean_ondemand(var_name, "inodes usage", ddo_inodes);
427 - }
428 - else {
429 - // don't show settings for this disk
430 - d->do_space = CONFIG_ONDEMAND_NO;
431 - d->do_inodes = CONFIG_ONDEMAND_NO;
432 - }
433 - }
434 -
435 - d->configured = 1;
436 - }
437 -
438 - RRDSET *st;
439 -
440 - // --------------------------------------------------------------------------
441 - // Do performance metrics
442 -
443 - if(d->do_io == CONFIG_ONDEMAND_YES || (d->do_io == CONFIG_ONDEMAND_ONDEMAND && (readsectors || writesectors))) {
444 - d->do_io = CONFIG_ONDEMAND_YES;
445 -
446 - st = rrdset_find_bytype(RRD_TYPE_DISK, disk);
447 - if(!st) {
448 - st = rrdset_create(RRD_TYPE_DISK, disk, NULL, family, "disk.io", "Disk I/O Bandwidth", "kilobytes/s", 2000, update_every, RRDSET_TYPE_AREA);
449 -
450 - rrddim_add(st, "reads", NULL, d->sector_size, 1024, RRDDIM_INCREMENTAL);
451 - rrddim_add(st, "writes", NULL, d->sector_size * -1, 1024, RRDDIM_INCREMENTAL);
452 - }
453 - else rrdset_next_usec(st, dt);
454 -
455 - last_readsectors = rrddim_set(st, "reads", readsectors);
456 - last_writesectors = rrddim_set(st, "writes", writesectors);
457 - rrdset_done(st);
458 - }
459 -
460 - // --------------------------------------------------------------------
461 -
462 - if(d->do_ops == CONFIG_ONDEMAND_YES || (d->do_ops == CONFIG_ONDEMAND_ONDEMAND && (reads || writes))) {
463 - d->do_ops = CONFIG_ONDEMAND_YES;
464 -
465 - st = rrdset_find_bytype("disk_ops", disk);
466 - if(!st) {
467 - st = rrdset_create("disk_ops", disk, NULL, family, "disk.ops", "Disk Completed I/O Operations", "operations/s", 2001, update_every, RRDSET_TYPE_LINE);
468 - st->isdetail = 1;
469 -
470 - rrddim_add(st, "reads", NULL, 1, 1, RRDDIM_INCREMENTAL);
471 - rrddim_add(st, "writes", NULL, -1, 1, RRDDIM_INCREMENTAL);
472 - }
473 - else rrdset_next_usec(st, dt);
474 -
475 - last_reads = rrddim_set(st, "reads", reads);
476 - last_writes = rrddim_set(st, "writes", writes);
477 - rrdset_done(st);
478 - }
479 -
480 - // --------------------------------------------------------------------
481 -
482 - if(d->do_qops == CONFIG_ONDEMAND_YES || (d->do_qops == CONFIG_ONDEMAND_ONDEMAND && queued_ios)) {
483 - d->do_qops = CONFIG_ONDEMAND_YES;
484 -
485 - st = rrdset_find_bytype("disk_qops", disk);
486 - if(!st) {
487 - st = rrdset_create("disk_qops", disk, NULL, family, "disk.qops", "Disk Current I/O Operations", "operations", 2002, update_every, RRDSET_TYPE_LINE);
488 - st->isdetail = 1;
489 -
490 - rrddim_add(st, "operations", NULL, 1, 1, RRDDIM_ABSOLUTE);
491 - }
492 - else rrdset_next_usec(st, dt);
493 -
494 - rrddim_set(st, "operations", queued_ios);
495 - rrdset_done(st);
496 - }
497 -
498 - // --------------------------------------------------------------------
499 -
500 - if(d->do_backlog == CONFIG_ONDEMAND_YES || (d->do_backlog == CONFIG_ONDEMAND_ONDEMAND && backlog_ms)) {
501 - d->do_backlog = CONFIG_ONDEMAND_YES;
502 -
503 - st = rrdset_find_bytype("disk_backlog", disk);
504 - if(!st) {
505 - st = rrdset_create("disk_backlog", disk, NULL, family, "disk.backlog", "Disk Backlog", "backlog (ms)", 2003, update_every, RRDSET_TYPE_AREA);
506 - st->isdetail = 1;
507 -
508 - rrddim_add(st, "backlog", NULL, 1, 10, RRDDIM_INCREMENTAL);
509 - }
510 - else rrdset_next_usec(st, dt);
511 -
512 - rrddim_set(st, "backlog", backlog_ms);
513 - rrdset_done(st);
514 - }
515 -
516 - // --------------------------------------------------------------------
517 -
518 - if(d->do_util == CONFIG_ONDEMAND_YES || (d->do_util == CONFIG_ONDEMAND_ONDEMAND && busy_ms)) {
519 - d->do_util = CONFIG_ONDEMAND_YES;
520 -
521 - st = rrdset_find_bytype("disk_util", disk);
522 - if(!st) {
523 - st = rrdset_create("disk_util", disk, NULL, family, "disk.util", "Disk Utilization Time", "% of time working", 2004, update_every, RRDSET_TYPE_AREA);
524 - st->isdetail = 1;
525 -
526 - rrddim_add(st, "utilization", NULL, 1, 10, RRDDIM_INCREMENTAL);
527 - }
528 - else rrdset_next_usec(st, dt);
529 -
530 - last_busy_ms = rrddim_set(st, "utilization", busy_ms);
531 - rrdset_done(st);
532 - }
533 -
534 - // --------------------------------------------------------------------
535 -
536 - if(d->do_mops == CONFIG_ONDEMAND_YES || (d->do_mops == CONFIG_ONDEMAND_ONDEMAND && (mreads || mwrites))) {
537 - d->do_mops = CONFIG_ONDEMAND_YES;
538 -
539 - st = rrdset_find_bytype("disk_mops", disk);
540 - if(!st) {
541 - st = rrdset_create("disk_mops", disk, NULL, family, "disk.mops", "Disk Merged Operations", "merged operations/s", 2021, update_every, RRDSET_TYPE_LINE);
542 - st->isdetail = 1;
543 -
544 - rrddim_add(st, "reads", NULL, 1, 1, RRDDIM_INCREMENTAL);
545 - rrddim_add(st, "writes", NULL, -1, 1, RRDDIM_INCREMENTAL);
546 - }
547 - else rrdset_next_usec(st, dt);
548 -
549 - rrddim_set(st, "reads", mreads);
550 - rrddim_set(st, "writes", mwrites);
551 - rrdset_done(st);
552 - }
553 -
554 - // --------------------------------------------------------------------
555 -
556 - if(d->do_iotime == CONFIG_ONDEMAND_YES || (d->do_iotime == CONFIG_ONDEMAND_ONDEMAND && (readms || writems))) {
557 - d->do_iotime = CONFIG_ONDEMAND_YES;
558 -
559 - st = rrdset_find_bytype("disk_iotime", disk);
560 - if(!st) {
561 - st = rrdset_create("disk_iotime", disk, NULL, family, "disk.iotime", "Disk Total I/O Time", "milliseconds/s", 2022, update_every, RRDSET_TYPE_LINE);
562 - st->isdetail = 1;
563 -
564 - rrddim_add(st, "reads", NULL, 1, 1, RRDDIM_INCREMENTAL);
565 - rrddim_add(st, "writes", NULL, -1, 1, RRDDIM_INCREMENTAL);
566 - }
567 - else rrdset_next_usec(st, dt);
568 -
569 - last_readms = rrddim_set(st, "reads", readms);
570 - last_writems = rrddim_set(st, "writes", writems);
571 - rrdset_done(st);
572 - }
573 -
574 - // --------------------------------------------------------------------
575 - // calculate differential charts
576 - // only if this is not the first time we run
577 -
578 - if(dt) {
579 - if( (d->do_iotime == CONFIG_ONDEMAND_YES || (d->do_iotime == CONFIG_ONDEMAND_ONDEMAND && (readms || writems))) &&
580 - (d->do_ops == CONFIG_ONDEMAND_YES || (d->do_ops == CONFIG_ONDEMAND_ONDEMAND && (reads || writes)))) {
581 - st = rrdset_find_bytype("disk_await", disk);
582 - if(!st) {
583 - st = rrdset_create("disk_await", disk, NULL, family, "disk.await", "Average Completed I/O Operation Time", "ms per operation", 2005, update_every, RRDSET_TYPE_LINE);
584 - st->isdetail = 1;
585 -
586 - rrddim_add(st, "reads", NULL, 1, 1, RRDDIM_ABSOLUTE);
587 - rrddim_add(st, "writes", NULL, -1, 1, RRDDIM_ABSOLUTE);
588 - }
589 - else rrdset_next_usec(st, dt);
590 -
591 - rrddim_set(st, "reads", (reads - last_reads) ? (readms - last_readms) / (reads - last_reads) : 0);
592 - rrddim_set(st, "writes", (writes - last_writes) ? (writems - last_writems) / (writes - last_writes) : 0);
593 - rrdset_done(st);
594 - }
595 -
596 - if( (d->do_io == CONFIG_ONDEMAND_YES || (d->do_io == CONFIG_ONDEMAND_ONDEMAND && (readsectors || writesectors))) &&
597 - (d->do_ops == CONFIG_ONDEMAND_YES || (d->do_ops == CONFIG_ONDEMAND_ONDEMAND && (reads || writes)))) {
598 - st = rrdset_find_bytype("disk_avgsz", disk);
599 - if(!st) {
600 - st = rrdset_create("disk_avgsz", disk, NULL, family, "disk.avgsz", "Average Completed I/O Operation Bandwidth", "kilobytes per operation", 2006, update_every, RRDSET_TYPE_AREA);
601 - st->isdetail = 1;
602 -
603 - rrddim_add(st, "reads", NULL, d->sector_size, 1024, RRDDIM_ABSOLUTE);
604 - rrddim_add(st, "writes", NULL, d->sector_size * -1, 1024, RRDDIM_ABSOLUTE);
605 - }
606 - else rrdset_next_usec(st, dt);
607 -
608 - rrddim_set(st, "reads", (reads - last_reads) ? (readsectors - last_readsectors) / (reads - last_reads) : 0);
609 - rrddim_set(st, "writes", (writes - last_writes) ? (writesectors - last_writesectors) / (writes - last_writes) : 0);
610 - rrdset_done(st);
611 - }
612 -
613 - if( (d->do_util == CONFIG_ONDEMAND_YES || (d->do_util == CONFIG_ONDEMAND_ONDEMAND && busy_ms)) &&
614 - (d->do_ops == CONFIG_ONDEMAND_YES || (d->do_ops == CONFIG_ONDEMAND_ONDEMAND && (reads || writes)))) {
615 - st = rrdset_find_bytype("disk_svctm", disk);
616 - if(!st) {
617 - st = rrdset_create("disk_svctm", disk, NULL, family, "disk.svctm", "Average Service Time", "ms per operation", 2007, update_every, RRDSET_TYPE_LINE);
618 - st->isdetail = 1;
619 -
620 - rrddim_add(st, "svctm", NULL, 1, 1, RRDDIM_ABSOLUTE);
621 - }
622 - else rrdset_next_usec(st, dt);
623 -
624 - rrddim_set(st, "svctm", ((reads - last_reads) + (writes - last_writes)) ? (busy_ms - last_busy_ms) / ((reads - last_reads) + (writes - last_writes)) : 0);
625 - rrdset_done(st);
626 - }
627 - }
628 -
629 - // --------------------------------------------------------------------------
630 - // space metrics
631 -
632 - if(d->mount_point && (d->do_space || d->do_inodes) ) {
633 - // collect space metrics using statvfs
634 -
635 - if (statvfs(d->mount_point, &buff_statvfs) < 0)
636 - error("Failed statvfs() for '%s' (disk '%s')", d->mount_point, d->disk);
637 - else {
638 - space_avail = buff_statvfs.f_bavail * buff_statvfs.f_bsize;
639 - space_avail_root = (buff_statvfs.f_bfree - buff_statvfs.f_bavail) * buff_statvfs.f_bsize;
640 - space_used = (buff_statvfs.f_blocks - buff_statvfs.f_bfree) * buff_statvfs.f_bsize;
641 -
642 - inodes_avail = buff_statvfs.f_favail;
643 - inodes_avail_root = buff_statvfs.f_ffree - buff_statvfs.f_favail;
644 - inodes_used = buff_statvfs.f_files - buff_statvfs.f_ffree;
645 -
646 - // verify we collected the metrics for the right disk.
647 - // if not the mountpoint has changed.
648 -
649 - if(stat(d->mount_point, &buff_stat) == -1)
650 - error("Failed to stat() for '%s' (disk '%s')", d->mount_point, d->disk);
651 - else {
652 - if(major(buff_stat.st_dev) == major && minor(buff_stat.st_dev) == minor) {
653 -
654 - // --------------------------------------------------------------------------
655 -
656 - if(d->do_space == CONFIG_ONDEMAND_YES || (d->do_space == CONFIG_ONDEMAND_ONDEMAND && (space_avail || space_avail_root || space_used))) {
657 - st = rrdset_find_bytype("disk_space", disk);
658 - if(!st) {
659 - st = rrdset_create("disk_space", disk, NULL, family, "disk.space", "Disk Space Usage", "GB", 2023, update_every, RRDSET_TYPE_STACKED);
660 - st->isdetail = 1;
661 -
662 - rrddim_add(st, "avail", NULL, 1, 1024*1024*1024, RRDDIM_ABSOLUTE);
663 - rrddim_add(st, "used" , NULL, 1, 1024*1024*1024, RRDDIM_ABSOLUTE);
664 - rrddim_add(st, "reserved_for_root", "reserved for root", 1, 1024*1024*1024, RRDDIM_ABSOLUTE);
665 - }
666 - else rrdset_next_usec(st, dt);
667 -
668 - rrddim_set(st, "avail", space_avail);
669 - rrddim_set(st, "used", space_used);
670 - rrddim_set(st, "reserved_for_root", space_avail_root);
671 - rrdset_done(st);
672 - }
673 -
674 - // --------------------------------------------------------------------------
675 -
676 - if(d->do_inodes == CONFIG_ONDEMAND_YES || (d->do_inodes == CONFIG_ONDEMAND_ONDEMAND && (inodes_avail || inodes_avail_root || inodes_used))) {
677 - st = rrdset_find_bytype("disk_inodes", disk);
678 - if(!st) {
679 - st = rrdset_create("disk_inodes", disk, NULL, family, "disk.inodes", "Disk Inodes Usage", "Inodes", 2024, update_every, RRDSET_TYPE_STACKED);
680 - st->isdetail = 1;
681 -
682 - rrddim_add(st, "avail", NULL, 1, 1, RRDDIM_ABSOLUTE);
683 - rrddim_add(st, "used" , NULL, 1, 1, RRDDIM_ABSOLUTE);
684 - rrddim_add(st, "reserved_for_root", "reserved for root", 1, 1, RRDDIM_ABSOLUTE);
685 - }
686 - else rrdset_next_usec(st, dt);
687 -
688 - rrddim_set(st, "avail", inodes_avail);
689 - rrddim_set(st, "used", inodes_used);
690 - rrddim_set(st, "reserved_for_root", inodes_avail_root);
691 - rrdset_done(st);
692 - }
693 - }
694 - }
695 - }
696 - }
697 - }
698 -
699 - return 0;
191 + static procfile *ff = NULL;
192 + static struct statvfs buff_statvfs;
193 + static struct stat buff_stat;
194 + static int global_enable_new_disks_detected_at_runtime = CONFIG_ONDEMAND_YES,
195 + global_enable_performance_for_physical_disks = CONFIG_ONDEMAND_ONDEMAND,
196 + global_enable_performance_for_virtual_disks = CONFIG_ONDEMAND_NO,
197 + global_enable_performance_for_partitions = CONFIG_ONDEMAND_NO,
198 + global_enable_performance_for_mountpoints = CONFIG_ONDEMAND_NO,
199 + global_enable_performance_for_virtual_mountpoints = CONFIG_ONDEMAND_ONDEMAND,
200 + global_enable_space_for_mountpoints = CONFIG_ONDEMAND_ONDEMAND,
201 + global_do_io = CONFIG_ONDEMAND_ONDEMAND,
202 + global_do_ops = CONFIG_ONDEMAND_ONDEMAND,
203 + global_do_mops = CONFIG_ONDEMAND_ONDEMAND,
204 + global_do_iotime = CONFIG_ONDEMAND_ONDEMAND,
205 + global_do_qops = CONFIG_ONDEMAND_ONDEMAND,
206 + global_do_util = CONFIG_ONDEMAND_ONDEMAND,
207 + global_do_backlog = CONFIG_ONDEMAND_ONDEMAND,
208 + global_do_space = CONFIG_ONDEMAND_ONDEMAND,
209 + global_do_inodes = CONFIG_ONDEMAND_ONDEMAND,
210 + globals_initialized = 0;
211 +
212 + if(unlikely(!globals_initialized)) {
213 + global_enable_new_disks_detected_at_runtime = config_get_boolean("plugin:proc:/proc/diskstats", "enable new disks detected at runtime", global_enable_new_disks_detected_at_runtime);
214 +
215 + global_enable_performance_for_physical_disks = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "performance metrics for physical disks", global_enable_performance_for_physical_disks);
216 + global_enable_performance_for_virtual_disks = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "performance metrics for virtual disks", global_enable_performance_for_virtual_disks);
217 + global_enable_performance_for_partitions = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "performance metrics for partitions", global_enable_performance_for_partitions);
218 + global_enable_performance_for_mountpoints = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "performance metrics for mounted filesystems", global_enable_performance_for_mountpoints);
219 + global_enable_performance_for_virtual_mountpoints = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "performance metrics for mounted virtual disks", global_enable_performance_for_virtual_mountpoints);
220 + global_enable_space_for_mountpoints = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "space metrics for mounted filesystems", global_enable_space_for_mountpoints);
221 +
222 + global_do_io = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "bandwidth for all disks", global_do_io);
223 + global_do_ops = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "operations for all disks", global_do_ops);
224 + global_do_mops = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "merged operations for all disks", global_do_mops);
225 + global_do_iotime = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "i/o time for all disks", global_do_iotime);
226 + global_do_qops = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "queued operations for all disks", global_do_qops);
227 + global_do_util = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "utilization percentage for all disks", global_do_util);
228 + global_do_backlog = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "backlog for all disks", global_do_backlog);
229 + global_do_space = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "space usage for all disks", global_do_space);
230 + global_do_inodes = config_get_boolean_ondemand("plugin:proc:/proc/diskstats", "inodes usage for all disks", global_do_inodes);
231 +
232 + globals_initialized = 1;
233 + }
234 +
235 + if(!ff) {
236 + char filename[FILENAME_MAX + 1];
237 + snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/diskstats");
238 + ff = procfile_open(config_get("plugin:proc:/proc/diskstats", "filename to monitor", filename), " \t", PROCFILE_FLAG_DEFAULT);
239 + }
240 + if(!ff) return 1;
241 +
242 + ff = procfile_readall(ff);
243 + if(!ff) return 0; // we return 0, so that we will retry to open it next time
244 +
245 + uint32_t lines = procfile_lines(ff), l;
246 + uint32_t words;
247 +
248 + for(l = 0; l < lines ;l++) {
249 + // --------------------------------------------------------------------------
250 + // Read parameters
251 +
252 + char *disk;
253 + unsigned long long major = 0, minor = 0,
254 + reads = 0, mreads = 0, readsectors = 0, readms = 0,
255 + writes = 0, mwrites = 0, writesectors = 0, writems = 0,
256 + queued_ios = 0, busy_ms = 0, backlog_ms = 0,
257 + space_avail = 0, space_avail_root = 0, space_used = 0,
258 + inodes_avail = 0, inodes_avail_root = 0, inodes_used = 0;
259 +
260 + unsigned long long last_reads = 0, last_readsectors = 0, last_readms = 0,
261 + last_writes = 0, last_writesectors = 0, last_writems = 0,
262 + last_busy_ms = 0;
263 +
264 + words = procfile_linewords(ff, l);
265 + if(words < 14) continue;
266 +
267 + major = strtoull(procfile_lineword(ff, l, 0), NULL, 10);
268 + minor = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
269 + disk = procfile_lineword(ff, l, 2);
270 +
271 + // # of reads completed # of writes completed
272 + // This is the total number of reads or writes completed successfully.
273 + reads = strtoull(procfile_lineword(ff, l, 3), NULL, 10); // rd_ios
274 + writes = strtoull(procfile_lineword(ff, l, 7), NULL, 10); // wr_ios
275 +
276 + // # of reads merged # of writes merged
277 + // Reads and writes which are adjacent to each other may be merged for
278 + // efficiency. Thus two 4K reads may become one 8K read before it is
279 + // ultimately handed to the disk, and so it will be counted (and queued)
280 + mreads = strtoull(procfile_lineword(ff, l, 4), NULL, 10); // rd_merges_or_rd_sec
281 + mwrites = strtoull(procfile_lineword(ff, l, 8), NULL, 10); // wr_merges
282 +
283 + // # of sectors read # of sectors written
284 + // This is the total number of sectors read or written successfully.
285 + readsectors = strtoull(procfile_lineword(ff, l, 5), NULL, 10); // rd_sec_or_wr_ios
286 + writesectors = strtoull(procfile_lineword(ff, l, 9), NULL, 10); // wr_sec
287 +
288 + // # of milliseconds spent reading # of milliseconds spent writing
289 + // This is the total number of milliseconds spent by all reads or writes (as
290 + // measured from __make_request() to end_that_request_last()).
291 + readms = strtoull(procfile_lineword(ff, l, 6), NULL, 10); // rd_ticks_or_wr_sec
292 + writems = strtoull(procfile_lineword(ff, l, 10), NULL, 10); // wr_ticks
293 +
294 + // # of I/Os currently in progress
295 + // The only field that should go to zero. Incremented as requests are
296 + // given to appropriate struct request_queue and decremented as they finish.
297 + queued_ios = strtoull(procfile_lineword(ff, l, 11), NULL, 10); // ios_pgr
298 +
299 + // # of milliseconds spent doing I/Os
300 + // This field increases so long as field queued_ios is nonzero.
301 + busy_ms = strtoull(procfile_lineword(ff, l, 12), NULL, 10); // tot_ticks
302 +
303 + // weighted # of milliseconds spent doing I/Os
304 + // This field is incremented at each I/O start, I/O completion, I/O
305 + // merge, or read of these stats by the number of I/Os in progress
306 + // (field queued_ios) times the number of milliseconds spent doing I/O since the
307 + // last update of this field. This can provide an easy measure of both
308 + // I/O completion time and the backlog that may be accumulating.
309 + backlog_ms = strtoull(procfile_lineword(ff, l, 13), NULL, 10); // rq_ticks
310 +
311 +
312 + // --------------------------------------------------------------------------
313 + // remove slashes from disk names
314 + char *s;
315 + for(s = disk; *s ;s++)
316 + if(*s == '/') *s = '_';
317 +
318 + // --------------------------------------------------------------------------
319 + // get a disk structure for the disk
320 +
321 + struct disk *d = get_disk(major, minor, disk);
322 +
323 +
324 + // --------------------------------------------------------------------------
325 + // Set its family based on mount point
326 +
327 + char *family = d->mount_point;
328 + if(!family) family = disk;
329 +
330 +
331 + // --------------------------------------------------------------------------
332 + // Check the configuration for the device
333 +
334 + if(unlikely(!d->configured)) {
335 + char var_name[4096 + 1];
336 + snprintfz(var_name, 4096, "plugin:proc:/proc/diskstats:%s", disk);
337 +
338 + int def_enable = config_get_boolean_ondemand(var_name, "enable", global_enable_new_disks_detected_at_runtime);
339 + if(def_enable == CONFIG_ONDEMAND_NO) {
340 + // the user does not want any metrics for this disk
341 + d->do_io = CONFIG_ONDEMAND_NO;
342 + d->do_ops = CONFIG_ONDEMAND_NO;
343 + d->do_mops = CONFIG_ONDEMAND_NO;
344 + d->do_iotime = CONFIG_ONDEMAND_NO;
345 + d->do_qops = CONFIG_ONDEMAND_NO;
346 + d->do_util = CONFIG_ONDEMAND_NO;
347 + d->do_backlog = CONFIG_ONDEMAND_NO;
348 + d->do_space = CONFIG_ONDEMAND_NO;
349 + d->do_inodes = CONFIG_ONDEMAND_NO;
350 + }
351 + else {
352 + // this disk is enabled
353 + // check its direct settings
354 +
355 + int def_performance = CONFIG_ONDEMAND_ONDEMAND;
356 + int def_space = (d->mount_point)?CONFIG_ONDEMAND_ONDEMAND:CONFIG_ONDEMAND_NO;
357 +
358 + // since this is 'on demand' we can figure the performance settings
359 + // based on the type of disk
360 +
361 + switch(d->type) {
362 + case DISK_TYPE_PHYSICAL:
363 + def_performance = global_enable_performance_for_physical_disks;
364 + break;
365 +
366 + case DISK_TYPE_PARTITION:
367 + def_performance = global_enable_performance_for_partitions;
368 + break;
369 +
370 + case DISK_TYPE_CONTAINER:
371 + def_performance = global_enable_performance_for_virtual_disks;
372 +
373 + if(d->mount_point)
374 + def_performance = select_positive_option(def_performance, global_enable_performance_for_virtual_mountpoints);
375 +
376 + break;
377 + }
378 +
379 + if(d->mount_point)
380 + def_performance = select_positive_option(def_performance, global_enable_performance_for_mountpoints);
381 +
382 + // ------------------------------------------------------------
383 + // now we have def_performance and def_space
384 + // to work further
385 +
386 + // def_performance
387 + // check the user configuration (this will also show our 'on demand' decision)
388 + def_performance = config_get_boolean_ondemand(var_name, "enable performance metrics", def_performance);
389 +
390 + int ddo_io = CONFIG_ONDEMAND_NO,
391 + ddo_ops = CONFIG_ONDEMAND_NO,
392 + ddo_mops = CONFIG_ONDEMAND_NO,
393 + ddo_iotime = CONFIG_ONDEMAND_NO,
394 + ddo_qops = CONFIG_ONDEMAND_NO,
395 + ddo_util = CONFIG_ONDEMAND_NO,
396 + ddo_backlog = CONFIG_ONDEMAND_NO;
397 +
398 + // we enable individual performance charts only when def_performance is not disabled
399 + if(def_performance != CONFIG_ONDEMAND_NO) {
400 + ddo_io = global_do_io,
401 + ddo_ops = global_do_ops,
402 + ddo_mops = global_do_mops,
403 + ddo_iotime = global_do_iotime,
404 + ddo_qops = global_do_qops,
405 + ddo_util = global_do_util,
406 + ddo_backlog = global_do_backlog;
407 + }
408 +
409 + d->do_io = config_get_boolean_ondemand(var_name, "bandwidth", ddo_io);
410 + d->do_ops = config_get_boolean_ondemand(var_name, "operations", ddo_ops);
411 + d->do_mops = config_get_boolean_ondemand(var_name, "merged operations", ddo_mops);
412 + d->do_iotime = config_get_boolean_ondemand(var_name, "i/o time", ddo_iotime);
413 + d->do_qops = config_get_boolean_ondemand(var_name, "queued operations", ddo_qops);
414 + d->do_util = config_get_boolean_ondemand(var_name, "utilization percentage", ddo_util);
415 + d->do_backlog = config_get_boolean_ondemand(var_name, "backlog", ddo_backlog);
416 +
417 + // def_space
418 + if(d->mount_point) {
419 + // check the user configuration (this will also show our 'on demand' decision)
420 + def_space = config_get_boolean_ondemand(var_name, "enable space metrics", def_space);
421 +
422 + int ddo_space = def_space,
423 + ddo_inodes = def_space;
424 +
425 + d->do_space = config_get_boolean_ondemand(var_name, "space usage", ddo_space);
426 + d->do_inodes = config_get_boolean_ondemand(var_name, "inodes usage", ddo_inodes);
427 + }
428 + else {
429 + // don't show settings for this disk
430 + d->do_space = CONFIG_ONDEMAND_NO;
431 + d->do_inodes = CONFIG_ONDEMAND_NO;
432 + }
433 + }
434 +
435 + d->configured = 1;
436 + }
437 +
438 + RRDSET *st;
439 +
440 + // --------------------------------------------------------------------------
441 + // Do performance metrics
442 +
443 + if(d->do_io == CONFIG_ONDEMAND_YES || (d->do_io == CONFIG_ONDEMAND_ONDEMAND && (readsectors || writesectors))) {
444 + d->do_io = CONFIG_ONDEMAND_YES;
445 +
446 + st = rrdset_find_bytype(RRD_TYPE_DISK, disk);
447 + if(!st) {
448 + st = rrdset_create(RRD_TYPE_DISK, disk, NULL, family, "disk.io", "Disk I/O Bandwidth", "kilobytes/s", 2000, update_every, RRDSET_TYPE_AREA);
449 +
450 + rrddim_add(st, "reads", NULL, d->sector_size, 1024, RRDDIM_INCREMENTAL);
451 + rrddim_add(st, "writes", NULL, d->sector_size * -1, 1024, RRDDIM_INCREMENTAL);
452 + }
453 + else rrdset_next_usec(st, dt);
454 +
455 + last_readsectors = rrddim_set(st, "reads", readsectors);
456 + last_writesectors = rrddim_set(st, "writes", writesectors);
457 + rrdset_done(st);
458 + }
459 +
460 + // --------------------------------------------------------------------
461 +
462 + if(d->do_ops == CONFIG_ONDEMAND_YES || (d->do_ops == CONFIG_ONDEMAND_ONDEMAND && (reads || writes))) {
463 + d->do_ops = CONFIG_ONDEMAND_YES;
464 +
465 + st = rrdset_find_bytype("disk_ops", disk);
466 + if(!st) {
467 + st = rrdset_create("disk_ops", disk, NULL, family, "disk.ops", "Disk Completed I/O Operations", "operations/s", 2001, update_every, RRDSET_TYPE_LINE);
468 + st->isdetail = 1;
469 +
470 + rrddim_add(st, "reads", NULL, 1, 1, RRDDIM_INCREMENTAL);
471 + rrddim_add(st, "writes", NULL, -1, 1, RRDDIM_INCREMENTAL);
472 + }
473 + else rrdset_next_usec(st, dt);
474 +
475 + last_reads = rrddim_set(st, "reads", reads);
476 + last_writes = rrddim_set(st, "writes", writes);
477 + rrdset_done(st);
478 + }
479 +
480 + // --------------------------------------------------------------------
481 +
482 + if(d->do_qops == CONFIG_ONDEMAND_YES || (d->do_qops == CONFIG_ONDEMAND_ONDEMAND && queued_ios)) {
483 + d->do_qops = CONFIG_ONDEMAND_YES;
484 +
485 + st = rrdset_find_bytype("disk_qops", disk);
486 + if(!st) {
487 + st = rrdset_create("disk_qops", disk, NULL, family, "disk.qops", "Disk Current I/O Operations", "operations", 2002, update_every, RRDSET_TYPE_LINE);
488 + st->isdetail = 1;
489 +
490 + rrddim_add(st, "operations", NULL, 1, 1, RRDDIM_ABSOLUTE);
491 + }
492 + else rrdset_next_usec(st, dt);
493 +
494 + rrddim_set(st, "operations", queued_ios);
495 + rrdset_done(st);
496 + }
497 +
498 + // --------------------------------------------------------------------
499 +
500 + if(d->do_backlog == CONFIG_ONDEMAND_YES || (d->do_backlog == CONFIG_ONDEMAND_ONDEMAND && backlog_ms)) {
501 + d->do_backlog = CONFIG_ONDEMAND_YES;
502 +
503 + st = rrdset_find_bytype("disk_backlog", disk);
504 + if(!st) {
505 + st = rrdset_create("disk_backlog", disk, NULL, family, "disk.backlog", "Disk Backlog", "backlog (ms)", 2003, update_every, RRDSET_TYPE_AREA);
506 + st->isdetail = 1;
507 +
508 + rrddim_add(st, "backlog", NULL, 1, 10, RRDDIM_INCREMENTAL);
509 + }
510 + else rrdset_next_usec(st, dt);
511 +
512 + rrddim_set(st, "backlog", backlog_ms);
513 + rrdset_done(st);
514 + }
515 +
516 + // --------------------------------------------------------------------
517 +
518 + if(d->do_util == CONFIG_ONDEMAND_YES || (d->do_util == CONFIG_ONDEMAND_ONDEMAND && busy_ms)) {
519 + d->do_util = CONFIG_ONDEMAND_YES;
520 +
521 + st = rrdset_find_bytype("disk_util", disk);
522 + if(!st) {
523 + st = rrdset_create("disk_util", disk, NULL, family, "disk.util", "Disk Utilization Time", "% of time working", 2004, update_every, RRDSET_TYPE_AREA);
524 + st->isdetail = 1;
525 +
526 + rrddim_add(st, "utilization", NULL, 1, 10, RRDDIM_INCREMENTAL);
527 + }
528 + else rrdset_next_usec(st, dt);
529 +
530 + last_busy_ms = rrddim_set(st, "utilization", busy_ms);
531 + rrdset_done(st);
532 + }
533 +
534 + // --------------------------------------------------------------------
535 +
536 + if(d->do_mops == CONFIG_ONDEMAND_YES || (d->do_mops == CONFIG_ONDEMAND_ONDEMAND && (mreads || mwrites))) {
537 + d->do_mops = CONFIG_ONDEMAND_YES;
538 +
539 + st = rrdset_find_bytype("disk_mops", disk);
540 + if(!st) {
541 + st = rrdset_create("disk_mops", disk, NULL, family, "disk.mops", "Disk Merged Operations", "merged operations/s", 2021, update_every, RRDSET_TYPE_LINE);
542 + st->isdetail = 1;
543 +
544 + rrddim_add(st, "reads", NULL, 1, 1, RRDDIM_INCREMENTAL);
545 + rrddim_add(st, "writes", NULL, -1, 1, RRDDIM_INCREMENTAL);
546 + }
547 + else rrdset_next_usec(st, dt);
548 +
549 + rrddim_set(st, "reads", mreads);
550 + rrddim_set(st, "writes", mwrites);
551 + rrdset_done(st);
552 + }
553 +
554 + // --------------------------------------------------------------------
555 +
556 + if(d->do_iotime == CONFIG_ONDEMAND_YES || (d->do_iotime == CONFIG_ONDEMAND_ONDEMAND && (readms || writems))) {
557 + d->do_iotime = CONFIG_ONDEMAND_YES;
558 +
559 + st = rrdset_find_bytype("disk_iotime", disk);
560 + if(!st) {
561 + st = rrdset_create("disk_iotime", disk, NULL, family, "disk.iotime", "Disk Total I/O Time", "milliseconds/s", 2022, update_every, RRDSET_TYPE_LINE);
562 + st->isdetail = 1;
563 +
564 + rrddim_add(st, "reads", NULL, 1, 1, RRDDIM_INCREMENTAL);
565 + rrddim_add(st, "writes", NULL, -1, 1, RRDDIM_INCREMENTAL);
566 + }
567 + else rrdset_next_usec(st, dt);
568 +
569 + last_readms = rrddim_set(st, "reads", readms);
570 + last_writems = rrddim_set(st, "writes", writems);
571 + rrdset_done(st);
572 + }
573 +
574 + // --------------------------------------------------------------------
575 + // calculate differential charts
576 + // only if this is not the first time we run
577 +
578 + if(dt) {
579 + if( (d->do_iotime == CONFIG_ONDEMAND_YES || (d->do_iotime == CONFIG_ONDEMAND_ONDEMAND && (readms || writems))) &&
580 + (d->do_ops == CONFIG_ONDEMAND_YES || (d->do_ops == CONFIG_ONDEMAND_ONDEMAND && (reads || writes)))) {
581 + st = rrdset_find_bytype("disk_await", disk);
582 + if(!st) {
583 + st = rrdset_create("disk_await", disk, NULL, family, "disk.await", "Average Completed I/O Operation Time", "ms per operation", 2005, update_every, RRDSET_TYPE_LINE);
584 + st->isdetail = 1;
585 +
586 + rrddim_add(st, "reads", NULL, 1, 1, RRDDIM_ABSOLUTE);
587 + rrddim_add(st, "writes", NULL, -1, 1, RRDDIM_ABSOLUTE);
588 + }
589 + else rrdset_next_usec(st, dt);
590 +
591 + rrddim_set(st, "reads", (reads - last_reads) ? (readms - last_readms) / (reads - last_reads) : 0);
592 + rrddim_set(st, "writes", (writes - last_writes) ? (writems - last_writems) / (writes - last_writes) : 0);
593 + rrdset_done(st);
594 + }
595 +
596 + if( (d->do_io == CONFIG_ONDEMAND_YES || (d->do_io == CONFIG_ONDEMAND_ONDEMAND && (readsectors || writesectors))) &&
597 + (d->do_ops == CONFIG_ONDEMAND_YES || (d->do_ops == CONFIG_ONDEMAND_ONDEMAND && (reads || writes)))) {
598 + st = rrdset_find_bytype("disk_avgsz", disk);
599 + if(!st) {
600 + st = rrdset_create("disk_avgsz", disk, NULL, family, "disk.avgsz", "Average Completed I/O Operation Bandwidth", "kilobytes per operation", 2006, update_every, RRDSET_TYPE_AREA);
601 + st->isdetail = 1;
602 +
603 + rrddim_add(st, "reads", NULL, d->sector_size, 1024, RRDDIM_ABSOLUTE);
604 + rrddim_add(st, "writes", NULL, d->sector_size * -1, 1024, RRDDIM_ABSOLUTE);
605 + }
606 + else rrdset_next_usec(st, dt);
607 +
608 + rrddim_set(st, "reads", (reads - last_reads) ? (readsectors - last_readsectors) / (reads - last_reads) : 0);
609 + rrddim_set(st, "writes", (writes - last_writes) ? (writesectors - last_writesectors) / (writes - last_writes) : 0);
610 + rrdset_done(st);
611 + }
612 +
613 + if( (d->do_util == CONFIG_ONDEMAND_YES || (d->do_util == CONFIG_ONDEMAND_ONDEMAND && busy_ms)) &&
614 + (d->do_ops == CONFIG_ONDEMAND_YES || (d->do_ops == CONFIG_ONDEMAND_ONDEMAND && (reads || writes)))) {
615 + st = rrdset_find_bytype("disk_svctm", disk);
616 + if(!st) {
617 + st = rrdset_create("disk_svctm", disk, NULL, family, "disk.svctm", "Average Service Time", "ms per operation", 2007, update_every, RRDSET_TYPE_LINE);
618 + st->isdetail = 1;
619 +
620 + rrddim_add(st, "svctm", NULL, 1, 1, RRDDIM_ABSOLUTE);
621 + }
622 + else rrdset_next_usec(st, dt);
623 +
624 + rrddim_set(st, "svctm", ((reads - last_reads) + (writes - last_writes)) ? (busy_ms - last_busy_ms) / ((reads - last_reads) + (writes - last_writes)) : 0);
625 + rrdset_done(st);
626 + }
627 + }
628 +
629 + // --------------------------------------------------------------------------
630 + // space metrics
631 +
632 + if(d->mount_point && (d->do_space || d->do_inodes) ) {
633 + // collect space metrics using statvfs
634 +
635 + if (statvfs(d->mount_point, &buff_statvfs) < 0)
636 + error("Failed statvfs() for '%s' (disk '%s')", d->mount_point, d->disk);
637 + else {
638 + space_avail = buff_statvfs.f_bavail * buff_statvfs.f_bsize;
639 + space_avail_root = (buff_statvfs.f_bfree - buff_statvfs.f_bavail) * buff_statvfs.f_bsize;
640 + space_used = (buff_statvfs.f_blocks - buff_statvfs.f_bfree) * buff_statvfs.f_bsize;
641 +
642 + inodes_avail = buff_statvfs.f_favail;
643 + inodes_avail_root = buff_statvfs.f_ffree - buff_statvfs.f_favail;
644 + inodes_used = buff_statvfs.f_files - buff_statvfs.f_ffree;
645 +
646 + // verify we collected the metrics for the right disk.
647 + // if not the mountpoint has changed.
648 +
649 + if(stat(d->mount_point, &buff_stat) == -1)
650 + error("Failed to stat() for '%s' (disk '%s')", d->mount_point, d->disk);
651 + else {
652 + if(major(buff_stat.st_dev) == major && minor(buff_stat.st_dev) == minor) {
653 +
654 + // --------------------------------------------------------------------------
655 +
656 + if(d->do_space == CONFIG_ONDEMAND_YES || (d->do_space == CONFIG_ONDEMAND_ONDEMAND && (space_avail || space_avail_root || space_used))) {
657 + st = rrdset_find_bytype("disk_space", disk);
658 + if(!st) {
659 + st = rrdset_create("disk_space", disk, NULL, family, "disk.space", "Disk Space Usage", "GB", 2023, update_every, RRDSET_TYPE_STACKED);
660 + st->isdetail = 1;
661 +
662 + rrddim_add(st, "avail", NULL, 1, 1024*1024*1024, RRDDIM_ABSOLUTE);
663 + rrddim_add(st, "used" , NULL, 1, 1024*1024*1024, RRDDIM_ABSOLUTE);
664 + rrddim_add(st, "reserved_for_root", "reserved for root", 1, 1024*1024*1024, RRDDIM_ABSOLUTE);
665 + }
666 + else rrdset_next_usec(st, dt);
667 +
668 + rrddim_set(st, "avail", space_avail);
669 + rrddim_set(st, "used", space_used);
670 + rrddim_set(st, "reserved_for_root", space_avail_root);
671 + rrdset_done(st);
672 + }
673 +
674 + // --------------------------------------------------------------------------
675 +
676 + if(d->do_inodes == CONFIG_ONDEMAND_YES || (d->do_inodes == CONFIG_ONDEMAND_ONDEMAND && (inodes_avail || inodes_avail_root || inodes_used))) {
677 + st = rrdset_find_bytype("disk_inodes", disk);
678 + if(!st) {
679 + st = rrdset_create("disk_inodes", disk, NULL, family, "disk.inodes", "Disk Inodes Usage", "Inodes", 2024, update_every, RRDSET_TYPE_STACKED);
680 + st->isdetail = 1;
681 +
682 + rrddim_add(st, "avail", NULL, 1, 1, RRDDIM_ABSOLUTE);
683 + rrddim_add(st, "used" , NULL, 1, 1, RRDDIM_ABSOLUTE);
684 + rrddim_add(st, "reserved_for_root", "reserved for root", 1, 1, RRDDIM_ABSOLUTE);
685 + }
686 + else rrdset_next_usec(st, dt);
687 +
688 + rrddim_set(st, "avail", inodes_avail);
689 + rrddim_set(st, "used", inodes_used);
690 + rrddim_set(st, "reserved_for_root", inodes_avail_root);
691 + rrdset_done(st);
692 + }
693 + }
694 + }
695 + }
696 + }
697 + }
698 +
699 + return 0;
700 }
src/proc_interrupts.c
+153 -153
@@ -3,11 +3,11 @@
3 #define MAX_INTERRUPT_NAME 50
4
5 struct interrupt {
6 - int used;
7 - char *id;
8 - char name[MAX_INTERRUPT_NAME + 1];
9 - unsigned long long total;
10 - unsigned long long value[];
6 + int used;
7 + char *id;
8 + char name[MAX_INTERRUPT_NAME + 1];
9 + unsigned long long total;
10 + unsigned long long value[];
11 };
12
13 // since each interrupt is variable in size
@@ -18,157 +18,157 @@ struct interrupt {
18 #define irrindex(base, line, cpus) ((struct interrupt *)&((char *)(base))[line * recordsize(cpus)])
19
20 static inline struct interrupt *get_interrupts_array(int lines, int cpus) {
21 - static struct interrupt *irrs = NULL;
22 - static int allocated = 0;
21 + static struct interrupt *irrs = NULL;
22 + static int allocated = 0;
23
24 - if(lines < allocated) return irrs;
25 - else {
26 - irrs = (struct interrupt *)reallocz(irrs, lines * recordsize(cpus));
27 - allocated = lines;
28 - }
24 + if(lines < allocated) return irrs;
25 + else {
26 + irrs = (struct interrupt *)reallocz(irrs, lines * recordsize(cpus));
27 + allocated = lines;
28 + }
29
30 - return irrs;
30 + return irrs;
31 }
32
33 int do_proc_interrupts(int update_every, unsigned long long dt) {
34 - static procfile *ff = NULL;
35 - static int cpus = -1, do_per_core = -1;
36 - struct interrupt *irrs = NULL;
37 -
38 - if(dt) {};
39 -
40 - if(do_per_core == -1) do_per_core = config_get_boolean("plugin:proc:/proc/interrupts", "interrupts per core", 1);
41 -
42 - if(!ff) {
43 - char filename[FILENAME_MAX + 1];
44 - snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/interrupts");
45 - ff = procfile_open(config_get("plugin:proc:/proc/interrupts", "filename to monitor", filename), " \t", PROCFILE_FLAG_DEFAULT);
46 - }
47 - if(!ff) return 1;
48 -
49 - ff = procfile_readall(ff);
50 - if(!ff) return 0; // we return 0, so that we will retry to open it next time
51 -
52 - uint32_t lines = procfile_lines(ff), l;
53 - uint32_t words = procfile_linewords(ff, 0), w;
54 -
55 - if(!lines) {
56 - error("Cannot read /proc/interrupts, zero lines reported.");
57 - return 1;
58 - }
59 -
60 - // find how many CPUs are there
61 - if(cpus == -1) {
62 - cpus = 0;
63 - for(w = 0; w < words ; w++) {
64 - if(strncmp(procfile_lineword(ff, 0, w), "CPU", 3) == 0)
65 - cpus++;
66 - }
67 - }
68 -
69 - if(!cpus) {
70 - error("PLUGIN: PROC_INTERRUPTS: Cannot find the number of CPUs in /proc/interrupts");
71 - return 1;
72 - }
73 -
74 - // allocate the size we need;
75 - irrs = get_interrupts_array(lines, cpus);
76 - irrs[0].used = 0;
77 -
78 - // loop through all lines
79 - for(l = 1; l < lines ;l++) {
80 - struct interrupt *irr = irrindex(irrs, l, cpus);
81 - irr->used = 0;
82 - irr->total = 0;
83 -
84 - words = procfile_linewords(ff, l);
85 - if(!words) continue;
86 -
87 - irr->id = procfile_lineword(ff, l, 0);
88 - if(!irr->id || !irr->id[0]) continue;
89 -
90 - int idlen = strlen(irr->id);
91 - if(irr->id[idlen - 1] == ':')
92 - irr->id[idlen - 1] = '\0';
93 -
94 - int c;
95 - for(c = 0; c < cpus ;c++) {
96 - if((c + 1) < (int)words)
97 - irr->value[c] = strtoull(procfile_lineword(ff, l, (uint32_t)(c + 1)), NULL, 10);
98 - else
99 - irr->value[c] = 0;
100 -
101 - irr->total += irr->value[c];
102 - }
103 -
104 - if(isdigit(irr->id[0]) && (uint32_t)(cpus + 2) < words) {
105 - strncpyz(irr->name, procfile_lineword(ff, l, words - 1), MAX_INTERRUPT_NAME);
106 - int nlen = strlen(irr->name);
107 - if(nlen < (MAX_INTERRUPT_NAME-1)) {
108 - irr->name[nlen] = '_';
109 - strncpyz(&irr->name[nlen + 1], irr->id, MAX_INTERRUPT_NAME - nlen);
110 - }
111 - }
112 - else {
113 - strncpyz(irr->name, irr->id, MAX_INTERRUPT_NAME);
114 - }
115 -
116 - irr->used = 1;
117 - }
118 -
119 - RRDSET *st;
120 -
121 - // --------------------------------------------------------------------
122 -
123 - st = rrdset_find_bytype("system", "interrupts");
124 - if(!st) {
125 - st = rrdset_create("system", "interrupts", NULL, "interrupts", NULL, "System interrupts", "interrupts/s", 1000, update_every, RRDSET_TYPE_STACKED);
126 -
127 - for(l = 0; l < lines ;l++) {
128 - struct interrupt *irr = irrindex(irrs, l, cpus);
129 - if(!irr->used) continue;
130 - rrddim_add(st, irr->id, irr->name, 1, 1, RRDDIM_INCREMENTAL);
131 - }
132 - }
133 - else rrdset_next(st);
134 -
135 - for(l = 0; l < lines ;l++) {
136 - struct interrupt *irr = irrindex(irrs, l, cpus);
137 - if(!irr->used) continue;
138 - rrddim_set(st, irr->id, irr->total);
139 - }
140 - rrdset_done(st);
141 -
142 - if(do_per_core) {
143 - int c;
144 -
145 - for(c = 0; c < cpus ; c++) {
146 - char id[256+1];
147 - snprintfz(id, 256, "cpu%d_interrupts", c);
148 -
149 - st = rrdset_find_bytype("cpu", id);
150 - if(!st) {
151 - char name[256+1], title[256+1];
152 - snprintfz(name, 256, "cpu%d_interrupts", c);
153 - snprintfz(title, 256, "CPU%d Interrupts", c);
154 - st = rrdset_create("cpu", id, name, "interrupts", "cpu.interrupts", title, "interrupts/s", 2000 + c, update_every, RRDSET_TYPE_STACKED);
155 -
156 - for(l = 0; l < lines ;l++) {
157 - struct interrupt *irr = irrindex(irrs, l, cpus);
158 - if(!irr->used) continue;
159 - rrddim_add(st, irr->id, irr->name, 1, 1, RRDDIM_INCREMENTAL);
160 - }
161 - }
162 - else rrdset_next(st);
163 -
164 - for(l = 0; l < lines ;l++) {
165 - struct interrupt *irr = irrindex(irrs, l, cpus);
166 - if(!irr->used) continue;
167 - rrddim_set(st, irr->id, irr->value[c]);
168 - }
169 - rrdset_done(st);
170 - }
171 - }
172 -
173 - return 0;
34 + static procfile *ff = NULL;
35 + static int cpus = -1, do_per_core = -1;
36 + struct interrupt *irrs = NULL;
37 +
38 + if(dt) {};
39 +
40 + if(do_per_core == -1) do_per_core = config_get_boolean("plugin:proc:/proc/interrupts", "interrupts per core", 1);
41 +
42 + if(!ff) {
43 + char filename[FILENAME_MAX + 1];
44 + snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/interrupts");
45 + ff = procfile_open(config_get("plugin:proc:/proc/interrupts", "filename to monitor", filename), " \t", PROCFILE_FLAG_DEFAULT);
46 + }
47 + if(!ff) return 1;
48 +
49 + ff = procfile_readall(ff);
50 + if(!ff) return 0; // we return 0, so that we will retry to open it next time
51 +
52 + uint32_t lines = procfile_lines(ff), l;
53 + uint32_t words = procfile_linewords(ff, 0), w;
54 +
55 + if(!lines) {
56 + error("Cannot read /proc/interrupts, zero lines reported.");
57 + return 1;
58 + }
59 +
60 + // find how many CPUs are there
61 + if(cpus == -1) {
62 + cpus = 0;
63 + for(w = 0; w < words ; w++) {
64 + if(strncmp(procfile_lineword(ff, 0, w), "CPU", 3) == 0)
65 + cpus++;
66 + }
67 + }
68 +
69 + if(!cpus) {
70 + error("PLUGIN: PROC_INTERRUPTS: Cannot find the number of CPUs in /proc/interrupts");
71 + return 1;
72 + }
73 +
74 + // allocate the size we need;
75 + irrs = get_interrupts_array(lines, cpus);
76 + irrs[0].used = 0;
77 +
78 + // loop through all lines
79 + for(l = 1; l < lines ;l++) {
80 + struct interrupt *irr = irrindex(irrs, l, cpus);
81 + irr->used = 0;
82 + irr->total = 0;
83 +
84 + words = procfile_linewords(ff, l);
85 + if(!words) continue;
86 +
87 + irr->id = procfile_lineword(ff, l, 0);
88 + if(!irr->id || !irr->id[0]) continue;
89 +
90 + int idlen = strlen(irr->id);
91 + if(irr->id[idlen - 1] == ':')
92 + irr->id[idlen - 1] = '\0';
93 +
94 + int c;
95 + for(c = 0; c < cpus ;c++) {
96 + if((c + 1) < (int)words)
97 + irr->value[c] = strtoull(procfile_lineword(ff, l, (uint32_t)(c + 1)), NULL, 10);
98 + else
99 + irr->value[c] = 0;
100 +
101 + irr->total += irr->value[c];
102 + }
103 +
104 + if(isdigit(irr->id[0]) && (uint32_t)(cpus + 2) < words) {
105 + strncpyz(irr->name, procfile_lineword(ff, l, words - 1), MAX_INTERRUPT_NAME);
106 + int nlen = strlen(irr->name);
107 + if(nlen < (MAX_INTERRUPT_NAME-1)) {
108 + irr->name[nlen] = '_';
109 + strncpyz(&irr->name[nlen + 1], irr->id, MAX_INTERRUPT_NAME - nlen);
110 + }
111 + }
112 + else {
113 + strncpyz(irr->name, irr->id, MAX_INTERRUPT_NAME);
114 + }
115 +
116 + irr->used = 1;
117 + }
118 +
119 + RRDSET *st;
120 +
121 + // --------------------------------------------------------------------
122 +
123 + st = rrdset_find_bytype("system", "interrupts");
124 + if(!st) {
125 + st = rrdset_create("system", "interrupts", NULL, "interrupts", NULL, "System interrupts", "interrupts/s", 1000, update_every, RRDSET_TYPE_STACKED);
126 +
127 + for(l = 0; l < lines ;l++) {
128 + struct interrupt *irr = irrindex(irrs, l, cpus);
129 + if(!irr->used) continue;
130 + rrddim_add(st, irr->id, irr->name, 1, 1, RRDDIM_INCREMENTAL);
131 + }
132 + }
133 + else rrdset_next(st);
134 +
135 + for(l = 0; l < lines ;l++) {
136 + struct interrupt *irr = irrindex(irrs, l, cpus);
137 + if(!irr->used) continue;
138 + rrddim_set(st, irr->id, irr->total);
139 + }
140 + rrdset_done(st);
141 +
142 + if(do_per_core) {
143 + int c;
144 +
145 + for(c = 0; c < cpus ; c++) {
146 + char id[256+1];
147 + snprintfz(id, 256, "cpu%d_interrupts", c);
148 +
149 + st = rrdset_find_bytype("cpu", id);
150 + if(!st) {
151 + char name[256+1], title[256+1];
152 + snprintfz(name, 256, "cpu%d_interrupts", c);
153 + snprintfz(title, 256, "CPU%d Interrupts", c);
154 + st = rrdset_create("cpu", id, name, "interrupts", "cpu.interrupts", title, "interrupts/s", 2000 + c, update_every, RRDSET_TYPE_STACKED);
155 +
156 + for(l = 0; l < lines ;l++) {
157 + struct interrupt *irr = irrindex(irrs, l, cpus);
158 + if(!irr->used) continue;
159 + rrddim_add(st, irr->id, irr->name, 1, 1, RRDDIM_INCREMENTAL);
160 + }
161 + }
162 + else rrdset_next(st);
163 +
164 + for(l = 0; l < lines ;l++) {
165 + struct interrupt *irr = irrindex(irrs, l, cpus);
166 + if(!irr->used) continue;
167 + rrddim_set(st, irr->id, irr->value[c]);
168 + }
169 + rrdset_done(st);
170 + }
171 + }
172 +
173 + return 0;
174 }
src/proc_loadavg.c
+55 -55
@@ -4,77 +4,77 @@
4 #define MIN_LOADAVG_UPDATE_EVERY 5
5
6 int do_proc_loadavg(int update_every, unsigned long long dt) {
7 - static procfile *ff = NULL;
8 - static int do_loadavg = -1, do_all_processes = -1;
7 + static procfile *ff = NULL;
8 + static int do_loadavg = -1, do_all_processes = -1;
9
10 - if(dt) {};
10 + if(dt) {};
11
12 - if(!ff) {
13 - char filename[FILENAME_MAX + 1];
14 - snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/loadavg");
15 - ff = procfile_open(config_get("plugin:proc:/proc/loadavg", "filename to monitor", filename), " \t,:|/", PROCFILE_FLAG_DEFAULT);
16 - }
17 - if(!ff) return 1;
12 + if(!ff) {
13 + char filename[FILENAME_MAX + 1];
14 + snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/loadavg");
15 + ff = procfile_open(config_get("plugin:proc:/proc/loadavg", "filename to monitor", filename), " \t,:|/", PROCFILE_FLAG_DEFAULT);
16 + }
17 + if(!ff) return 1;
18
19 - ff = procfile_readall(ff);
20 - if(!ff) return 0; // we return 0, so that we will retry to open it next time
19 + ff = procfile_readall(ff);
20 + if(!ff) return 0; // we return 0, so that we will retry to open it next time
21
22 - if(do_loadavg == -1) do_loadavg = config_get_boolean("plugin:proc:/proc/loadavg", "enable load average", 1);
23 - if(do_all_processes == -1) do_all_processes = config_get_boolean("plugin:proc:/proc/loadavg", "enable total processes", 1);
22 + if(do_loadavg == -1) do_loadavg = config_get_boolean("plugin:proc:/proc/loadavg", "enable load average", 1);
23 + if(do_all_processes == -1) do_all_processes = config_get_boolean("plugin:proc:/proc/loadavg", "enable total processes", 1);
24
25 - if(procfile_lines(ff) < 1) {
26 - error("/proc/loadavg has no lines.");
27 - return 1;
28 - }
29 - if(procfile_linewords(ff, 0) < 6) {
30 - error("/proc/loadavg has less than 6 words in it.");
31 - return 1;
32 - }
25 + if(procfile_lines(ff) < 1) {
26 + error("/proc/loadavg has no lines.");
27 + return 1;
28 + }
29 + if(procfile_linewords(ff, 0) < 6) {
30 + error("/proc/loadavg has less than 6 words in it.");
31 + return 1;
32 + }
33
34 - double load1 = strtod(procfile_lineword(ff, 0, 0), NULL);
35 - double load5 = strtod(procfile_lineword(ff, 0, 1), NULL);
36 - double load15 = strtod(procfile_lineword(ff, 0, 2), NULL);
34 + double load1 = strtod(procfile_lineword(ff, 0, 0), NULL);
35 + double load5 = strtod(procfile_lineword(ff, 0, 1), NULL);
36 + double load15 = strtod(procfile_lineword(ff, 0, 2), NULL);
37
38 - //unsigned long long running_processes = strtoull(procfile_lineword(ff, 0, 3), NULL, 10);
39 - unsigned long long active_processes = strtoull(procfile_lineword(ff, 0, 4), NULL, 10);
40 - //unsigned long long next_pid = strtoull(procfile_lineword(ff, 0, 5), NULL, 10);
38 + //unsigned long long running_processes = strtoull(procfile_lineword(ff, 0, 3), NULL, 10);
39 + unsigned long long active_processes = strtoull(procfile_lineword(ff, 0, 4), NULL, 10);
40 + //unsigned long long next_pid = strtoull(procfile_lineword(ff, 0, 5), NULL, 10);
41
42
43 - RRDSET *st;
43 + RRDSET *st;
44
45 - // --------------------------------------------------------------------
45 + // --------------------------------------------------------------------
46
47 - if(do_loadavg) {
48 - st = rrdset_find_byname("system.load");
49 - if(!st) {
50 - st = rrdset_create("system", "load", NULL, "load", NULL, "System Load Average", "load", 100, (update_every < MIN_LOADAVG_UPDATE_EVERY)?MIN_LOADAVG_UPDATE_EVERY:update_every, RRDSET_TYPE_LINE);
47 + if(do_loadavg) {
48 + st = rrdset_find_byname("system.load");
49 + if(!st) {
50 + st = rrdset_create("system", "load", NULL, "load", NULL, "System Load Average", "load", 100, (update_every < MIN_LOADAVG_UPDATE_EVERY)?MIN_LOADAVG_UPDATE_EVERY:update_every, RRDSET_TYPE_LINE);
51
52 - rrddim_add(st, "load1", NULL, 1, 1000, RRDDIM_ABSOLUTE);
53 - rrddim_add(st, "load5", NULL, 1, 1000, RRDDIM_ABSOLUTE);
54 - rrddim_add(st, "load15", NULL, 1, 1000, RRDDIM_ABSOLUTE);
55 - }
56 - else rrdset_next(st);
52 + rrddim_add(st, "load1", NULL, 1, 1000, RRDDIM_ABSOLUTE);
53 + rrddim_add(st, "load5", NULL, 1, 1000, RRDDIM_ABSOLUTE);
54 + rrddim_add(st, "load15", NULL, 1, 1000, RRDDIM_ABSOLUTE);
55 + }
56 + else rrdset_next(st);
57
58 - rrddim_set(st, "load1", load1 * 1000);
59 - rrddim_set(st, "load5", load5 * 1000);
60 - rrddim_set(st, "load15", load15 * 1000);
61 - rrdset_done(st);
62 - }
58 + rrddim_set(st, "load1", load1 * 1000);
59 + rrddim_set(st, "load5", load5 * 1000);
60 + rrddim_set(st, "load15", load15 * 1000);
61 + rrdset_done(st);
62 + }
63
64 - // --------------------------------------------------------------------
64 + // --------------------------------------------------------------------
65
66 - if(do_all_processes) {
67 - st = rrdset_find_byname("system.active_processes");
68 - if(!st) {
69 - st = rrdset_create("system", "active_processes", NULL, "processes", NULL, "System Active Processes", "processes", 750, update_every, RRDSET_TYPE_LINE);
66 + if(do_all_processes) {
67 + st = rrdset_find_byname("system.active_processes");
68 + if(!st) {
69 + st = rrdset_create("system", "active_processes", NULL, "processes", NULL, "System Active Processes", "processes", 750, update_every, RRDSET_TYPE_LINE);
70
71 - rrddim_add(st, "active", NULL, 1, 1, RRDDIM_ABSOLUTE);
72 - }
73 - else rrdset_next(st);
71 + rrddim_add(st, "active", NULL, 1, 1, RRDDIM_ABSOLUTE);
72 + }
73 + else rrdset_next(st);
74
75 - rrddim_set(st, "active", active_processes);
76 - rrdset_done(st);
77 - }
75 + rrddim_set(st, "active", active_processes);
76 + rrdset_done(st);
77 + }
78
79 - return 0;
79 + return 0;
80 }
src/proc_meminfo.c
+234 -234
@@ -4,239 +4,239 @@
4 #define MAX_PROC_MEMINFO_NAME 1024
5
6 int do_proc_meminfo(int update_every, unsigned long long dt) {
7 - static procfile *ff = NULL;
8 -
9 - static int do_ram = -1, do_swap = -1, do_hwcorrupt = -1, do_committed = -1, do_writeback = -1, do_kernel = -1, do_slab = -1;
10 -
11 - if(do_ram == -1) do_ram = config_get_boolean("plugin:proc:/proc/meminfo", "system ram", 1);
12 - if(do_swap == -1) do_swap = config_get_boolean("plugin:proc:/proc/meminfo", "system swap", 1);
13 - if(do_hwcorrupt == -1) do_hwcorrupt = config_get_boolean_ondemand("plugin:proc:/proc/meminfo", "hardware corrupted ECC", CONFIG_ONDEMAND_ONDEMAND);
14 - if(do_committed == -1) do_committed = config_get_boolean("plugin:proc:/proc/meminfo", "committed memory", 1);
15 - if(do_writeback == -1) do_writeback = config_get_boolean("plugin:proc:/proc/meminfo", "writeback memory", 1);
16 - if(do_kernel == -1) do_kernel = config_get_boolean("plugin:proc:/proc/meminfo", "kernel memory", 1);
17 - if(do_slab == -1) do_slab = config_get_boolean("plugin:proc:/proc/meminfo", "slab memory", 1);
18 -
19 - if(dt) {};
20 -
21 - if(!ff) {
22 - char filename[FILENAME_MAX + 1];
23 - snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/meminfo");
24 - ff = procfile_open(config_get("plugin:proc:/proc/meminfo", "filename to monitor", filename), " \t:", PROCFILE_FLAG_DEFAULT);
25 - }
26 - if(!ff) return 1;
27 -
28 - ff = procfile_readall(ff);
29 - if(!ff) return 0; // we return 0, so that we will retry to open it next time
30 -
31 - uint32_t lines = procfile_lines(ff), l;
32 - uint32_t words;
33 -
34 - int hwcorrupted = 0;
35 -
36 - unsigned long long MemTotal = 0, MemFree = 0, Buffers = 0, Cached = 0, SwapCached = 0,
37 - Active = 0, Inactive = 0, ActiveAnon = 0, InactiveAnon = 0, ActiveFile = 0, InactiveFile = 0,
38 - Unevictable = 0, Mlocked = 0, SwapTotal = 0, SwapFree = 0, Dirty = 0, Writeback = 0, AnonPages = 0,
39 - Mapped = 0, Shmem = 0, Slab = 0, SReclaimable = 0, SUnreclaim = 0, KernelStack = 0, PageTables = 0,
40 - NFS_Unstable = 0, Bounce = 0, WritebackTmp = 0, CommitLimit = 0, Committed_AS = 0,
41 - VmallocTotal = 0, VmallocUsed = 0, VmallocChunk = 0,
42 - AnonHugePages = 0, HugePages_Total = 0, HugePages_Free = 0, HugePages_Rsvd = 0, HugePages_Surp = 0, Hugepagesize = 0,
43 - DirectMap4k = 0, DirectMap2M = 0, HardwareCorrupted = 0;
44 -
45 - for(l = 0; l < lines ;l++) {
46 - words = procfile_linewords(ff, l);
47 - if(words < 2) continue;
48 -
49 - char *name = procfile_lineword(ff, l, 0);
50 - unsigned long long value = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
51 -
52 - if(!MemTotal && strcmp(name, "MemTotal") == 0) MemTotal = value;
53 - else if(!MemFree && strcmp(name, "MemFree") == 0) MemFree = value;
54 - else if(!Buffers && strcmp(name, "Buffers") == 0) Buffers = value;
55 - else if(!Cached && strcmp(name, "Cached") == 0) Cached = value;
56 - else if(!SwapCached && strcmp(name, "SwapCached") == 0) SwapCached = value;
57 - else if(!Active && strcmp(name, "Active") == 0) Active = value;
58 - else if(!Inactive && strcmp(name, "Inactive") == 0) Inactive = value;
59 - else if(!ActiveAnon && strcmp(name, "ActiveAnon") == 0) ActiveAnon = value;
60 - else if(!InactiveAnon && strcmp(name, "InactiveAnon") == 0) InactiveAnon = value;
61 - else if(!ActiveFile && strcmp(name, "ActiveFile") == 0) ActiveFile = value;
62 - else if(!InactiveFile && strcmp(name, "InactiveFile") == 0) InactiveFile = value;
63 - else if(!Unevictable && strcmp(name, "Unevictable") == 0) Unevictable = value;
64 - else if(!Mlocked && strcmp(name, "Mlocked") == 0) Mlocked = value;
65 - else if(!SwapTotal && strcmp(name, "SwapTotal") == 0) SwapTotal = value;
66 - else if(!SwapFree && strcmp(name, "SwapFree") == 0) SwapFree = value;
67 - else if(!Dirty && strcmp(name, "Dirty") == 0) Dirty = value;
68 - else if(!Writeback && strcmp(name, "Writeback") == 0) Writeback = value;
69 - else if(!AnonPages && strcmp(name, "AnonPages") == 0) AnonPages = value;
70 - else if(!Mapped && strcmp(name, "Mapped") == 0) Mapped = value;
71 - else if(!Shmem && strcmp(name, "Shmem") == 0) Shmem = value;
72 - else if(!Slab && strcmp(name, "Slab") == 0) Slab = value;
73 - else if(!SReclaimable && strcmp(name, "SReclaimable") == 0) SReclaimable = value;
74 - else if(!SUnreclaim && strcmp(name, "SUnreclaim") == 0) SUnreclaim = value;
75 - else if(!KernelStack && strcmp(name, "KernelStack") == 0) KernelStack = value;
76 - else if(!PageTables && strcmp(name, "PageTables") == 0) PageTables = value;
77 - else if(!NFS_Unstable && strcmp(name, "NFS_Unstable") == 0) NFS_Unstable = value;
78 - else if(!Bounce && strcmp(name, "Bounce") == 0) Bounce = value;
79 - else if(!WritebackTmp && strcmp(name, "WritebackTmp") == 0) WritebackTmp = value;
80 - else if(!CommitLimit && strcmp(name, "CommitLimit") == 0) CommitLimit = value;
81 - else if(!Committed_AS && strcmp(name, "Committed_AS") == 0) Committed_AS = value;
82 - else if(!VmallocTotal && strcmp(name, "VmallocTotal") == 0) VmallocTotal = value;
83 - else if(!VmallocUsed && strcmp(name, "VmallocUsed") == 0) VmallocUsed = value;
84 - else if(!VmallocChunk && strcmp(name, "VmallocChunk") == 0) VmallocChunk = value;
85 - else if(!HardwareCorrupted && strcmp(name, "HardwareCorrupted") == 0) { HardwareCorrupted = value; hwcorrupted = 1; }
86 - else if(!AnonHugePages && strcmp(name, "AnonHugePages") == 0) AnonHugePages = value;
87 - else if(!HugePages_Total && strcmp(name, "HugePages_Total") == 0) HugePages_Total = value;
88 - else if(!HugePages_Free && strcmp(name, "HugePages_Free") == 0) HugePages_Free = value;
89 - else if(!HugePages_Rsvd && strcmp(name, "HugePages_Rsvd") == 0) HugePages_Rsvd = value;
90 - else if(!HugePages_Surp && strcmp(name, "HugePages_Surp") == 0) HugePages_Surp = value;
91 - else if(!Hugepagesize && strcmp(name, "Hugepagesize") == 0) Hugepagesize = value;
92 - else if(!DirectMap4k && strcmp(name, "DirectMap4k") == 0) DirectMap4k = value;
93 - else if(!DirectMap2M && strcmp(name, "DirectMap2M") == 0) DirectMap2M = value;
94 - }
95 -
96 - RRDSET *st;
97 -
98 - // --------------------------------------------------------------------
99 -
100 - // http://stackoverflow.com/questions/3019748/how-to-reliably-measure-available-memory-in-linux
101 - unsigned long long MemUsed = MemTotal - MemFree - Cached - Buffers;
102 -
103 - if(do_ram) {
104 - st = rrdset_find("system.ram");
105 - if(!st) {
106 - st = rrdset_create("system", "ram", NULL, "ram", NULL, "System RAM", "MB", 200, update_every, RRDSET_TYPE_STACKED);
107 -
108 - rrddim_add(st, "buffers", NULL, 1, 1024, RRDDIM_ABSOLUTE);
109 - rrddim_add(st, "used", NULL, 1, 1024, RRDDIM_ABSOLUTE);
110 - rrddim_add(st, "cached", NULL, 1, 1024, RRDDIM_ABSOLUTE);
111 - rrddim_add(st, "free", NULL, 1, 1024, RRDDIM_ABSOLUTE);
112 - }
113 - else rrdset_next(st);
114 -
115 - rrddim_set(st, "used", MemUsed);
116 - rrddim_set(st, "free", MemFree);
117 - rrddim_set(st, "cached", Cached);
118 - rrddim_set(st, "buffers", Buffers);
119 - rrdset_done(st);
120 - }
121 -
122 - // --------------------------------------------------------------------
123 -
124 - unsigned long long SwapUsed = SwapTotal - SwapFree;
125 -
126 - if(do_swap) {
127 - st = rrdset_find("system.swap");
128 - if(!st) {
129 - st = rrdset_create("system", "swap", NULL, "swap", NULL, "System Swap", "MB", 201, update_every, RRDSET_TYPE_STACKED);
130 - st->isdetail = 1;
131 -
132 - rrddim_add(st, "free", NULL, 1, 1024, RRDDIM_ABSOLUTE);
133 - rrddim_add(st, "used", NULL, 1, 1024, RRDDIM_ABSOLUTE);
134 - }
135 - else rrdset_next(st);
136 -
137 - rrddim_set(st, "used", SwapUsed);
138 - rrddim_set(st, "free", SwapFree);
139 - rrdset_done(st);
140 - }
141 -
142 - // --------------------------------------------------------------------
143 -
144 - if(hwcorrupted && do_hwcorrupt && HardwareCorrupted > 0) {
145 - do_hwcorrupt = CONFIG_ONDEMAND_YES;
146 -
147 - st = rrdset_find("mem.hwcorrupt");
148 - if(!st) {
149 - st = rrdset_create("mem", "hwcorrupt", NULL, "errors", NULL, "Hardware Corrupted ECC", "MB", 9000, update_every, RRDSET_TYPE_LINE);
150 - st->isdetail = 1;
151 -
152 - rrddim_add(st, "HardwareCorrupted", NULL, 1, 1024, RRDDIM_ABSOLUTE);
153 - }
154 - else rrdset_next(st);
155 -
156 - rrddim_set(st, "HardwareCorrupted", HardwareCorrupted);
157 - rrdset_done(st);
158 - }
159 -
160 - // --------------------------------------------------------------------
161 -
162 - if(do_committed) {
163 - st = rrdset_find("mem.committed");
164 - if(!st) {
165 - st = rrdset_create("mem", "committed", NULL, "system", NULL, "Committed (Allocated) Memory", "MB", 5000, update_every, RRDSET_TYPE_AREA);
166 - st->isdetail = 1;
167 -
168 - rrddim_add(st, "Committed_AS", NULL, 1, 1024, RRDDIM_ABSOLUTE);
169 - }
170 - else rrdset_next(st);
171 -
172 - rrddim_set(st, "Committed_AS", Committed_AS);
173 - rrdset_done(st);
174 - }
175 -
176 - // --------------------------------------------------------------------
177 -
178 - if(do_writeback) {
179 - st = rrdset_find("mem.writeback");
180 - if(!st) {
181 - st = rrdset_create("mem", "writeback", NULL, "kernel", NULL, "Writeback Memory", "MB", 4000, update_every, RRDSET_TYPE_LINE);
182 - st->isdetail = 1;
183 -
184 - rrddim_add(st, "Dirty", NULL, 1, 1024, RRDDIM_ABSOLUTE);
185 - rrddim_add(st, "Writeback", NULL, 1, 1024, RRDDIM_ABSOLUTE);
186 - rrddim_add(st, "FuseWriteback", NULL, 1, 1024, RRDDIM_ABSOLUTE);
187 - rrddim_add(st, "NfsWriteback", NULL, 1, 1024, RRDDIM_ABSOLUTE);
188 - rrddim_add(st, "Bounce", NULL, 1, 1024, RRDDIM_ABSOLUTE);
189 - }
190 - else rrdset_next(st);
191 -
192 - rrddim_set(st, "Dirty", Dirty);
193 - rrddim_set(st, "Writeback", Writeback);
194 - rrddim_set(st, "FuseWriteback", WritebackTmp);
195 - rrddim_set(st, "NfsWriteback", NFS_Unstable);
196 - rrddim_set(st, "Bounce", Bounce);
197 - rrdset_done(st);
198 - }
199 -
200 - // --------------------------------------------------------------------
201 -
202 - if(do_kernel) {
203 - st = rrdset_find("mem.kernel");
204 - if(!st) {
205 - st = rrdset_create("mem", "kernel", NULL, "kernel", NULL, "Memory Used by Kernel", "MB", 6000, update_every, RRDSET_TYPE_STACKED);
206 - st->isdetail = 1;
207 -
208 - rrddim_add(st, "Slab", NULL, 1, 1024, RRDDIM_ABSOLUTE);
209 - rrddim_add(st, "KernelStack", NULL, 1, 1024, RRDDIM_ABSOLUTE);
210 - rrddim_add(st, "PageTables", NULL, 1, 1024, RRDDIM_ABSOLUTE);
211 - rrddim_add(st, "VmallocUsed", NULL, 1, 1024, RRDDIM_ABSOLUTE);
212 - }
213 - else rrdset_next(st);
214 -
215 - rrddim_set(st, "KernelStack", KernelStack);
216 - rrddim_set(st, "Slab", Slab);
217 - rrddim_set(st, "PageTables", PageTables);
218 - rrddim_set(st, "VmallocUsed", VmallocUsed);
219 - rrdset_done(st);
220 - }
221 -
222 - // --------------------------------------------------------------------
223 -
224 - if(do_slab) {
225 - st = rrdset_find("mem.slab");
226 - if(!st) {
227 - st = rrdset_create("mem", "slab", NULL, "slab", NULL, "Reclaimable Kernel Memory", "MB", 6500, update_every, RRDSET_TYPE_STACKED);
228 - st->isdetail = 1;
229 -
230 - rrddim_add(st, "reclaimable", NULL, 1, 1024, RRDDIM_ABSOLUTE);
231 - rrddim_add(st, "unreclaimable", NULL, 1, 1024, RRDDIM_ABSOLUTE);
232 - }
233 - else rrdset_next(st);
234 -
235 - rrddim_set(st, "reclaimable", SReclaimable);
236 - rrddim_set(st, "unreclaimable", SUnreclaim);
237 - rrdset_done(st);
238 - }
239 -
240 - return 0;
7 + static procfile *ff = NULL;
8 +
9 + static int do_ram = -1, do_swap = -1, do_hwcorrupt = -1, do_committed = -1, do_writeback = -1, do_kernel = -1, do_slab = -1;
10 +
11 + if(do_ram == -1) do_ram = config_get_boolean("plugin:proc:/proc/meminfo", "system ram", 1);
12 + if(do_swap == -1) do_swap = config_get_boolean("plugin:proc:/proc/meminfo", "system swap", 1);
13 + if(do_hwcorrupt == -1) do_hwcorrupt = config_get_boolean_ondemand("plugin:proc:/proc/meminfo", "hardware corrupted ECC", CONFIG_ONDEMAND_ONDEMAND);
14 + if(do_committed == -1) do_committed = config_get_boolean("plugin:proc:/proc/meminfo", "committed memory", 1);
15 + if(do_writeback == -1) do_writeback = config_get_boolean("plugin:proc:/proc/meminfo", "writeback memory", 1);
16 + if(do_kernel == -1) do_kernel = config_get_boolean("plugin:proc:/proc/meminfo", "kernel memory", 1);
17 + if(do_slab == -1) do_slab = config_get_boolean("plugin:proc:/proc/meminfo", "slab memory", 1);
18 +
19 + if(dt) {};
20 +
21 + if(!ff) {
22 + char filename[FILENAME_MAX + 1];
23 + snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/meminfo");
24 + ff = procfile_open(config_get("plugin:proc:/proc/meminfo", "filename to monitor", filename), " \t:", PROCFILE_FLAG_DEFAULT);
25 + }
26 + if(!ff) return 1;
27 +
28 + ff = procfile_readall(ff);
29 + if(!ff) return 0; // we return 0, so that we will retry to open it next time
30 +
31 + uint32_t lines = procfile_lines(ff), l;
32 + uint32_t words;
33 +
34 + int hwcorrupted = 0;
35 +
36 + unsigned long long MemTotal = 0, MemFree = 0, Buffers = 0, Cached = 0, SwapCached = 0,
37 + Active = 0, Inactive = 0, ActiveAnon = 0, InactiveAnon = 0, ActiveFile = 0, InactiveFile = 0,
38 + Unevictable = 0, Mlocked = 0, SwapTotal = 0, SwapFree = 0, Dirty = 0, Writeback = 0, AnonPages = 0,
39 + Mapped = 0, Shmem = 0, Slab = 0, SReclaimable = 0, SUnreclaim = 0, KernelStack = 0, PageTables = 0,
40 + NFS_Unstable = 0, Bounce = 0, WritebackTmp = 0, CommitLimit = 0, Committed_AS = 0,
41 + VmallocTotal = 0, VmallocUsed = 0, VmallocChunk = 0,
42 + AnonHugePages = 0, HugePages_Total = 0, HugePages_Free = 0, HugePages_Rsvd = 0, HugePages_Surp = 0, Hugepagesize = 0,
43 + DirectMap4k = 0, DirectMap2M = 0, HardwareCorrupted = 0;
44 +
45 + for(l = 0; l < lines ;l++) {
46 + words = procfile_linewords(ff, l);
47 + if(words < 2) continue;
48 +
49 + char *name = procfile_lineword(ff, l, 0);
50 + unsigned long long value = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
51 +
52 + if(!MemTotal && strcmp(name, "MemTotal") == 0) MemTotal = value;
53 + else if(!MemFree && strcmp(name, "MemFree") == 0) MemFree = value;
54 + else if(!Buffers && strcmp(name, "Buffers") == 0) Buffers = value;
55 + else if(!Cached && strcmp(name, "Cached") == 0) Cached = value;
56 + else if(!SwapCached && strcmp(name, "SwapCached") == 0) SwapCached = value;
57 + else if(!Active && strcmp(name, "Active") == 0) Active = value;
58 + else if(!Inactive && strcmp(name, "Inactive") == 0) Inactive = value;
59 + else if(!ActiveAnon && strcmp(name, "ActiveAnon") == 0) ActiveAnon = value;
60 + else if(!InactiveAnon && strcmp(name, "InactiveAnon") == 0) InactiveAnon = value;
61 + else if(!ActiveFile && strcmp(name, "ActiveFile") == 0) ActiveFile = value;
62 + else if(!InactiveFile && strcmp(name, "InactiveFile") == 0) InactiveFile = value;
63 + else if(!Unevictable && strcmp(name, "Unevictable") == 0) Unevictable = value;
64 + else if(!Mlocked && strcmp(name, "Mlocked") == 0) Mlocked = value;
65 + else if(!SwapTotal && strcmp(name, "SwapTotal") == 0) SwapTotal = value;
66 + else if(!SwapFree && strcmp(name, "SwapFree") == 0) SwapFree = value;
67 + else if(!Dirty && strcmp(name, "Dirty") == 0) Dirty = value;
68 + else if(!Writeback && strcmp(name, "Writeback") == 0) Writeback = value;
69 + else if(!AnonPages && strcmp(name, "AnonPages") == 0) AnonPages = value;
70 + else if(!Mapped && strcmp(name, "Mapped") == 0) Mapped = value;
71 + else if(!Shmem && strcmp(name, "Shmem") == 0) Shmem = value;
72 + else if(!Slab && strcmp(name, "Slab") == 0) Slab = value;
73 + else if(!SReclaimable && strcmp(name, "SReclaimable") == 0) SReclaimable = value;
74 + else if(!SUnreclaim && strcmp(name, "SUnreclaim") == 0) SUnreclaim = value;
75 + else if(!KernelStack && strcmp(name, "KernelStack") == 0) KernelStack = value;
76 + else if(!PageTables && strcmp(name, "PageTables") == 0) PageTables = value;
77 + else if(!NFS_Unstable && strcmp(name, "NFS_Unstable") == 0) NFS_Unstable = value;
78 + else if(!Bounce && strcmp(name, "Bounce") == 0) Bounce = value;
79 + else if(!WritebackTmp && strcmp(name, "WritebackTmp") == 0) WritebackTmp = value;
80 + else if(!CommitLimit && strcmp(name, "CommitLimit") == 0) CommitLimit = value;
81 + else if(!Committed_AS && strcmp(name, "Committed_AS") == 0) Committed_AS = value;
82 + else if(!VmallocTotal && strcmp(name, "VmallocTotal") == 0) VmallocTotal = value;
83 + else if(!VmallocUsed && strcmp(name, "VmallocUsed") == 0) VmallocUsed = value;
84 + else if(!VmallocChunk && strcmp(name, "VmallocChunk") == 0) VmallocChunk = value;
85 + else if(!HardwareCorrupted && strcmp(name, "HardwareCorrupted") == 0) { HardwareCorrupted = value; hwcorrupted = 1; }
86 + else if(!AnonHugePages && strcmp(name, "AnonHugePages") == 0) AnonHugePages = value;
87 + else if(!HugePages_Total && strcmp(name, "HugePages_Total") == 0) HugePages_Total = value;
88 + else if(!HugePages_Free && strcmp(name, "HugePages_Free") == 0) HugePages_Free = value;
89 + else if(!HugePages_Rsvd && strcmp(name, "HugePages_Rsvd") == 0) HugePages_Rsvd = value;
90 + else if(!HugePages_Surp && strcmp(name, "HugePages_Surp") == 0) HugePages_Surp = value;
91 + else if(!Hugepagesize && strcmp(name, "Hugepagesize") == 0) Hugepagesize = value;
92 + else if(!DirectMap4k && strcmp(name, "DirectMap4k") == 0) DirectMap4k = value;
93 + else if(!DirectMap2M && strcmp(name, "DirectMap2M") == 0) DirectMap2M = value;
94 + }
95 +
96 + RRDSET *st;
97 +
98 + // --------------------------------------------------------------------
99 +
100 + // http://stackoverflow.com/questions/3019748/how-to-reliably-measure-available-memory-in-linux
101 + unsigned long long MemUsed = MemTotal - MemFree - Cached - Buffers;
102 +
103 + if(do_ram) {
104 + st = rrdset_find("system.ram");
105 + if(!st) {
106 + st = rrdset_create("system", "ram", NULL, "ram", NULL, "System RAM", "MB", 200, update_every, RRDSET_TYPE_STACKED);
107 +
108 + rrddim_add(st, "buffers", NULL, 1, 1024, RRDDIM_ABSOLUTE);
109 + rrddim_add(st, "used", NULL, 1, 1024, RRDDIM_ABSOLUTE);
110 + rrddim_add(st, "cached", NULL, 1, 1024, RRDDIM_ABSOLUTE);
111 + rrddim_add(st, "free", NULL, 1, 1024, RRDDIM_ABSOLUTE);
112 + }
113 + else rrdset_next(st);
114 +
115 + rrddim_set(st, "used", MemUsed);
116 + rrddim_set(st, "free", MemFree);
117 + rrddim_set(st, "cached", Cached);
118 + rrddim_set(st, "buffers", Buffers);
119 + rrdset_done(st);
120 + }
121 +
122 + // --------------------------------------------------------------------
123 +
124 + unsigned long long SwapUsed = SwapTotal - SwapFree;
125 +
126 + if(do_swap) {
127 + st = rrdset_find("system.swap");
128 + if(!st) {
129 + st = rrdset_create("system", "swap", NULL, "swap", NULL, "System Swap", "MB", 201, update_every, RRDSET_TYPE_STACKED);
130 + st->isdetail = 1;
131 +
132 + rrddim_add(st, "free", NULL, 1, 1024, RRDDIM_ABSOLUTE);
133 + rrddim_add(st, "used", NULL, 1, 1024, RRDDIM_ABSOLUTE);
134 + }
135 + else rrdset_next(st);
136 +
137 + rrddim_set(st, "used", SwapUsed);
138 + rrddim_set(st, "free", SwapFree);
139 + rrdset_done(st);
140 + }
141 +
142 + // --------------------------------------------------------------------
143 +
144 + if(hwcorrupted && do_hwcorrupt && HardwareCorrupted > 0) {
145 + do_hwcorrupt = CONFIG_ONDEMAND_YES;
146 +
147 + st = rrdset_find("mem.hwcorrupt");
148 + if(!st) {
149 + st = rrdset_create("mem", "hwcorrupt", NULL, "errors", NULL, "Hardware Corrupted ECC", "MB", 9000, update_every, RRDSET_TYPE_LINE);
150 + st->isdetail = 1;
151 +
152 + rrddim_add(st, "HardwareCorrupted", NULL, 1, 1024, RRDDIM_ABSOLUTE);
153 + }
154 + else rrdset_next(st);
155 +
156 + rrddim_set(st, "HardwareCorrupted", HardwareCorrupted);
157 + rrdset_done(st);
158 + }
159 +
160 + // --------------------------------------------------------------------
161 +
162 + if(do_committed) {
163 + st = rrdset_find("mem.committed");
164 + if(!st) {
165 + st = rrdset_create("mem", "committed", NULL, "system", NULL, "Committed (Allocated) Memory", "MB", 5000, update_every, RRDSET_TYPE_AREA);
166 + st->isdetail = 1;
167 +
168 + rrddim_add(st, "Committed_AS", NULL, 1, 1024, RRDDIM_ABSOLUTE);
169 + }
170 + else rrdset_next(st);
171 +
172 + rrddim_set(st, "Committed_AS", Committed_AS);
173 + rrdset_done(st);
174 + }
175 +
176 + // --------------------------------------------------------------------
177 +
178 + if(do_writeback) {
179 + st = rrdset_find("mem.writeback");
180 + if(!st) {
181 + st = rrdset_create("mem", "writeback", NULL, "kernel", NULL, "Writeback Memory", "MB", 4000, update_every, RRDSET_TYPE_LINE);
182 + st->isdetail = 1;
183 +
184 + rrddim_add(st, "Dirty", NULL, 1, 1024, RRDDIM_ABSOLUTE);
185 + rrddim_add(st, "Writeback", NULL, 1, 1024, RRDDIM_ABSOLUTE);
186 + rrddim_add(st, "FuseWriteback", NULL, 1, 1024, RRDDIM_ABSOLUTE);
187 + rrddim_add(st, "NfsWriteback", NULL, 1, 1024, RRDDIM_ABSOLUTE);
188 + rrddim_add(st, "Bounce", NULL, 1, 1024, RRDDIM_ABSOLUTE);
189 + }
190 + else rrdset_next(st);
191 +
192 + rrddim_set(st, "Dirty", Dirty);
193 + rrddim_set(st, "Writeback", Writeback);
194 + rrddim_set(st, "FuseWriteback", WritebackTmp);
195 + rrddim_set(st, "NfsWriteback", NFS_Unstable);
196 + rrddim_set(st, "Bounce", Bounce);
197 + rrdset_done(st);
198 + }
199 +
200 + // --------------------------------------------------------------------
201 +
202 + if(do_kernel) {
203 + st = rrdset_find("mem.kernel");
204 + if(!st) {
205 + st = rrdset_create("mem", "kernel", NULL, "kernel", NULL, "Memory Used by Kernel", "MB", 6000, update_every, RRDSET_TYPE_STACKED);
206 + st->isdetail = 1;
207 +
208 + rrddim_add(st, "Slab", NULL, 1, 1024, RRDDIM_ABSOLUTE);
209 + rrddim_add(st, "KernelStack", NULL, 1, 1024, RRDDIM_ABSOLUTE);
210 + rrddim_add(st, "PageTables", NULL, 1, 1024, RRDDIM_ABSOLUTE);
211 + rrddim_add(st, "VmallocUsed", NULL, 1, 1024, RRDDIM_ABSOLUTE);
212 + }
213 + else rrdset_next(st);
214 +
215 + rrddim_set(st, "KernelStack", KernelStack);
216 + rrddim_set(st, "Slab", Slab);
217 + rrddim_set(st, "PageTables", PageTables);
218 + rrddim_set(st, "VmallocUsed", VmallocUsed);
219 + rrdset_done(st);
220 + }
221 +
222 + // --------------------------------------------------------------------
223 +
224 + if(do_slab) {
225 + st = rrdset_find("mem.slab");
226 + if(!st) {
227 + st = rrdset_create("mem", "slab", NULL, "slab", NULL, "Reclaimable Kernel Memory", "MB", 6500, update_every, RRDSET_TYPE_STACKED);
228 + st->isdetail = 1;
229 +
230 + rrddim_add(st, "reclaimable", NULL, 1, 1024, RRDDIM_ABSOLUTE);
231 + rrddim_add(st, "unreclaimable", NULL, 1, 1024, RRDDIM_ABSOLUTE);
232 + }
233 + else rrdset_next(st);
234 +
235 + rrddim_set(st, "reclaimable", SReclaimable);
236 + rrddim_set(st, "unreclaimable", SUnreclaim);
237 + rrdset_done(st);
238 + }
239 +
240 + return 0;
241 }
242
src/proc_net_dev.c
+232 -232
@@ -1,236 +1,236 @@
1 #include "common.h"
2
3 int do_proc_net_dev(int update_every, unsigned long long dt) {
4 - static procfile *ff = NULL;
5 - static int enable_new_interfaces = -1, enable_ifb_interfaces = -1;
6 - static int do_bandwidth = -1, do_packets = -1, do_errors = -1, do_drops = -1, do_fifo = -1, do_compressed = -1, do_events = -1;
7 -
8 - if(dt) {};
9 -
10 - if(!ff) {
11 - char filename[FILENAME_MAX + 1];
12 - snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/net/dev");
13 - ff = procfile_open(config_get("plugin:proc:/proc/net/dev", "filename to monitor", filename), " \t,:|", PROCFILE_FLAG_DEFAULT);
14 - }
15 - if(!ff) return 1;
16 -
17 - ff = procfile_readall(ff);
18 - if(!ff) return 0; // we return 0, so that we will retry to open it next time
19 -
20 - if(enable_new_interfaces == -1) enable_new_interfaces = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "enable new interfaces detected at runtime", CONFIG_ONDEMAND_ONDEMAND);
21 - if(enable_ifb_interfaces == -1) enable_ifb_interfaces = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "enable ifb interfaces", CONFIG_ONDEMAND_NO);
22 -
23 - if(do_bandwidth == -1) do_bandwidth = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "bandwidth for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
24 - if(do_packets == -1) do_packets = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "packets for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
25 - if(do_errors == -1) do_errors = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "errors for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
26 - if(do_drops == -1) do_drops = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "drops for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
27 - if(do_fifo == -1) do_fifo = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "fifo for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
28 - if(do_compressed == -1) do_compressed = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "compressed packets for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
29 - if(do_events == -1) do_events = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "frames, collisions, carrier counters for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
30 -
31 - uint32_t lines = procfile_lines(ff), l;
32 - uint32_t words;
33 -
34 - char *iface;
35 - unsigned long long rbytes, rpackets, rerrors, rdrops, rfifo, rframe, rcompressed, rmulticast;
36 - unsigned long long tbytes, tpackets, terrors, tdrops, tfifo, tcollisions, tcarrier, tcompressed;
37 -
38 - for(l = 2; l < lines ;l++) {
39 - words = procfile_linewords(ff, l);
40 - if(words < 17) continue;
41 -
42 - iface = procfile_lineword(ff, l, 0);
43 -
44 - rbytes = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
45 - rpackets = strtoull(procfile_lineword(ff, l, 2), NULL, 10);
46 - rerrors = strtoull(procfile_lineword(ff, l, 3), NULL, 10);
47 - rdrops = strtoull(procfile_lineword(ff, l, 4), NULL, 10);
48 - rfifo = strtoull(procfile_lineword(ff, l, 5), NULL, 10);
49 - rframe = strtoull(procfile_lineword(ff, l, 6), NULL, 10);
50 - rcompressed = strtoull(procfile_lineword(ff, l, 7), NULL, 10);
51 - rmulticast = strtoull(procfile_lineword(ff, l, 8), NULL, 10);
52 -
53 - tbytes = strtoull(procfile_lineword(ff, l, 9), NULL, 10);
54 - tpackets = strtoull(procfile_lineword(ff, l, 10), NULL, 10);
55 - terrors = strtoull(procfile_lineword(ff, l, 11), NULL, 10);
56 - tdrops = strtoull(procfile_lineword(ff, l, 12), NULL, 10);
57 - tfifo = strtoull(procfile_lineword(ff, l, 13), NULL, 10);
58 - tcollisions = strtoull(procfile_lineword(ff, l, 14), NULL, 10);
59 - tcarrier = strtoull(procfile_lineword(ff, l, 15), NULL, 10);
60 - tcompressed = strtoull(procfile_lineword(ff, l, 16), NULL, 10);
61 -
62 - int ddo_bandwidth = do_bandwidth, ddo_packets = do_packets, ddo_errors = do_errors, ddo_drops = do_drops, ddo_fifo = do_fifo, ddo_compressed = do_compressed, ddo_events = do_events;
63 -
64 - int default_enable = enable_new_interfaces;
65 -
66 - // prevent unused interfaces from creating charts
67 - if(strcmp(iface, "lo") == 0)
68 - default_enable = 0;
69 - else {
70 - int len = strlen(iface);
71 - if(len >= 4 && strcmp(&iface[len-4], "-ifb") == 0)
72 - default_enable = enable_ifb_interfaces;
73 - }
74 -
75 - // check if the user wants it
76 - {
77 - char var_name[512 + 1];
78 - snprintfz(var_name, 512, "plugin:proc:/proc/net/dev:%s", iface);
79 - default_enable = config_get_boolean_ondemand(var_name, "enabled", default_enable);
80 - if(default_enable == CONFIG_ONDEMAND_NO) continue;
81 - if(default_enable == CONFIG_ONDEMAND_ONDEMAND && !rbytes && !tbytes) continue;
82 -
83 - ddo_bandwidth = config_get_boolean_ondemand(var_name, "bandwidth", ddo_bandwidth);
84 - ddo_packets = config_get_boolean_ondemand(var_name, "packets", ddo_packets);
85 - ddo_errors = config_get_boolean_ondemand(var_name, "errors", ddo_errors);
86 - ddo_drops = config_get_boolean_ondemand(var_name, "drops", ddo_drops);
87 - ddo_fifo = config_get_boolean_ondemand(var_name, "fifo", ddo_fifo);
88 - ddo_compressed = config_get_boolean_ondemand(var_name, "compressed", ddo_compressed);
89 - ddo_events = config_get_boolean_ondemand(var_name, "events", ddo_events);
90 -
91 - if(ddo_bandwidth == CONFIG_ONDEMAND_ONDEMAND && rbytes == 0 && tbytes == 0) ddo_bandwidth = 0;
92 - if(ddo_errors == CONFIG_ONDEMAND_ONDEMAND && rerrors == 0 && terrors == 0) ddo_errors = 0;
93 - if(ddo_drops == CONFIG_ONDEMAND_ONDEMAND && rdrops == 0 && tdrops == 0) ddo_drops = 0;
94 - if(ddo_fifo == CONFIG_ONDEMAND_ONDEMAND && rfifo == 0 && tfifo == 0) ddo_fifo = 0;
95 - if(ddo_compressed == CONFIG_ONDEMAND_ONDEMAND && rcompressed == 0 && tcompressed == 0) ddo_compressed = 0;
96 - if(ddo_events == CONFIG_ONDEMAND_ONDEMAND && rframe == 0 && tcollisions == 0 && tcarrier == 0) ddo_events = 0;
97 -
98 - // for absolute values, we need to switch the setting to 'yes'
99 - // to allow it refresh from now on
100 - // if(ddo_fifo == CONFIG_ONDEMAND_ONDEMAND) config_set(var_name, "fifo", "yes");
101 - }
102 -
103 - RRDSET *st;
104 -
105 - // --------------------------------------------------------------------
106 -
107 - if(ddo_bandwidth) {
108 - st = rrdset_find_bytype("net", iface);
109 - if(!st) {
110 - st = rrdset_create("net", iface, NULL, iface, "net.net", "Bandwidth", "kilobits/s", 7000, update_every, RRDSET_TYPE_AREA);
111 -
112 - rrddim_add(st, "received", NULL, 8, 1024, RRDDIM_INCREMENTAL);
113 - rrddim_add(st, "sent", NULL, -8, 1024, RRDDIM_INCREMENTAL);
114 - }
115 - else rrdset_next(st);
116 -
117 - rrddim_set(st, "received", rbytes);
118 - rrddim_set(st, "sent", tbytes);
119 - rrdset_done(st);
120 - }
121 -
122 - // --------------------------------------------------------------------
123 -
124 - if(ddo_packets) {
125 - st = rrdset_find_bytype("net_packets", iface);
126 - if(!st) {
127 - st = rrdset_create("net_packets", iface, NULL, iface, "net.packets", "Packets", "packets/s", 7001, update_every, RRDSET_TYPE_LINE);
128 - st->isdetail = 1;
129 -
130 - rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
131 - rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
132 - rrddim_add(st, "multicast", NULL, 1, 1, RRDDIM_INCREMENTAL);
133 - }
134 - else rrdset_next(st);
135 -
136 - rrddim_set(st, "received", rpackets);
137 - rrddim_set(st, "sent", tpackets);
138 - rrddim_set(st, "multicast", rmulticast);
139 - rrdset_done(st);
140 - }
141 -
142 - // --------------------------------------------------------------------
143 -
144 - if(ddo_errors) {
145 - st = rrdset_find_bytype("net_errors", iface);
146 - if(!st) {
147 - st = rrdset_create("net_errors", iface, NULL, iface, "net.errors", "Interface Errors", "errors/s", 7002, update_every, RRDSET_TYPE_LINE);
148 - st->isdetail = 1;
149 -
150 - rrddim_add(st, "inbound", NULL, 1, 1, RRDDIM_INCREMENTAL);
151 - rrddim_add(st, "outbound", NULL, -1, 1, RRDDIM_INCREMENTAL);
152 - }
153 - else rrdset_next(st);
154 -
155 - rrddim_set(st, "inbound", rerrors);
156 - rrddim_set(st, "outbound", terrors);
157 - rrdset_done(st);
158 - }
159 -
160 - // --------------------------------------------------------------------
161 -
162 - if(ddo_drops) {
163 - st = rrdset_find_bytype("net_drops", iface);
164 - if(!st) {
165 - st = rrdset_create("net_drops", iface, NULL, iface, "net.drops", "Interface Drops", "drops/s", 7003, update_every, RRDSET_TYPE_LINE);
166 - st->isdetail = 1;
167 -
168 - rrddim_add(st, "inbound", NULL, 1, 1, RRDDIM_INCREMENTAL);
169 - rrddim_add(st, "outbound", NULL, -1, 1, RRDDIM_INCREMENTAL);
170 - }
171 - else rrdset_next(st);
172 -
173 - rrddim_set(st, "inbound", rdrops);
174 - rrddim_set(st, "outbound", tdrops);
175 - rrdset_done(st);
176 - }
177 -
178 - // --------------------------------------------------------------------
179 -
180 - if(ddo_fifo) {
181 - st = rrdset_find_bytype("net_fifo", iface);
182 - if(!st) {
183 - st = rrdset_create("net_fifo", iface, NULL, iface, "net.fifo", "Interface FIFO Buffer Errors", "errors", 7004, update_every, RRDSET_TYPE_LINE);
184 - st->isdetail = 1;
185 -
186 - rrddim_add(st, "receive", NULL, 1, 1, RRDDIM_INCREMENTAL);
187 - rrddim_add(st, "transmit", NULL, -1, 1, RRDDIM_INCREMENTAL);
188 - }
189 - else rrdset_next(st);
190 -
191 - rrddim_set(st, "receive", rfifo);
192 - rrddim_set(st, "transmit", tfifo);
193 - rrdset_done(st);
194 - }
195 -
196 - // --------------------------------------------------------------------
197 -
198 - if(ddo_compressed) {
199 - st = rrdset_find_bytype("net_compressed", iface);
200 - if(!st) {
201 - st = rrdset_create("net_compressed", iface, NULL, iface, "net.compressed", "Compressed Packets", "packets/s", 7005, update_every, RRDSET_TYPE_LINE);
202 - st->isdetail = 1;
203 -
204 - rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
205 - rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
206 - }
207 - else rrdset_next(st);
208 -
209 - rrddim_set(st, "received", rcompressed);
210 - rrddim_set(st, "sent", tcompressed);
211 - rrdset_done(st);
212 - }
213 -
214 - // --------------------------------------------------------------------
215 -
216 - if(ddo_events) {
217 - st = rrdset_find_bytype("net_events", iface);
218 - if(!st) {
219 - st = rrdset_create("net_events", iface, NULL, iface, "net.events", "Network Interface Events", "events/s", 7006, update_every, RRDSET_TYPE_LINE);
220 - st->isdetail = 1;
221 -
222 - rrddim_add(st, "frames", NULL, 1, 1, RRDDIM_INCREMENTAL);
223 - rrddim_add(st, "collisions", NULL, -1, 1, RRDDIM_INCREMENTAL);
224 - rrddim_add(st, "carrier", NULL, -1, 1, RRDDIM_INCREMENTAL);
225 - }
226 - else rrdset_next(st);
227 -
228 - rrddim_set(st, "frames", rframe);
229 - rrddim_set(st, "collisions", tcollisions);
230 - rrddim_set(st, "carrier", tcarrier);
231 - rrdset_done(st);
232 - }
233 - }
234 -
235 - return 0;
4 + static procfile *ff = NULL;
5 + static int enable_new_interfaces = -1, enable_ifb_interfaces = -1;
6 + static int do_bandwidth = -1, do_packets = -1, do_errors = -1, do_drops = -1, do_fifo = -1, do_compressed = -1, do_events = -1;
7 +
8 + if(dt) {};
9 +
10 + if(!ff) {
11 + char filename[FILENAME_MAX + 1];
12 + snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/net/dev");
13 + ff = procfile_open(config_get("plugin:proc:/proc/net/dev", "filename to monitor", filename), " \t,:|", PROCFILE_FLAG_DEFAULT);
14 + }
15 + if(!ff) return 1;
16 +
17 + ff = procfile_readall(ff);
18 + if(!ff) return 0; // we return 0, so that we will retry to open it next time
19 +
20 + if(enable_new_interfaces == -1) enable_new_interfaces = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "enable new interfaces detected at runtime", CONFIG_ONDEMAND_ONDEMAND);
21 + if(enable_ifb_interfaces == -1) enable_ifb_interfaces = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "enable ifb interfaces", CONFIG_ONDEMAND_NO);
22 +
23 + if(do_bandwidth == -1) do_bandwidth = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "bandwidth for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
24 + if(do_packets == -1) do_packets = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "packets for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
25 + if(do_errors == -1) do_errors = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "errors for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
26 + if(do_drops == -1) do_drops = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "drops for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
27 + if(do_fifo == -1) do_fifo = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "fifo for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
28 + if(do_compressed == -1) do_compressed = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "compressed packets for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
29 + if(do_events == -1) do_events = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "frames, collisions, carrier counters for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
30 +
31 + uint32_t lines = procfile_lines(ff), l;
32 + uint32_t words;
33 +
34 + char *iface;
35 + unsigned long long rbytes, rpackets, rerrors, rdrops, rfifo, rframe, rcompressed, rmulticast;
36 + unsigned long long tbytes, tpackets, terrors, tdrops, tfifo, tcollisions, tcarrier, tcompressed;
37 +
38 + for(l = 2; l < lines ;l++) {
39 + words = procfile_linewords(ff, l);
40 + if(words < 17) continue;
41 +
42 + iface = procfile_lineword(ff, l, 0);
43 +
44 + rbytes = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
45 + rpackets = strtoull(procfile_lineword(ff, l, 2), NULL, 10);
46 + rerrors = strtoull(procfile_lineword(ff, l, 3), NULL, 10);
47 + rdrops = strtoull(procfile_lineword(ff, l, 4), NULL, 10);
48 + rfifo = strtoull(procfile_lineword(ff, l, 5), NULL, 10);
49 + rframe = strtoull(procfile_lineword(ff, l, 6), NULL, 10);
50 + rcompressed = strtoull(procfile_lineword(ff, l, 7), NULL, 10);
51 + rmulticast = strtoull(procfile_lineword(ff, l, 8), NULL, 10);
52 +
53 + tbytes = strtoull(procfile_lineword(ff, l, 9), NULL, 10);
54 + tpackets = strtoull(procfile_lineword(ff, l, 10), NULL, 10);
55 + terrors = strtoull(procfile_lineword(ff, l, 11), NULL, 10);
56 + tdrops = strtoull(procfile_lineword(ff, l, 12), NULL, 10);
57 + tfifo = strtoull(procfile_lineword(ff, l, 13), NULL, 10);
58 + tcollisions = strtoull(procfile_lineword(ff, l, 14), NULL, 10);
59 + tcarrier = strtoull(procfile_lineword(ff, l, 15), NULL, 10);
60 + tcompressed = strtoull(procfile_lineword(ff, l, 16), NULL, 10);
61 +
62 + int ddo_bandwidth = do_bandwidth, ddo_packets = do_packets, ddo_errors = do_errors, ddo_drops = do_drops, ddo_fifo = do_fifo, ddo_compressed = do_compressed, ddo_events = do_events;
63 +
64 + int default_enable = enable_new_interfaces;
65 +
66 + // prevent unused interfaces from creating charts
67 + if(strcmp(iface, "lo") == 0)
68 + default_enable = 0;
69 + else {
70 + int len = strlen(iface);
71 + if(len >= 4 && strcmp(&iface[len-4], "-ifb") == 0)
72 + default_enable = enable_ifb_interfaces;
73 + }
74 +
75 + // check if the user wants it
76 + {
77 + char var_name[512 + 1];
78 + snprintfz(var_name, 512, "plugin:proc:/proc/net/dev:%s", iface);
79 + default_enable = config_get_boolean_ondemand(var_name, "enabled", default_enable);
80 + if(default_enable == CONFIG_ONDEMAND_NO) continue;
81 + if(default_enable == CONFIG_ONDEMAND_ONDEMAND && !rbytes && !tbytes) continue;
82 +
83 + ddo_bandwidth = config_get_boolean_ondemand(var_name, "bandwidth", ddo_bandwidth);
84 + ddo_packets = config_get_boolean_ondemand(var_name, "packets", ddo_packets);
85 + ddo_errors = config_get_boolean_ondemand(var_name, "errors", ddo_errors);
86 + ddo_drops = config_get_boolean_ondemand(var_name, "drops", ddo_drops);
87 + ddo_fifo = config_get_boolean_ondemand(var_name, "fifo", ddo_fifo);
88 + ddo_compressed = config_get_boolean_ondemand(var_name, "compressed", ddo_compressed);
89 + ddo_events = config_get_boolean_ondemand(var_name, "events", ddo_events);
90 +
91 + if(ddo_bandwidth == CONFIG_ONDEMAND_ONDEMAND && rbytes == 0 && tbytes == 0) ddo_bandwidth = 0;
92 + if(ddo_errors == CONFIG_ONDEMAND_ONDEMAND && rerrors == 0 && terrors == 0) ddo_errors = 0;
93 + if(ddo_drops == CONFIG_ONDEMAND_ONDEMAND && rdrops == 0 && tdrops == 0) ddo_drops = 0;
94 + if(ddo_fifo == CONFIG_ONDEMAND_ONDEMAND && rfifo == 0 && tfifo == 0) ddo_fifo = 0;
95 + if(ddo_compressed == CONFIG_ONDEMAND_ONDEMAND && rcompressed == 0 && tcompressed == 0) ddo_compressed = 0;
96 + if(ddo_events == CONFIG_ONDEMAND_ONDEMAND && rframe == 0 && tcollisions == 0 && tcarrier == 0) ddo_events = 0;
97 +
98 + // for absolute values, we need to switch the setting to 'yes'
99 + // to allow it refresh from now on
100 + // if(ddo_fifo == CONFIG_ONDEMAND_ONDEMAND) config_set(var_name, "fifo", "yes");
101 + }
102 +
103 + RRDSET *st;
104 +
105 + // --------------------------------------------------------------------
106 +
107 + if(ddo_bandwidth) {
108 + st = rrdset_find_bytype("net", iface);
109 + if(!st) {
110 + st = rrdset_create("net", iface, NULL, iface, "net.net", "Bandwidth", "kilobits/s", 7000, update_every, RRDSET_TYPE_AREA);
111 +
112 + rrddim_add(st, "received", NULL, 8, 1024, RRDDIM_INCREMENTAL);
113 + rrddim_add(st, "sent", NULL, -8, 1024, RRDDIM_INCREMENTAL);
114 + }
115 + else rrdset_next(st);
116 +
117 + rrddim_set(st, "received", rbytes);
118 + rrddim_set(st, "sent", tbytes);
119 + rrdset_done(st);
120 + }
121 +
122 + // --------------------------------------------------------------------
123 +
124 + if(ddo_packets) {
125 + st = rrdset_find_bytype("net_packets", iface);
126 + if(!st) {
127 + st = rrdset_create("net_packets", iface, NULL, iface, "net.packets", "Packets", "packets/s", 7001, update_every, RRDSET_TYPE_LINE);
128 + st->isdetail = 1;
129 +
130 + rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
131 + rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
132 + rrddim_add(st, "multicast", NULL, 1, 1, RRDDIM_INCREMENTAL);
133 + }
134 + else rrdset_next(st);
135 +
136 + rrddim_set(st, "received", rpackets);
137 + rrddim_set(st, "sent", tpackets);
138 + rrddim_set(st, "multicast", rmulticast);
139 + rrdset_done(st);
140 + }
141 +
142 + // --------------------------------------------------------------------
143 +
144 + if(ddo_errors) {
145 + st = rrdset_find_bytype("net_errors", iface);
146 + if(!st) {
147 + st = rrdset_create("net_errors", iface, NULL, iface, "net.errors", "Interface Errors", "errors/s", 7002, update_every, RRDSET_TYPE_LINE);
148 + st->isdetail = 1;
149 +
150 + rrddim_add(st, "inbound", NULL, 1, 1, RRDDIM_INCREMENTAL);
151 + rrddim_add(st, "outbound", NULL, -1, 1, RRDDIM_INCREMENTAL);
152 + }
153 + else rrdset_next(st);
154 +
155 + rrddim_set(st, "inbound", rerrors);
156 + rrddim_set(st, "outbound", terrors);
157 + rrdset_done(st);
158 + }
159 +
160 + // --------------------------------------------------------------------
161 +
162 + if(ddo_drops) {
163 + st = rrdset_find_bytype("net_drops", iface);
164 + if(!st) {
165 + st = rrdset_create("net_drops", iface, NULL, iface, "net.drops", "Interface Drops", "drops/s", 7003, update_every, RRDSET_TYPE_LINE);
166 + st->isdetail = 1;
167 +
168 + rrddim_add(st, "inbound", NULL, 1, 1, RRDDIM_INCREMENTAL);
169 + rrddim_add(st, "outbound", NULL, -1, 1, RRDDIM_INCREMENTAL);
170 + }
171 + else rrdset_next(st);
172 +
173 + rrddim_set(st, "inbound", rdrops);
174 + rrddim_set(st, "outbound", tdrops);
175 + rrdset_done(st);
176 + }
177 +
178 + // --------------------------------------------------------------------
179 +
180 + if(ddo_fifo) {
181 + st = rrdset_find_bytype("net_fifo", iface);
182 + if(!st) {
183 + st = rrdset_create("net_fifo", iface, NULL, iface, "net.fifo", "Interface FIFO Buffer Errors", "errors", 7004, update_every, RRDSET_TYPE_LINE);
184 + st->isdetail = 1;
185 +
186 + rrddim_add(st, "receive", NULL, 1, 1, RRDDIM_INCREMENTAL);
187 + rrddim_add(st, "transmit", NULL, -1, 1, RRDDIM_INCREMENTAL);
188 + }
189 + else rrdset_next(st);
190 +
191 + rrddim_set(st, "receive", rfifo);
192 + rrddim_set(st, "transmit", tfifo);
193 + rrdset_done(st);
194 + }
195 +
196 + // --------------------------------------------------------------------
197 +
198 + if(ddo_compressed) {
199 + st = rrdset_find_bytype("net_compressed", iface);
200 + if(!st) {
201 + st = rrdset_create("net_compressed", iface, NULL, iface, "net.compressed", "Compressed Packets", "packets/s", 7005, update_every, RRDSET_TYPE_LINE);
202 + st->isdetail = 1;
203 +
204 + rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
205 + rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
206 + }
207 + else rrdset_next(st);
208 +
209 + rrddim_set(st, "received", rcompressed);
210 + rrddim_set(st, "sent", tcompressed);
211 + rrdset_done(st);
212 + }
213 +
214 + // --------------------------------------------------------------------
215 +
216 + if(ddo_events) {
217 + st = rrdset_find_bytype("net_events", iface);
218 + if(!st) {
219 + st = rrdset_create("net_events", iface, NULL, iface, "net.events", "Network Interface Events", "events/s", 7006, update_every, RRDSET_TYPE_LINE);
220 + st->isdetail = 1;
221 +
222 + rrddim_add(st, "frames", NULL, 1, 1, RRDDIM_INCREMENTAL);
223 + rrddim_add(st, "collisions", NULL, -1, 1, RRDDIM_INCREMENTAL);
224 + rrddim_add(st, "carrier", NULL, -1, 1, RRDDIM_INCREMENTAL);
225 + }
226 + else rrdset_next(st);
227 +
228 + rrddim_set(st, "frames", rframe);
229 + rrddim_set(st, "collisions", tcollisions);
230 + rrddim_set(st, "carrier", tcarrier);
231 + rrdset_done(st);
232 + }
233 + }
234 +
235 + return 0;
236 }
src/proc_net_ip_vs_stats.c
+65 -65
@@ -1,92 +1,92 @@
1 #include "common.h"
2
3 -#define RRD_TYPE_NET_IPVS "ipvs"
4 -#define RRD_TYPE_NET_IPVS_LEN strlen(RRD_TYPE_NET_IPVS)
3 +#define RRD_TYPE_NET_IPVS "ipvs"
4 +#define RRD_TYPE_NET_IPVS_LEN strlen(RRD_TYPE_NET_IPVS)
5
6 int do_proc_net_ip_vs_stats(int update_every, unsigned long long dt) {
7 - static int do_bandwidth = -1, do_sockets = -1, do_packets = -1;
8 - static procfile *ff = NULL;
7 + static int do_bandwidth = -1, do_sockets = -1, do_packets = -1;
8 + static procfile *ff = NULL;
9
10 - if(do_bandwidth == -1) do_bandwidth = config_get_boolean("plugin:proc:/proc/net/ip_vs_stats", "IPVS bandwidth", 1);
11 - if(do_sockets == -1) do_sockets = config_get_boolean("plugin:proc:/proc/net/ip_vs_stats", "IPVS connections", 1);
12 - if(do_packets == -1) do_packets = config_get_boolean("plugin:proc:/proc/net/ip_vs_stats", "IPVS packets", 1);
10 + if(do_bandwidth == -1) do_bandwidth = config_get_boolean("plugin:proc:/proc/net/ip_vs_stats", "IPVS bandwidth", 1);
11 + if(do_sockets == -1) do_sockets = config_get_boolean("plugin:proc:/proc/net/ip_vs_stats", "IPVS connections", 1);
12 + if(do_packets == -1) do_packets = config_get_boolean("plugin:proc:/proc/net/ip_vs_stats", "IPVS packets", 1);
13
14 - if(dt) {};
14 + if(dt) {};
15
16 - if(!ff) {
17 - char filename[FILENAME_MAX + 1];
18 - snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/net/ip_vs_stats");
19 - ff = procfile_open(config_get("plugin:proc:/proc/net/ip_vs_stats", "filename to monitor", filename), " \t,:|", PROCFILE_FLAG_DEFAULT);
20 - }
21 - if(!ff) return 1;
16 + if(!ff) {
17 + char filename[FILENAME_MAX + 1];
18 + snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/net/ip_vs_stats");
19 + ff = procfile_open(config_get("plugin:proc:/proc/net/ip_vs_stats", "filename to monitor", filename), " \t,:|", PROCFILE_FLAG_DEFAULT);
20 + }
21 + if(!ff) return 1;
22
23 - ff = procfile_readall(ff);
24 - if(!ff) return 0; // we return 0, so that we will retry to open it next time
23 + ff = procfile_readall(ff);
24 + if(!ff) return 0; // we return 0, so that we will retry to open it next time
25
26 - // make sure we have 3 lines
27 - if(procfile_lines(ff) < 3) return 1;
26 + // make sure we have 3 lines
27 + if(procfile_lines(ff) < 3) return 1;
28
29 - // make sure we have 5 words on the 3rd line
30 - if(procfile_linewords(ff, 2) < 5) return 1;
29 + // make sure we have 5 words on the 3rd line
30 + if(procfile_linewords(ff, 2) < 5) return 1;
31
32 - unsigned long long entries, InPackets, OutPackets, InBytes, OutBytes;
32 + unsigned long long entries, InPackets, OutPackets, InBytes, OutBytes;
33
34 - entries = strtoull(procfile_lineword(ff, 2, 0), NULL, 16);
35 - InPackets = strtoull(procfile_lineword(ff, 2, 1), NULL, 16);
36 - OutPackets = strtoull(procfile_lineword(ff, 2, 2), NULL, 16);
37 - InBytes = strtoull(procfile_lineword(ff, 2, 3), NULL, 16);
38 - OutBytes = strtoull(procfile_lineword(ff, 2, 4), NULL, 16);
34 + entries = strtoull(procfile_lineword(ff, 2, 0), NULL, 16);
35 + InPackets = strtoull(procfile_lineword(ff, 2, 1), NULL, 16);
36 + OutPackets = strtoull(procfile_lineword(ff, 2, 2), NULL, 16);
37 + InBytes = strtoull(procfile_lineword(ff, 2, 3), NULL, 16);
38 + OutBytes = strtoull(procfile_lineword(ff, 2, 4), NULL, 16);
39
40 - RRDSET *st;
40 + RRDSET *st;
41
42 - // --------------------------------------------------------------------
42 + // --------------------------------------------------------------------
43
44 - if(do_sockets) {
45 - st = rrdset_find(RRD_TYPE_NET_IPVS ".sockets");
46 - if(!st) {
47 - st = rrdset_create(RRD_TYPE_NET_IPVS, "sockets", NULL, RRD_TYPE_NET_IPVS, NULL, "IPVS New Connections", "connections/s", 1001, update_every, RRDSET_TYPE_LINE);
44 + if(do_sockets) {
45 + st = rrdset_find(RRD_TYPE_NET_IPVS ".sockets");
46 + if(!st) {
47 + st = rrdset_create(RRD_TYPE_NET_IPVS, "sockets", NULL, RRD_TYPE_NET_IPVS, NULL, "IPVS New Connections", "connections/s", 1001, update_every, RRDSET_TYPE_LINE);
48
49 - rrddim_add(st, "connections", NULL, 1, 1, RRDDIM_INCREMENTAL);
50 - }
51 - else rrdset_next(st);
49 + rrddim_add(st, "connections", NULL, 1, 1, RRDDIM_INCREMENTAL);
50 + }
51 + else rrdset_next(st);
52
53 - rrddim_set(st, "connections", entries);
54 - rrdset_done(st);
55 - }
53 + rrddim_set(st, "connections", entries);
54 + rrdset_done(st);
55 + }
56
57 - // --------------------------------------------------------------------
57 + // --------------------------------------------------------------------
58
59 - if(do_packets) {
60 - st = rrdset_find(RRD_TYPE_NET_IPVS ".packets");
61 - if(!st) {
62 - st = rrdset_create(RRD_TYPE_NET_IPVS, "packets", NULL, RRD_TYPE_NET_IPVS, NULL, "IPVS Packets", "packets/s", 1002, update_every, RRDSET_TYPE_LINE);
59 + if(do_packets) {
60 + st = rrdset_find(RRD_TYPE_NET_IPVS ".packets");
61 + if(!st) {
62 + st = rrdset_create(RRD_TYPE_NET_IPVS, "packets", NULL, RRD_TYPE_NET_IPVS, NULL, "IPVS Packets", "packets/s", 1002, update_every, RRDSET_TYPE_LINE);
63
64 - rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
65 - rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
66 - }
67 - else rrdset_next(st);
64 + rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
65 + rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
66 + }
67 + else rrdset_next(st);
68
69 - rrddim_set(st, "received", InPackets);
70 - rrddim_set(st, "sent", OutPackets);
71 - rrdset_done(st);
72 - }
69 + rrddim_set(st, "received", InPackets);
70 + rrddim_set(st, "sent", OutPackets);
71 + rrdset_done(st);
72 + }
73
74 - // --------------------------------------------------------------------
74 + // --------------------------------------------------------------------
75
76 - if(do_bandwidth) {
77 - st = rrdset_find(RRD_TYPE_NET_IPVS ".net");
78 - if(!st) {
79 - st = rrdset_create(RRD_TYPE_NET_IPVS, "net", NULL, RRD_TYPE_NET_IPVS, NULL, "IPVS Bandwidth", "kilobits/s", 1000, update_every, RRDSET_TYPE_AREA);
76 + if(do_bandwidth) {
77 + st = rrdset_find(RRD_TYPE_NET_IPVS ".net");
78 + if(!st) {
79 + st = rrdset_create(RRD_TYPE_NET_IPVS, "net", NULL, RRD_TYPE_NET_IPVS, NULL, "IPVS Bandwidth", "kilobits/s", 1000, update_every, RRDSET_TYPE_AREA);
80
81 - rrddim_add(st, "received", NULL, 8, 1024, RRDDIM_INCREMENTAL);
82 - rrddim_add(st, "sent", NULL, -8, 1024, RRDDIM_INCREMENTAL);
83 - }
84 - else rrdset_next(st);
81 + rrddim_add(st, "received", NULL, 8, 1024, RRDDIM_INCREMENTAL);
82 + rrddim_add(st, "sent", NULL, -8, 1024, RRDDIM_INCREMENTAL);
83 + }
84 + else rrdset_next(st);
85
86 - rrddim_set(st, "received", InBytes);
87 - rrddim_set(st, "sent", OutBytes);
88 - rrdset_done(st);
89 - }
86 + rrddim_set(st, "received", InBytes);
87 + rrddim_set(st, "sent", OutBytes);
88 + rrdset_done(st);
89 + }
90
91 - return 0;
91 + return 0;
92 }
src/proc_net_netstat.c
+175 -175
@@ -1,179 +1,179 @@
1 #include "common.h"
2
3 int do_proc_net_netstat(int update_every, unsigned long long dt) {
4 - static int do_bandwidth = -1, do_inerrors = -1, do_mcast = -1, do_bcast = -1, do_mcast_p = -1, do_bcast_p = -1;
5 - static procfile *ff = NULL;
6 -
7 - if(do_bandwidth == -1) do_bandwidth = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "bandwidth", CONFIG_ONDEMAND_ONDEMAND);
8 - if(do_inerrors == -1) do_inerrors = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "input errors", CONFIG_ONDEMAND_ONDEMAND);
9 - if(do_mcast == -1) do_mcast = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "multicast bandwidth", CONFIG_ONDEMAND_ONDEMAND);
10 - if(do_bcast == -1) do_bcast = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "broadcast bandwidth", CONFIG_ONDEMAND_ONDEMAND);
11 - if(do_mcast_p == -1) do_mcast_p = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "multicast packets", CONFIG_ONDEMAND_ONDEMAND);
12 - if(do_bcast_p == -1) do_bcast_p = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "broadcast packets", CONFIG_ONDEMAND_ONDEMAND);
13 -
14 - if(dt) {};
15 -
16 - if(!ff) {
17 - char filename[FILENAME_MAX + 1];
18 - snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/net/netstat");
19 - ff = procfile_open(config_get("plugin:proc:/proc/net/netstat", "filename to monitor", filename), " \t:", PROCFILE_FLAG_DEFAULT);
20 - }
21 - if(!ff) return 1;
22 -
23 - ff = procfile_readall(ff);
24 - if(!ff) return 0; // we return 0, so that we will retry to open it next time
25 -
26 - uint32_t lines = procfile_lines(ff), l;
27 - uint32_t words;
28 -
29 - for(l = 0; l < lines ;l++) {
30 - if(strcmp(procfile_lineword(ff, l, 0), "IpExt") == 0) {
31 - l++; // we need the next line
32 -
33 - if(strcmp(procfile_lineword(ff, l, 0), "IpExt") != 0) {
34 - error("Cannot read IpExt line from /proc/net/netstat.");
35 - break;
36 - }
37 - words = procfile_linewords(ff, l);
38 - if(words < 12) {
39 - error("Cannot read /proc/net/netstat IpExt line. Expected 12 params, read %u.", words);
40 - continue;
41 - }
42 -
43 - unsigned long long
44 - InNoRoutes = 0, InTruncatedPkts = 0,
45 - InOctets = 0, InMcastPkts = 0, InBcastPkts = 0, InMcastOctets = 0, InBcastOctets = 0,
46 - OutOctets = 0, OutMcastPkts = 0, OutBcastPkts = 0, OutMcastOctets = 0, OutBcastOctets = 0;
47 -
48 - InNoRoutes = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
49 - InTruncatedPkts = strtoull(procfile_lineword(ff, l, 2), NULL, 10);
50 - InMcastPkts = strtoull(procfile_lineword(ff, l, 3), NULL, 10);
51 - OutMcastPkts = strtoull(procfile_lineword(ff, l, 4), NULL, 10);
52 - InBcastPkts = strtoull(procfile_lineword(ff, l, 5), NULL, 10);
53 - OutBcastPkts = strtoull(procfile_lineword(ff, l, 6), NULL, 10);
54 - InOctets = strtoull(procfile_lineword(ff, l, 7), NULL, 10);
55 - OutOctets = strtoull(procfile_lineword(ff, l, 8), NULL, 10);
56 - InMcastOctets = strtoull(procfile_lineword(ff, l, 9), NULL, 10);
57 - OutMcastOctets = strtoull(procfile_lineword(ff, l, 10), NULL, 10);
58 - InBcastOctets = strtoull(procfile_lineword(ff, l, 11), NULL, 10);
59 - OutBcastOctets = strtoull(procfile_lineword(ff, l, 12), NULL, 10);
60 -
61 - RRDSET *st;
62 -
63 - // --------------------------------------------------------------------
64 -
65 - if(do_bandwidth == CONFIG_ONDEMAND_YES || (do_bandwidth == CONFIG_ONDEMAND_ONDEMAND && (InOctets || OutOctets))) {
66 - do_bandwidth = CONFIG_ONDEMAND_YES;
67 - st = rrdset_find("system.ipv4");
68 - if(!st) {
69 - st = rrdset_create("system", "ipv4", NULL, "network", NULL, "IPv4 Bandwidth", "kilobits/s", 500, update_every, RRDSET_TYPE_AREA);
70 -
71 - rrddim_add(st, "received", NULL, 8, 1024, RRDDIM_INCREMENTAL);
72 - rrddim_add(st, "sent", NULL, -8, 1024, RRDDIM_INCREMENTAL);
73 - }
74 - else rrdset_next(st);
75 -
76 - rrddim_set(st, "sent", OutOctets);
77 - rrddim_set(st, "received", InOctets);
78 - rrdset_done(st);
79 - }
80 -
81 - // --------------------------------------------------------------------
82 -
83 - if(do_inerrors == CONFIG_ONDEMAND_YES || (do_inerrors == CONFIG_ONDEMAND_ONDEMAND && (InNoRoutes || InTruncatedPkts))) {
84 - do_inerrors = CONFIG_ONDEMAND_YES;
85 - st = rrdset_find("ipv4.inerrors");
86 - if(!st) {
87 - st = rrdset_create("ipv4", "inerrors", NULL, "errors", NULL, "IPv4 Input Errors", "packets/s", 4000, update_every, RRDSET_TYPE_LINE);
88 - st->isdetail = 1;
89 -
90 - rrddim_add(st, "noroutes", NULL, 1, 1, RRDDIM_INCREMENTAL);
91 - rrddim_add(st, "truncated", NULL, 1, 1, RRDDIM_INCREMENTAL);
92 - }
93 - else rrdset_next(st);
94 -
95 - rrddim_set(st, "noroutes", InNoRoutes);
96 - rrddim_set(st, "truncated", InTruncatedPkts);
97 - rrdset_done(st);
98 - }
99 -
100 - // --------------------------------------------------------------------
101 -
102 - if(do_mcast == CONFIG_ONDEMAND_YES || (do_mcast == CONFIG_ONDEMAND_ONDEMAND && (InMcastOctets || OutMcastOctets))) {
103 - do_mcast = CONFIG_ONDEMAND_YES;
104 - st = rrdset_find("ipv4.mcast");
105 - if(!st) {
106 - st = rrdset_create("ipv4", "mcast", NULL, "multicast", NULL, "IPv4 Multicast Bandwidth", "kilobits/s", 9000, update_every, RRDSET_TYPE_AREA);
107 - st->isdetail = 1;
108 -
109 - rrddim_add(st, "received", NULL, 8, 1024, RRDDIM_INCREMENTAL);
110 - rrddim_add(st, "sent", NULL, -8, 1024, RRDDIM_INCREMENTAL);
111 - }
112 - else rrdset_next(st);
113 -
114 - rrddim_set(st, "sent", OutMcastOctets);
115 - rrddim_set(st, "received", InMcastOctets);
116 - rrdset_done(st);
117 - }
118 -
119 - // --------------------------------------------------------------------
120 -
121 - if(do_bcast == CONFIG_ONDEMAND_YES || (do_bcast == CONFIG_ONDEMAND_ONDEMAND && (InBcastOctets || OutBcastOctets))) {
122 - do_bcast = CONFIG_ONDEMAND_YES;
123 - st = rrdset_find("ipv4.bcast");
124 - if(!st) {
125 - st = rrdset_create("ipv4", "bcast", NULL, "broadcast", NULL, "IPv4 Broadcast Bandwidth", "kilobits/s", 8000, update_every, RRDSET_TYPE_AREA);
126 - st->isdetail = 1;
127 -
128 - rrddim_add(st, "received", NULL, 8, 1024, RRDDIM_INCREMENTAL);
129 - rrddim_add(st, "sent", NULL, -8, 1024, RRDDIM_INCREMENTAL);
130 - }
131 - else rrdset_next(st);
132 -
133 - rrddim_set(st, "sent", OutBcastOctets);
134 - rrddim_set(st, "received", InBcastOctets);
135 - rrdset_done(st);
136 - }
137 -
138 - // --------------------------------------------------------------------
139 -
140 - if(do_mcast_p == CONFIG_ONDEMAND_YES || (do_mcast_p == CONFIG_ONDEMAND_ONDEMAND && (InMcastPkts || OutMcastPkts))) {
141 - do_mcast_p = CONFIG_ONDEMAND_YES;
142 - st = rrdset_find("ipv4.mcastpkts");
143 - if(!st) {
144 - st = rrdset_create("ipv4", "mcastpkts", NULL, "multicast", NULL, "IPv4 Multicast Packets", "packets/s", 9500, update_every, RRDSET_TYPE_LINE);
145 - st->isdetail = 1;
146 -
147 - rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
148 - rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
149 - }
150 - else rrdset_next(st);
151 -
152 - rrddim_set(st, "sent", OutMcastPkts);
153 - rrddim_set(st, "received", InMcastPkts);
154 - rrdset_done(st);
155 - }
156 -
157 - // --------------------------------------------------------------------
158 -
159 - if(do_bcast_p == CONFIG_ONDEMAND_YES || (do_bcast_p == CONFIG_ONDEMAND_ONDEMAND && (InBcastPkts || OutBcastPkts))) {
160 - do_bcast_p = CONFIG_ONDEMAND_YES;
161 - st = rrdset_find("ipv4.bcastpkts");
162 - if(!st) {
163 - st = rrdset_create("ipv4", "bcastpkts", NULL, "broadcast", NULL, "IPv4 Broadcast Packets", "packets/s", 8500, update_every, RRDSET_TYPE_LINE);
164 - st->isdetail = 1;
165 -
166 - rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
167 - rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
168 - }
169 - else rrdset_next(st);
170 -
171 - rrddim_set(st, "sent", OutBcastPkts);
172 - rrddim_set(st, "received", InBcastPkts);
173 - rrdset_done(st);
174 - }
175 - }
176 - }
177 -
178 - return 0;
4 + static int do_bandwidth = -1, do_inerrors = -1, do_mcast = -1, do_bcast = -1, do_mcast_p = -1, do_bcast_p = -1;
5 + static procfile *ff = NULL;
6 +
7 + if(do_bandwidth == -1) do_bandwidth = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "bandwidth", CONFIG_ONDEMAND_ONDEMAND);
8 + if(do_inerrors == -1) do_inerrors = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "input errors", CONFIG_ONDEMAND_ONDEMAND);
9 + if(do_mcast == -1) do_mcast = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "multicast bandwidth", CONFIG_ONDEMAND_ONDEMAND);
10 + if(do_bcast == -1) do_bcast = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "broadcast bandwidth", CONFIG_ONDEMAND_ONDEMAND);
11 + if(do_mcast_p == -1) do_mcast_p = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "multicast packets", CONFIG_ONDEMAND_ONDEMAND);
12 + if(do_bcast_p == -1) do_bcast_p = config_get_boolean_ondemand("plugin:proc:/proc/net/netstat", "broadcast packets", CONFIG_ONDEMAND_ONDEMAND);
13 +
14 + if(dt) {};
15 +
16 + if(!ff) {
17 + char filename[FILENAME_MAX + 1];
18 + snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/net/netstat");
19 + ff = procfile_open(config_get("plugin:proc:/proc/net/netstat", "filename to monitor", filename), " \t:", PROCFILE_FLAG_DEFAULT);
20 + }
21 + if(!ff) return 1;
22 +
23 + ff = procfile_readall(ff);
24 + if(!ff) return 0; // we return 0, so that we will retry to open it next time
25 +
26 + uint32_t lines = procfile_lines(ff), l;
27 + uint32_t words;
28 +
29 + for(l = 0; l < lines ;l++) {
30 + if(strcmp(procfile_lineword(ff, l, 0), "IpExt") == 0) {
31 + l++; // we need the next line
32 +
33 + if(strcmp(procfile_lineword(ff, l, 0), "IpExt") != 0) {
34 + error("Cannot read IpExt line from /proc/net/netstat.");
35 + break;
36 + }
37 + words = procfile_linewords(ff, l);
38 + if(words < 12) {
39 + error("Cannot read /proc/net/netstat IpExt line. Expected 12 params, read %u.", words);
40 + continue;
41 + }
42 +
43 + unsigned long long
44 + InNoRoutes = 0, InTruncatedPkts = 0,
45 + InOctets = 0, InMcastPkts = 0, InBcastPkts = 0, InMcastOctets = 0, InBcastOctets = 0,
46 + OutOctets = 0, OutMcastPkts = 0, OutBcastPkts = 0, OutMcastOctets = 0, OutBcastOctets = 0;
47 +
48 + InNoRoutes = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
49 + InTruncatedPkts = strtoull(procfile_lineword(ff, l, 2), NULL, 10);
50 + InMcastPkts = strtoull(procfile_lineword(ff, l, 3), NULL, 10);
51 + OutMcastPkts = strtoull(procfile_lineword(ff, l, 4), NULL, 10);
52 + InBcastPkts = strtoull(procfile_lineword(ff, l, 5), NULL, 10);
53 + OutBcastPkts = strtoull(procfile_lineword(ff, l, 6), NULL, 10);
54 + InOctets = strtoull(procfile_lineword(ff, l, 7), NULL, 10);
55 + OutOctets = strtoull(procfile_lineword(ff, l, 8), NULL, 10);
56 + InMcastOctets = strtoull(procfile_lineword(ff, l, 9), NULL, 10);
57 + OutMcastOctets = strtoull(procfile_lineword(ff, l, 10), NULL, 10);
58 + InBcastOctets = strtoull(procfile_lineword(ff, l, 11), NULL, 10);
59 + OutBcastOctets = strtoull(procfile_lineword(ff, l, 12), NULL, 10);
60 +
61 + RRDSET *st;
62 +
63 + // --------------------------------------------------------------------
64 +
65 + if(do_bandwidth == CONFIG_ONDEMAND_YES || (do_bandwidth == CONFIG_ONDEMAND_ONDEMAND && (InOctets || OutOctets))) {
66 + do_bandwidth = CONFIG_ONDEMAND_YES;
67 + st = rrdset_find("system.ipv4");
68 + if(!st) {
69 + st = rrdset_create("system", "ipv4", NULL, "network", NULL, "IPv4 Bandwidth", "kilobits/s", 500, update_every, RRDSET_TYPE_AREA);
70 +
71 + rrddim_add(st, "received", NULL, 8, 1024, RRDDIM_INCREMENTAL);
72 + rrddim_add(st, "sent", NULL, -8, 1024, RRDDIM_INCREMENTAL);
73 + }
74 + else rrdset_next(st);
75 +
76 + rrddim_set(st, "sent", OutOctets);
77 + rrddim_set(st, "received", InOctets);
78 + rrdset_done(st);
79 + }
80 +
81 + // --------------------------------------------------------------------
82 +
83 + if(do_inerrors == CONFIG_ONDEMAND_YES || (do_inerrors == CONFIG_ONDEMAND_ONDEMAND && (InNoRoutes || InTruncatedPkts))) {
84 + do_inerrors = CONFIG_ONDEMAND_YES;
85 + st = rrdset_find("ipv4.inerrors");
86 + if(!st) {
87 + st = rrdset_create("ipv4", "inerrors", NULL, "errors", NULL, "IPv4 Input Errors", "packets/s", 4000, update_every, RRDSET_TYPE_LINE);
88 + st->isdetail = 1;
89 +
90 + rrddim_add(st, "noroutes", NULL, 1, 1, RRDDIM_INCREMENTAL);
91 + rrddim_add(st, "truncated", NULL, 1, 1, RRDDIM_INCREMENTAL);
92 + }
93 + else rrdset_next(st);
94 +
95 + rrddim_set(st, "noroutes", InNoRoutes);
96 + rrddim_set(st, "truncated", InTruncatedPkts);
97 + rrdset_done(st);
98 + }
99 +
100 + // --------------------------------------------------------------------
101 +
102 + if(do_mcast == CONFIG_ONDEMAND_YES || (do_mcast == CONFIG_ONDEMAND_ONDEMAND && (InMcastOctets || OutMcastOctets))) {
103 + do_mcast = CONFIG_ONDEMAND_YES;
104 + st = rrdset_find("ipv4.mcast");
105 + if(!st) {
106 + st = rrdset_create("ipv4", "mcast", NULL, "multicast", NULL, "IPv4 Multicast Bandwidth", "kilobits/s", 9000, update_every, RRDSET_TYPE_AREA);
107 + st->isdetail = 1;
108 +
109 + rrddim_add(st, "received", NULL, 8, 1024, RRDDIM_INCREMENTAL);
110 + rrddim_add(st, "sent", NULL, -8, 1024, RRDDIM_INCREMENTAL);
111 + }
112 + else rrdset_next(st);
113 +
114 + rrddim_set(st, "sent", OutMcastOctets);
115 + rrddim_set(st, "received", InMcastOctets);
116 + rrdset_done(st);
117 + }
118 +
119 + // --------------------------------------------------------------------
120 +
121 + if(do_bcast == CONFIG_ONDEMAND_YES || (do_bcast == CONFIG_ONDEMAND_ONDEMAND && (InBcastOctets || OutBcastOctets))) {
122 + do_bcast = CONFIG_ONDEMAND_YES;
123 + st = rrdset_find("ipv4.bcast");
124 + if(!st) {
125 + st = rrdset_create("ipv4", "bcast", NULL, "broadcast", NULL, "IPv4 Broadcast Bandwidth", "kilobits/s", 8000, update_every, RRDSET_TYPE_AREA);
126 + st->isdetail = 1;
127 +
128 + rrddim_add(st, "received", NULL, 8, 1024, RRDDIM_INCREMENTAL);
129 + rrddim_add(st, "sent", NULL, -8, 1024, RRDDIM_INCREMENTAL);
130 + }
131 + else rrdset_next(st);
132 +
133 + rrddim_set(st, "sent", OutBcastOctets);
134 + rrddim_set(st, "received", InBcastOctets);
135 + rrdset_done(st);
136 + }
137 +
138 + // --------------------------------------------------------------------
139 +
140 + if(do_mcast_p == CONFIG_ONDEMAND_YES || (do_mcast_p == CONFIG_ONDEMAND_ONDEMAND && (InMcastPkts || OutMcastPkts))) {
141 + do_mcast_p = CONFIG_ONDEMAND_YES;
142 + st = rrdset_find("ipv4.mcastpkts");
143 + if(!st) {
144 + st = rrdset_create("ipv4", "mcastpkts", NULL, "multicast", NULL, "IPv4 Multicast Packets", "packets/s", 9500, update_every, RRDSET_TYPE_LINE);
145 + st->isdetail = 1;
146 +
147 + rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
148 + rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
149 + }
150 + else rrdset_next(st);
151 +
152 + rrddim_set(st, "sent", OutMcastPkts);
153 + rrddim_set(st, "received", InMcastPkts);
154 + rrdset_done(st);
155 + }
156 +
157 + // --------------------------------------------------------------------
158 +
159 + if(do_bcast_p == CONFIG_ONDEMAND_YES || (do_bcast_p == CONFIG_ONDEMAND_ONDEMAND && (InBcastPkts || OutBcastPkts))) {
160 + do_bcast_p = CONFIG_ONDEMAND_YES;
161 + st = rrdset_find("ipv4.bcastpkts");
162 + if(!st) {
163 + st = rrdset_create("ipv4", "bcastpkts", NULL, "broadcast", NULL, "IPv4 Broadcast Packets", "packets/s", 8500, update_every, RRDSET_TYPE_LINE);
164 + st->isdetail = 1;
165 +
166 + rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
167 + rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
168 + }
169 + else rrdset_next(st);
170 +
171 + rrddim_set(st, "sent", OutBcastPkts);
172 + rrddim_set(st, "received", InBcastPkts);
173 + rrdset_done(st);
174 + }
175 + }
176 + }
177 +
178 + return 0;
179 }
src/proc_net_rpc_nfsd.c
+656 -656
@@ -1,681 +1,681 @@
1 #include "common.h"
2
3 struct nfsd_procs {
4 - char name[30];
5 - unsigned long long proc2;
6 - unsigned long long proc3;
7 - unsigned long long proc4;
8 - int present2;
9 - int present3;
10 - int present4;
4 + char name[30];
5 + unsigned long long proc2;
6 + unsigned long long proc3;
7 + unsigned long long proc4;
8 + int present2;
9 + int present3;
10 + int present4;
11 };
12
13 struct nfsd_procs nfsd_proc_values[] = {
14 - { "null", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
15 - { "getattr", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
16 - { "setattr", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
17 - { "lookup", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
18 - { "access", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
19 - { "readlink", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
20 - { "read", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
21 - { "write", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
22 - { "create", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
23 - { "mkdir", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
24 - { "symlink", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
25 - { "mknod", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
26 - { "remove", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
27 - { "rmdir", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
28 - { "rename", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
29 - { "link", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
30 - { "readdir", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
31 - { "readdirplus", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
32 - { "fsstat", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
33 - { "fsinfo", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
34 - { "pathconf", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
35 - { "commit", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
36 - { "", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
14 + { "null", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
15 + { "getattr", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
16 + { "setattr", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
17 + { "lookup", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
18 + { "access", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
19 + { "readlink", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
20 + { "read", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
21 + { "write", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
22 + { "create", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
23 + { "mkdir", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
24 + { "symlink", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
25 + { "mknod", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
26 + { "remove", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
27 + { "rmdir", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
28 + { "rename", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
29 + { "link", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
30 + { "readdir", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
31 + { "readdirplus", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
32 + { "fsstat", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
33 + { "fsinfo", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
34 + { "pathconf", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
35 + { "commit", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
36 + { "", 0ULL, 0ULL, 0ULL, 0, 0, 0 },
37 };
38
39 struct nfsd4_ops {
40 - char name[30];
41 - unsigned long long value;
42 - int present;
40 + char name[30];
41 + unsigned long long value;
42 + int present;
43 };
44
45 struct nfsd4_ops nfsd4_ops_values[] = {
46 - { "access", 0ULL, 0},
47 - { "close", 0ULL, 0},
48 - { "commit", 0ULL, 0},
49 - { "create", 0ULL, 0},
50 - { "delegpurge", 0ULL, 0},
51 - { "delegreturn", 0ULL, 0},
52 - { "getattr", 0ULL, 0},
53 - { "getfh", 0ULL, 0},
54 - { "link", 0ULL, 0},
55 - { "lock", 0ULL, 0},
56 - { "lockt", 0ULL, 0},
57 - { "locku", 0ULL, 0},
58 - { "lookup", 0ULL, 0},
59 - { "lookupp", 0ULL, 0},
60 - { "nverify", 0ULL, 0},
61 - { "open", 0ULL, 0},
62 - { "openattr", 0ULL, 0},
63 - { "open_confirm", 0ULL, 0},
64 - { "open_downgrade", 0ULL, 0},
65 - { "putfh", 0ULL, 0},
66 - { "putpubfh", 0ULL, 0},
67 - { "putrootfh", 0ULL, 0},
68 - { "read", 0ULL, 0},
69 - { "readdir", 0ULL, 0},
70 - { "readlink", 0ULL, 0},
71 - { "remove", 0ULL, 0},
72 - { "rename", 0ULL, 0},
73 - { "renew", 0ULL, 0},
74 - { "restorefh", 0ULL, 0},
75 - { "savefh", 0ULL, 0},
76 - { "secinfo", 0ULL, 0},
77 - { "setattr", 0ULL, 0},
78 - { "setclientid", 0ULL, 0},
79 - { "setclientid_confirm", 0ULL, 0},
80 - { "verify", 0ULL, 0},
81 - { "write", 0ULL, 0},
82 - { "release_lockowner", 0ULL, 0},
83 -
84 - /* nfs41 */
85 - { "backchannel_ctl", 0ULL, 0},
86 - { "bind_conn_to_session", 0ULL, 0},
87 - { "exchange_id", 0ULL, 0},
88 - { "create_session", 0ULL, 0},
89 - { "destroy_session", 0ULL, 0},
90 - { "free_stateid", 0ULL, 0},
91 - { "get_dir_delegation", 0ULL, 0},
92 - { "getdeviceinfo", 0ULL, 0},
93 - { "getdevicelist", 0ULL, 0},
94 - { "layoutcommit", 0ULL, 0},
95 - { "layoutget", 0ULL, 0},
96 - { "layoutreturn", 0ULL, 0},
97 - { "secinfo_no_name", 0ULL, 0},
98 - { "sequence", 0ULL, 0},
99 - { "set_ssv", 0ULL, 0},
100 - { "test_stateid", 0ULL, 0},
101 - { "want_delegation", 0ULL, 0},
102 - { "destroy_clientid", 0ULL, 0},
103 - { "reclaim_complete", 0ULL, 0},
104 -
105 - /* nfs42 */
106 - { "allocate", 0ULL, 0},
107 - { "copy", 0ULL, 0},
108 - { "copy_notify", 0ULL, 0},
109 - { "deallocate", 0ULL, 0},
110 - { "io_advise", 0ULL, 0},
111 - { "layouterror", 0ULL, 0},
112 - { "layoutstats", 0ULL, 0},
113 - { "offload_cancel", 0ULL, 0},
114 - { "offload_status", 0ULL, 0},
115 - { "read_plus", 0ULL, 0},
116 - { "seek", 0ULL, 0},
117 - { "write_same", 0ULL, 0},
118 -
119 - /* termination */
120 - { "", 0ULL, 0 }
46 + { "access", 0ULL, 0},
47 + { "close", 0ULL, 0},
48 + { "commit", 0ULL, 0},
49 + { "create", 0ULL, 0},
50 + { "delegpurge", 0ULL, 0},
51 + { "delegreturn", 0ULL, 0},
52 + { "getattr", 0ULL, 0},
53 + { "getfh", 0ULL, 0},
54 + { "link", 0ULL, 0},
55 + { "lock", 0ULL, 0},
56 + { "lockt", 0ULL, 0},
57 + { "locku", 0ULL, 0},
58 + { "lookup", 0ULL, 0},
59 + { "lookupp", 0ULL, 0},
60 + { "nverify", 0ULL, 0},
61 + { "open", 0ULL, 0},
62 + { "openattr", 0ULL, 0},
63 + { "open_confirm", 0ULL, 0},
64 + { "open_downgrade", 0ULL, 0},
65 + { "putfh", 0ULL, 0},
66 + { "putpubfh", 0ULL, 0},
67 + { "putrootfh", 0ULL, 0},
68 + { "read", 0ULL, 0},
69 + { "readdir", 0ULL, 0},
70 + { "readlink", 0ULL, 0},
71 + { "remove", 0ULL, 0},
72 + { "rename", 0ULL, 0},
73 + { "renew", 0ULL, 0},
74 + { "restorefh", 0ULL, 0},
75 + { "savefh", 0ULL, 0},
76 + { "secinfo", 0ULL, 0},
77 + { "setattr", 0ULL, 0},
78 + { "setclientid", 0ULL, 0},
79 + { "setclientid_confirm", 0ULL, 0},
80 + { "verify", 0ULL, 0},
81 + { "write", 0ULL, 0},
82 + { "release_lockowner", 0ULL, 0},
83 +
84 + /* nfs41 */
85 + { "backchannel_ctl", 0ULL, 0},
86 + { "bind_conn_to_session", 0ULL, 0},
87 + { "exchange_id", 0ULL, 0},
88 + { "create_session", 0ULL, 0},
89 + { "destroy_session", 0ULL, 0},
90 + { "free_stateid", 0ULL, 0},
91 + { "get_dir_delegation", 0ULL, 0},
92 + { "getdeviceinfo", 0ULL, 0},
93 + { "getdevicelist", 0ULL, 0},
94 + { "layoutcommit", 0ULL, 0},
95 + { "layoutget", 0ULL, 0},
96 + { "layoutreturn", 0ULL, 0},
97 + { "secinfo_no_name", 0ULL, 0},
98 + { "sequence", 0ULL, 0},
99 + { "set_ssv", 0ULL, 0},
100 + { "test_stateid", 0ULL, 0},
101 + { "want_delegation", 0ULL, 0},
102 + { "destroy_clientid", 0ULL, 0},
103 + { "reclaim_complete", 0ULL, 0},
104 +
105 + /* nfs42 */
106 + { "allocate", 0ULL, 0},
107 + { "copy", 0ULL, 0},
108 + { "copy_notify", 0ULL, 0},
109 + { "deallocate", 0ULL, 0},
110 + { "io_advise", 0ULL, 0},
111 + { "layouterror", 0ULL, 0},
112 + { "layoutstats", 0ULL, 0},
113 + { "offload_cancel", 0ULL, 0},
114 + { "offload_status", 0ULL, 0},
115 + { "read_plus", 0ULL, 0},
116 + { "seek", 0ULL, 0},
117 + { "write_same", 0ULL, 0},
118 +
119 + /* termination */
120 + { "", 0ULL, 0 }
121 };
122
123
124 int do_proc_net_rpc_nfsd(int update_every, unsigned long long dt) {
125 - static procfile *ff = NULL;
126 - static int do_rc = -1, do_fh = -1, do_io = -1, do_th = -1, do_ra = -1, do_net = -1, do_rpc = -1, do_proc2 = -1, do_proc3 = -1, do_proc4 = -1, do_proc4ops = -1;
127 - static int ra_warning = 0, th_warning = 0, proc2_warning = 0, proc3_warning = 0, proc4_warning = 0, proc4ops_warning = 0;
128 -
129 - if(dt) {};
130 -
131 - if(!ff) {
132 - char filename[FILENAME_MAX + 1];
133 - snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/net/rpc/nfsd");
134 - ff = procfile_open(config_get("plugin:proc:/proc/net/rpc/nfsd", "filename to monitor", filename), " \t", PROCFILE_FLAG_DEFAULT);
135 - }
136 - if(!ff) return 1;
137 -
138 - ff = procfile_readall(ff);
139 - if(!ff) return 0; // we return 0, so that we will retry to open it next time
140 -
141 - if(do_rc == -1) do_rc = config_get_boolean("plugin:proc:/proc/net/rpc/nfsd", "read cache", 1);
142 - if(do_fh == -1) do_fh = config_get_boolean("plugin:proc:/proc/net/rpc/nfsd", "file handles", 1);
143 - if(do_io == -1) do_io = config_get_boolean("plugin:proc:/proc/net/rpc/nfsd", "I/O", 1);
144 - if(do_th == -1) do_th = config_get_boolean("plugin:proc:/proc/net/rpc/nfsd", "threads", 1);
145 - if(do_ra == -1) do_ra = config_get_boolean("plugin:proc:/proc/net/rpc/nfsd", "read ahead", 1);
146 - if(do_net == -1) do_net = config_get_boolean("plugin:proc:/proc/net/rpc/nfsd", "network", 1);
147 - if(do_rpc == -1) do_rpc = config_get_boolean("plugin:proc:/proc/net/rpc/nfsd", "rpc", 1);
148 - if(do_proc2 == -1) do_proc2 = config_get_boolean("plugin:proc:/proc/net/rpc/nfsd", "NFS v2 procedures", 1);
149 - if(do_proc3 == -1) do_proc3 = config_get_boolean("plugin:proc:/proc/net/rpc/nfsd", "NFS v3 procedures", 1);
150 - if(do_proc4 == -1) do_proc4 = config_get_boolean("plugin:proc:/proc/net/rpc/nfsd", "NFS v4 procedures", 1);
151 - if(do_proc4ops == -1) do_proc4ops = config_get_boolean("plugin:proc:/proc/net/rpc/nfsd", "NFS v4 operations", 1);
152 -
153 - // if they are enabled, reset them to 1
154 - // later we do them =2 to avoid doing strcmp for all lines
155 - if(do_rc) do_rc = 1;
156 - if(do_fh) do_fh = 1;
157 - if(do_io) do_io = 1;
158 - if(do_th) do_th = 1;
159 - if(do_ra) do_ra = 1;
160 - if(do_net) do_net = 1;
161 - if(do_rpc) do_rpc = 1;
162 - if(do_proc2) do_proc2 = 1;
163 - if(do_proc3) do_proc3 = 1;
164 - if(do_proc4) do_proc4 = 1;
165 - if(do_proc4ops) do_proc4ops = 1;
166 -
167 - uint32_t lines = procfile_lines(ff), l;
168 - uint32_t words;
169 -
170 - char *type;
171 - unsigned long long rc_hits = 0, rc_misses = 0, rc_nocache = 0;
172 - unsigned long long fh_stale = 0, fh_total_lookups = 0, fh_anonymous_lookups = 0, fh_dir_not_in_dcache = 0, fh_non_dir_not_in_dcache = 0;
173 - unsigned long long io_read = 0, io_write = 0;
174 - unsigned long long th_threads = 0, th_fullcnt = 0, th_hist10 = 0, th_hist20 = 0, th_hist30 = 0, th_hist40 = 0, th_hist50 = 0, th_hist60 = 0, th_hist70 = 0, th_hist80 = 0, th_hist90 = 0, th_hist100 = 0;
175 - unsigned long long ra_size = 0, ra_hist10 = 0, ra_hist20 = 0, ra_hist30 = 0, ra_hist40 = 0, ra_hist50 = 0, ra_hist60 = 0, ra_hist70 = 0, ra_hist80 = 0, ra_hist90 = 0, ra_hist100 = 0, ra_none = 0;
176 - unsigned long long net_count = 0, net_udp_count = 0, net_tcp_count = 0, net_tcp_connections = 0;
177 - unsigned long long rpc_count = 0, rpc_bad_format = 0, rpc_bad_auth = 0, rpc_bad_client = 0;
178 -
179 - for(l = 0; l < lines ;l++) {
180 - words = procfile_linewords(ff, l);
181 - if(!words) continue;
182 -
183 - type = procfile_lineword(ff, l, 0);
184 -
185 - if(do_rc == 1 && strcmp(type, "rc") == 0) {
186 - if(words < 4) {
187 - error("%s line of /proc/net/rpc/nfsd has %u words, expected %d", type, words, 4);
188 - continue;
189 - }
190 -
191 - rc_hits = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
192 - rc_misses = strtoull(procfile_lineword(ff, l, 2), NULL, 10);
193 - rc_nocache = strtoull(procfile_lineword(ff, l, 3), NULL, 10);
194 -
195 - unsigned long long sum = rc_hits + rc_misses + rc_nocache;
196 - if(sum == 0ULL) do_rc = -1;
197 - else do_rc = 2;
198 - }
199 - else if(do_fh == 1 && strcmp(type, "fh") == 0) {
200 - if(words < 6) {
201 - error("%s line of /proc/net/rpc/nfsd has %u words, expected %d", type, words, 6);
202 - continue;
203 - }
204 -
205 - fh_stale = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
206 - fh_total_lookups = strtoull(procfile_lineword(ff, l, 2), NULL, 10);
207 - fh_anonymous_lookups = strtoull(procfile_lineword(ff, l, 3), NULL, 10);
208 - fh_dir_not_in_dcache = strtoull(procfile_lineword(ff, l, 4), NULL, 10);
209 - fh_non_dir_not_in_dcache = strtoull(procfile_lineword(ff, l, 5), NULL, 10);
210 -
211 - unsigned long long sum = fh_stale + fh_total_lookups + fh_anonymous_lookups + fh_dir_not_in_dcache + fh_non_dir_not_in_dcache;
212 - if(sum == 0ULL) do_fh = -1;
213 - else do_fh = 2;
214 - }
215 - else if(do_io == 1 && strcmp(type, "io") == 0) {
216 - if(words < 3) {
217 - error("%s line of /proc/net/rpc/nfsd has %u words, expected %d", type, words, 3);
218 - continue;
219 - }
220 -
221 - io_read = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
222 - io_write = strtoull(procfile_lineword(ff, l, 2), NULL, 10);
223 -
224 - unsigned long long sum = io_read + io_write;
225 - if(sum == 0ULL) do_io = -1;
226 - else do_io = 2;
227 - }
228 - else if(do_th == 1 && strcmp(type, "th") == 0) {
229 - if(words < 13) {
230 - error("%s line of /proc/net/rpc/nfsd has %u words, expected %d", type, words, 13);
231 - continue;
232 - }
233 -
234 - th_threads = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
235 - th_fullcnt = strtoull(procfile_lineword(ff, l, 2), NULL, 10);
236 - th_hist10 = (unsigned long long)(atof(procfile_lineword(ff, l, 3)) * 1000.0);
237 - th_hist20 = (unsigned long long)(atof(procfile_lineword(ff, l, 4)) * 1000.0);
238 - th_hist30 = (unsigned long long)(atof(procfile_lineword(ff, l, 5)) * 1000.0);
239 - th_hist40 = (unsigned long long)(atof(procfile_lineword(ff, l, 6)) * 1000.0);
240 - th_hist50 = (unsigned long long)(atof(procfile_lineword(ff, l, 7)) * 1000.0);
241 - th_hist60 = (unsigned long long)(atof(procfile_lineword(ff, l, 8)) * 1000.0);
242 - th_hist70 = (unsigned long long)(atof(procfile_lineword(ff, l, 9)) * 1000.0);
243 - th_hist80 = (unsigned long long)(atof(procfile_lineword(ff, l, 10)) * 1000.0);
244 - th_hist90 = (unsigned long long)(atof(procfile_lineword(ff, l, 11)) * 1000.0);
245 - th_hist100 = (unsigned long long)(atof(procfile_lineword(ff, l, 12)) * 1000.0);
246 -
247 - // threads histogram has been disabled on recent kernels
248 - // http://permalink.gmane.org/gmane.linux.nfs/24528
249 - unsigned long long sum = th_hist10 + th_hist20 + th_hist30 + th_hist40 + th_hist50 + th_hist60 + th_hist70 + th_hist80 + th_hist90 + th_hist100;
250 - if(sum == 0ULL) {
251 - if(!th_warning) {
252 - info("Disabling /proc/net/rpc/nfsd threads histogram. It seems unused on this machine. It will be enabled automatically when found with data in it.");
253 - th_warning = 1;
254 - }
255 - do_th = -1;
256 - }
257 - else do_th = 2;
258 - }
259 - else if(do_ra == 1 && strcmp(type, "ra") == 0) {
260 - if(words < 13) {
261 - error("%s line of /proc/net/rpc/nfsd has %u words, expected %d", type, words, 13);
262 - continue;
263 - }
264 -
265 - ra_size = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
266 - ra_hist10 = strtoull(procfile_lineword(ff, l, 2), NULL, 10);
267 - ra_hist20 = strtoull(procfile_lineword(ff, l, 3), NULL, 10);
268 - ra_hist30 = strtoull(procfile_lineword(ff, l, 4), NULL, 10);
269 - ra_hist40 = strtoull(procfile_lineword(ff, l, 5), NULL, 10);
270 - ra_hist50 = strtoull(procfile_lineword(ff, l, 6), NULL, 10);
271 - ra_hist60 = strtoull(procfile_lineword(ff, l, 7), NULL, 10);
272 - ra_hist70 = strtoull(procfile_lineword(ff, l, 8), NULL, 10);
273 - ra_hist80 = strtoull(procfile_lineword(ff, l, 9), NULL, 10);
274 - ra_hist90 = strtoull(procfile_lineword(ff, l, 10), NULL, 10);
275 - ra_hist100 = strtoull(procfile_lineword(ff, l, 11), NULL, 10);
276 - ra_none = strtoull(procfile_lineword(ff, l, 12), NULL, 10);
277 -
278 - unsigned long long sum = ra_hist10 + ra_hist20 + ra_hist30 + ra_hist40 + ra_hist50 + ra_hist60 + ra_hist70 + ra_hist80 + ra_hist90 + ra_hist100 + ra_none;
279 - if(sum == 0ULL) {
280 - if(!ra_warning) {
281 - info("Disabling /proc/net/rpc/nfsd read ahead histogram. It seems unused on this machine. It will be enabled automatically when found with data in it.");
282 - ra_warning = 1;
283 - }
284 - do_ra = -1;
285 - }
286 - else do_ra = 2;
287 - }
288 - else if(do_net == 1 && strcmp(type, "net") == 0) {
289 - if(words < 5) {
290 - error("%s line of /proc/net/rpc/nfsd has %u words, expected %d", type, words, 5);
291 - continue;
292 - }
293 -
294 - net_count = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
295 - net_udp_count = strtoull(procfile_lineword(ff, l, 2), NULL, 10);
296 - net_tcp_count = strtoull(procfile_lineword(ff, l, 3), NULL, 10);
297 - net_tcp_connections = strtoull(procfile_lineword(ff, l, 4), NULL, 10);
298 -
299 - unsigned long long sum = net_count + net_udp_count + net_tcp_count + net_tcp_connections;
300 - if(sum == 0ULL) do_net = -1;
301 - else do_net = 2;
302 - }
303 - else if(do_rpc == 1 && strcmp(type, "rpc") == 0) {
304 - if(words < 6) {
305 - error("%s line of /proc/net/rpc/nfsd has %u words, expected %d", type, words, 6);
306 - continue;
307 - }
308 -
309 - rpc_count = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
310 - rpc_bad_format = strtoull(procfile_lineword(ff, l, 2), NULL, 10);
311 - rpc_bad_auth = strtoull(procfile_lineword(ff, l, 3), NULL, 10);
312 - rpc_bad_client = strtoull(procfile_lineword(ff, l, 4), NULL, 10);
313 -
314 - unsigned long long sum = rpc_count + rpc_bad_format + rpc_bad_auth + rpc_bad_client;
315 - if(sum == 0ULL) do_rpc = -1;
316 - else do_rpc = 2;
317 - }
318 - else if(do_proc2 == 1 && strcmp(type, "proc2") == 0) {
319 - // the first number is the count of numbers present
320 - // so we start for word 2
321 -
322 - unsigned long long sum = 0;
323 - unsigned int i, j;
324 - for(i = 0, j = 2; j < words && nfsd_proc_values[i].name[0] ; i++, j++) {
325 - nfsd_proc_values[i].proc2 = strtoull(procfile_lineword(ff, l, j), NULL, 10);
326 - nfsd_proc_values[i].present2 = 1;
327 - sum += nfsd_proc_values[i].proc2;
328 - }
329 -
330 - if(sum == 0ULL) {
331 - if(!proc2_warning) {
332 - error("Disabling /proc/net/rpc/nfsd v2 procedure calls chart. It seems unused on this machine. It will be enabled automatically when found with data in it.");
333 - proc2_warning = 1;
334 - }
335 - do_proc2 = 0;
336 - }
337 - else do_proc2 = 2;
338 - }
339 - else if(do_proc3 == 1 && strcmp(type, "proc3") == 0) {
340 - // the first number is the count of numbers present
341 - // so we start for word 2
342 -
343 - unsigned long long sum = 0;
344 - unsigned int i, j;
345 - for(i = 0, j = 2; j < words && nfsd_proc_values[i].name[0] ; i++, j++) {
346 - nfsd_proc_values[i].proc3 = strtoull(procfile_lineword(ff, l, j), NULL, 10);
347 - nfsd_proc_values[i].present3 = 1;
348 - sum += nfsd_proc_values[i].proc3;
349 - }
350 -
351 - if(sum == 0ULL) {
352 - if(!proc3_warning) {
353 - info("Disabling /proc/net/rpc/nfsd v3 procedure calls chart. It seems unused on this machine. It will be enabled automatically when found with data in it.");
354 - proc3_warning = 1;
355 - }
356 - do_proc3 = 0;
357 - }
358 - else do_proc3 = 2;
359 - }
360 - else if(do_proc4 == 1 && strcmp(type, "proc4") == 0) {
361 - // the first number is the count of numbers present
362 - // so we start for word 2
363 -
364 - unsigned long long sum = 0;
365 - unsigned int i, j;
366 - for(i = 0, j = 2; j < words && nfsd_proc_values[i].name[0] ; i++, j++) {
367 - nfsd_proc_values[i].proc4 = strtoull(procfile_lineword(ff, l, j), NULL, 10);
368 - nfsd_proc_values[i].present4 = 1;
369 - sum += nfsd_proc_values[i].proc4;
370 - }
371 -
372 - if(sum == 0ULL) {
373 - if(!proc4_warning) {
374 - info("Disabling /proc/net/rpc/nfsd v4 procedure calls chart. It seems unused on this machine. It will be enabled automatically when found with data in it.");
375 - proc4_warning = 1;
376 - }
377 - do_proc4 = 0;
378 - }
379 - else do_proc4 = 2;
380 - }
381 - else if(do_proc4ops == 1 && strcmp(type, "proc4ops") == 0) {
382 - // the first number is the count of numbers present
383 - // so we start for word 2
384 -
385 - unsigned long long sum = 0;
386 - unsigned int i, j;
387 - for(i = 0, j = 2; j < words && nfsd4_ops_values[i].name[0] ; i++, j++) {
388 - nfsd4_ops_values[i].value = strtoull(procfile_lineword(ff, l, j), NULL, 10);
389 - nfsd4_ops_values[i].present = 1;
390 - sum += nfsd4_ops_values[i].value;
391 - }
392 -
393 - if(sum == 0ULL) {
394 - if(!proc4ops_warning) {
395 - info("Disabling /proc/net/rpc/nfsd v4 operations chart. It seems unused on this machine. It will be enabled automatically when found with data in it.");
396 - proc4ops_warning = 1;
397 - }
398 - do_proc4ops = 0;
399 - }
400 - else do_proc4ops = 2;
401 - }
402 - }
403 -
404 - RRDSET *st;
405 -
406 - // --------------------------------------------------------------------
407 -
408 - if(do_rc == 2) {
409 - st = rrdset_find_bytype("nfsd", "readcache");
410 - if(!st) {
411 - st = rrdset_create("nfsd", "readcache", NULL, "nfsd", NULL, "Read Cache", "reads/s", 5000, update_every, RRDSET_TYPE_STACKED);
412 -
413 - rrddim_add(st, "hits", NULL, 1, 1, RRDDIM_INCREMENTAL);
414 - rrddim_add(st, "misses", NULL, 1, 1, RRDDIM_INCREMENTAL);
415 - rrddim_add(st, "nocache", NULL, 1, 1, RRDDIM_INCREMENTAL);
416 - }
417 - else rrdset_next(st);
418 -
419 - rrddim_set(st, "hits", rc_hits);
420 - rrddim_set(st, "misses", rc_misses);
421 - rrddim_set(st, "nocache", rc_nocache);
422 - rrdset_done(st);
423 - }
424 -
425 - // --------------------------------------------------------------------
426 -
427 - if(do_fh == 2) {
428 - st = rrdset_find_bytype("nfsd", "filehandles");
429 - if(!st) {
430 - st = rrdset_create("nfsd", "filehandles", NULL, "nfsd", NULL, "File Handles", "handles/s", 5001, update_every, RRDSET_TYPE_LINE);
431 - st->isdetail = 1;
432 -
433 - rrddim_add(st, "stale", NULL, 1, 1, RRDDIM_ABSOLUTE);
434 - rrddim_add(st, "total_lookups", NULL, 1, 1, RRDDIM_INCREMENTAL);
435 - rrddim_add(st, "anonymous_lookups", NULL, 1, 1, RRDDIM_INCREMENTAL);
436 - rrddim_add(st, "dir_not_in_dcache", NULL, -1, 1, RRDDIM_INCREMENTAL);
437 - rrddim_add(st, "non_dir_not_in_dcache", NULL, -1, 1, RRDDIM_INCREMENTAL);
438 - }
439 - else rrdset_next(st);
440 -
441 - rrddim_set(st, "stale", fh_stale);
442 - rrddim_set(st, "total_lookups", fh_total_lookups);
443 - rrddim_set(st, "anonymous_lookups", fh_anonymous_lookups);
444 - rrddim_set(st, "dir_not_in_dcache", fh_dir_not_in_dcache);
445 - rrddim_set(st, "non_dir_not_in_dcache", fh_non_dir_not_in_dcache);
446 - rrdset_done(st);
447 - }
448 -
449 - // --------------------------------------------------------------------
450 -
451 - if(do_io == 2) {
452 - st = rrdset_find_bytype("nfsd", "io");
453 - if(!st) {
454 - st = rrdset_create("nfsd", "io", NULL, "nfsd", NULL, "I/O", "kilobytes/s", 5002, update_every, RRDSET_TYPE_AREA);
455 -
456 - rrddim_add(st, "read", NULL, 1, 1000, RRDDIM_INCREMENTAL);
457 - rrddim_add(st, "write", NULL, -1, 1000, RRDDIM_INCREMENTAL);
458 - }
459 - else rrdset_next(st);
460 -
461 - rrddim_set(st, "read", io_read);
462 - rrddim_set(st, "write", io_write);
463 - rrdset_done(st);
464 - }
465 -
466 - // --------------------------------------------------------------------
467 -
468 - if(do_th == 2) {
469 - st = rrdset_find_bytype("nfsd", "threads");
470 - if(!st) {
471 - st = rrdset_create("nfsd", "threads", NULL, "nfsd", NULL, "Threads", "threads", 5003, update_every, RRDSET_TYPE_LINE);
472 -
473 - rrddim_add(st, "threads", NULL, 1, 1, RRDDIM_ABSOLUTE);
474 - }
475 - else rrdset_next(st);
476 -
477 - rrddim_set(st, "threads", th_threads);
478 - rrdset_done(st);
479 -
480 - st = rrdset_find_bytype("nfsd", "threads_fullcnt");
481 - if(!st) {
482 - st = rrdset_create("nfsd", "threads_fullcnt", NULL, "nfsd", NULL, "Threads Full Count", "ops/s", 5004, update_every, RRDSET_TYPE_LINE);
483 -
484 - rrddim_add(st, "full_count", NULL, 1, 1, RRDDIM_INCREMENTAL);
485 - }
486 - else rrdset_next(st);
487 -
488 - rrddim_set(st, "full_count", th_fullcnt);
489 - rrdset_done(st);
490 -
491 - st = rrdset_find_bytype("nfsd", "threads_histogram");
492 - if(!st) {
493 - st = rrdset_create("nfsd", "threads_histogram", NULL, "nfsd", NULL, "Threads Usage Histogram", "percentage", 5005, update_every, RRDSET_TYPE_LINE);
494 -
495 - rrddim_add(st, "0%-10%", NULL, 1, 1000, RRDDIM_ABSOLUTE);
496 - rrddim_add(st, "10%-20%", NULL, 1, 1000, RRDDIM_ABSOLUTE);
497 - rrddim_add(st, "20%-30%", NULL, 1, 1000, RRDDIM_ABSOLUTE);
498 - rrddim_add(st, "30%-40%", NULL, 1, 1000, RRDDIM_ABSOLUTE);
499 - rrddim_add(st, "40%-50%", NULL, 1, 1000, RRDDIM_ABSOLUTE);
500 - rrddim_add(st, "50%-60%", NULL, 1, 1000, RRDDIM_ABSOLUTE);
501 - rrddim_add(st, "60%-70%", NULL, 1, 1000, RRDDIM_ABSOLUTE);
502 - rrddim_add(st, "70%-80%", NULL, 1, 1000, RRDDIM_ABSOLUTE);
503 - rrddim_add(st, "80%-90%", NULL, 1, 1000, RRDDIM_ABSOLUTE);
504 - rrddim_add(st, "90%-100%", NULL, 1, 1000, RRDDIM_ABSOLUTE);
505 - }
506 - else rrdset_next(st);
507 -
508 - rrddim_set(st, "0%-10%", th_hist10);
509 - rrddim_set(st, "10%-20%", th_hist20);
510 - rrddim_set(st, "20%-30%", th_hist30);
511 - rrddim_set(st, "30%-40%", th_hist40);
512 - rrddim_set(st, "40%-50%", th_hist50);
513 - rrddim_set(st, "50%-60%", th_hist60);
514 - rrddim_set(st, "60%-70%", th_hist70);
515 - rrddim_set(st, "70%-80%", th_hist80);
516 - rrddim_set(st, "80%-90%", th_hist90);
517 - rrddim_set(st, "90%-100%", th_hist100);
518 - rrdset_done(st);
519 - }
520 -
521 - // --------------------------------------------------------------------
522 -
523 - if(do_ra == 2) {
524 - st = rrdset_find_bytype("nfsd", "readahead");
525 - if(!st) {
526 - st = rrdset_create("nfsd", "readahead", NULL, "nfsd", NULL, "Read Ahead Depth", "percentage", 5005, update_every, RRDSET_TYPE_STACKED);
527 -
528 - rrddim_add(st, "10%", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
529 - rrddim_add(st, "20%", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
530 - rrddim_add(st, "30%", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
531 - rrddim_add(st, "40%", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
532 - rrddim_add(st, "50%", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
533 - rrddim_add(st, "60%", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
534 - rrddim_add(st, "70%", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
535 - rrddim_add(st, "80%", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
536 - rrddim_add(st, "90%", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
537 - rrddim_add(st, "100%", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
538 - rrddim_add(st, "misses", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
539 - }
540 - else rrdset_next(st);
541 -
542 - // ignore ra_size
543 - if(ra_size) {};
544 -
545 - rrddim_set(st, "10%", ra_hist10);
546 - rrddim_set(st, "20%", ra_hist20);
547 - rrddim_set(st, "30%", ra_hist30);
548 - rrddim_set(st, "40%", ra_hist40);
549 - rrddim_set(st, "50%", ra_hist50);
550 - rrddim_set(st, "60%", ra_hist60);
551 - rrddim_set(st, "70%", ra_hist70);
552 - rrddim_set(st, "80%", ra_hist80);
553 - rrddim_set(st, "90%", ra_hist90);
554 - rrddim_set(st, "100%", ra_hist100);
555 - rrddim_set(st, "misses", ra_none);
556 - rrdset_done(st);
557 - }
558 -
559 - // --------------------------------------------------------------------
560 -
561 - if(do_net == 2) {
562 - st = rrdset_find_bytype("nfsd", "net");
563 - if(!st) {
564 - st = rrdset_create("nfsd", "net", NULL, "nfsd", NULL, "Network Reads", "reads/s", 5007, update_every, RRDSET_TYPE_STACKED);
565 - st->isdetail = 1;
566 -
567 - rrddim_add(st, "udp", NULL, 1, 1, RRDDIM_INCREMENTAL);
568 - rrddim_add(st, "tcp", NULL, 1, 1, RRDDIM_INCREMENTAL);
569 - }
570 - else rrdset_next(st);
571 -
572 - // ignore net_count, net_tcp_connections
573 - if(net_count) {};
574 - if(net_tcp_connections) {};
575 -
576 - rrddim_set(st, "udp", net_udp_count);
577 - rrddim_set(st, "tcp", net_tcp_count);
578 - rrdset_done(st);
579 - }
580 -
581 - // --------------------------------------------------------------------
582 -
583 - if(do_rpc == 2) {
584 - st = rrdset_find_bytype("nfsd", "rpc");
585 - if(!st) {
586 - st = rrdset_create("nfsd", "rpc", NULL, "nfsd", NULL, "Remote Procedure Calls", "calls/s", 5008, update_every, RRDSET_TYPE_LINE);
587 - st->isdetail = 1;
588 -
589 - rrddim_add(st, "all", NULL, 1, 1, RRDDIM_INCREMENTAL);
590 - rrddim_add(st, "bad_format", NULL, -1, 1, RRDDIM_INCREMENTAL);
591 - rrddim_add(st, "bad_auth", NULL, -1, 1, RRDDIM_INCREMENTAL);
592 - }
593 - else rrdset_next(st);
594 -
595 - // ignore rpc_bad_client
596 - if(rpc_bad_client) {};
597 -
598 - rrddim_set(st, "all", rpc_count);
599 - rrddim_set(st, "bad_format", rpc_bad_format);
600 - rrddim_set(st, "bad_auth", rpc_bad_auth);
601 - rrdset_done(st);
602 - }
603 -
604 - // --------------------------------------------------------------------
605 -
606 - if(do_proc2 == 2) {
607 - unsigned int i;
608 - st = rrdset_find_bytype("nfsd", "proc2");
609 - if(!st) {
610 - st = rrdset_create("nfsd", "proc2", NULL, "nfsd", NULL, "NFS v2 Calls", "calls/s", 5009, update_every, RRDSET_TYPE_STACKED);
611 -
612 - for(i = 0; nfsd_proc_values[i].present2 ; i++)
613 - rrddim_add(st, nfsd_proc_values[i].name, NULL, 1, 1, RRDDIM_INCREMENTAL);
614 - }
615 - else rrdset_next(st);
616 -
617 - for(i = 0; nfsd_proc_values[i].present2 ; i++)
618 - rrddim_set(st, nfsd_proc_values[i].name, nfsd_proc_values[i].proc2);
619 -
620 - rrdset_done(st);
621 - }
622 -
623 - // --------------------------------------------------------------------
624 -
625 - if(do_proc3 == 2) {
626 - unsigned int i;
627 - st = rrdset_find_bytype("nfsd", "proc3");
628 - if(!st) {
629 - st = rrdset_create("nfsd", "proc3", NULL, "nfsd", NULL, "NFS v3 Calls", "calls/s", 5010, update_every, RRDSET_TYPE_STACKED);
630 -
631 - for(i = 0; nfsd_proc_values[i].present3 ; i++)
632 - rrddim_add(st, nfsd_proc_values[i].name, NULL, 1, 1, RRDDIM_INCREMENTAL);
633 - }
634 - else rrdset_next(st);
635 -
636 - for(i = 0; nfsd_proc_values[i].present3 ; i++)
637 - rrddim_set(st, nfsd_proc_values[i].name, nfsd_proc_values[i].proc3);
638 -
639 - rrdset_done(st);
640 - }
641 -
642 - // --------------------------------------------------------------------
643 -
644 - if(do_proc4 == 2) {
645 - unsigned int i;
646 - st = rrdset_find_bytype("nfsd", "proc4");
647 - if(!st) {
648 - st = rrdset_create("nfsd", "proc4", NULL, "nfsd", NULL, "NFS v4 Calls", "calls/s", 5011, update_every, RRDSET_TYPE_STACKED);
649 -
650 - for(i = 0; nfsd_proc_values[i].present4 ; i++)
651 - rrddim_add(st, nfsd_proc_values[i].name, NULL, 1, 1, RRDDIM_INCREMENTAL);
652 - }
653 - else rrdset_next(st);
125 + static procfile *ff = NULL;
126 + static int do_rc = -1, do_fh = -1, do_io = -1, do_th = -1, do_ra = -1, do_net = -1, do_rpc = -1, do_proc2 = -1, do_proc3 = -1, do_proc4 = -1, do_proc4ops = -1;
127 + static int ra_warning = 0, th_warning = 0, proc2_warning = 0, proc3_warning = 0, proc4_warning = 0, proc4ops_warning = 0;
128 +
129 + if(dt) {};
130 +
131 + if(!ff) {
132 + char filename[FILENAME_MAX + 1];
133 + snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/net/rpc/nfsd");
134 + ff = procfile_open(config_get("plugin:proc:/proc/net/rpc/nfsd", "filename to monitor", filename), " \t", PROCFILE_FLAG_DEFAULT);
135 + }
136 + if(!ff) return 1;
137 +
138 + ff = procfile_readall(ff);
139 + if(!ff) return 0; // we return 0, so that we will retry to open it next time
140 +
141 + if(do_rc == -1) do_rc = config_get_boolean("plugin:proc:/proc/net/rpc/nfsd", "read cache", 1);
142 + if(do_fh == -1) do_fh = config_get_boolean("plugin:proc:/proc/net/rpc/nfsd", "file handles", 1);
143 + if(do_io == -1) do_io = config_get_boolean("plugin:proc:/proc/net/rpc/nfsd", "I/O", 1);
144 + if(do_th == -1) do_th = config_get_boolean("plugin:proc:/proc/net/rpc/nfsd", "threads", 1);
145 + if(do_ra == -1) do_ra = config_get_boolean("plugin:proc:/proc/net/rpc/nfsd", "read ahead", 1);
146 + if(do_net == -1) do_net = config_get_boolean("plugin:proc:/proc/net/rpc/nfsd", "network", 1);
147 + if(do_rpc == -1) do_rpc = config_get_boolean("plugin:proc:/proc/net/rpc/nfsd", "rpc", 1);
148 + if(do_proc2 == -1) do_proc2 = config_get_boolean("plugin:proc:/proc/net/rpc/nfsd", "NFS v2 procedures", 1);
149 + if(do_proc3 == -1) do_proc3 = config_get_boolean("plugin:proc:/proc/net/rpc/nfsd", "NFS v3 procedures", 1);
150 + if(do_proc4 == -1) do_proc4 = config_get_boolean("plugin:proc:/proc/net/rpc/nfsd", "NFS v4 procedures", 1);
151 + if(do_proc4ops == -1) do_proc4ops = config_get_boolean("plugin:proc:/proc/net/rpc/nfsd", "NFS v4 operations", 1);
152 +
153 + // if they are enabled, reset them to 1
154 + // later we do them =2 to avoid doing strcmp for all lines
155 + if(do_rc) do_rc = 1;
156 + if(do_fh) do_fh = 1;
157 + if(do_io) do_io = 1;
158 + if(do_th) do_th = 1;
159 + if(do_ra) do_ra = 1;
160 + if(do_net) do_net = 1;
161 + if(do_rpc) do_rpc = 1;
162 + if(do_proc2) do_proc2 = 1;
163 + if(do_proc3) do_proc3 = 1;
164 + if(do_proc4) do_proc4 = 1;
165 + if(do_proc4ops) do_proc4ops = 1;
166 +
167 + uint32_t lines = procfile_lines(ff), l;
168 + uint32_t words;
169 +
170 + char *type;
171 + unsigned long long rc_hits = 0, rc_misses = 0, rc_nocache = 0;
172 + unsigned long long fh_stale = 0, fh_total_lookups = 0, fh_anonymous_lookups = 0, fh_dir_not_in_dcache = 0, fh_non_dir_not_in_dcache = 0;
173 + unsigned long long io_read = 0, io_write = 0;
174 + unsigned long long th_threads = 0, th_fullcnt = 0, th_hist10 = 0, th_hist20 = 0, th_hist30 = 0, th_hist40 = 0, th_hist50 = 0, th_hist60 = 0, th_hist70 = 0, th_hist80 = 0, th_hist90 = 0, th_hist100 = 0;
175 + unsigned long long ra_size = 0, ra_hist10 = 0, ra_hist20 = 0, ra_hist30 = 0, ra_hist40 = 0, ra_hist50 = 0, ra_hist60 = 0, ra_hist70 = 0, ra_hist80 = 0, ra_hist90 = 0, ra_hist100 = 0, ra_none = 0;
176 + unsigned long long net_count = 0, net_udp_count = 0, net_tcp_count = 0, net_tcp_connections = 0;
177 + unsigned long long rpc_count = 0, rpc_bad_format = 0, rpc_bad_auth = 0, rpc_bad_client = 0;
178 +
179 + for(l = 0; l < lines ;l++) {
180 + words = procfile_linewords(ff, l);
181 + if(!words) continue;
182 +
183 + type = procfile_lineword(ff, l, 0);
184 +
185 + if(do_rc == 1 && strcmp(type, "rc") == 0) {
186 + if(words < 4) {
187 + error("%s line of /proc/net/rpc/nfsd has %u words, expected %d", type, words, 4);
188 + continue;
189 + }
190 +
191 + rc_hits = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
192 + rc_misses = strtoull(procfile_lineword(ff, l, 2), NULL, 10);
193 + rc_nocache = strtoull(procfile_lineword(ff, l, 3), NULL, 10);
194 +
195 + unsigned long long sum = rc_hits + rc_misses + rc_nocache;
196 + if(sum == 0ULL) do_rc = -1;
197 + else do_rc = 2;
198 + }
199 + else if(do_fh == 1 && strcmp(type, "fh") == 0) {
200 + if(words < 6) {
201 + error("%s line of /proc/net/rpc/nfsd has %u words, expected %d", type, words, 6);
202 + continue;
203 + }
204 +
205 + fh_stale = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
206 + fh_total_lookups = strtoull(procfile_lineword(ff, l, 2), NULL, 10);
207 + fh_anonymous_lookups = strtoull(procfile_lineword(ff, l, 3), NULL, 10);
208 + fh_dir_not_in_dcache = strtoull(procfile_lineword(ff, l, 4), NULL, 10);
209 + fh_non_dir_not_in_dcache = strtoull(procfile_lineword(ff, l, 5), NULL, 10);
210 +
211 + unsigned long long sum = fh_stale + fh_total_lookups + fh_anonymous_lookups + fh_dir_not_in_dcache + fh_non_dir_not_in_dcache;
212 + if(sum == 0ULL) do_fh = -1;
213 + else do_fh = 2;
214 + }
215 + else if(do_io == 1 && strcmp(type, "io") == 0) {
216 + if(words < 3) {
217 + error("%s line of /proc/net/rpc/nfsd has %u words, expected %d", type, words, 3);
218 + continue;
219 + }
220 +
221 + io_read = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
222 + io_write = strtoull(procfile_lineword(ff, l, 2), NULL, 10);
223 +
224 + unsigned long long sum = io_read + io_write;
225 + if(sum == 0ULL) do_io = -1;
226 + else do_io = 2;
227 + }
228 + else if(do_th == 1 && strcmp(type, "th") == 0) {
229 + if(words < 13) {
230 + error("%s line of /proc/net/rpc/nfsd has %u words, expected %d", type, words, 13);
231 + continue;
232 + }
233 +
234 + th_threads = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
235 + th_fullcnt = strtoull(procfile_lineword(ff, l, 2), NULL, 10);
236 + th_hist10 = (unsigned long long)(atof(procfile_lineword(ff, l, 3)) * 1000.0);
237 + th_hist20 = (unsigned long long)(atof(procfile_lineword(ff, l, 4)) * 1000.0);
238 + th_hist30 = (unsigned long long)(atof(procfile_lineword(ff, l, 5)) * 1000.0);
239 + th_hist40 = (unsigned long long)(atof(procfile_lineword(ff, l, 6)) * 1000.0);
240 + th_hist50 = (unsigned long long)(atof(procfile_lineword(ff, l, 7)) * 1000.0);
241 + th_hist60 = (unsigned long long)(atof(procfile_lineword(ff, l, 8)) * 1000.0);
242 + th_hist70 = (unsigned long long)(atof(procfile_lineword(ff, l, 9)) * 1000.0);
243 + th_hist80 = (unsigned long long)(atof(procfile_lineword(ff, l, 10)) * 1000.0);
244 + th_hist90 = (unsigned long long)(atof(procfile_lineword(ff, l, 11)) * 1000.0);
245 + th_hist100 = (unsigned long long)(atof(procfile_lineword(ff, l, 12)) * 1000.0);
246 +
247 + // threads histogram has been disabled on recent kernels
248 + // http://permalink.gmane.org/gmane.linux.nfs/24528
249 + unsigned long long sum = th_hist10 + th_hist20 + th_hist30 + th_hist40 + th_hist50 + th_hist60 + th_hist70 + th_hist80 + th_hist90 + th_hist100;
250 + if(sum == 0ULL) {
251 + if(!th_warning) {
252 + info("Disabling /proc/net/rpc/nfsd threads histogram. It seems unused on this machine. It will be enabled automatically when found with data in it.");
253 + th_warning = 1;
254 + }
255 + do_th = -1;
256 + }
257 + else do_th = 2;
258 + }
259 + else if(do_ra == 1 && strcmp(type, "ra") == 0) {
260 + if(words < 13) {
261 + error("%s line of /proc/net/rpc/nfsd has %u words, expected %d", type, words, 13);
262 + continue;
263 + }
264 +
265 + ra_size = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
266 + ra_hist10 = strtoull(procfile_lineword(ff, l, 2), NULL, 10);
267 + ra_hist20 = strtoull(procfile_lineword(ff, l, 3), NULL, 10);
268 + ra_hist30 = strtoull(procfile_lineword(ff, l, 4), NULL, 10);
269 + ra_hist40 = strtoull(procfile_lineword(ff, l, 5), NULL, 10);
270 + ra_hist50 = strtoull(procfile_lineword(ff, l, 6), NULL, 10);
271 + ra_hist60 = strtoull(procfile_lineword(ff, l, 7), NULL, 10);
272 + ra_hist70 = strtoull(procfile_lineword(ff, l, 8), NULL, 10);
273 + ra_hist80 = strtoull(procfile_lineword(ff, l, 9), NULL, 10);
274 + ra_hist90 = strtoull(procfile_lineword(ff, l, 10), NULL, 10);
275 + ra_hist100 = strtoull(procfile_lineword(ff, l, 11), NULL, 10);
276 + ra_none = strtoull(procfile_lineword(ff, l, 12), NULL, 10);
277 +
278 + unsigned long long sum = ra_hist10 + ra_hist20 + ra_hist30 + ra_hist40 + ra_hist50 + ra_hist60 + ra_hist70 + ra_hist80 + ra_hist90 + ra_hist100 + ra_none;
279 + if(sum == 0ULL) {
280 + if(!ra_warning) {
281 + info("Disabling /proc/net/rpc/nfsd read ahead histogram. It seems unused on this machine. It will be enabled automatically when found with data in it.");
282 + ra_warning = 1;
283 + }
284 + do_ra = -1;
285 + }
286 + else do_ra = 2;
287 + }
288 + else if(do_net == 1 && strcmp(type, "net") == 0) {
289 + if(words < 5) {
290 + error("%s line of /proc/net/rpc/nfsd has %u words, expected %d", type, words, 5);
291 + continue;
292 + }
293 +
294 + net_count = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
295 + net_udp_count = strtoull(procfile_lineword(ff, l, 2), NULL, 10);
296 + net_tcp_count = strtoull(procfile_lineword(ff, l, 3), NULL, 10);
297 + net_tcp_connections = strtoull(procfile_lineword(ff, l, 4), NULL, 10);
298 +
299 + unsigned long long sum = net_count + net_udp_count + net_tcp_count + net_tcp_connections;
300 + if(sum == 0ULL) do_net = -1;
301 + else do_net = 2;
302 + }
303 + else if(do_rpc == 1 && strcmp(type, "rpc") == 0) {
304 + if(words < 6) {
305 + error("%s line of /proc/net/rpc/nfsd has %u words, expected %d", type, words, 6);
306 + continue;
307 + }
308 +
309 + rpc_count = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
310 + rpc_bad_format = strtoull(procfile_lineword(ff, l, 2), NULL, 10);
311 + rpc_bad_auth = strtoull(procfile_lineword(ff, l, 3), NULL, 10);
312 + rpc_bad_client = strtoull(procfile_lineword(ff, l, 4), NULL, 10);
313 +
314 + unsigned long long sum = rpc_count + rpc_bad_format + rpc_bad_auth + rpc_bad_client;
315 + if(sum == 0ULL) do_rpc = -1;
316 + else do_rpc = 2;
317 + }
318 + else if(do_proc2 == 1 && strcmp(type, "proc2") == 0) {
319 + // the first number is the count of numbers present
320 + // so we start for word 2
321 +
322 + unsigned long long sum = 0;
323 + unsigned int i, j;
324 + for(i = 0, j = 2; j < words && nfsd_proc_values[i].name[0] ; i++, j++) {
325 + nfsd_proc_values[i].proc2 = strtoull(procfile_lineword(ff, l, j), NULL, 10);
326 + nfsd_proc_values[i].present2 = 1;
327 + sum += nfsd_proc_values[i].proc2;
328 + }
329 +
330 + if(sum == 0ULL) {
331 + if(!proc2_warning) {
332 + error("Disabling /proc/net/rpc/nfsd v2 procedure calls chart. It seems unused on this machine. It will be enabled automatically when found with data in it.");
333 + proc2_warning = 1;
334 + }
335 + do_proc2 = 0;
336 + }
337 + else do_proc2 = 2;
338 + }
339 + else if(do_proc3 == 1 && strcmp(type, "proc3") == 0) {
340 + // the first number is the count of numbers present
341 + // so we start for word 2
342 +
343 + unsigned long long sum = 0;
344 + unsigned int i, j;
345 + for(i = 0, j = 2; j < words && nfsd_proc_values[i].name[0] ; i++, j++) {
346 + nfsd_proc_values[i].proc3 = strtoull(procfile_lineword(ff, l, j), NULL, 10);
347 + nfsd_proc_values[i].present3 = 1;
348 + sum += nfsd_proc_values[i].proc3;
349 + }
350 +
351 + if(sum == 0ULL) {
352 + if(!proc3_warning) {
353 + info("Disabling /proc/net/rpc/nfsd v3 procedure calls chart. It seems unused on this machine. It will be enabled automatically when found with data in it.");
354 + proc3_warning = 1;
355 + }
356 + do_proc3 = 0;
357 + }
358 + else do_proc3 = 2;
359 + }
360 + else if(do_proc4 == 1 && strcmp(type, "proc4") == 0) {
361 + // the first number is the count of numbers present
362 + // so we start for word 2
363 +
364 + unsigned long long sum = 0;
365 + unsigned int i, j;
366 + for(i = 0, j = 2; j < words && nfsd_proc_values[i].name[0] ; i++, j++) {
367 + nfsd_proc_values[i].proc4 = strtoull(procfile_lineword(ff, l, j), NULL, 10);
368 + nfsd_proc_values[i].present4 = 1;
369 + sum += nfsd_proc_values[i].proc4;
370 + }
371 +
372 + if(sum == 0ULL) {
373 + if(!proc4_warning) {
374 + info("Disabling /proc/net/rpc/nfsd v4 procedure calls chart. It seems unused on this machine. It will be enabled automatically when found with data in it.");
375 + proc4_warning = 1;
376 + }
377 + do_proc4 = 0;
378 + }
379 + else do_proc4 = 2;
380 + }
381 + else if(do_proc4ops == 1 && strcmp(type, "proc4ops") == 0) {
382 + // the first number is the count of numbers present
383 + // so we start for word 2
384 +
385 + unsigned long long sum = 0;
386 + unsigned int i, j;
387 + for(i = 0, j = 2; j < words && nfsd4_ops_values[i].name[0] ; i++, j++) {
388 + nfsd4_ops_values[i].value = strtoull(procfile_lineword(ff, l, j), NULL, 10);
389 + nfsd4_ops_values[i].present = 1;
390 + sum += nfsd4_ops_values[i].value;
391 + }
392 +
393 + if(sum == 0ULL) {
394 + if(!proc4ops_warning) {
395 + info("Disabling /proc/net/rpc/nfsd v4 operations chart. It seems unused on this machine. It will be enabled automatically when found with data in it.");
396 + proc4ops_warning = 1;
397 + }
398 + do_proc4ops = 0;
399 + }
400 + else do_proc4ops = 2;
401 + }
402 + }
403 +
404 + RRDSET *st;
405 +
406 + // --------------------------------------------------------------------
407 +
408 + if(do_rc == 2) {
409 + st = rrdset_find_bytype("nfsd", "readcache");
410 + if(!st) {
411 + st = rrdset_create("nfsd", "readcache", NULL, "nfsd", NULL, "Read Cache", "reads/s", 5000, update_every, RRDSET_TYPE_STACKED);
412 +
413 + rrddim_add(st, "hits", NULL, 1, 1, RRDDIM_INCREMENTAL);
414 + rrddim_add(st, "misses", NULL, 1, 1, RRDDIM_INCREMENTAL);
415 + rrddim_add(st, "nocache", NULL, 1, 1, RRDDIM_INCREMENTAL);
416 + }
417 + else rrdset_next(st);
418 +
419 + rrddim_set(st, "hits", rc_hits);
420 + rrddim_set(st, "misses", rc_misses);
421 + rrddim_set(st, "nocache", rc_nocache);
422 + rrdset_done(st);
423 + }
424 +
425 + // --------------------------------------------------------------------
426 +
427 + if(do_fh == 2) {
428 + st = rrdset_find_bytype("nfsd", "filehandles");
429 + if(!st) {
430 + st = rrdset_create("nfsd", "filehandles", NULL, "nfsd", NULL, "File Handles", "handles/s", 5001, update_every, RRDSET_TYPE_LINE);
431 + st->isdetail = 1;
432 +
433 + rrddim_add(st, "stale", NULL, 1, 1, RRDDIM_ABSOLUTE);
434 + rrddim_add(st, "total_lookups", NULL, 1, 1, RRDDIM_INCREMENTAL);
435 + rrddim_add(st, "anonymous_lookups", NULL, 1, 1, RRDDIM_INCREMENTAL);
436 + rrddim_add(st, "dir_not_in_dcache", NULL, -1, 1, RRDDIM_INCREMENTAL);
437 + rrddim_add(st, "non_dir_not_in_dcache", NULL, -1, 1, RRDDIM_INCREMENTAL);
438 + }
439 + else rrdset_next(st);
440 +
441 + rrddim_set(st, "stale", fh_stale);
442 + rrddim_set(st, "total_lookups", fh_total_lookups);
443 + rrddim_set(st, "anonymous_lookups", fh_anonymous_lookups);
444 + rrddim_set(st, "dir_not_in_dcache", fh_dir_not_in_dcache);
445 + rrddim_set(st, "non_dir_not_in_dcache", fh_non_dir_not_in_dcache);
446 + rrdset_done(st);
447 + }
448 +
449 + // --------------------------------------------------------------------
450 +
451 + if(do_io == 2) {
452 + st = rrdset_find_bytype("nfsd", "io");
453 + if(!st) {
454 + st = rrdset_create("nfsd", "io", NULL, "nfsd", NULL, "I/O", "kilobytes/s", 5002, update_every, RRDSET_TYPE_AREA);
455 +
456 + rrddim_add(st, "read", NULL, 1, 1000, RRDDIM_INCREMENTAL);
457 + rrddim_add(st, "write", NULL, -1, 1000, RRDDIM_INCREMENTAL);
458 + }
459 + else rrdset_next(st);
460 +
461 + rrddim_set(st, "read", io_read);
462 + rrddim_set(st, "write", io_write);
463 + rrdset_done(st);
464 + }
465 +
466 + // --------------------------------------------------------------------
467 +
468 + if(do_th == 2) {
469 + st = rrdset_find_bytype("nfsd", "threads");
470 + if(!st) {
471 + st = rrdset_create("nfsd", "threads", NULL, "nfsd", NULL, "Threads", "threads", 5003, update_every, RRDSET_TYPE_LINE);
472 +
473 + rrddim_add(st, "threads", NULL, 1, 1, RRDDIM_ABSOLUTE);
474 + }
475 + else rrdset_next(st);
476 +
477 + rrddim_set(st, "threads", th_threads);
478 + rrdset_done(st);
479 +
480 + st = rrdset_find_bytype("nfsd", "threads_fullcnt");
481 + if(!st) {
482 + st = rrdset_create("nfsd", "threads_fullcnt", NULL, "nfsd", NULL, "Threads Full Count", "ops/s", 5004, update_every, RRDSET_TYPE_LINE);
483 +
484 + rrddim_add(st, "full_count", NULL, 1, 1, RRDDIM_INCREMENTAL);
485 + }
486 + else rrdset_next(st);
487 +
488 + rrddim_set(st, "full_count", th_fullcnt);
489 + rrdset_done(st);
490 +
491 + st = rrdset_find_bytype("nfsd", "threads_histogram");
492 + if(!st) {
493 + st = rrdset_create("nfsd", "threads_histogram", NULL, "nfsd", NULL, "Threads Usage Histogram", "percentage", 5005, update_every, RRDSET_TYPE_LINE);
494 +
495 + rrddim_add(st, "0%-10%", NULL, 1, 1000, RRDDIM_ABSOLUTE);
496 + rrddim_add(st, "10%-20%", NULL, 1, 1000, RRDDIM_ABSOLUTE);
497 + rrddim_add(st, "20%-30%", NULL, 1, 1000, RRDDIM_ABSOLUTE);
498 + rrddim_add(st, "30%-40%", NULL, 1, 1000, RRDDIM_ABSOLUTE);
499 + rrddim_add(st, "40%-50%", NULL, 1, 1000, RRDDIM_ABSOLUTE);
500 + rrddim_add(st, "50%-60%", NULL, 1, 1000, RRDDIM_ABSOLUTE);
501 + rrddim_add(st, "60%-70%", NULL, 1, 1000, RRDDIM_ABSOLUTE);
502 + rrddim_add(st, "70%-80%", NULL, 1, 1000, RRDDIM_ABSOLUTE);
503 + rrddim_add(st, "80%-90%", NULL, 1, 1000, RRDDIM_ABSOLUTE);
504 + rrddim_add(st, "90%-100%", NULL, 1, 1000, RRDDIM_ABSOLUTE);
505 + }
506 + else rrdset_next(st);
507 +
508 + rrddim_set(st, "0%-10%", th_hist10);
509 + rrddim_set(st, "10%-20%", th_hist20);
510 + rrddim_set(st, "20%-30%", th_hist30);
511 + rrddim_set(st, "30%-40%", th_hist40);
512 + rrddim_set(st, "40%-50%", th_hist50);
513 + rrddim_set(st, "50%-60%", th_hist60);
514 + rrddim_set(st, "60%-70%", th_hist70);
515 + rrddim_set(st, "70%-80%", th_hist80);
516 + rrddim_set(st, "80%-90%", th_hist90);
517 + rrddim_set(st, "90%-100%", th_hist100);
518 + rrdset_done(st);
519 + }
520 +
521 + // --------------------------------------------------------------------
522 +
523 + if(do_ra == 2) {
524 + st = rrdset_find_bytype("nfsd", "readahead");
525 + if(!st) {
526 + st = rrdset_create("nfsd", "readahead", NULL, "nfsd", NULL, "Read Ahead Depth", "percentage", 5005, update_every, RRDSET_TYPE_STACKED);
527 +
528 + rrddim_add(st, "10%", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
529 + rrddim_add(st, "20%", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
530 + rrddim_add(st, "30%", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
531 + rrddim_add(st, "40%", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
532 + rrddim_add(st, "50%", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
533 + rrddim_add(st, "60%", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
534 + rrddim_add(st, "70%", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
535 + rrddim_add(st, "80%", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
536 + rrddim_add(st, "90%", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
537 + rrddim_add(st, "100%", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
538 + rrddim_add(st, "misses", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
539 + }
540 + else rrdset_next(st);
541 +
542 + // ignore ra_size
543 + if(ra_size) {};
544 +
545 + rrddim_set(st, "10%", ra_hist10);
546 + rrddim_set(st, "20%", ra_hist20);
547 + rrddim_set(st, "30%", ra_hist30);
548 + rrddim_set(st, "40%", ra_hist40);
549 + rrddim_set(st, "50%", ra_hist50);
550 + rrddim_set(st, "60%", ra_hist60);
551 + rrddim_set(st, "70%", ra_hist70);
552 + rrddim_set(st, "80%", ra_hist80);
553 + rrddim_set(st, "90%", ra_hist90);
554 + rrddim_set(st, "100%", ra_hist100);
555 + rrddim_set(st, "misses", ra_none);
556 + rrdset_done(st);
557 + }
558 +
559 + // --------------------------------------------------------------------
560 +
561 + if(do_net == 2) {
562 + st = rrdset_find_bytype("nfsd", "net");
563 + if(!st) {
564 + st = rrdset_create("nfsd", "net", NULL, "nfsd", NULL, "Network Reads", "reads/s", 5007, update_every, RRDSET_TYPE_STACKED);
565 + st->isdetail = 1;
566 +
567 + rrddim_add(st, "udp", NULL, 1, 1, RRDDIM_INCREMENTAL);
568 + rrddim_add(st, "tcp", NULL, 1, 1, RRDDIM_INCREMENTAL);
569 + }
570 + else rrdset_next(st);
571 +
572 + // ignore net_count, net_tcp_connections
573 + if(net_count) {};
574 + if(net_tcp_connections) {};
575 +
576 + rrddim_set(st, "udp", net_udp_count);
577 + rrddim_set(st, "tcp", net_tcp_count);
578 + rrdset_done(st);
579 + }
580 +
581 + // --------------------------------------------------------------------
582 +
583 + if(do_rpc == 2) {
584 + st = rrdset_find_bytype("nfsd", "rpc");
585 + if(!st) {
586 + st = rrdset_create("nfsd", "rpc", NULL, "nfsd", NULL, "Remote Procedure Calls", "calls/s", 5008, update_every, RRDSET_TYPE_LINE);
587 + st->isdetail = 1;
588 +
589 + rrddim_add(st, "all", NULL, 1, 1, RRDDIM_INCREMENTAL);
590 + rrddim_add(st, "bad_format", NULL, -1, 1, RRDDIM_INCREMENTAL);
591 + rrddim_add(st, "bad_auth", NULL, -1, 1, RRDDIM_INCREMENTAL);
592 + }
593 + else rrdset_next(st);
594 +
595 + // ignore rpc_bad_client
596 + if(rpc_bad_client) {};
597 +
598 + rrddim_set(st, "all", rpc_count);
599 + rrddim_set(st, "bad_format", rpc_bad_format);
600 + rrddim_set(st, "bad_auth", rpc_bad_auth);
601 + rrdset_done(st);
602 + }
603 +
604 + // --------------------------------------------------------------------
605 +
606 + if(do_proc2 == 2) {
607 + unsigned int i;
608 + st = rrdset_find_bytype("nfsd", "proc2");
609 + if(!st) {
610 + st = rrdset_create("nfsd", "proc2", NULL, "nfsd", NULL, "NFS v2 Calls", "calls/s", 5009, update_every, RRDSET_TYPE_STACKED);
611 +
612 + for(i = 0; nfsd_proc_values[i].present2 ; i++)
613 + rrddim_add(st, nfsd_proc_values[i].name, NULL, 1, 1, RRDDIM_INCREMENTAL);
614 + }
615 + else rrdset_next(st);
616 +
617 + for(i = 0; nfsd_proc_values[i].present2 ; i++)
618 + rrddim_set(st, nfsd_proc_values[i].name, nfsd_proc_values[i].proc2);
619 +
620 + rrdset_done(st);
621 + }
622 +
623 + // --------------------------------------------------------------------
624 +
625 + if(do_proc3 == 2) {
626 + unsigned int i;
627 + st = rrdset_find_bytype("nfsd", "proc3");
628 + if(!st) {
629 + st = rrdset_create("nfsd", "proc3", NULL, "nfsd", NULL, "NFS v3 Calls", "calls/s", 5010, update_every, RRDSET_TYPE_STACKED);
630 +
631 + for(i = 0; nfsd_proc_values[i].present3 ; i++)
632 + rrddim_add(st, nfsd_proc_values[i].name, NULL, 1, 1, RRDDIM_INCREMENTAL);
633 + }
634 + else rrdset_next(st);
635 +
636 + for(i = 0; nfsd_proc_values[i].present3 ; i++)
637 + rrddim_set(st, nfsd_proc_values[i].name, nfsd_proc_values[i].proc3);
638 +
639 + rrdset_done(st);
640 + }
641 +
642 + // --------------------------------------------------------------------
643 +
644 + if(do_proc4 == 2) {
645 + unsigned int i;
646 + st = rrdset_find_bytype("nfsd", "proc4");
647 + if(!st) {
648 + st = rrdset_create("nfsd", "proc4", NULL, "nfsd", NULL, "NFS v4 Calls", "calls/s", 5011, update_every, RRDSET_TYPE_STACKED);
649 +
650 + for(i = 0; nfsd_proc_values[i].present4 ; i++)
651 + rrddim_add(st, nfsd_proc_values[i].name, NULL, 1, 1, RRDDIM_INCREMENTAL);
652 + }
653 + else rrdset_next(st);
654
655 - for(i = 0; nfsd_proc_values[i].present4 ; i++)
656 - rrddim_set(st, nfsd_proc_values[i].name, nfsd_proc_values[i].proc4);
655 + for(i = 0; nfsd_proc_values[i].present4 ; i++)
656 + rrddim_set(st, nfsd_proc_values[i].name, nfsd_proc_values[i].proc4);
657
658 - rrdset_done(st);
659 - }
658 + rrdset_done(st);
659 + }
660
661 - // --------------------------------------------------------------------
661 + // --------------------------------------------------------------------
662
663 - if(do_proc4ops == 2) {
664 - unsigned int i;
665 - st = rrdset_find_bytype("nfsd", "proc4ops");
666 - if(!st) {
667 - st = rrdset_create("nfsd", "proc4ops", NULL, "nfsd", NULL, "NFS v4 Operations", "operations/s", 5012, update_every, RRDSET_TYPE_STACKED);
663 + if(do_proc4ops == 2) {
664 + unsigned int i;
665 + st = rrdset_find_bytype("nfsd", "proc4ops");
666 + if(!st) {
667 + st = rrdset_create("nfsd", "proc4ops", NULL, "nfsd", NULL, "NFS v4 Operations", "operations/s", 5012, update_every, RRDSET_TYPE_STACKED);
668
669 - for(i = 0; nfsd4_ops_values[i].present ; i++)
670 - rrddim_add(st, nfsd4_ops_values[i].name, NULL, 1, 1, RRDDIM_INCREMENTAL);
671 - }
672 - else rrdset_next(st);
669 + for(i = 0; nfsd4_ops_values[i].present ; i++)
670 + rrddim_add(st, nfsd4_ops_values[i].name, NULL, 1, 1, RRDDIM_INCREMENTAL);
671 + }
672 + else rrdset_next(st);
673
674 - for(i = 0; nfsd4_ops_values[i].present ; i++)
675 - rrddim_set(st, nfsd4_ops_values[i].name, nfsd4_ops_values[i].value);
674 + for(i = 0; nfsd4_ops_values[i].present ; i++)
675 + rrddim_set(st, nfsd4_ops_values[i].name, nfsd4_ops_values[i].value);
676
677 - rrdset_done(st);
678 - }
677 + rrdset_done(st);
678 + }
679
680 - return 0;
680 + return 0;
681 }
src/proc_net_snmp.c
+348 -348
@@ -1,354 +1,354 @@
1 #include "common.h"
2
3 -#define RRD_TYPE_NET_SNMP "ipv4"
4 -#define RRD_TYPE_NET_SNMP_LEN strlen(RRD_TYPE_NET_SNMP)
3 +#define RRD_TYPE_NET_SNMP "ipv4"
4 +#define RRD_TYPE_NET_SNMP_LEN strlen(RRD_TYPE_NET_SNMP)
5
6 int do_proc_net_snmp(int update_every, unsigned long long dt) {
7 - static procfile *ff = NULL;
8 - static int do_ip_packets = -1, do_ip_fragsout = -1, do_ip_fragsin = -1, do_ip_errors = -1,
9 - do_tcp_sockets = -1, do_tcp_packets = -1, do_tcp_errors = -1, do_tcp_handshake = -1,
10 - do_udp_packets = -1, do_udp_errors = -1;
11 -
12 - if(do_ip_packets == -1) do_ip_packets = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 packets", 1);
13 - if(do_ip_fragsout == -1) do_ip_fragsout = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 fragments sent", 1);
14 - if(do_ip_fragsin == -1) do_ip_fragsin = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 fragments assembly", 1);
15 - if(do_ip_errors == -1) do_ip_errors = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 errors", 1);
16 - if(do_tcp_sockets == -1) do_tcp_sockets = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 TCP connections", 1);
17 - if(do_tcp_packets == -1) do_tcp_packets = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 TCP packets", 1);
18 - if(do_tcp_errors == -1) do_tcp_errors = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 TCP errors", 1);
19 - if(do_tcp_handshake == -1) do_tcp_handshake = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 TCP handshake issues", 1);
20 - if(do_udp_packets == -1) do_udp_packets = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 UDP packets", 1);
21 - if(do_udp_errors == -1) do_udp_errors = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 UDP errors", 1);
22 -
23 - if(dt) {};
24 -
25 - if(!ff) {
26 - char filename[FILENAME_MAX + 1];
27 - snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/net/snmp");
28 - ff = procfile_open(config_get("plugin:proc:/proc/net/snmp", "filename to monitor", filename), " \t:", PROCFILE_FLAG_DEFAULT);
29 - }
30 - if(!ff) return 1;
31 -
32 - ff = procfile_readall(ff);
33 - if(!ff) return 0; // we return 0, so that we will retry to open it next time
34 -
35 - uint32_t lines = procfile_lines(ff), l;
36 - uint32_t words;
37 -
38 - RRDSET *st;
39 -
40 - for(l = 0; l < lines ;l++) {
41 - if(strcmp(procfile_lineword(ff, l, 0), "Ip") == 0) {
42 - l++;
43 -
44 - if(strcmp(procfile_lineword(ff, l, 0), "Ip") != 0) {
45 - error("Cannot read Ip line from /proc/net/snmp.");
46 - break;
47 - }
48 -
49 - words = procfile_linewords(ff, l);
50 - if(words < 20) {
51 - error("Cannot read /proc/net/snmp Ip line. Expected 20 params, read %u.", words);
52 - continue;
53 - }
54 -
55 - // see also http://net-snmp.sourceforge.net/docs/mibs/ip.html
56 - unsigned long long Forwarding, DefaultTTL, InReceives, InHdrErrors, InAddrErrors, ForwDatagrams, InUnknownProtos, InDiscards, InDelivers,
57 - OutRequests, OutDiscards, OutNoRoutes, ReasmTimeout, ReasmReqds, ReasmOKs, ReasmFails, FragOKs, FragFails, FragCreates;
58 -
59 - Forwarding = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
60 - DefaultTTL = strtoull(procfile_lineword(ff, l, 2), NULL, 10);
61 - InReceives = strtoull(procfile_lineword(ff, l, 3), NULL, 10);
62 - InHdrErrors = strtoull(procfile_lineword(ff, l, 4), NULL, 10);
63 - InAddrErrors = strtoull(procfile_lineword(ff, l, 5), NULL, 10);
64 - ForwDatagrams = strtoull(procfile_lineword(ff, l, 6), NULL, 10);
65 - InUnknownProtos = strtoull(procfile_lineword(ff, l, 7), NULL, 10);
66 - InDiscards = strtoull(procfile_lineword(ff, l, 8), NULL, 10);
67 - InDelivers = strtoull(procfile_lineword(ff, l, 9), NULL, 10);
68 - OutRequests = strtoull(procfile_lineword(ff, l, 10), NULL, 10);
69 - OutDiscards = strtoull(procfile_lineword(ff, l, 11), NULL, 10);
70 - OutNoRoutes = strtoull(procfile_lineword(ff, l, 12), NULL, 10);
71 - ReasmTimeout = strtoull(procfile_lineword(ff, l, 13), NULL, 10);
72 - ReasmReqds = strtoull(procfile_lineword(ff, l, 14), NULL, 10);
73 - ReasmOKs = strtoull(procfile_lineword(ff, l, 15), NULL, 10);
74 - ReasmFails = strtoull(procfile_lineword(ff, l, 16), NULL, 10);
75 - FragOKs = strtoull(procfile_lineword(ff, l, 17), NULL, 10);
76 - FragFails = strtoull(procfile_lineword(ff, l, 18), NULL, 10);
77 - FragCreates = strtoull(procfile_lineword(ff, l, 19), NULL, 10);
78 -
79 - // these are not counters
80 - if(Forwarding) {}; // is forwarding enabled?
81 - if(DefaultTTL) {}; // the default ttl on packets
82 - if(ReasmTimeout) {}; // Reassembly timeout
83 -
84 - // this counter is not used
85 - if(InDelivers) {}; // total number of packets delivered to IP user-protocols
86 -
87 - // --------------------------------------------------------------------
88 -
89 - if(do_ip_packets) {
90 - st = rrdset_find(RRD_TYPE_NET_SNMP ".packets");
91 - if(!st) {
92 - st = rrdset_create(RRD_TYPE_NET_SNMP, "packets", NULL, "packets", NULL, "IPv4 Packets", "packets/s", 3000, update_every, RRDSET_TYPE_LINE);
93 -
94 - rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
95 - rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
96 - rrddim_add(st, "forwarded", NULL, 1, 1, RRDDIM_INCREMENTAL);
97 - }
98 - else rrdset_next(st);
99 -
100 - rrddim_set(st, "sent", OutRequests);
101 - rrddim_set(st, "received", InReceives);
102 - rrddim_set(st, "forwarded", ForwDatagrams);
103 - rrdset_done(st);
104 - }
105 -
106 - // --------------------------------------------------------------------
107 -
108 - if(do_ip_fragsout) {
109 - st = rrdset_find(RRD_TYPE_NET_SNMP ".fragsout");
110 - if(!st) {
111 - st = rrdset_create(RRD_TYPE_NET_SNMP, "fragsout", NULL, "fragments", NULL, "IPv4 Fragments Sent", "packets/s", 3010, update_every, RRDSET_TYPE_LINE);
112 - st->isdetail = 1;
113 -
114 - rrddim_add(st, "ok", NULL, 1, 1, RRDDIM_INCREMENTAL);
115 - rrddim_add(st, "failed", NULL, -1, 1, RRDDIM_INCREMENTAL);
116 - rrddim_add(st, "all", NULL, 1, 1, RRDDIM_INCREMENTAL);
117 - }
118 - else rrdset_next(st);
119 -
120 - rrddim_set(st, "ok", FragOKs);
121 - rrddim_set(st, "failed", FragFails);
122 - rrddim_set(st, "all", FragCreates);
123 - rrdset_done(st);
124 - }
125 -
126 - // --------------------------------------------------------------------
127 -
128 - if(do_ip_fragsin) {
129 - st = rrdset_find(RRD_TYPE_NET_SNMP ".fragsin");
130 - if(!st) {
131 - st = rrdset_create(RRD_TYPE_NET_SNMP, "fragsin", NULL, "fragments", NULL, "IPv4 Fragments Reassembly", "packets/s", 3011, update_every, RRDSET_TYPE_LINE);
132 - st->isdetail = 1;
133 -
134 - rrddim_add(st, "ok", NULL, 1, 1, RRDDIM_INCREMENTAL);
135 - rrddim_add(st, "failed", NULL, -1, 1, RRDDIM_INCREMENTAL);
136 - rrddim_add(st, "all", NULL, 1, 1, RRDDIM_INCREMENTAL);
137 - }
138 - else rrdset_next(st);
139 -
140 - rrddim_set(st, "ok", ReasmOKs);
141 - rrddim_set(st, "failed", ReasmFails);
142 - rrddim_set(st, "all", ReasmReqds);
143 - rrdset_done(st);
144 - }
145 -
146 - // --------------------------------------------------------------------
147 -
148 - if(do_ip_errors) {
149 - st = rrdset_find(RRD_TYPE_NET_SNMP ".errors");
150 - if(!st) {
151 - st = rrdset_create(RRD_TYPE_NET_SNMP, "errors", NULL, "errors", NULL, "IPv4 Errors", "packets/s", 3002, update_every, RRDSET_TYPE_LINE);
152 - st->isdetail = 1;
153 -
154 - rrddim_add(st, "InDiscards", NULL, 1, 1, RRDDIM_INCREMENTAL);
155 - rrddim_add(st, "OutDiscards", NULL, -1, 1, RRDDIM_INCREMENTAL);
156 -
157 - rrddim_add(st, "InHdrErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
158 - rrddim_add(st, "InAddrErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
159 - rrddim_add(st, "InUnknownProtos", NULL, 1, 1, RRDDIM_INCREMENTAL);
160 -
161 - rrddim_add(st, "OutNoRoutes", NULL, -1, 1, RRDDIM_INCREMENTAL);
162 - }
163 - else rrdset_next(st);
164 -
165 - rrddim_set(st, "InDiscards", InDiscards);
166 - rrddim_set(st, "OutDiscards", OutDiscards);
167 - rrddim_set(st, "InHdrErrors", InHdrErrors);
168 - rrddim_set(st, "InAddrErrors", InAddrErrors);
169 - rrddim_set(st, "InUnknownProtos", InUnknownProtos);
170 - rrddim_set(st, "OutNoRoutes", OutNoRoutes);
171 - rrdset_done(st);
172 - }
173 - }
174 - else if(strcmp(procfile_lineword(ff, l, 0), "Tcp") == 0) {
175 - l++;
176 -
177 - if(strcmp(procfile_lineword(ff, l, 0), "Tcp") != 0) {
178 - error("Cannot read Tcp line from /proc/net/snmp.");
179 - break;
180 - }
181 -
182 - words = procfile_linewords(ff, l);
183 - if(words < 15) {
184 - error("Cannot read /proc/net/snmp Tcp line. Expected 15 params, read %u.", words);
185 - continue;
186 - }
187 -
188 - unsigned long long RtoAlgorithm, RtoMin, RtoMax, MaxConn, ActiveOpens, PassiveOpens, AttemptFails, EstabResets,
189 - CurrEstab, InSegs, OutSegs, RetransSegs, InErrs, OutRsts;
190 -
191 - RtoAlgorithm = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
192 - RtoMin = strtoull(procfile_lineword(ff, l, 2), NULL, 10);
193 - RtoMax = strtoull(procfile_lineword(ff, l, 3), NULL, 10);
194 - MaxConn = strtoull(procfile_lineword(ff, l, 4), NULL, 10);
195 - ActiveOpens = strtoull(procfile_lineword(ff, l, 5), NULL, 10);
196 - PassiveOpens = strtoull(procfile_lineword(ff, l, 6), NULL, 10);
197 - AttemptFails = strtoull(procfile_lineword(ff, l, 7), NULL, 10);
198 - EstabResets = strtoull(procfile_lineword(ff, l, 8), NULL, 10);
199 - CurrEstab = strtoull(procfile_lineword(ff, l, 9), NULL, 10);
200 - InSegs = strtoull(procfile_lineword(ff, l, 10), NULL, 10);
201 - OutSegs = strtoull(procfile_lineword(ff, l, 11), NULL, 10);
202 - RetransSegs = strtoull(procfile_lineword(ff, l, 12), NULL, 10);
203 - InErrs = strtoull(procfile_lineword(ff, l, 13), NULL, 10);
204 - OutRsts = strtoull(procfile_lineword(ff, l, 14), NULL, 10);
205 -
206 - // these are not counters
207 - if(RtoAlgorithm) {};
208 - if(RtoMin) {};
209 - if(RtoMax) {};
210 - if(MaxConn) {};
211 -
212 - // --------------------------------------------------------------------
213 -
214 - // see http://net-snmp.sourceforge.net/docs/mibs/tcp.html
215 - if(do_tcp_sockets) {
216 - st = rrdset_find(RRD_TYPE_NET_SNMP ".tcpsock");
217 - if(!st) {
218 - st = rrdset_create(RRD_TYPE_NET_SNMP, "tcpsock", NULL, "tcp", NULL, "IPv4 TCP Connections", "active connections", 2500, update_every, RRDSET_TYPE_LINE);
219 -
220 - rrddim_add(st, "connections", NULL, 1, 1, RRDDIM_ABSOLUTE);
221 - }
222 - else rrdset_next(st);
223 -
224 - rrddim_set(st, "connections", CurrEstab);
225 - rrdset_done(st);
226 - }
227 -
228 - // --------------------------------------------------------------------
229 -
230 - if(do_tcp_packets) {
231 - st = rrdset_find(RRD_TYPE_NET_SNMP ".tcppackets");
232 - if(!st) {
233 - st = rrdset_create(RRD_TYPE_NET_SNMP, "tcppackets", NULL, "tcp", NULL, "IPv4 TCP Packets", "packets/s", 2600, update_every, RRDSET_TYPE_LINE);
234 -
235 - rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
236 - rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
237 - }
238 - else rrdset_next(st);
239 -
240 - rrddim_set(st, "received", InSegs);
241 - rrddim_set(st, "sent", OutSegs);
242 - rrdset_done(st);
243 - }
244 -
245 - // --------------------------------------------------------------------
246 -
247 - if(do_tcp_errors) {
248 - st = rrdset_find(RRD_TYPE_NET_SNMP ".tcperrors");
249 - if(!st) {
250 - st = rrdset_create(RRD_TYPE_NET_SNMP, "tcperrors", NULL, "tcp", NULL, "IPv4 TCP Errors", "packets/s", 2700, update_every, RRDSET_TYPE_LINE);
251 - st->isdetail = 1;
252 -
253 - rrddim_add(st, "InErrs", NULL, 1, 1, RRDDIM_INCREMENTAL);
254 - rrddim_add(st, "RetransSegs", NULL, -1, 1, RRDDIM_INCREMENTAL);
255 - }
256 - else rrdset_next(st);
257 -
258 - rrddim_set(st, "InErrs", InErrs);
259 - rrddim_set(st, "RetransSegs", RetransSegs);
260 - rrdset_done(st);
261 - }
262 -
263 - // --------------------------------------------------------------------
264 -
265 - if(do_tcp_handshake) {
266 - st = rrdset_find(RRD_TYPE_NET_SNMP ".tcphandshake");
267 - if(!st) {
268 - st = rrdset_create(RRD_TYPE_NET_SNMP, "tcphandshake", NULL, "tcp", NULL, "IPv4 TCP Handshake Issues", "events/s", 2900, update_every, RRDSET_TYPE_LINE);
269 - st->isdetail = 1;
270 -
271 - rrddim_add(st, "EstabResets", NULL, 1, 1, RRDDIM_INCREMENTAL);
272 - rrddim_add(st, "OutRsts", NULL, -1, 1, RRDDIM_INCREMENTAL);
273 - rrddim_add(st, "ActiveOpens", NULL, 1, 1, RRDDIM_INCREMENTAL);
274 - rrddim_add(st, "PassiveOpens", NULL, 1, 1, RRDDIM_INCREMENTAL);
275 - rrddim_add(st, "AttemptFails", NULL, 1, 1, RRDDIM_INCREMENTAL);
276 - }
277 - else rrdset_next(st);
278 -
279 - rrddim_set(st, "EstabResets", EstabResets);
280 - rrddim_set(st, "OutRsts", OutRsts);
281 - rrddim_set(st, "ActiveOpens", ActiveOpens);
282 - rrddim_set(st, "PassiveOpens", PassiveOpens);
283 - rrddim_set(st, "AttemptFails", AttemptFails);
284 - rrdset_done(st);
285 - }
286 - }
287 - else if(strcmp(procfile_lineword(ff, l, 0), "Udp") == 0) {
288 - l++;
289 -
290 - if(strcmp(procfile_lineword(ff, l, 0), "Udp") != 0) {
291 - error("Cannot read Udp line from /proc/net/snmp.");
292 - break;
293 - }
294 -
295 - words = procfile_linewords(ff, l);
296 - if(words < 7) {
297 - error("Cannot read /proc/net/snmp Udp line. Expected 7 params, read %u.", words);
298 - continue;
299 - }
300 -
301 - unsigned long long InDatagrams, NoPorts, InErrors, OutDatagrams, RcvbufErrors, SndbufErrors;
302 -
303 - InDatagrams = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
304 - NoPorts = strtoull(procfile_lineword(ff, l, 2), NULL, 10);
305 - InErrors = strtoull(procfile_lineword(ff, l, 3), NULL, 10);
306 - OutDatagrams = strtoull(procfile_lineword(ff, l, 4), NULL, 10);
307 - RcvbufErrors = strtoull(procfile_lineword(ff, l, 5), NULL, 10);
308 - SndbufErrors = strtoull(procfile_lineword(ff, l, 6), NULL, 10);
309 -
310 - // --------------------------------------------------------------------
311 -
312 - // see http://net-snmp.sourceforge.net/docs/mibs/udp.html
313 - if(do_udp_packets) {
314 - st = rrdset_find(RRD_TYPE_NET_SNMP ".udppackets");
315 - if(!st) {
316 - st = rrdset_create(RRD_TYPE_NET_SNMP, "udppackets", NULL, "udp", NULL, "IPv4 UDP Packets", "packets/s", 2601, update_every, RRDSET_TYPE_LINE);
317 -
318 - rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
319 - rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
320 - }
321 - else rrdset_next(st);
322 -
323 - rrddim_set(st, "received", InDatagrams);
324 - rrddim_set(st, "sent", OutDatagrams);
325 - rrdset_done(st);
326 - }
327 -
328 - // --------------------------------------------------------------------
329 -
330 - if(do_udp_errors) {
331 - st = rrdset_find(RRD_TYPE_NET_SNMP ".udperrors");
332 - if(!st) {
333 - st = rrdset_create(RRD_TYPE_NET_SNMP, "udperrors", NULL, "udp", NULL, "IPv4 UDP Errors", "events/s", 2701, update_every, RRDSET_TYPE_LINE);
334 - st->isdetail = 1;
335 -
336 - rrddim_add(st, "RcvbufErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
337 - rrddim_add(st, "SndbufErrors", NULL, -1, 1, RRDDIM_INCREMENTAL);
338 - rrddim_add(st, "InErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
339 - rrddim_add(st, "NoPorts", NULL, 1, 1, RRDDIM_INCREMENTAL);
340 - }
341 - else rrdset_next(st);
342 -
343 - rrddim_set(st, "InErrors", InErrors);
344 - rrddim_set(st, "NoPorts", NoPorts);
345 - rrddim_set(st, "RcvbufErrors", RcvbufErrors);
346 - rrddim_set(st, "SndbufErrors", SndbufErrors);
347 - rrdset_done(st);
348 - }
349 - }
350 - }
351 -
352 - return 0;
7 + static procfile *ff = NULL;
8 + static int do_ip_packets = -1, do_ip_fragsout = -1, do_ip_fragsin = -1, do_ip_errors = -1,
9 + do_tcp_sockets = -1, do_tcp_packets = -1, do_tcp_errors = -1, do_tcp_handshake = -1,
10 + do_udp_packets = -1, do_udp_errors = -1;
11 +
12 + if(do_ip_packets == -1) do_ip_packets = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 packets", 1);
13 + if(do_ip_fragsout == -1) do_ip_fragsout = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 fragments sent", 1);
14 + if(do_ip_fragsin == -1) do_ip_fragsin = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 fragments assembly", 1);
15 + if(do_ip_errors == -1) do_ip_errors = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 errors", 1);
16 + if(do_tcp_sockets == -1) do_tcp_sockets = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 TCP connections", 1);
17 + if(do_tcp_packets == -1) do_tcp_packets = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 TCP packets", 1);
18 + if(do_tcp_errors == -1) do_tcp_errors = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 TCP errors", 1);
19 + if(do_tcp_handshake == -1) do_tcp_handshake = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 TCP handshake issues", 1);
20 + if(do_udp_packets == -1) do_udp_packets = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 UDP packets", 1);
21 + if(do_udp_errors == -1) do_udp_errors = config_get_boolean("plugin:proc:/proc/net/snmp", "ipv4 UDP errors", 1);
22 +
23 + if(dt) {};
24 +
25 + if(!ff) {
26 + char filename[FILENAME_MAX + 1];
27 + snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/net/snmp");
28 + ff = procfile_open(config_get("plugin:proc:/proc/net/snmp", "filename to monitor", filename), " \t:", PROCFILE_FLAG_DEFAULT);
29 + }
30 + if(!ff) return 1;
31 +
32 + ff = procfile_readall(ff);
33 + if(!ff) return 0; // we return 0, so that we will retry to open it next time
34 +
35 + uint32_t lines = procfile_lines(ff), l;
36 + uint32_t words;
37 +
38 + RRDSET *st;
39 +
40 + for(l = 0; l < lines ;l++) {
41 + if(strcmp(procfile_lineword(ff, l, 0), "Ip") == 0) {
42 + l++;
43 +
44 + if(strcmp(procfile_lineword(ff, l, 0), "Ip") != 0) {
45 + error("Cannot read Ip line from /proc/net/snmp.");
46 + break;
47 + }
48 +
49 + words = procfile_linewords(ff, l);
50 + if(words < 20) {
51 + error("Cannot read /proc/net/snmp Ip line. Expected 20 params, read %u.", words);
52 + continue;
53 + }
54 +
55 + // see also http://net-snmp.sourceforge.net/docs/mibs/ip.html
56 + unsigned long long Forwarding, DefaultTTL, InReceives, InHdrErrors, InAddrErrors, ForwDatagrams, InUnknownProtos, InDiscards, InDelivers,
57 + OutRequests, OutDiscards, OutNoRoutes, ReasmTimeout, ReasmReqds, ReasmOKs, ReasmFails, FragOKs, FragFails, FragCreates;
58 +
59 + Forwarding = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
60 + DefaultTTL = strtoull(procfile_lineword(ff, l, 2), NULL, 10);
61 + InReceives = strtoull(procfile_lineword(ff, l, 3), NULL, 10);
62 + InHdrErrors = strtoull(procfile_lineword(ff, l, 4), NULL, 10);
63 + InAddrErrors = strtoull(procfile_lineword(ff, l, 5), NULL, 10);
64 + ForwDatagrams = strtoull(procfile_lineword(ff, l, 6), NULL, 10);
65 + InUnknownProtos = strtoull(procfile_lineword(ff, l, 7), NULL, 10);
66 + InDiscards = strtoull(procfile_lineword(ff, l, 8), NULL, 10);
67 + InDelivers = strtoull(procfile_lineword(ff, l, 9), NULL, 10);
68 + OutRequests = strtoull(procfile_lineword(ff, l, 10), NULL, 10);
69 + OutDiscards = strtoull(procfile_lineword(ff, l, 11), NULL, 10);
70 + OutNoRoutes = strtoull(procfile_lineword(ff, l, 12), NULL, 10);
71 + ReasmTimeout = strtoull(procfile_lineword(ff, l, 13), NULL, 10);
72 + ReasmReqds = strtoull(procfile_lineword(ff, l, 14), NULL, 10);
73 + ReasmOKs = strtoull(procfile_lineword(ff, l, 15), NULL, 10);
74 + ReasmFails = strtoull(procfile_lineword(ff, l, 16), NULL, 10);
75 + FragOKs = strtoull(procfile_lineword(ff, l, 17), NULL, 10);
76 + FragFails = strtoull(procfile_lineword(ff, l, 18), NULL, 10);
77 + FragCreates = strtoull(procfile_lineword(ff, l, 19), NULL, 10);
78 +
79 + // these are not counters
80 + if(Forwarding) {}; // is forwarding enabled?
81 + if(DefaultTTL) {}; // the default ttl on packets
82 + if(ReasmTimeout) {}; // Reassembly timeout
83 +
84 + // this counter is not used
85 + if(InDelivers) {}; // total number of packets delivered to IP user-protocols
86 +
87 + // --------------------------------------------------------------------
88 +
89 + if(do_ip_packets) {
90 + st = rrdset_find(RRD_TYPE_NET_SNMP ".packets");
91 + if(!st) {
92 + st = rrdset_create(RRD_TYPE_NET_SNMP, "packets", NULL, "packets", NULL, "IPv4 Packets", "packets/s", 3000, update_every, RRDSET_TYPE_LINE);
93 +
94 + rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
95 + rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
96 + rrddim_add(st, "forwarded", NULL, 1, 1, RRDDIM_INCREMENTAL);
97 + }
98 + else rrdset_next(st);
99 +
100 + rrddim_set(st, "sent", OutRequests);
101 + rrddim_set(st, "received", InReceives);
102 + rrddim_set(st, "forwarded", ForwDatagrams);
103 + rrdset_done(st);
104 + }
105 +
106 + // --------------------------------------------------------------------
107 +
108 + if(do_ip_fragsout) {
109 + st = rrdset_find(RRD_TYPE_NET_SNMP ".fragsout");
110 + if(!st) {
111 + st = rrdset_create(RRD_TYPE_NET_SNMP, "fragsout", NULL, "fragments", NULL, "IPv4 Fragments Sent", "packets/s", 3010, update_every, RRDSET_TYPE_LINE);
112 + st->isdetail = 1;
113 +
114 + rrddim_add(st, "ok", NULL, 1, 1, RRDDIM_INCREMENTAL);
115 + rrddim_add(st, "failed", NULL, -1, 1, RRDDIM_INCREMENTAL);
116 + rrddim_add(st, "all", NULL, 1, 1, RRDDIM_INCREMENTAL);
117 + }
118 + else rrdset_next(st);
119 +
120 + rrddim_set(st, "ok", FragOKs);
121 + rrddim_set(st, "failed", FragFails);
122 + rrddim_set(st, "all", FragCreates);
123 + rrdset_done(st);
124 + }
125 +
126 + // --------------------------------------------------------------------
127 +
128 + if(do_ip_fragsin) {
129 + st = rrdset_find(RRD_TYPE_NET_SNMP ".fragsin");
130 + if(!st) {
131 + st = rrdset_create(RRD_TYPE_NET_SNMP, "fragsin", NULL, "fragments", NULL, "IPv4 Fragments Reassembly", "packets/s", 3011, update_every, RRDSET_TYPE_LINE);
132 + st->isdetail = 1;
133 +
134 + rrddim_add(st, "ok", NULL, 1, 1, RRDDIM_INCREMENTAL);
135 + rrddim_add(st, "failed", NULL, -1, 1, RRDDIM_INCREMENTAL);
136 + rrddim_add(st, "all", NULL, 1, 1, RRDDIM_INCREMENTAL);
137 + }
138 + else rrdset_next(st);
139 +
140 + rrddim_set(st, "ok", ReasmOKs);
141 + rrddim_set(st, "failed", ReasmFails);
142 + rrddim_set(st, "all", ReasmReqds);
143 + rrdset_done(st);
144 + }
145 +
146 + // --------------------------------------------------------------------
147 +
148 + if(do_ip_errors) {
149 + st = rrdset_find(RRD_TYPE_NET_SNMP ".errors");
150 + if(!st) {
151 + st = rrdset_create(RRD_TYPE_NET_SNMP, "errors", NULL, "errors", NULL, "IPv4 Errors", "packets/s", 3002, update_every, RRDSET_TYPE_LINE);
152 + st->isdetail = 1;
153 +
154 + rrddim_add(st, "InDiscards", NULL, 1, 1, RRDDIM_INCREMENTAL);
155 + rrddim_add(st, "OutDiscards", NULL, -1, 1, RRDDIM_INCREMENTAL);
156 +
157 + rrddim_add(st, "InHdrErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
158 + rrddim_add(st, "InAddrErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
159 + rrddim_add(st, "InUnknownProtos", NULL, 1, 1, RRDDIM_INCREMENTAL);
160 +
161 + rrddim_add(st, "OutNoRoutes", NULL, -1, 1, RRDDIM_INCREMENTAL);
162 + }
163 + else rrdset_next(st);
164 +
165 + rrddim_set(st, "InDiscards", InDiscards);
166 + rrddim_set(st, "OutDiscards", OutDiscards);
167 + rrddim_set(st, "InHdrErrors", InHdrErrors);
168 + rrddim_set(st, "InAddrErrors", InAddrErrors);
169 + rrddim_set(st, "InUnknownProtos", InUnknownProtos);
170 + rrddim_set(st, "OutNoRoutes", OutNoRoutes);
171 + rrdset_done(st);
172 + }
173 + }
174 + else if(strcmp(procfile_lineword(ff, l, 0), "Tcp") == 0) {
175 + l++;
176 +
177 + if(strcmp(procfile_lineword(ff, l, 0), "Tcp") != 0) {
178 + error("Cannot read Tcp line from /proc/net/snmp.");
179 + break;
180 + }
181 +
182 + words = procfile_linewords(ff, l);
183 + if(words < 15) {
184 + error("Cannot read /proc/net/snmp Tcp line. Expected 15 params, read %u.", words);
185 + continue;
186 + }
187 +
188 + unsigned long long RtoAlgorithm, RtoMin, RtoMax, MaxConn, ActiveOpens, PassiveOpens, AttemptFails, EstabResets,
189 + CurrEstab, InSegs, OutSegs, RetransSegs, InErrs, OutRsts;
190 +
191 + RtoAlgorithm = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
192 + RtoMin = strtoull(procfile_lineword(ff, l, 2), NULL, 10);
193 + RtoMax = strtoull(procfile_lineword(ff, l, 3), NULL, 10);
194 + MaxConn = strtoull(procfile_lineword(ff, l, 4), NULL, 10);
195 + ActiveOpens = strtoull(procfile_lineword(ff, l, 5), NULL, 10);
196 + PassiveOpens = strtoull(procfile_lineword(ff, l, 6), NULL, 10);
197 + AttemptFails = strtoull(procfile_lineword(ff, l, 7), NULL, 10);
198 + EstabResets = strtoull(procfile_lineword(ff, l, 8), NULL, 10);
199 + CurrEstab = strtoull(procfile_lineword(ff, l, 9), NULL, 10);
200 + InSegs = strtoull(procfile_lineword(ff, l, 10), NULL, 10);
201 + OutSegs = strtoull(procfile_lineword(ff, l, 11), NULL, 10);
202 + RetransSegs = strtoull(procfile_lineword(ff, l, 12), NULL, 10);
203 + InErrs = strtoull(procfile_lineword(ff, l, 13), NULL, 10);
204 + OutRsts = strtoull(procfile_lineword(ff, l, 14), NULL, 10);
205 +
206 + // these are not counters
207 + if(RtoAlgorithm) {};
208 + if(RtoMin) {};
209 + if(RtoMax) {};
210 + if(MaxConn) {};
211 +
212 + // --------------------------------------------------------------------
213 +
214 + // see http://net-snmp.sourceforge.net/docs/mibs/tcp.html
215 + if(do_tcp_sockets) {
216 + st = rrdset_find(RRD_TYPE_NET_SNMP ".tcpsock");
217 + if(!st) {
218 + st = rrdset_create(RRD_TYPE_NET_SNMP, "tcpsock", NULL, "tcp", NULL, "IPv4 TCP Connections", "active connections", 2500, update_every, RRDSET_TYPE_LINE);
219 +
220 + rrddim_add(st, "connections", NULL, 1, 1, RRDDIM_ABSOLUTE);
221 + }
222 + else rrdset_next(st);
223 +
224 + rrddim_set(st, "connections", CurrEstab);
225 + rrdset_done(st);
226 + }
227 +
228 + // --------------------------------------------------------------------
229 +
230 + if(do_tcp_packets) {
231 + st = rrdset_find(RRD_TYPE_NET_SNMP ".tcppackets");
232 + if(!st) {
233 + st = rrdset_create(RRD_TYPE_NET_SNMP, "tcppackets", NULL, "tcp", NULL, "IPv4 TCP Packets", "packets/s", 2600, update_every, RRDSET_TYPE_LINE);
234 +
235 + rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
236 + rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
237 + }
238 + else rrdset_next(st);
239 +
240 + rrddim_set(st, "received", InSegs);
241 + rrddim_set(st, "sent", OutSegs);
242 + rrdset_done(st);
243 + }
244 +
245 + // --------------------------------------------------------------------
246 +
247 + if(do_tcp_errors) {
248 + st = rrdset_find(RRD_TYPE_NET_SNMP ".tcperrors");
249 + if(!st) {
250 + st = rrdset_create(RRD_TYPE_NET_SNMP, "tcperrors", NULL, "tcp", NULL, "IPv4 TCP Errors", "packets/s", 2700, update_every, RRDSET_TYPE_LINE);
251 + st->isdetail = 1;
252 +
253 + rrddim_add(st, "InErrs", NULL, 1, 1, RRDDIM_INCREMENTAL);
254 + rrddim_add(st, "RetransSegs", NULL, -1, 1, RRDDIM_INCREMENTAL);
255 + }
256 + else rrdset_next(st);
257 +
258 + rrddim_set(st, "InErrs", InErrs);
259 + rrddim_set(st, "RetransSegs", RetransSegs);
260 + rrdset_done(st);
261 + }
262 +
263 + // --------------------------------------------------------------------
264 +
265 + if(do_tcp_handshake) {
266 + st = rrdset_find(RRD_TYPE_NET_SNMP ".tcphandshake");
267 + if(!st) {
268 + st = rrdset_create(RRD_TYPE_NET_SNMP, "tcphandshake", NULL, "tcp", NULL, "IPv4 TCP Handshake Issues", "events/s", 2900, update_every, RRDSET_TYPE_LINE);
269 + st->isdetail = 1;
270 +
271 + rrddim_add(st, "EstabResets", NULL, 1, 1, RRDDIM_INCREMENTAL);
272 + rrddim_add(st, "OutRsts", NULL, -1, 1, RRDDIM_INCREMENTAL);
273 + rrddim_add(st, "ActiveOpens", NULL, 1, 1, RRDDIM_INCREMENTAL);
274 + rrddim_add(st, "PassiveOpens", NULL, 1, 1, RRDDIM_INCREMENTAL);
275 + rrddim_add(st, "AttemptFails", NULL, 1, 1, RRDDIM_INCREMENTAL);
276 + }
277 + else rrdset_next(st);
278 +
279 + rrddim_set(st, "EstabResets", EstabResets);
280 + rrddim_set(st, "OutRsts", OutRsts);
281 + rrddim_set(st, "ActiveOpens", ActiveOpens);
282 + rrddim_set(st, "PassiveOpens", PassiveOpens);
283 + rrddim_set(st, "AttemptFails", AttemptFails);
284 + rrdset_done(st);
285 + }
286 + }
287 + else if(strcmp(procfile_lineword(ff, l, 0), "Udp") == 0) {
288 + l++;
289 +
290 + if(strcmp(procfile_lineword(ff, l, 0), "Udp") != 0) {
291 + error("Cannot read Udp line from /proc/net/snmp.");
292 + break;
293 + }
294 +
295 + words = procfile_linewords(ff, l);
296 + if(words < 7) {
297 + error("Cannot read /proc/net/snmp Udp line. Expected 7 params, read %u.", words);
298 + continue;
299 + }
300 +
301 + unsigned long long InDatagrams, NoPorts, InErrors, OutDatagrams, RcvbufErrors, SndbufErrors;
302 +
303 + InDatagrams = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
304 + NoPorts = strtoull(procfile_lineword(ff, l, 2), NULL, 10);
305 + InErrors = strtoull(procfile_lineword(ff, l, 3), NULL, 10);
306 + OutDatagrams = strtoull(procfile_lineword(ff, l, 4), NULL, 10);
307 + RcvbufErrors = strtoull(procfile_lineword(ff, l, 5), NULL, 10);
308 + SndbufErrors = strtoull(procfile_lineword(ff, l, 6), NULL, 10);
309 +
310 + // --------------------------------------------------------------------
311 +
312 + // see http://net-snmp.sourceforge.net/docs/mibs/udp.html
313 + if(do_udp_packets) {
314 + st = rrdset_find(RRD_TYPE_NET_SNMP ".udppackets");
315 + if(!st) {
316 + st = rrdset_create(RRD_TYPE_NET_SNMP, "udppackets", NULL, "udp", NULL, "IPv4 UDP Packets", "packets/s", 2601, update_every, RRDSET_TYPE_LINE);
317 +
318 + rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
319 + rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
320 + }
321 + else rrdset_next(st);
322 +
323 + rrddim_set(st, "received", InDatagrams);
324 + rrddim_set(st, "sent", OutDatagrams);
325 + rrdset_done(st);
326 + }
327 +
328 + // --------------------------------------------------------------------
329 +
330 + if(do_udp_errors) {
331 + st = rrdset_find(RRD_TYPE_NET_SNMP ".udperrors");
332 + if(!st) {
333 + st = rrdset_create(RRD_TYPE_NET_SNMP, "udperrors", NULL, "udp", NULL, "IPv4 UDP Errors", "events/s", 2701, update_every, RRDSET_TYPE_LINE);
334 + st->isdetail = 1;
335 +
336 + rrddim_add(st, "RcvbufErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
337 + rrddim_add(st, "SndbufErrors", NULL, -1, 1, RRDDIM_INCREMENTAL);
338 + rrddim_add(st, "InErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
339 + rrddim_add(st, "NoPorts", NULL, 1, 1, RRDDIM_INCREMENTAL);
340 + }
341 + else rrdset_next(st);
342 +
343 + rrddim_set(st, "InErrors", InErrors);
344 + rrddim_set(st, "NoPorts", NoPorts);
345 + rrddim_set(st, "RcvbufErrors", RcvbufErrors);
346 + rrddim_set(st, "SndbufErrors", SndbufErrors);
347 + rrdset_done(st);
348 + }
349 + }
350 + }
351 +
352 + return 0;
353 }
354
src/proc_net_snmp6.c
+1048 -1048
@@ -1,1054 +1,1054 @@
1 #include "common.h"
2
3 -#define RRD_TYPE_NET_SNMP6 "ipv6"
4 -#define RRD_TYPE_NET_SNMP6_LEN strlen(RRD_TYPE_NET_SNMP6)
3 +#define RRD_TYPE_NET_SNMP6 "ipv6"
4 +#define RRD_TYPE_NET_SNMP6_LEN strlen(RRD_TYPE_NET_SNMP6)
5
6 int do_proc_net_snmp6(int update_every, unsigned long long dt) {
7 - static procfile *ff = NULL;
8 - static int gen_hashes = -1;
9 -
10 - static int do_ip_packets = -1, do_ip_fragsout = -1, do_ip_fragsin = -1, do_ip_errors = -1,
11 - do_udplite_packets = -1, do_udplite_errors = -1,
12 - do_udp_packets = -1, do_udp_errors = -1,
13 - do_bandwidth = -1, do_mcast = -1, do_bcast = -1, do_mcast_p = -1,
14 - do_icmp = -1, do_icmp_redir = -1, do_icmp_errors = -1, do_icmp_echos = -1, do_icmp_groupmemb = -1,
15 - do_icmp_router = -1, do_icmp_neighbor = -1, do_icmp_mldv2 = -1, do_icmp_types = -1, do_ect = -1;
16 -
17 - static uint32_t hash_Ip6InReceives = -1;
18 -
19 - static uint32_t hash_Ip6InHdrErrors = -1;
20 - static uint32_t hash_Ip6InTooBigErrors = -1;
21 - static uint32_t hash_Ip6InNoRoutes = -1;
22 - static uint32_t hash_Ip6InAddrErrors = -1;
23 - static uint32_t hash_Ip6InUnknownProtos = -1;
24 - static uint32_t hash_Ip6InTruncatedPkts = -1;
25 - static uint32_t hash_Ip6InDiscards = -1;
26 - static uint32_t hash_Ip6InDelivers = -1;
27 -
28 - static uint32_t hash_Ip6OutForwDatagrams = -1;
29 - static uint32_t hash_Ip6OutRequests = -1;
30 - static uint32_t hash_Ip6OutDiscards = -1;
31 - static uint32_t hash_Ip6OutNoRoutes = -1;
32 -
33 - static uint32_t hash_Ip6ReasmTimeout = -1;
34 - static uint32_t hash_Ip6ReasmReqds = -1;
35 - static uint32_t hash_Ip6ReasmOKs = -1;
36 - static uint32_t hash_Ip6ReasmFails = -1;
37 -
38 - static uint32_t hash_Ip6FragOKs = -1;
39 - static uint32_t hash_Ip6FragFails = -1;
40 - static uint32_t hash_Ip6FragCreates = -1;
41 -
42 - static uint32_t hash_Ip6InMcastPkts = -1;
43 - static uint32_t hash_Ip6OutMcastPkts = -1;
44 -
45 - static uint32_t hash_Ip6InOctets = -1;
46 - static uint32_t hash_Ip6OutOctets = -1;
47 -
48 - static uint32_t hash_Ip6InMcastOctets = -1;
49 - static uint32_t hash_Ip6OutMcastOctets = -1;
50 - static uint32_t hash_Ip6InBcastOctets = -1;
51 - static uint32_t hash_Ip6OutBcastOctets = -1;
52 -
53 - static uint32_t hash_Ip6InNoECTPkts = -1;
54 - static uint32_t hash_Ip6InECT1Pkts = -1;
55 - static uint32_t hash_Ip6InECT0Pkts = -1;
56 - static uint32_t hash_Ip6InCEPkts = -1;
57 -
58 - static uint32_t hash_Icmp6InMsgs = -1;
59 - static uint32_t hash_Icmp6InErrors = -1;
60 - static uint32_t hash_Icmp6OutMsgs = -1;
61 - static uint32_t hash_Icmp6OutErrors = -1;
62 - static uint32_t hash_Icmp6InCsumErrors = -1;
63 - static uint32_t hash_Icmp6InDestUnreachs = -1;
64 - static uint32_t hash_Icmp6InPktTooBigs = -1;
65 - static uint32_t hash_Icmp6InTimeExcds = -1;
66 - static uint32_t hash_Icmp6InParmProblems = -1;
67 - static uint32_t hash_Icmp6InEchos = -1;
68 - static uint32_t hash_Icmp6InEchoReplies = -1;
69 - static uint32_t hash_Icmp6InGroupMembQueries = -1;
70 - static uint32_t hash_Icmp6InGroupMembResponses = -1;
71 - static uint32_t hash_Icmp6InGroupMembReductions = -1;
72 - static uint32_t hash_Icmp6InRouterSolicits = -1;
73 - static uint32_t hash_Icmp6InRouterAdvertisements = -1;
74 - static uint32_t hash_Icmp6InNeighborSolicits = -1;
75 - static uint32_t hash_Icmp6InNeighborAdvertisements = -1;
76 - static uint32_t hash_Icmp6InRedirects = -1;
77 - static uint32_t hash_Icmp6InMLDv2Reports = -1;
78 - static uint32_t hash_Icmp6OutDestUnreachs = -1;
79 - static uint32_t hash_Icmp6OutPktTooBigs = -1;
80 - static uint32_t hash_Icmp6OutTimeExcds = -1;
81 - static uint32_t hash_Icmp6OutParmProblems = -1;
82 - static uint32_t hash_Icmp6OutEchos = -1;
83 - static uint32_t hash_Icmp6OutEchoReplies = -1;
84 - static uint32_t hash_Icmp6OutGroupMembQueries = -1;
85 - static uint32_t hash_Icmp6OutGroupMembResponses = -1;
86 - static uint32_t hash_Icmp6OutGroupMembReductions = -1;
87 - static uint32_t hash_Icmp6OutRouterSolicits = -1;
88 - static uint32_t hash_Icmp6OutRouterAdvertisements = -1;
89 - static uint32_t hash_Icmp6OutNeighborSolicits = -1;
90 - static uint32_t hash_Icmp6OutNeighborAdvertisements = -1;
91 - static uint32_t hash_Icmp6OutRedirects = -1;
92 - static uint32_t hash_Icmp6OutMLDv2Reports = -1;
93 - static uint32_t hash_Icmp6InType1 = -1;
94 - static uint32_t hash_Icmp6InType128 = -1;
95 - static uint32_t hash_Icmp6InType129 = -1;
96 - static uint32_t hash_Icmp6InType136 = -1;
97 - static uint32_t hash_Icmp6OutType1 = -1;
98 - static uint32_t hash_Icmp6OutType128 = -1;
99 - static uint32_t hash_Icmp6OutType129 = -1;
100 - static uint32_t hash_Icmp6OutType133 = -1;
101 - static uint32_t hash_Icmp6OutType135 = -1;
102 - static uint32_t hash_Icmp6OutType143 = -1;
103 -
104 - static uint32_t hash_Udp6InDatagrams = -1;
105 - static uint32_t hash_Udp6NoPorts = -1;
106 - static uint32_t hash_Udp6InErrors = -1;
107 - static uint32_t hash_Udp6OutDatagrams = -1;
108 - static uint32_t hash_Udp6RcvbufErrors = -1;
109 - static uint32_t hash_Udp6SndbufErrors = -1;
110 - static uint32_t hash_Udp6InCsumErrors = -1;
111 - static uint32_t hash_Udp6IgnoredMulti = -1;
112 -
113 - static uint32_t hash_UdpLite6InDatagrams = -1;
114 - static uint32_t hash_UdpLite6NoPorts = -1;
115 - static uint32_t hash_UdpLite6InErrors = -1;
116 - static uint32_t hash_UdpLite6OutDatagrams = -1;
117 - static uint32_t hash_UdpLite6RcvbufErrors = -1;
118 - static uint32_t hash_UdpLite6SndbufErrors = -1;
119 - static uint32_t hash_UdpLite6InCsumErrors = -1;
120 -
121 - if(gen_hashes != 1) {
122 - gen_hashes = 1;
123 - hash_Ip6InReceives = simple_hash("Ip6InReceives");
124 - hash_Ip6InHdrErrors = simple_hash("Ip6InHdrErrors");
125 - hash_Ip6InTooBigErrors = simple_hash("Ip6InTooBigErrors");
126 - hash_Ip6InNoRoutes = simple_hash("Ip6InNoRoutes");
127 - hash_Ip6InAddrErrors = simple_hash("Ip6InAddrErrors");
128 - hash_Ip6InUnknownProtos = simple_hash("Ip6InUnknownProtos");
129 - hash_Ip6InTruncatedPkts = simple_hash("Ip6InTruncatedPkts");
130 - hash_Ip6InDiscards = simple_hash("Ip6InDiscards");
131 - hash_Ip6InDelivers = simple_hash("Ip6InDelivers");
132 - hash_Ip6OutForwDatagrams = simple_hash("Ip6OutForwDatagrams");
133 - hash_Ip6OutRequests = simple_hash("Ip6OutRequests");
134 - hash_Ip6OutDiscards = simple_hash("Ip6OutDiscards");
135 - hash_Ip6OutNoRoutes = simple_hash("Ip6OutNoRoutes");
136 - hash_Ip6ReasmTimeout = simple_hash("Ip6ReasmTimeout");
137 - hash_Ip6ReasmReqds = simple_hash("Ip6ReasmReqds");
138 - hash_Ip6ReasmOKs = simple_hash("Ip6ReasmOKs");
139 - hash_Ip6ReasmFails = simple_hash("Ip6ReasmFails");
140 - hash_Ip6FragOKs = simple_hash("Ip6FragOKs");
141 - hash_Ip6FragFails = simple_hash("Ip6FragFails");
142 - hash_Ip6FragCreates = simple_hash("Ip6FragCreates");
143 - hash_Ip6InMcastPkts = simple_hash("Ip6InMcastPkts");
144 - hash_Ip6OutMcastPkts = simple_hash("Ip6OutMcastPkts");
145 - hash_Ip6InOctets = simple_hash("Ip6InOctets");
146 - hash_Ip6OutOctets = simple_hash("Ip6OutOctets");
147 - hash_Ip6InMcastOctets = simple_hash("Ip6InMcastOctets");
148 - hash_Ip6OutMcastOctets = simple_hash("Ip6OutMcastOctets");
149 - hash_Ip6InBcastOctets = simple_hash("Ip6InBcastOctets");
150 - hash_Ip6OutBcastOctets = simple_hash("Ip6OutBcastOctets");
151 - hash_Ip6InNoECTPkts = simple_hash("Ip6InNoECTPkts");
152 - hash_Ip6InECT1Pkts = simple_hash("Ip6InECT1Pkts");
153 - hash_Ip6InECT0Pkts = simple_hash("Ip6InECT0Pkts");
154 - hash_Ip6InCEPkts = simple_hash("Ip6InCEPkts");
155 - hash_Icmp6InMsgs = simple_hash("Icmp6InMsgs");
156 - hash_Icmp6InErrors = simple_hash("Icmp6InErrors");
157 - hash_Icmp6OutMsgs = simple_hash("Icmp6OutMsgs");
158 - hash_Icmp6OutErrors = simple_hash("Icmp6OutErrors");
159 - hash_Icmp6InCsumErrors = simple_hash("Icmp6InCsumErrors");
160 - hash_Icmp6InDestUnreachs = simple_hash("Icmp6InDestUnreachs");
161 - hash_Icmp6InPktTooBigs = simple_hash("Icmp6InPktTooBigs");
162 - hash_Icmp6InTimeExcds = simple_hash("Icmp6InTimeExcds");
163 - hash_Icmp6InParmProblems = simple_hash("Icmp6InParmProblems");
164 - hash_Icmp6InEchos = simple_hash("Icmp6InEchos");
165 - hash_Icmp6InEchoReplies = simple_hash("Icmp6InEchoReplies");
166 - hash_Icmp6InGroupMembQueries = simple_hash("Icmp6InGroupMembQueries");
167 - hash_Icmp6InGroupMembResponses = simple_hash("Icmp6InGroupMembResponses");
168 - hash_Icmp6InGroupMembReductions = simple_hash("Icmp6InGroupMembReductions");
169 - hash_Icmp6InRouterSolicits = simple_hash("Icmp6InRouterSolicits");
170 - hash_Icmp6InRouterAdvertisements = simple_hash("Icmp6InRouterAdvertisements");
171 - hash_Icmp6InNeighborSolicits = simple_hash("Icmp6InNeighborSolicits");
172 - hash_Icmp6InNeighborAdvertisements = simple_hash("Icmp6InNeighborAdvertisements");
173 - hash_Icmp6InRedirects = simple_hash("Icmp6InRedirects");
174 - hash_Icmp6InMLDv2Reports = simple_hash("Icmp6InMLDv2Reports");
175 - hash_Icmp6OutDestUnreachs = simple_hash("Icmp6OutDestUnreachs");
176 - hash_Icmp6OutPktTooBigs = simple_hash("Icmp6OutPktTooBigs");
177 - hash_Icmp6OutTimeExcds = simple_hash("Icmp6OutTimeExcds");
178 - hash_Icmp6OutParmProblems = simple_hash("Icmp6OutParmProblems");
179 - hash_Icmp6OutEchos = simple_hash("Icmp6OutEchos");
180 - hash_Icmp6OutEchoReplies = simple_hash("Icmp6OutEchoReplies");
181 - hash_Icmp6OutGroupMembQueries = simple_hash("Icmp6OutGroupMembQueries");
182 - hash_Icmp6OutGroupMembResponses = simple_hash("Icmp6OutGroupMembResponses");
183 - hash_Icmp6OutGroupMembReductions = simple_hash("Icmp6OutGroupMembReductions");
184 - hash_Icmp6OutRouterSolicits = simple_hash("Icmp6OutRouterSolicits");
185 - hash_Icmp6OutRouterAdvertisements = simple_hash("Icmp6OutRouterAdvertisements");
186 - hash_Icmp6OutNeighborSolicits = simple_hash("Icmp6OutNeighborSolicits");
187 - hash_Icmp6OutNeighborAdvertisements = simple_hash("Icmp6OutNeighborAdvertisements");
188 - hash_Icmp6OutRedirects = simple_hash("Icmp6OutRedirects");
189 - hash_Icmp6OutMLDv2Reports = simple_hash("Icmp6OutMLDv2Reports");
190 - hash_Icmp6InType1 = simple_hash("Icmp6InType1");
191 - hash_Icmp6InType128 = simple_hash("Icmp6InType128");
192 - hash_Icmp6InType129 = simple_hash("Icmp6InType129");
193 - hash_Icmp6InType136 = simple_hash("Icmp6InType136");
194 - hash_Icmp6OutType1 = simple_hash("Icmp6OutType1");
195 - hash_Icmp6OutType128 = simple_hash("Icmp6OutType128");
196 - hash_Icmp6OutType129 = simple_hash("Icmp6OutType129");
197 - hash_Icmp6OutType133 = simple_hash("Icmp6OutType133");
198 - hash_Icmp6OutType135 = simple_hash("Icmp6OutType135");
199 - hash_Icmp6OutType143 = simple_hash("Icmp6OutType143");
200 - hash_Udp6InDatagrams = simple_hash("Udp6InDatagrams");
201 - hash_Udp6NoPorts = simple_hash("Udp6NoPorts");
202 - hash_Udp6InErrors = simple_hash("Udp6InErrors");
203 - hash_Udp6OutDatagrams = simple_hash("Udp6OutDatagrams");
204 - hash_Udp6RcvbufErrors = simple_hash("Udp6RcvbufErrors");
205 - hash_Udp6SndbufErrors = simple_hash("Udp6SndbufErrors");
206 - hash_Udp6InCsumErrors = simple_hash("Udp6InCsumErrors");
207 - hash_Udp6IgnoredMulti = simple_hash("Udp6IgnoredMulti");
208 - hash_UdpLite6InDatagrams = simple_hash("UdpLite6InDatagrams");
209 - hash_UdpLite6NoPorts = simple_hash("UdpLite6NoPorts");
210 - hash_UdpLite6InErrors = simple_hash("UdpLite6InErrors");
211 - hash_UdpLite6OutDatagrams = simple_hash("UdpLite6OutDatagrams");
212 - hash_UdpLite6RcvbufErrors = simple_hash("UdpLite6RcvbufErrors");
213 - hash_UdpLite6SndbufErrors = simple_hash("UdpLite6SndbufErrors");
214 - hash_UdpLite6InCsumErrors = simple_hash("UdpLite6InCsumErrors");
215 - }
216 -
217 - if(do_ip_packets == -1) do_ip_packets = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "ipv6 packets", CONFIG_ONDEMAND_ONDEMAND);
218 - if(do_ip_fragsout == -1) do_ip_fragsout = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "ipv6 fragments sent", CONFIG_ONDEMAND_ONDEMAND);
219 - if(do_ip_fragsin == -1) do_ip_fragsin = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "ipv6 fragments assembly", CONFIG_ONDEMAND_ONDEMAND);
220 - if(do_ip_errors == -1) do_ip_errors = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "ipv6 errors", CONFIG_ONDEMAND_ONDEMAND);
221 - if(do_udp_packets == -1) do_udp_packets = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "ipv6 UDP packets", CONFIG_ONDEMAND_ONDEMAND);
222 - if(do_udp_errors == -1) do_udp_errors = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "ipv6 UDP errors", CONFIG_ONDEMAND_ONDEMAND);
223 - if(do_udplite_packets == -1) do_udplite_packets = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "ipv6 UDPlite packets", CONFIG_ONDEMAND_ONDEMAND);
224 - if(do_udplite_errors == -1) do_udplite_errors = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "ipv6 UDPlite errors", CONFIG_ONDEMAND_ONDEMAND);
225 - if(do_bandwidth == -1) do_bandwidth = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "bandwidth", CONFIG_ONDEMAND_ONDEMAND);
226 - if(do_mcast == -1) do_mcast = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "multicast bandwidth", CONFIG_ONDEMAND_ONDEMAND);
227 - if(do_bcast == -1) do_bcast = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "broadcast bandwidth", CONFIG_ONDEMAND_ONDEMAND);
228 - if(do_mcast_p == -1) do_mcast_p = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "multicast packets", CONFIG_ONDEMAND_ONDEMAND);
229 - if(do_icmp == -1) do_icmp = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "icmp", CONFIG_ONDEMAND_ONDEMAND);
230 - if(do_icmp_redir == -1) do_icmp_redir = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "icmp redirects", CONFIG_ONDEMAND_ONDEMAND);
231 - if(do_icmp_errors == -1) do_icmp_errors = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "icmp errors", CONFIG_ONDEMAND_ONDEMAND);
232 - if(do_icmp_echos == -1) do_icmp_echos = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "icmp echos", CONFIG_ONDEMAND_ONDEMAND);
233 - if(do_icmp_groupmemb == -1) do_icmp_groupmemb = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "icmp group membership", CONFIG_ONDEMAND_ONDEMAND);
234 - if(do_icmp_router == -1) do_icmp_router = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "icmp router", CONFIG_ONDEMAND_ONDEMAND);
235 - if(do_icmp_neighbor == -1) do_icmp_neighbor = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "icmp neighbor", CONFIG_ONDEMAND_ONDEMAND);
236 - if(do_icmp_mldv2 == -1) do_icmp_mldv2 = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "icmp mldv2", CONFIG_ONDEMAND_ONDEMAND);
237 - if(do_icmp_types == -1) do_icmp_types = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "icmp types", CONFIG_ONDEMAND_ONDEMAND);
238 - if(do_ect == -1) do_ect = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "ect", CONFIG_ONDEMAND_ONDEMAND);
239 -
240 - if(dt) {};
241 -
242 - if(!ff) {
243 - char filename[FILENAME_MAX + 1];
244 - snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/net/snmp6");
245 - ff = procfile_open(config_get("plugin:proc:/proc/net/snmp6", "filename to monitor", filename), " \t:", PROCFILE_FLAG_DEFAULT);
246 - }
247 - if(!ff) return 1;
248 -
249 - ff = procfile_readall(ff);
250 - if(!ff) return 0; // we return 0, so that we will retry to open it next time
251 -
252 - uint32_t lines = procfile_lines(ff), l;
253 - uint32_t words;
254 -
255 - unsigned long long Ip6InReceives = 0ULL;
256 - unsigned long long Ip6InHdrErrors = 0ULL;
257 - unsigned long long Ip6InTooBigErrors = 0ULL;
258 - unsigned long long Ip6InNoRoutes = 0ULL;
259 - unsigned long long Ip6InAddrErrors = 0ULL;
260 - unsigned long long Ip6InUnknownProtos = 0ULL;
261 - unsigned long long Ip6InTruncatedPkts = 0ULL;
262 - unsigned long long Ip6InDiscards = 0ULL;
263 - unsigned long long Ip6InDelivers = 0ULL;
264 - unsigned long long Ip6OutForwDatagrams = 0ULL;
265 - unsigned long long Ip6OutRequests = 0ULL;
266 - unsigned long long Ip6OutDiscards = 0ULL;
267 - unsigned long long Ip6OutNoRoutes = 0ULL;
268 - unsigned long long Ip6ReasmTimeout = 0ULL;
269 - unsigned long long Ip6ReasmReqds = 0ULL;
270 - unsigned long long Ip6ReasmOKs = 0ULL;
271 - unsigned long long Ip6ReasmFails = 0ULL;
272 - unsigned long long Ip6FragOKs = 0ULL;
273 - unsigned long long Ip6FragFails = 0ULL;
274 - unsigned long long Ip6FragCreates = 0ULL;
275 - unsigned long long Ip6InMcastPkts = 0ULL;
276 - unsigned long long Ip6OutMcastPkts = 0ULL;
277 - unsigned long long Ip6InOctets = 0ULL;
278 - unsigned long long Ip6OutOctets = 0ULL;
279 - unsigned long long Ip6InMcastOctets = 0ULL;
280 - unsigned long long Ip6OutMcastOctets = 0ULL;
281 - unsigned long long Ip6InBcastOctets = 0ULL;
282 - unsigned long long Ip6OutBcastOctets = 0ULL;
283 - unsigned long long Ip6InNoECTPkts = 0ULL;
284 - unsigned long long Ip6InECT1Pkts = 0ULL;
285 - unsigned long long Ip6InECT0Pkts = 0ULL;
286 - unsigned long long Ip6InCEPkts = 0ULL;
287 - unsigned long long Icmp6InMsgs = 0ULL;
288 - unsigned long long Icmp6InErrors = 0ULL;
289 - unsigned long long Icmp6OutMsgs = 0ULL;
290 - unsigned long long Icmp6OutErrors = 0ULL;
291 - unsigned long long Icmp6InCsumErrors = 0ULL;
292 - unsigned long long Icmp6InDestUnreachs = 0ULL;
293 - unsigned long long Icmp6InPktTooBigs = 0ULL;
294 - unsigned long long Icmp6InTimeExcds = 0ULL;
295 - unsigned long long Icmp6InParmProblems = 0ULL;
296 - unsigned long long Icmp6InEchos = 0ULL;
297 - unsigned long long Icmp6InEchoReplies = 0ULL;
298 - unsigned long long Icmp6InGroupMembQueries = 0ULL;
299 - unsigned long long Icmp6InGroupMembResponses = 0ULL;
300 - unsigned long long Icmp6InGroupMembReductions = 0ULL;
301 - unsigned long long Icmp6InRouterSolicits = 0ULL;
302 - unsigned long long Icmp6InRouterAdvertisements = 0ULL;
303 - unsigned long long Icmp6InNeighborSolicits = 0ULL;
304 - unsigned long long Icmp6InNeighborAdvertisements = 0ULL;
305 - unsigned long long Icmp6InRedirects = 0ULL;
306 - unsigned long long Icmp6InMLDv2Reports = 0ULL;
307 - unsigned long long Icmp6OutDestUnreachs = 0ULL;
308 - unsigned long long Icmp6OutPktTooBigs = 0ULL;
309 - unsigned long long Icmp6OutTimeExcds = 0ULL;
310 - unsigned long long Icmp6OutParmProblems = 0ULL;
311 - unsigned long long Icmp6OutEchos = 0ULL;
312 - unsigned long long Icmp6OutEchoReplies = 0ULL;
313 - unsigned long long Icmp6OutGroupMembQueries = 0ULL;
314 - unsigned long long Icmp6OutGroupMembResponses = 0ULL;
315 - unsigned long long Icmp6OutGroupMembReductions = 0ULL;
316 - unsigned long long Icmp6OutRouterSolicits = 0ULL;
317 - unsigned long long Icmp6OutRouterAdvertisements = 0ULL;
318 - unsigned long long Icmp6OutNeighborSolicits = 0ULL;
319 - unsigned long long Icmp6OutNeighborAdvertisements = 0ULL;
320 - unsigned long long Icmp6OutRedirects = 0ULL;
321 - unsigned long long Icmp6OutMLDv2Reports = 0ULL;
322 - unsigned long long Icmp6InType1 = 0ULL;
323 - unsigned long long Icmp6InType128 = 0ULL;
324 - unsigned long long Icmp6InType129 = 0ULL;
325 - unsigned long long Icmp6InType136 = 0ULL;
326 - unsigned long long Icmp6OutType1 = 0ULL;
327 - unsigned long long Icmp6OutType128 = 0ULL;
328 - unsigned long long Icmp6OutType129 = 0ULL;
329 - unsigned long long Icmp6OutType133 = 0ULL;
330 - unsigned long long Icmp6OutType135 = 0ULL;
331 - unsigned long long Icmp6OutType143 = 0ULL;
332 - unsigned long long Udp6InDatagrams = 0ULL;
333 - unsigned long long Udp6NoPorts = 0ULL;
334 - unsigned long long Udp6InErrors = 0ULL;
335 - unsigned long long Udp6OutDatagrams = 0ULL;
336 - unsigned long long Udp6RcvbufErrors = 0ULL;
337 - unsigned long long Udp6SndbufErrors = 0ULL;
338 - unsigned long long Udp6InCsumErrors = 0ULL;
339 - unsigned long long Udp6IgnoredMulti = 0ULL;
340 - unsigned long long UdpLite6InDatagrams = 0ULL;
341 - unsigned long long UdpLite6NoPorts = 0ULL;
342 - unsigned long long UdpLite6InErrors = 0ULL;
343 - unsigned long long UdpLite6OutDatagrams = 0ULL;
344 - unsigned long long UdpLite6RcvbufErrors = 0ULL;
345 - unsigned long long UdpLite6SndbufErrors = 0ULL;
346 - unsigned long long UdpLite6InCsumErrors = 0ULL;
347 -
348 - for(l = 0; l < lines ;l++) {
349 - words = procfile_linewords(ff, l);
350 - if(words < 2) {
351 - if(words) error("Cannot read /proc/net/snmp6 line %u. Expected 2 params, read %u.", l, words);
352 - continue;
353 - }
354 -
355 - char *name = procfile_lineword(ff, l, 0);
356 - char * value = procfile_lineword(ff, l, 1);
357 - if(!name || !*name || !value || !*value) continue;
358 -
359 - uint32_t hash = simple_hash(name);
360 -
361 - if(0) ;
362 - else if(hash == hash_Ip6InReceives && strcmp(name, "Ip6InReceives") == 0) Ip6InReceives = strtoull(value, NULL, 10);
363 - else if(hash == hash_Ip6InHdrErrors && strcmp(name, "Ip6InHdrErrors") == 0) Ip6InHdrErrors = strtoull(value, NULL, 10);
364 - else if(hash == hash_Ip6InTooBigErrors && strcmp(name, "Ip6InTooBigErrors") == 0) Ip6InTooBigErrors = strtoull(value, NULL, 10);
365 - else if(hash == hash_Ip6InNoRoutes && strcmp(name, "Ip6InNoRoutes") == 0) Ip6InNoRoutes = strtoull(value, NULL, 10);
366 - else if(hash == hash_Ip6InAddrErrors && strcmp(name, "Ip6InAddrErrors") == 0) Ip6InAddrErrors = strtoull(value, NULL, 10);
367 - else if(hash == hash_Ip6InUnknownProtos && strcmp(name, "Ip6InUnknownProtos") == 0) Ip6InUnknownProtos = strtoull(value, NULL, 10);
368 - else if(hash == hash_Ip6InTruncatedPkts && strcmp(name, "Ip6InTruncatedPkts") == 0) Ip6InTruncatedPkts = strtoull(value, NULL, 10);
369 - else if(hash == hash_Ip6InDiscards && strcmp(name, "Ip6InDiscards") == 0) Ip6InDiscards = strtoull(value, NULL, 10);
370 - else if(hash == hash_Ip6InDelivers && strcmp(name, "Ip6InDelivers") == 0) Ip6InDelivers = strtoull(value, NULL, 10);
371 - else if(hash == hash_Ip6OutForwDatagrams && strcmp(name, "Ip6OutForwDatagrams") == 0) Ip6OutForwDatagrams = strtoull(value, NULL, 10);
372 - else if(hash == hash_Ip6OutRequests && strcmp(name, "Ip6OutRequests") == 0) Ip6OutRequests = strtoull(value, NULL, 10);
373 - else if(hash == hash_Ip6OutDiscards && strcmp(name, "Ip6OutDiscards") == 0) Ip6OutDiscards = strtoull(value, NULL, 10);
374 - else if(hash == hash_Ip6OutNoRoutes && strcmp(name, "Ip6OutNoRoutes") == 0) Ip6OutNoRoutes = strtoull(value, NULL, 10);
375 - else if(hash == hash_Ip6ReasmTimeout && strcmp(name, "Ip6ReasmTimeout") == 0) Ip6ReasmTimeout = strtoull(value, NULL, 10);
376 - else if(hash == hash_Ip6ReasmReqds && strcmp(name, "Ip6ReasmReqds") == 0) Ip6ReasmReqds = strtoull(value, NULL, 10);
377 - else if(hash == hash_Ip6ReasmOKs && strcmp(name, "Ip6ReasmOKs") == 0) Ip6ReasmOKs = strtoull(value, NULL, 10);
378 - else if(hash == hash_Ip6ReasmFails && strcmp(name, "Ip6ReasmFails") == 0) Ip6ReasmFails = strtoull(value, NULL, 10);
379 - else if(hash == hash_Ip6FragOKs && strcmp(name, "Ip6FragOKs") == 0) Ip6FragOKs = strtoull(value, NULL, 10);
380 - else if(hash == hash_Ip6FragFails && strcmp(name, "Ip6FragFails") == 0) Ip6FragFails = strtoull(value, NULL, 10);
381 - else if(hash == hash_Ip6FragCreates && strcmp(name, "Ip6FragCreates") == 0) Ip6FragCreates = strtoull(value, NULL, 10);
382 - else if(hash == hash_Ip6InMcastPkts && strcmp(name, "Ip6InMcastPkts") == 0) Ip6InMcastPkts = strtoull(value, NULL, 10);
383 - else if(hash == hash_Ip6OutMcastPkts && strcmp(name, "Ip6OutMcastPkts") == 0) Ip6OutMcastPkts = strtoull(value, NULL, 10);
384 - else if(hash == hash_Ip6InOctets && strcmp(name, "Ip6InOctets") == 0) Ip6InOctets = strtoull(value, NULL, 10);
385 - else if(hash == hash_Ip6OutOctets && strcmp(name, "Ip6OutOctets") == 0) Ip6OutOctets = strtoull(value, NULL, 10);
386 - else if(hash == hash_Ip6InMcastOctets && strcmp(name, "Ip6InMcastOctets") == 0) Ip6InMcastOctets = strtoull(value, NULL, 10);
387 - else if(hash == hash_Ip6OutMcastOctets && strcmp(name, "Ip6OutMcastOctets") == 0) Ip6OutMcastOctets = strtoull(value, NULL, 10);
388 - else if(hash == hash_Ip6InBcastOctets && strcmp(name, "Ip6InBcastOctets") == 0) Ip6InBcastOctets = strtoull(value, NULL, 10);
389 - else if(hash == hash_Ip6OutBcastOctets && strcmp(name, "Ip6OutBcastOctets") == 0) Ip6OutBcastOctets = strtoull(value, NULL, 10);
390 - else if(hash == hash_Ip6InNoECTPkts && strcmp(name, "Ip6InNoECTPkts") == 0) Ip6InNoECTPkts = strtoull(value, NULL, 10);
391 - else if(hash == hash_Ip6InECT1Pkts && strcmp(name, "Ip6InECT1Pkts") == 0) Ip6InECT1Pkts = strtoull(value, NULL, 10);
392 - else if(hash == hash_Ip6InECT0Pkts && strcmp(name, "Ip6InECT0Pkts") == 0) Ip6InECT0Pkts = strtoull(value, NULL, 10);
393 - else if(hash == hash_Ip6InCEPkts && strcmp(name, "Ip6InCEPkts") == 0) Ip6InCEPkts = strtoull(value, NULL, 10);
394 - else if(hash == hash_Icmp6InMsgs && strcmp(name, "Icmp6InMsgs") == 0) Icmp6InMsgs = strtoull(value, NULL, 10);
395 - else if(hash == hash_Icmp6InErrors && strcmp(name, "Icmp6InErrors") == 0) Icmp6InErrors = strtoull(value, NULL, 10);
396 - else if(hash == hash_Icmp6OutMsgs && strcmp(name, "Icmp6OutMsgs") == 0) Icmp6OutMsgs = strtoull(value, NULL, 10);
397 - else if(hash == hash_Icmp6OutErrors && strcmp(name, "Icmp6OutErrors") == 0) Icmp6OutErrors = strtoull(value, NULL, 10);
398 - else if(hash == hash_Icmp6InCsumErrors && strcmp(name, "Icmp6InCsumErrors") == 0) Icmp6InCsumErrors = strtoull(value, NULL, 10);
399 - else if(hash == hash_Icmp6InDestUnreachs && strcmp(name, "Icmp6InDestUnreachs") == 0) Icmp6InDestUnreachs = strtoull(value, NULL, 10);
400 - else if(hash == hash_Icmp6InPktTooBigs && strcmp(name, "Icmp6InPktTooBigs") == 0) Icmp6InPktTooBigs = strtoull(value, NULL, 10);
401 - else if(hash == hash_Icmp6InTimeExcds && strcmp(name, "Icmp6InTimeExcds") == 0) Icmp6InTimeExcds = strtoull(value, NULL, 10);
402 - else if(hash == hash_Icmp6InParmProblems && strcmp(name, "Icmp6InParmProblems") == 0) Icmp6InParmProblems = strtoull(value, NULL, 10);
403 - else if(hash == hash_Icmp6InEchos && strcmp(name, "Icmp6InEchos") == 0) Icmp6InEchos = strtoull(value, NULL, 10);
404 - else if(hash == hash_Icmp6InEchoReplies && strcmp(name, "Icmp6InEchoReplies") == 0) Icmp6InEchoReplies = strtoull(value, NULL, 10);
405 - else if(hash == hash_Icmp6InGroupMembQueries && strcmp(name, "Icmp6InGroupMembQueries") == 0) Icmp6InGroupMembQueries = strtoull(value, NULL, 10);
406 - else if(hash == hash_Icmp6InGroupMembResponses && strcmp(name, "Icmp6InGroupMembResponses") == 0) Icmp6InGroupMembResponses = strtoull(value, NULL, 10);
407 - else if(hash == hash_Icmp6InGroupMembReductions && strcmp(name, "Icmp6InGroupMembReductions") == 0) Icmp6InGroupMembReductions = strtoull(value, NULL, 10);
408 - else if(hash == hash_Icmp6InRouterSolicits && strcmp(name, "Icmp6InRouterSolicits") == 0) Icmp6InRouterSolicits = strtoull(value, NULL, 10);
409 - else if(hash == hash_Icmp6InRouterAdvertisements && strcmp(name, "Icmp6InRouterAdvertisements") == 0) Icmp6InRouterAdvertisements = strtoull(value, NULL, 10);
410 - else if(hash == hash_Icmp6InNeighborSolicits && strcmp(name, "Icmp6InNeighborSolicits") == 0) Icmp6InNeighborSolicits = strtoull(value, NULL, 10);
411 - else if(hash == hash_Icmp6InNeighborAdvertisements && strcmp(name, "Icmp6InNeighborAdvertisements") == 0) Icmp6InNeighborAdvertisements = strtoull(value, NULL, 10);
412 - else if(hash == hash_Icmp6InRedirects && strcmp(name, "Icmp6InRedirects") == 0) Icmp6InRedirects = strtoull(value, NULL, 10);
413 - else if(hash == hash_Icmp6InMLDv2Reports && strcmp(name, "Icmp6InMLDv2Reports") == 0) Icmp6InMLDv2Reports = strtoull(value, NULL, 10);
414 - else if(hash == hash_Icmp6OutDestUnreachs && strcmp(name, "Icmp6OutDestUnreachs") == 0) Icmp6OutDestUnreachs = strtoull(value, NULL, 10);
415 - else if(hash == hash_Icmp6OutPktTooBigs && strcmp(name, "Icmp6OutPktTooBigs") == 0) Icmp6OutPktTooBigs = strtoull(value, NULL, 10);
416 - else if(hash == hash_Icmp6OutTimeExcds && strcmp(name, "Icmp6OutTimeExcds") == 0) Icmp6OutTimeExcds = strtoull(value, NULL, 10);
417 - else if(hash == hash_Icmp6OutParmProblems && strcmp(name, "Icmp6OutParmProblems") == 0) Icmp6OutParmProblems = strtoull(value, NULL, 10);
418 - else if(hash == hash_Icmp6OutEchos && strcmp(name, "Icmp6OutEchos") == 0) Icmp6OutEchos = strtoull(value, NULL, 10);
419 - else if(hash == hash_Icmp6OutEchoReplies && strcmp(name, "Icmp6OutEchoReplies") == 0) Icmp6OutEchoReplies = strtoull(value, NULL, 10);
420 - else if(hash == hash_Icmp6OutGroupMembQueries && strcmp(name, "Icmp6OutGroupMembQueries") == 0) Icmp6OutGroupMembQueries = strtoull(value, NULL, 10);
421 - else if(hash == hash_Icmp6OutGroupMembResponses && strcmp(name, "Icmp6OutGroupMembResponses") == 0) Icmp6OutGroupMembResponses = strtoull(value, NULL, 10);
422 - else if(hash == hash_Icmp6OutGroupMembReductions && strcmp(name, "Icmp6OutGroupMembReductions") == 0) Icmp6OutGroupMembReductions = strtoull(value, NULL, 10);
423 - else if(hash == hash_Icmp6OutRouterSolicits && strcmp(name, "Icmp6OutRouterSolicits") == 0) Icmp6OutRouterSolicits = strtoull(value, NULL, 10);
424 - else if(hash == hash_Icmp6OutRouterAdvertisements && strcmp(name, "Icmp6OutRouterAdvertisements") == 0) Icmp6OutRouterAdvertisements = strtoull(value, NULL, 10);
425 - else if(hash == hash_Icmp6OutNeighborSolicits && strcmp(name, "Icmp6OutNeighborSolicits") == 0) Icmp6OutNeighborSolicits = strtoull(value, NULL, 10);
426 - else if(hash == hash_Icmp6OutNeighborAdvertisements && strcmp(name, "Icmp6OutNeighborAdvertisements") == 0) Icmp6OutNeighborAdvertisements = strtoull(value, NULL, 10);
427 - else if(hash == hash_Icmp6OutRedirects && strcmp(name, "Icmp6OutRedirects") == 0) Icmp6OutRedirects = strtoull(value, NULL, 10);
428 - else if(hash == hash_Icmp6OutMLDv2Reports && strcmp(name, "Icmp6OutMLDv2Reports") == 0) Icmp6OutMLDv2Reports = strtoull(value, NULL, 10);
429 - else if(hash == hash_Icmp6InType1 && strcmp(name, "Icmp6InType1") == 0) Icmp6InType1 = strtoull(value, NULL, 10);
430 - else if(hash == hash_Icmp6InType128 && strcmp(name, "Icmp6InType128") == 0) Icmp6InType128 = strtoull(value, NULL, 10);
431 - else if(hash == hash_Icmp6InType129 && strcmp(name, "Icmp6InType129") == 0) Icmp6InType129 = strtoull(value, NULL, 10);
432 - else if(hash == hash_Icmp6InType136 && strcmp(name, "Icmp6InType136") == 0) Icmp6InType136 = strtoull(value, NULL, 10);
433 - else if(hash == hash_Icmp6OutType1 && strcmp(name, "Icmp6OutType1") == 0) Icmp6OutType1 = strtoull(value, NULL, 10);
434 - else if(hash == hash_Icmp6OutType128 && strcmp(name, "Icmp6OutType128") == 0) Icmp6OutType128 = strtoull(value, NULL, 10);
435 - else if(hash == hash_Icmp6OutType129 && strcmp(name, "Icmp6OutType129") == 0) Icmp6OutType129 = strtoull(value, NULL, 10);
436 - else if(hash == hash_Icmp6OutType133 && strcmp(name, "Icmp6OutType133") == 0) Icmp6OutType133 = strtoull(value, NULL, 10);
437 - else if(hash == hash_Icmp6OutType135 && strcmp(name, "Icmp6OutType135") == 0) Icmp6OutType135 = strtoull(value, NULL, 10);
438 - else if(hash == hash_Icmp6OutType143 && strcmp(name, "Icmp6OutType143") == 0) Icmp6OutType143 = strtoull(value, NULL, 10);
439 - else if(hash == hash_Udp6InDatagrams && strcmp(name, "Udp6InDatagrams") == 0) Udp6InDatagrams = strtoull(value, NULL, 10);
440 - else if(hash == hash_Udp6NoPorts && strcmp(name, "Udp6NoPorts") == 0) Udp6NoPorts = strtoull(value, NULL, 10);
441 - else if(hash == hash_Udp6InErrors && strcmp(name, "Udp6InErrors") == 0) Udp6InErrors = strtoull(value, NULL, 10);
442 - else if(hash == hash_Udp6OutDatagrams && strcmp(name, "Udp6OutDatagrams") == 0) Udp6OutDatagrams = strtoull(value, NULL, 10);
443 - else if(hash == hash_Udp6RcvbufErrors && strcmp(name, "Udp6RcvbufErrors") == 0) Udp6RcvbufErrors = strtoull(value, NULL, 10);
444 - else if(hash == hash_Udp6SndbufErrors && strcmp(name, "Udp6SndbufErrors") == 0) Udp6SndbufErrors = strtoull(value, NULL, 10);
445 - else if(hash == hash_Udp6InCsumErrors && strcmp(name, "Udp6InCsumErrors") == 0) Udp6InCsumErrors = strtoull(value, NULL, 10);
446 - else if(hash == hash_Udp6IgnoredMulti && strcmp(name, "Udp6IgnoredMulti") == 0) Udp6IgnoredMulti = strtoull(value, NULL, 10);
447 - else if(hash == hash_UdpLite6InDatagrams && strcmp(name, "UdpLite6InDatagrams") == 0) UdpLite6InDatagrams = strtoull(value, NULL, 10);
448 - else if(hash == hash_UdpLite6NoPorts && strcmp(name, "UdpLite6NoPorts") == 0) UdpLite6NoPorts = strtoull(value, NULL, 10);
449 - else if(hash == hash_UdpLite6InErrors && strcmp(name, "UdpLite6InErrors") == 0) UdpLite6InErrors = strtoull(value, NULL, 10);
450 - else if(hash == hash_UdpLite6OutDatagrams && strcmp(name, "UdpLite6OutDatagrams") == 0) UdpLite6OutDatagrams = strtoull(value, NULL, 10);
451 - else if(hash == hash_UdpLite6RcvbufErrors && strcmp(name, "UdpLite6RcvbufErrors") == 0) UdpLite6RcvbufErrors = strtoull(value, NULL, 10);
452 - else if(hash == hash_UdpLite6SndbufErrors && strcmp(name, "UdpLite6SndbufErrors") == 0) UdpLite6SndbufErrors = strtoull(value, NULL, 10);
453 - else if(hash == hash_UdpLite6InCsumErrors && strcmp(name, "UdpLite6InCsumErrors") == 0) UdpLite6InCsumErrors = strtoull(value, NULL, 10);
454 - }
455 -
456 - RRDSET *st;
457 -
458 - // --------------------------------------------------------------------
459 -
460 - if(do_bandwidth == CONFIG_ONDEMAND_YES || (do_bandwidth == CONFIG_ONDEMAND_ONDEMAND && (Ip6InOctets || Ip6OutOctets))) {
461 - do_bandwidth = CONFIG_ONDEMAND_YES;
462 - st = rrdset_find("system.ipv6");
463 - if(!st) {
464 - st = rrdset_create("system", "ipv6", NULL, "network", NULL, "IPv6 Bandwidth", "kilobits/s", 500, update_every, RRDSET_TYPE_AREA);
465 -
466 - rrddim_add(st, "received", NULL, 8, 1024, RRDDIM_INCREMENTAL);
467 - rrddim_add(st, "sent", NULL, -8, 1024, RRDDIM_INCREMENTAL);
468 - }
469 - else rrdset_next(st);
470 -
471 - rrddim_set(st, "sent", Ip6OutOctets);
472 - rrddim_set(st, "received", Ip6InOctets);
473 - rrdset_done(st);
474 - }
475 -
476 - // --------------------------------------------------------------------
477 -
478 - if(do_ip_packets == CONFIG_ONDEMAND_YES || (do_ip_packets == CONFIG_ONDEMAND_ONDEMAND && (Ip6InReceives || Ip6OutRequests || Ip6InDelivers || Ip6OutForwDatagrams))) {
479 - do_ip_packets = CONFIG_ONDEMAND_YES;
480 - st = rrdset_find(RRD_TYPE_NET_SNMP6 ".packets");
481 - if(!st) {
482 - st = rrdset_create(RRD_TYPE_NET_SNMP6, "packets", NULL, "packets", NULL, "IPv6 Packets", "packets/s", 3000, update_every, RRDSET_TYPE_LINE);
483 -
484 - rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
485 - rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
486 - rrddim_add(st, "forwarded", NULL, 1, 1, RRDDIM_INCREMENTAL);
487 - rrddim_add(st, "delivers", NULL, -1, 1, RRDDIM_INCREMENTAL);
488 - }
489 - else rrdset_next(st);
490 -
491 - rrddim_set(st, "sent", Ip6OutRequests);
492 - rrddim_set(st, "received", Ip6InReceives);
493 - rrddim_set(st, "forwarded", Ip6InDelivers);
494 - rrddim_set(st, "delivers", Ip6OutForwDatagrams);
495 - rrdset_done(st);
496 - }
497 -
498 - // --------------------------------------------------------------------
499 -
500 - if(do_ip_fragsout == CONFIG_ONDEMAND_YES || (do_ip_fragsout == CONFIG_ONDEMAND_ONDEMAND && (Ip6FragOKs || Ip6FragFails || Ip6FragCreates))) {
501 - do_ip_fragsout = CONFIG_ONDEMAND_YES;
502 - st = rrdset_find(RRD_TYPE_NET_SNMP6 ".fragsout");
503 - if(!st) {
504 - st = rrdset_create(RRD_TYPE_NET_SNMP6, "fragsout", NULL, "fragments", NULL, "IPv6 Fragments Sent", "packets/s", 3010, update_every, RRDSET_TYPE_LINE);
505 - st->isdetail = 1;
506 -
507 - rrddim_add(st, "ok", NULL, 1, 1, RRDDIM_INCREMENTAL);
508 - rrddim_add(st, "failed", NULL, -1, 1, RRDDIM_INCREMENTAL);
509 - rrddim_add(st, "all", NULL, 1, 1, RRDDIM_INCREMENTAL);
510 - }
511 - else rrdset_next(st);
512 -
513 - rrddim_set(st, "ok", Ip6FragOKs);
514 - rrddim_set(st, "failed", Ip6FragFails);
515 - rrddim_set(st, "all", Ip6FragCreates);
516 - rrdset_done(st);
517 - }
518 -
519 - // --------------------------------------------------------------------
520 -
521 - if(do_ip_fragsin == CONFIG_ONDEMAND_YES || (do_ip_fragsin == CONFIG_ONDEMAND_ONDEMAND
522 - && (
523 - Ip6ReasmOKs
524 - || Ip6ReasmFails
525 - || Ip6ReasmTimeout
526 - || Ip6ReasmReqds
527 - ))) {
528 - do_ip_fragsin = CONFIG_ONDEMAND_YES;
529 - st = rrdset_find(RRD_TYPE_NET_SNMP6 ".fragsin");
530 - if(!st) {
531 - st = rrdset_create(RRD_TYPE_NET_SNMP6, "fragsin", NULL, "fragments", NULL, "IPv6 Fragments Reassembly", "packets/s", 3011, update_every, RRDSET_TYPE_LINE);
532 - st->isdetail = 1;
533 -
534 - rrddim_add(st, "ok", NULL, 1, 1, RRDDIM_INCREMENTAL);
535 - rrddim_add(st, "failed", NULL, -1, 1, RRDDIM_INCREMENTAL);
536 - rrddim_add(st, "timeout", NULL, -1, 1, RRDDIM_INCREMENTAL);
537 - rrddim_add(st, "all", NULL, 1, 1, RRDDIM_INCREMENTAL);
538 - }
539 - else rrdset_next(st);
540 -
541 - rrddim_set(st, "ok", Ip6ReasmOKs);
542 - rrddim_set(st, "failed", Ip6ReasmFails);
543 - rrddim_set(st, "timeout", Ip6ReasmTimeout);
544 - rrddim_set(st, "all", Ip6ReasmReqds);
545 - rrdset_done(st);
546 - }
547 -
548 - // --------------------------------------------------------------------
549 -
550 - if(do_ip_errors == CONFIG_ONDEMAND_YES || (do_ip_errors == CONFIG_ONDEMAND_ONDEMAND
551 - && (
552 - Ip6InDiscards
553 - || Ip6OutDiscards
554 - || Ip6InHdrErrors
555 - || Ip6InAddrErrors
556 - || Ip6InUnknownProtos
557 - || Ip6InTooBigErrors
558 - || Ip6InTruncatedPkts
559 - || Ip6InNoRoutes
560 - ))) {
561 - do_ip_errors = CONFIG_ONDEMAND_YES;
562 - st = rrdset_find(RRD_TYPE_NET_SNMP6 ".errors");
563 - if(!st) {
564 - st = rrdset_create(RRD_TYPE_NET_SNMP6, "errors", NULL, "errors", NULL, "IPv6 Errors", "packets/s", 3002, update_every, RRDSET_TYPE_LINE);
565 - st->isdetail = 1;
566 -
567 - rrddim_add(st, "InDiscards", NULL, 1, 1, RRDDIM_INCREMENTAL);
568 - rrddim_add(st, "OutDiscards", NULL, -1, 1, RRDDIM_INCREMENTAL);
569 -
570 - rrddim_add(st, "InHdrErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
571 - rrddim_add(st, "InAddrErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
572 - rrddim_add(st, "InUnknownProtos", NULL, 1, 1, RRDDIM_INCREMENTAL);
573 - rrddim_add(st, "InTooBigErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
574 - rrddim_add(st, "InTruncatedPkts", NULL, 1, 1, RRDDIM_INCREMENTAL);
575 - rrddim_add(st, "InNoRoutes", NULL, 1, 1, RRDDIM_INCREMENTAL);
576 -
577 - rrddim_add(st, "OutNoRoutes", NULL, -1, 1, RRDDIM_INCREMENTAL);
578 - }
579 - else rrdset_next(st);
580 -
581 - rrddim_set(st, "InDiscards", Ip6InDiscards);
582 - rrddim_set(st, "OutDiscards", Ip6OutDiscards);
583 -
584 - rrddim_set(st, "InHdrErrors", Ip6InHdrErrors);
585 - rrddim_set(st, "InAddrErrors", Ip6InAddrErrors);
586 - rrddim_set(st, "InUnknownProtos", Ip6InUnknownProtos);
587 - rrddim_set(st, "InTooBigErrors", Ip6InTooBigErrors);
588 - rrddim_set(st, "InTruncatedPkts", Ip6InTruncatedPkts);
589 - rrddim_set(st, "InNoRoutes", Ip6InNoRoutes);
590 -
591 - rrddim_set(st, "OutNoRoutes", Ip6OutNoRoutes);
592 - rrdset_done(st);
593 - }
594 -
595 - // --------------------------------------------------------------------
596 -
597 - if(do_udp_packets == CONFIG_ONDEMAND_YES || (do_udp_packets == CONFIG_ONDEMAND_ONDEMAND && (Udp6InDatagrams || Udp6OutDatagrams))) {
598 - do_udp_packets = CONFIG_ONDEMAND_YES;
599 - st = rrdset_find(RRD_TYPE_NET_SNMP6 ".udppackets");
600 - if(!st) {
601 - st = rrdset_create(RRD_TYPE_NET_SNMP6, "udppackets", NULL, "udp", NULL, "IPv6 UDP Packets", "packets/s", 3601, update_every, RRDSET_TYPE_LINE);
602 -
603 - rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
604 - rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
605 - }
606 - else rrdset_next(st);
607 -
608 - rrddim_set(st, "received", Udp6InDatagrams);
609 - rrddim_set(st, "sent", Udp6OutDatagrams);
610 - rrdset_done(st);
611 - }
612 -
613 - // --------------------------------------------------------------------
614 -
615 - if(do_udp_errors == CONFIG_ONDEMAND_YES || (do_udp_errors == CONFIG_ONDEMAND_ONDEMAND
616 - && (
617 - Udp6InErrors
618 - || Udp6NoPorts
619 - || Udp6RcvbufErrors
620 - || Udp6SndbufErrors
621 - || Udp6InCsumErrors
622 - || Udp6IgnoredMulti
623 - ))) {
624 - do_udp_errors = CONFIG_ONDEMAND_YES;
625 - st = rrdset_find(RRD_TYPE_NET_SNMP6 ".udperrors");
626 - if(!st) {
627 - st = rrdset_create(RRD_TYPE_NET_SNMP6, "udperrors", NULL, "udp", NULL, "IPv6 UDP Errors", "events/s", 3701, update_every, RRDSET_TYPE_LINE);
628 - st->isdetail = 1;
629 -
630 - rrddim_add(st, "RcvbufErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
631 - rrddim_add(st, "SndbufErrors", NULL, -1, 1, RRDDIM_INCREMENTAL);
632 - rrddim_add(st, "InErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
633 - rrddim_add(st, "NoPorts", NULL, 1, 1, RRDDIM_INCREMENTAL);
634 - rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
635 - rrddim_add(st, "IgnoredMulti", NULL, 1, 1, RRDDIM_INCREMENTAL);
636 - }
637 - else rrdset_next(st);
638 -
639 - rrddim_set(st, "InErrors", Udp6InErrors);
640 - rrddim_set(st, "NoPorts", Udp6NoPorts);
641 - rrddim_set(st, "RcvbufErrors", Udp6RcvbufErrors);
642 - rrddim_set(st, "SndbufErrors", Udp6SndbufErrors);
643 - rrddim_set(st, "InCsumErrors", Udp6InCsumErrors);
644 - rrddim_set(st, "IgnoredMulti", Udp6IgnoredMulti);
645 - rrdset_done(st);
646 - }
647 -
648 - // --------------------------------------------------------------------
649 -
650 - if(do_udplite_packets == CONFIG_ONDEMAND_YES || (do_udplite_packets == CONFIG_ONDEMAND_ONDEMAND && (UdpLite6InDatagrams || UdpLite6OutDatagrams))) {
651 - do_udplite_packets = CONFIG_ONDEMAND_YES;
652 - st = rrdset_find(RRD_TYPE_NET_SNMP6 ".udplitepackets");
653 - if(!st) {
654 - st = rrdset_create(RRD_TYPE_NET_SNMP6, "udplitepackets", NULL, "udplite", NULL, "IPv6 UDPlite Packets", "packets/s", 3601, update_every, RRDSET_TYPE_LINE);
655 -
656 - rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
657 - rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
658 - }
659 - else rrdset_next(st);
660 -
661 - rrddim_set(st, "received", UdpLite6InDatagrams);
662 - rrddim_set(st, "sent", UdpLite6OutDatagrams);
663 - rrdset_done(st);
664 - }
665 -
666 - // --------------------------------------------------------------------
667 -
668 - if(do_udplite_errors == CONFIG_ONDEMAND_YES || (do_udplite_errors == CONFIG_ONDEMAND_ONDEMAND
669 - && (
670 - UdpLite6InErrors
671 - || UdpLite6NoPorts
672 - || UdpLite6RcvbufErrors
673 - || UdpLite6SndbufErrors
674 - || Udp6InCsumErrors
675 - || UdpLite6InCsumErrors
676 - ))) {
677 - do_udplite_errors = CONFIG_ONDEMAND_YES;
678 - st = rrdset_find(RRD_TYPE_NET_SNMP6 ".udpliteerrors");
679 - if(!st) {
680 - st = rrdset_create(RRD_TYPE_NET_SNMP6, "udpliteerrors", NULL, "udplite", NULL, "IPv6 UDP Lite Errors", "events/s", 3701, update_every, RRDSET_TYPE_LINE);
681 - st->isdetail = 1;
682 -
683 - rrddim_add(st, "RcvbufErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
684 - rrddim_add(st, "SndbufErrors", NULL, -1, 1, RRDDIM_INCREMENTAL);
685 - rrddim_add(st, "InErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
686 - rrddim_add(st, "NoPorts", NULL, 1, 1, RRDDIM_INCREMENTAL);
687 - rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
688 - }
689 - else rrdset_next(st);
690 -
691 - rrddim_set(st, "InErrors", UdpLite6InErrors);
692 - rrddim_set(st, "NoPorts", UdpLite6NoPorts);
693 - rrddim_set(st, "RcvbufErrors", UdpLite6RcvbufErrors);
694 - rrddim_set(st, "SndbufErrors", UdpLite6SndbufErrors);
695 - rrddim_set(st, "InCsumErrors", UdpLite6InCsumErrors);
696 - rrdset_done(st);
697 - }
698 -
699 - // --------------------------------------------------------------------
700 -
701 - if(do_mcast == CONFIG_ONDEMAND_YES || (do_mcast == CONFIG_ONDEMAND_ONDEMAND && (Ip6OutMcastOctets || Ip6InMcastOctets))) {
702 - do_mcast = CONFIG_ONDEMAND_YES;
703 - st = rrdset_find(RRD_TYPE_NET_SNMP6 ".mcast");
704 - if(!st) {
705 - st = rrdset_create(RRD_TYPE_NET_SNMP6, "mcast", NULL, "multicast", NULL, "IPv6 Multicast Bandwidth", "kilobits/s", 9000, update_every, RRDSET_TYPE_AREA);
706 - st->isdetail = 1;
707 -
708 - rrddim_add(st, "received", NULL, 8, 1024, RRDDIM_INCREMENTAL);
709 - rrddim_add(st, "sent", NULL, -8, 1024, RRDDIM_INCREMENTAL);
710 - }
711 - else rrdset_next(st);
712 -
713 - rrddim_set(st, "sent", Ip6OutMcastOctets);
714 - rrddim_set(st, "received", Ip6InMcastOctets);
715 - rrdset_done(st);
716 - }
717 -
718 - // --------------------------------------------------------------------
719 -
720 - if(do_bcast == CONFIG_ONDEMAND_YES || (do_bcast == CONFIG_ONDEMAND_ONDEMAND && (Ip6OutBcastOctets || Ip6InBcastOctets))) {
721 - do_bcast = CONFIG_ONDEMAND_YES;
722 - st = rrdset_find(RRD_TYPE_NET_SNMP6 ".bcast");
723 - if(!st) {
724 - st = rrdset_create(RRD_TYPE_NET_SNMP6, "bcast", NULL, "broadcast", NULL, "IPv6 Broadcast Bandwidth", "kilobits/s", 8000, update_every, RRDSET_TYPE_AREA);
725 - st->isdetail = 1;
726 -
727 - rrddim_add(st, "received", NULL, 8, 1024, RRDDIM_INCREMENTAL);
728 - rrddim_add(st, "sent", NULL, -8, 1024, RRDDIM_INCREMENTAL);
729 - }
730 - else rrdset_next(st);
731 -
732 - rrddim_set(st, "sent", Ip6OutBcastOctets);
733 - rrddim_set(st, "received", Ip6InBcastOctets);
734 - rrdset_done(st);
735 - }
736 -
737 - // --------------------------------------------------------------------
738 -
739 - if(do_mcast_p == CONFIG_ONDEMAND_YES || (do_mcast_p == CONFIG_ONDEMAND_ONDEMAND && (Ip6OutMcastPkts || Ip6InMcastPkts))) {
740 - do_mcast_p = CONFIG_ONDEMAND_YES;
741 - st = rrdset_find(RRD_TYPE_NET_SNMP6 ".mcastpkts");
742 - if(!st) {
743 - st = rrdset_create(RRD_TYPE_NET_SNMP6, "mcastpkts", NULL, "multicast", NULL, "IPv6 Multicast Packets", "packets/s", 9500, update_every, RRDSET_TYPE_LINE);
744 - st->isdetail = 1;
745 -
746 - rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
747 - rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
748 - }
749 - else rrdset_next(st);
750 -
751 - rrddim_set(st, "sent", Ip6OutMcastPkts);
752 - rrddim_set(st, "received", Ip6InMcastPkts);
753 - rrdset_done(st);
754 - }
755 -
756 - // --------------------------------------------------------------------
757 -
758 - if(do_icmp == CONFIG_ONDEMAND_YES || (do_icmp == CONFIG_ONDEMAND_ONDEMAND && (Icmp6InMsgs || Icmp6OutMsgs))) {
759 - do_icmp = CONFIG_ONDEMAND_YES;
760 - st = rrdset_find(RRD_TYPE_NET_SNMP6 ".icmp");
761 - if(!st) {
762 - st = rrdset_create(RRD_TYPE_NET_SNMP6, "icmp", NULL, "icmp", NULL, "IPv6 ICMP Messages", "messages/s", 10000, update_every, RRDSET_TYPE_LINE);
763 -
764 - rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
765 - rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
766 - }
767 - else rrdset_next(st);
768 -
769 - rrddim_set(st, "sent", Icmp6InMsgs);
770 - rrddim_set(st, "received", Icmp6OutMsgs);
771 - rrdset_done(st);
772 - }
773 -
774 - // --------------------------------------------------------------------
775 -
776 - if(do_icmp_redir == CONFIG_ONDEMAND_YES || (do_icmp_redir == CONFIG_ONDEMAND_ONDEMAND && (Icmp6InRedirects || Icmp6OutRedirects))) {
777 - do_icmp_redir = CONFIG_ONDEMAND_YES;
778 - st = rrdset_find(RRD_TYPE_NET_SNMP6 ".icmpredir");
779 - if(!st) {
780 - st = rrdset_create(RRD_TYPE_NET_SNMP6, "icmpredir", NULL, "icmp", NULL, "IPv6 ICMP Redirects", "redirects/s", 10050, update_every, RRDSET_TYPE_LINE);
781 -
782 - rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
783 - rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
784 - }
785 - else rrdset_next(st);
786 -
787 - rrddim_set(st, "sent", Icmp6InRedirects);
788 - rrddim_set(st, "received", Icmp6OutRedirects);
789 - rrdset_done(st);
790 - }
791 -
792 - // --------------------------------------------------------------------
793 -
794 - if(do_icmp_errors == CONFIG_ONDEMAND_YES || (do_icmp_errors == CONFIG_ONDEMAND_ONDEMAND
795 - && (
796 - Icmp6InErrors
797 - || Icmp6OutErrors
798 - || Icmp6InCsumErrors
799 - || Icmp6InDestUnreachs
800 - || Icmp6InPktTooBigs
801 - || Icmp6InTimeExcds
802 - || Icmp6InParmProblems
803 - || Icmp6OutDestUnreachs
804 - || Icmp6OutPktTooBigs
805 - || Icmp6OutTimeExcds
806 - || Icmp6OutParmProblems
807 - ))) {
808 - do_icmp_errors = CONFIG_ONDEMAND_YES;
809 - st = rrdset_find(RRD_TYPE_NET_SNMP6 ".icmperrors");
810 - if(!st) {
811 - st = rrdset_create(RRD_TYPE_NET_SNMP6, "icmperrors", NULL, "icmp", NULL, "IPv6 ICMP Errors", "errors/s", 10100, update_every, RRDSET_TYPE_LINE);
812 -
813 - rrddim_add(st, "InErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
814 - rrddim_add(st, "OutErrors", NULL, -1, 1, RRDDIM_INCREMENTAL);
815 -
816 - rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
817 - rrddim_add(st, "InDestUnreachs", NULL, 1, 1, RRDDIM_INCREMENTAL);
818 - rrddim_add(st, "InPktTooBigs", NULL, 1, 1, RRDDIM_INCREMENTAL);
819 - rrddim_add(st, "InTimeExcds", NULL, 1, 1, RRDDIM_INCREMENTAL);
820 - rrddim_add(st, "InParmProblems", NULL, 1, 1, RRDDIM_INCREMENTAL);
821 - rrddim_add(st, "OutDestUnreachs", NULL, -1, 1, RRDDIM_INCREMENTAL);
822 - rrddim_add(st, "OutPktTooBigs", NULL, -1, 1, RRDDIM_INCREMENTAL);
823 - rrddim_add(st, "OutTimeExcds", NULL, -1, 1, RRDDIM_INCREMENTAL);
824 - rrddim_add(st, "OutParmProblems", NULL, -1, 1, RRDDIM_INCREMENTAL);
825 - }
826 - else rrdset_next(st);
827 -
828 - rrddim_set(st, "InErrors", Icmp6InErrors);
829 - rrddim_set(st, "OutErrors", Icmp6OutErrors);
830 - rrddim_set(st, "InCsumErrors", Icmp6InCsumErrors);
831 - rrddim_set(st, "InDestUnreachs", Icmp6InDestUnreachs);
832 - rrddim_set(st, "InPktTooBigs", Icmp6InPktTooBigs);
833 - rrddim_set(st, "InTimeExcds", Icmp6InTimeExcds);
834 - rrddim_set(st, "InParmProblems", Icmp6InParmProblems);
835 - rrddim_set(st, "OutDestUnreachs", Icmp6OutDestUnreachs);
836 - rrddim_set(st, "OutPktTooBigs", Icmp6OutPktTooBigs);
837 - rrddim_set(st, "OutTimeExcds", Icmp6OutTimeExcds);
838 - rrddim_set(st, "OutParmProblems", Icmp6OutParmProblems);
839 - rrdset_done(st);
840 - }
841 -
842 - // --------------------------------------------------------------------
843 -
844 - if(do_icmp_echos == CONFIG_ONDEMAND_YES || (do_icmp_echos == CONFIG_ONDEMAND_ONDEMAND
845 - && (
846 - Icmp6InEchos
847 - || Icmp6OutEchos
848 - || Icmp6InEchoReplies
849 - || Icmp6OutEchoReplies
850 - ))) {
851 - do_icmp_echos = CONFIG_ONDEMAND_YES;
852 - st = rrdset_find(RRD_TYPE_NET_SNMP6 ".icmpechos");
853 - if(!st) {
854 - st = rrdset_create(RRD_TYPE_NET_SNMP6, "icmpechos", NULL, "icmp", NULL, "IPv6 ICMP Echo", "messages/s", 10200, update_every, RRDSET_TYPE_LINE);
855 -
856 - rrddim_add(st, "InEchos", NULL, 1, 1, RRDDIM_INCREMENTAL);
857 - rrddim_add(st, "OutEchos", NULL, -1, 1, RRDDIM_INCREMENTAL);
858 - rrddim_add(st, "InEchoReplies", NULL, 1, 1, RRDDIM_INCREMENTAL);
859 - rrddim_add(st, "OutEchoReplies", NULL, -1, 1, RRDDIM_INCREMENTAL);
860 - }
861 - else rrdset_next(st);
862 -
863 - rrddim_set(st, "InEchos", Icmp6InEchos);
864 - rrddim_set(st, "OutEchos", Icmp6OutEchos);
865 - rrddim_set(st, "InEchoReplies", Icmp6InEchoReplies);
866 - rrddim_set(st, "OutEchoReplies", Icmp6OutEchoReplies);
867 - rrdset_done(st);
868 - }
869 -
870 - // --------------------------------------------------------------------
871 -
872 - if(do_icmp_groupmemb == CONFIG_ONDEMAND_YES || (do_icmp_groupmemb == CONFIG_ONDEMAND_ONDEMAND
873 - && (
874 - Icmp6InGroupMembQueries
875 - || Icmp6OutGroupMembQueries
876 - || Icmp6InGroupMembResponses
877 - || Icmp6OutGroupMembResponses
878 - || Icmp6InGroupMembReductions
879 - || Icmp6OutGroupMembReductions
880 - ))) {
881 - do_icmp_groupmemb = CONFIG_ONDEMAND_YES;
882 - st = rrdset_find(RRD_TYPE_NET_SNMP6 ".groupmemb");
883 - if(!st) {
884 - st = rrdset_create(RRD_TYPE_NET_SNMP6, "groupmemb", NULL, "icmp", NULL, "IPv6 ICMP Group Membership", "messages/s", 10300, update_every, RRDSET_TYPE_LINE);
885 -
886 - rrddim_add(st, "InQueries", NULL, 1, 1, RRDDIM_INCREMENTAL);
887 - rrddim_add(st, "OutQueries", NULL, -1, 1, RRDDIM_INCREMENTAL);
888 - rrddim_add(st, "InResponses", NULL, 1, 1, RRDDIM_INCREMENTAL);
889 - rrddim_add(st, "OutResponses", NULL, -1, 1, RRDDIM_INCREMENTAL);
890 - rrddim_add(st, "InReductions", NULL, 1, 1, RRDDIM_INCREMENTAL);
891 - rrddim_add(st, "OutReductions", NULL, -1, 1, RRDDIM_INCREMENTAL);
892 - }
893 - else rrdset_next(st);
894 -
895 - rrddim_set(st, "InQueries", Icmp6InGroupMembQueries);
896 - rrddim_set(st, "OutQueries", Icmp6OutGroupMembQueries);
897 - rrddim_set(st, "InResponses", Icmp6InGroupMembResponses);
898 - rrddim_set(st, "OutResponses", Icmp6OutGroupMembResponses);
899 - rrddim_set(st, "InReductions", Icmp6InGroupMembReductions);
900 - rrddim_set(st, "OutReductions", Icmp6OutGroupMembReductions);
901 - rrdset_done(st);
902 - }
903 -
904 - // --------------------------------------------------------------------
905 -
906 - if(do_icmp_router == CONFIG_ONDEMAND_YES || (do_icmp_router == CONFIG_ONDEMAND_ONDEMAND
907 - && (
908 - Icmp6InRouterSolicits
909 - || Icmp6OutRouterSolicits
910 - || Icmp6InRouterAdvertisements
911 - || Icmp6OutRouterAdvertisements
912 - ))) {
913 - do_icmp_router = CONFIG_ONDEMAND_YES;
914 - st = rrdset_find(RRD_TYPE_NET_SNMP6 ".icmprouter");
915 - if(!st) {
916 - st = rrdset_create(RRD_TYPE_NET_SNMP6, "icmprouter", NULL, "icmp", NULL, "IPv6 Router Messages", "messages/s", 10400, update_every, RRDSET_TYPE_LINE);
917 -
918 - rrddim_add(st, "InSolicits", NULL, 1, 1, RRDDIM_INCREMENTAL);
919 - rrddim_add(st, "OutSolicits", NULL, -1, 1, RRDDIM_INCREMENTAL);
920 - rrddim_add(st, "InAdvertisements", NULL, 1, 1, RRDDIM_INCREMENTAL);
921 - rrddim_add(st, "OutAdvertisements", NULL, -1, 1, RRDDIM_INCREMENTAL);
922 - }
923 - else rrdset_next(st);
924 -
925 - rrddim_set(st, "InSolicits", Icmp6InRouterSolicits);
926 - rrddim_set(st, "OutSolicits", Icmp6OutRouterSolicits);
927 - rrddim_set(st, "InAdvertisements", Icmp6InRouterAdvertisements);
928 - rrddim_set(st, "OutAdvertisements", Icmp6OutRouterAdvertisements);
929 - rrdset_done(st);
930 - }
931 -
932 - // --------------------------------------------------------------------
933 -
934 - if(do_icmp_neighbor == CONFIG_ONDEMAND_YES || (do_icmp_neighbor == CONFIG_ONDEMAND_ONDEMAND
935 - && (
936 - Icmp6InNeighborSolicits
937 - || Icmp6OutNeighborSolicits
938 - || Icmp6InNeighborAdvertisements
939 - || Icmp6OutNeighborAdvertisements
940 - ))) {
941 - do_icmp_neighbor = CONFIG_ONDEMAND_YES;
942 - st = rrdset_find(RRD_TYPE_NET_SNMP6 ".icmpneighbor");
943 - if(!st) {
944 - st = rrdset_create(RRD_TYPE_NET_SNMP6, "icmpneighbor", NULL, "icmp", NULL, "IPv6 Neighbor Messages", "messages/s", 10500, update_every, RRDSET_TYPE_LINE);
945 -
946 - rrddim_add(st, "InSolicits", NULL, 1, 1, RRDDIM_INCREMENTAL);
947 - rrddim_add(st, "OutSolicits", NULL, -1, 1, RRDDIM_INCREMENTAL);
948 - rrddim_add(st, "InAdvertisements", NULL, 1, 1, RRDDIM_INCREMENTAL);
949 - rrddim_add(st, "OutAdvertisements", NULL, -1, 1, RRDDIM_INCREMENTAL);
950 - }
951 - else rrdset_next(st);
952 -
953 - rrddim_set(st, "InSolicits", Icmp6InNeighborSolicits);
954 - rrddim_set(st, "OutSolicits", Icmp6OutNeighborSolicits);
955 - rrddim_set(st, "InAdvertisements", Icmp6InNeighborAdvertisements);
956 - rrddim_set(st, "OutAdvertisements", Icmp6OutNeighborAdvertisements);
957 - rrdset_done(st);
958 - }
959 -
960 - // --------------------------------------------------------------------
961 -
962 - if(do_icmp_mldv2 == CONFIG_ONDEMAND_YES || (do_icmp_mldv2 == CONFIG_ONDEMAND_ONDEMAND && (Icmp6InMLDv2Reports || Icmp6OutMLDv2Reports))) {
963 - do_icmp_mldv2 = CONFIG_ONDEMAND_YES;
964 - st = rrdset_find(RRD_TYPE_NET_SNMP6 ".icmpmldv2");
965 - if(!st) {
966 - st = rrdset_create(RRD_TYPE_NET_SNMP6, "icmpmldv2", NULL, "icmp", NULL, "IPv6 ICMP MLDv2 Reports", "reports/s", 10600, update_every, RRDSET_TYPE_LINE);
967 -
968 - rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
969 - rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
970 - }
971 - else rrdset_next(st);
972 -
973 - rrddim_set(st, "sent", Icmp6InMLDv2Reports);
974 - rrddim_set(st, "received", Icmp6OutMLDv2Reports);
975 - rrdset_done(st);
976 - }
977 -
978 - // --------------------------------------------------------------------
979 -
980 - if(do_icmp_types == CONFIG_ONDEMAND_YES || (do_icmp_types == CONFIG_ONDEMAND_ONDEMAND
981 - && (
982 - Icmp6InType1
983 - || Icmp6InType128
984 - || Icmp6InType129
985 - || Icmp6InType136
986 - || Icmp6OutType1
987 - || Icmp6OutType128
988 - || Icmp6OutType129
989 - || Icmp6OutType133
990 - || Icmp6OutType135
991 - || Icmp6OutType143
992 - ))) {
993 - do_icmp_types = CONFIG_ONDEMAND_YES;
994 - st = rrdset_find(RRD_TYPE_NET_SNMP6 ".icmptypes");
995 - if(!st) {
996 - st = rrdset_create(RRD_TYPE_NET_SNMP6, "icmptypes", NULL, "icmp", NULL, "IPv6 ICMP Types", "messages/s", 10700, update_every, RRDSET_TYPE_LINE);
997 -
998 - rrddim_add(st, "InType1", NULL, 1, 1, RRDDIM_INCREMENTAL);
999 - rrddim_add(st, "InType128", NULL, 1, 1, RRDDIM_INCREMENTAL);
1000 - rrddim_add(st, "InType129", NULL, 1, 1, RRDDIM_INCREMENTAL);
1001 - rrddim_add(st, "InType136", NULL, 1, 1, RRDDIM_INCREMENTAL);
1002 - rrddim_add(st, "OutType1", NULL, -1, 1, RRDDIM_INCREMENTAL);
1003 - rrddim_add(st, "OutType128", NULL, -1, 1, RRDDIM_INCREMENTAL);
1004 - rrddim_add(st, "OutType129", NULL, -1, 1, RRDDIM_INCREMENTAL);
1005 - rrddim_add(st, "OutType133", NULL, -1, 1, RRDDIM_INCREMENTAL);
1006 - rrddim_add(st, "OutType135", NULL, -1, 1, RRDDIM_INCREMENTAL);
1007 - rrddim_add(st, "OutType143", NULL, -1, 1, RRDDIM_INCREMENTAL);
1008 - }
1009 - else rrdset_next(st);
1010 -
1011 - rrddim_set(st, "InType1", Icmp6InType1);
1012 - rrddim_set(st, "InType128", Icmp6InType128);
1013 - rrddim_set(st, "InType129", Icmp6InType129);
1014 - rrddim_set(st, "InType136", Icmp6InType136);
1015 - rrddim_set(st, "OutType1", Icmp6OutType1);
1016 - rrddim_set(st, "OutType128", Icmp6OutType128);
1017 - rrddim_set(st, "OutType129", Icmp6OutType129);
1018 - rrddim_set(st, "OutType133", Icmp6OutType133);
1019 - rrddim_set(st, "OutType135", Icmp6OutType135);
1020 - rrddim_set(st, "OutType143", Icmp6OutType143);
1021 - rrdset_done(st);
1022 - }
1023 -
1024 - // --------------------------------------------------------------------
1025 -
1026 - if(do_ect == CONFIG_ONDEMAND_YES || (do_ect == CONFIG_ONDEMAND_ONDEMAND
1027 - && (
1028 - Ip6InNoECTPkts
1029 - || Ip6InECT1Pkts
1030 - || Ip6InECT0Pkts
1031 - || Ip6InCEPkts
1032 - ))) {
1033 - do_ect = CONFIG_ONDEMAND_YES;
1034 - st = rrdset_find(RRD_TYPE_NET_SNMP6 ".ect");
1035 - if(!st) {
1036 - st = rrdset_create(RRD_TYPE_NET_SNMP6, "ect", NULL, "packets", NULL, "IPv6 ECT Packets", "packets/s", 10800, update_every, RRDSET_TYPE_LINE);
1037 -
1038 - rrddim_add(st, "InNoECTPkts", NULL, 1, 1, RRDDIM_INCREMENTAL);
1039 - rrddim_add(st, "InECT1Pkts", NULL, 1, 1, RRDDIM_INCREMENTAL);
1040 - rrddim_add(st, "InECT0Pkts", NULL, 1, 1, RRDDIM_INCREMENTAL);
1041 - rrddim_add(st, "InCEPkts", NULL, 1, 1, RRDDIM_INCREMENTAL);
1042 - }
1043 - else rrdset_next(st);
1044 -
1045 - rrddim_set(st, "InNoECTPkts", Ip6InNoECTPkts);
1046 - rrddim_set(st, "InECT1Pkts", Ip6InECT1Pkts);
1047 - rrddim_set(st, "InECT0Pkts", Ip6InECT0Pkts);
1048 - rrddim_set(st, "InCEPkts", Ip6InCEPkts);
1049 - rrdset_done(st);
1050 - }
1051 -
1052 - return 0;
7 + static procfile *ff = NULL;
8 + static int gen_hashes = -1;
9 +
10 + static int do_ip_packets = -1, do_ip_fragsout = -1, do_ip_fragsin = -1, do_ip_errors = -1,
11 + do_udplite_packets = -1, do_udplite_errors = -1,
12 + do_udp_packets = -1, do_udp_errors = -1,
13 + do_bandwidth = -1, do_mcast = -1, do_bcast = -1, do_mcast_p = -1,
14 + do_icmp = -1, do_icmp_redir = -1, do_icmp_errors = -1, do_icmp_echos = -1, do_icmp_groupmemb = -1,
15 + do_icmp_router = -1, do_icmp_neighbor = -1, do_icmp_mldv2 = -1, do_icmp_types = -1, do_ect = -1;
16 +
17 + static uint32_t hash_Ip6InReceives = -1;
18 +
19 + static uint32_t hash_Ip6InHdrErrors = -1;
20 + static uint32_t hash_Ip6InTooBigErrors = -1;
21 + static uint32_t hash_Ip6InNoRoutes = -1;
22 + static uint32_t hash_Ip6InAddrErrors = -1;
23 + static uint32_t hash_Ip6InUnknownProtos = -1;
24 + static uint32_t hash_Ip6InTruncatedPkts = -1;
25 + static uint32_t hash_Ip6InDiscards = -1;
26 + static uint32_t hash_Ip6InDelivers = -1;
27 +
28 + static uint32_t hash_Ip6OutForwDatagrams = -1;
29 + static uint32_t hash_Ip6OutRequests = -1;
30 + static uint32_t hash_Ip6OutDiscards = -1;
31 + static uint32_t hash_Ip6OutNoRoutes = -1;
32 +
33 + static uint32_t hash_Ip6ReasmTimeout = -1;
34 + static uint32_t hash_Ip6ReasmReqds = -1;
35 + static uint32_t hash_Ip6ReasmOKs = -1;
36 + static uint32_t hash_Ip6ReasmFails = -1;
37 +
38 + static uint32_t hash_Ip6FragOKs = -1;
39 + static uint32_t hash_Ip6FragFails = -1;
40 + static uint32_t hash_Ip6FragCreates = -1;
41 +
42 + static uint32_t hash_Ip6InMcastPkts = -1;
43 + static uint32_t hash_Ip6OutMcastPkts = -1;
44 +
45 + static uint32_t hash_Ip6InOctets = -1;
46 + static uint32_t hash_Ip6OutOctets = -1;
47 +
48 + static uint32_t hash_Ip6InMcastOctets = -1;
49 + static uint32_t hash_Ip6OutMcastOctets = -1;
50 + static uint32_t hash_Ip6InBcastOctets = -1;
51 + static uint32_t hash_Ip6OutBcastOctets = -1;
52 +
53 + static uint32_t hash_Ip6InNoECTPkts = -1;
54 + static uint32_t hash_Ip6InECT1Pkts = -1;
55 + static uint32_t hash_Ip6InECT0Pkts = -1;
56 + static uint32_t hash_Ip6InCEPkts = -1;
57 +
58 + static uint32_t hash_Icmp6InMsgs = -1;
59 + static uint32_t hash_Icmp6InErrors = -1;
60 + static uint32_t hash_Icmp6OutMsgs = -1;
61 + static uint32_t hash_Icmp6OutErrors = -1;
62 + static uint32_t hash_Icmp6InCsumErrors = -1;
63 + static uint32_t hash_Icmp6InDestUnreachs = -1;
64 + static uint32_t hash_Icmp6InPktTooBigs = -1;
65 + static uint32_t hash_Icmp6InTimeExcds = -1;
66 + static uint32_t hash_Icmp6InParmProblems = -1;
67 + static uint32_t hash_Icmp6InEchos = -1;
68 + static uint32_t hash_Icmp6InEchoReplies = -1;
69 + static uint32_t hash_Icmp6InGroupMembQueries = -1;
70 + static uint32_t hash_Icmp6InGroupMembResponses = -1;
71 + static uint32_t hash_Icmp6InGroupMembReductions = -1;
72 + static uint32_t hash_Icmp6InRouterSolicits = -1;
73 + static uint32_t hash_Icmp6InRouterAdvertisements = -1;
74 + static uint32_t hash_Icmp6InNeighborSolicits = -1;
75 + static uint32_t hash_Icmp6InNeighborAdvertisements = -1;
76 + static uint32_t hash_Icmp6InRedirects = -1;
77 + static uint32_t hash_Icmp6InMLDv2Reports = -1;
78 + static uint32_t hash_Icmp6OutDestUnreachs = -1;
79 + static uint32_t hash_Icmp6OutPktTooBigs = -1;
80 + static uint32_t hash_Icmp6OutTimeExcds = -1;
81 + static uint32_t hash_Icmp6OutParmProblems = -1;
82 + static uint32_t hash_Icmp6OutEchos = -1;
83 + static uint32_t hash_Icmp6OutEchoReplies = -1;
84 + static uint32_t hash_Icmp6OutGroupMembQueries = -1;
85 + static uint32_t hash_Icmp6OutGroupMembResponses = -1;
86 + static uint32_t hash_Icmp6OutGroupMembReductions = -1;
87 + static uint32_t hash_Icmp6OutRouterSolicits = -1;
88 + static uint32_t hash_Icmp6OutRouterAdvertisements = -1;
89 + static uint32_t hash_Icmp6OutNeighborSolicits = -1;
90 + static uint32_t hash_Icmp6OutNeighborAdvertisements = -1;
91 + static uint32_t hash_Icmp6OutRedirects = -1;
92 + static uint32_t hash_Icmp6OutMLDv2Reports = -1;
93 + static uint32_t hash_Icmp6InType1 = -1;
94 + static uint32_t hash_Icmp6InType128 = -1;
95 + static uint32_t hash_Icmp6InType129 = -1;
96 + static uint32_t hash_Icmp6InType136 = -1;
97 + static uint32_t hash_Icmp6OutType1 = -1;
98 + static uint32_t hash_Icmp6OutType128 = -1;
99 + static uint32_t hash_Icmp6OutType129 = -1;
100 + static uint32_t hash_Icmp6OutType133 = -1;
101 + static uint32_t hash_Icmp6OutType135 = -1;
102 + static uint32_t hash_Icmp6OutType143 = -1;
103 +
104 + static uint32_t hash_Udp6InDatagrams = -1;
105 + static uint32_t hash_Udp6NoPorts = -1;
106 + static uint32_t hash_Udp6InErrors = -1;
107 + static uint32_t hash_Udp6OutDatagrams = -1;
108 + static uint32_t hash_Udp6RcvbufErrors = -1;
109 + static uint32_t hash_Udp6SndbufErrors = -1;
110 + static uint32_t hash_Udp6InCsumErrors = -1;
111 + static uint32_t hash_Udp6IgnoredMulti = -1;
112 +
113 + static uint32_t hash_UdpLite6InDatagrams = -1;
114 + static uint32_t hash_UdpLite6NoPorts = -1;
115 + static uint32_t hash_UdpLite6InErrors = -1;
116 + static uint32_t hash_UdpLite6OutDatagrams = -1;
117 + static uint32_t hash_UdpLite6RcvbufErrors = -1;
118 + static uint32_t hash_UdpLite6SndbufErrors = -1;
119 + static uint32_t hash_UdpLite6InCsumErrors = -1;
120 +
121 + if(gen_hashes != 1) {
122 + gen_hashes = 1;
123 + hash_Ip6InReceives = simple_hash("Ip6InReceives");
124 + hash_Ip6InHdrErrors = simple_hash("Ip6InHdrErrors");
125 + hash_Ip6InTooBigErrors = simple_hash("Ip6InTooBigErrors");
126 + hash_Ip6InNoRoutes = simple_hash("Ip6InNoRoutes");
127 + hash_Ip6InAddrErrors = simple_hash("Ip6InAddrErrors");
128 + hash_Ip6InUnknownProtos = simple_hash("Ip6InUnknownProtos");
129 + hash_Ip6InTruncatedPkts = simple_hash("Ip6InTruncatedPkts");
130 + hash_Ip6InDiscards = simple_hash("Ip6InDiscards");
131 + hash_Ip6InDelivers = simple_hash("Ip6InDelivers");
132 + hash_Ip6OutForwDatagrams = simple_hash("Ip6OutForwDatagrams");
133 + hash_Ip6OutRequests = simple_hash("Ip6OutRequests");
134 + hash_Ip6OutDiscards = simple_hash("Ip6OutDiscards");
135 + hash_Ip6OutNoRoutes = simple_hash("Ip6OutNoRoutes");
136 + hash_Ip6ReasmTimeout = simple_hash("Ip6ReasmTimeout");
137 + hash_Ip6ReasmReqds = simple_hash("Ip6ReasmReqds");
138 + hash_Ip6ReasmOKs = simple_hash("Ip6ReasmOKs");
139 + hash_Ip6ReasmFails = simple_hash("Ip6ReasmFails");
140 + hash_Ip6FragOKs = simple_hash("Ip6FragOKs");
141 + hash_Ip6FragFails = simple_hash("Ip6FragFails");
142 + hash_Ip6FragCreates = simple_hash("Ip6FragCreates");
143 + hash_Ip6InMcastPkts = simple_hash("Ip6InMcastPkts");
144 + hash_Ip6OutMcastPkts = simple_hash("Ip6OutMcastPkts");
145 + hash_Ip6InOctets = simple_hash("Ip6InOctets");
146 + hash_Ip6OutOctets = simple_hash("Ip6OutOctets");
147 + hash_Ip6InMcastOctets = simple_hash("Ip6InMcastOctets");
148 + hash_Ip6OutMcastOctets = simple_hash("Ip6OutMcastOctets");
149 + hash_Ip6InBcastOctets = simple_hash("Ip6InBcastOctets");
150 + hash_Ip6OutBcastOctets = simple_hash("Ip6OutBcastOctets");
151 + hash_Ip6InNoECTPkts = simple_hash("Ip6InNoECTPkts");
152 + hash_Ip6InECT1Pkts = simple_hash("Ip6InECT1Pkts");
153 + hash_Ip6InECT0Pkts = simple_hash("Ip6InECT0Pkts");
154 + hash_Ip6InCEPkts = simple_hash("Ip6InCEPkts");
155 + hash_Icmp6InMsgs = simple_hash("Icmp6InMsgs");
156 + hash_Icmp6InErrors = simple_hash("Icmp6InErrors");
157 + hash_Icmp6OutMsgs = simple_hash("Icmp6OutMsgs");
158 + hash_Icmp6OutErrors = simple_hash("Icmp6OutErrors");
159 + hash_Icmp6InCsumErrors = simple_hash("Icmp6InCsumErrors");
160 + hash_Icmp6InDestUnreachs = simple_hash("Icmp6InDestUnreachs");
161 + hash_Icmp6InPktTooBigs = simple_hash("Icmp6InPktTooBigs");
162 + hash_Icmp6InTimeExcds = simple_hash("Icmp6InTimeExcds");
163 + hash_Icmp6InParmProblems = simple_hash("Icmp6InParmProblems");
164 + hash_Icmp6InEchos = simple_hash("Icmp6InEchos");
165 + hash_Icmp6InEchoReplies = simple_hash("Icmp6InEchoReplies");
166 + hash_Icmp6InGroupMembQueries = simple_hash("Icmp6InGroupMembQueries");
167 + hash_Icmp6InGroupMembResponses = simple_hash("Icmp6InGroupMembResponses");
168 + hash_Icmp6InGroupMembReductions = simple_hash("Icmp6InGroupMembReductions");
169 + hash_Icmp6InRouterSolicits = simple_hash("Icmp6InRouterSolicits");
170 + hash_Icmp6InRouterAdvertisements = simple_hash("Icmp6InRouterAdvertisements");
171 + hash_Icmp6InNeighborSolicits = simple_hash("Icmp6InNeighborSolicits");
172 + hash_Icmp6InNeighborAdvertisements = simple_hash("Icmp6InNeighborAdvertisements");
173 + hash_Icmp6InRedirects = simple_hash("Icmp6InRedirects");
174 + hash_Icmp6InMLDv2Reports = simple_hash("Icmp6InMLDv2Reports");
175 + hash_Icmp6OutDestUnreachs = simple_hash("Icmp6OutDestUnreachs");
176 + hash_Icmp6OutPktTooBigs = simple_hash("Icmp6OutPktTooBigs");
177 + hash_Icmp6OutTimeExcds = simple_hash("Icmp6OutTimeExcds");
178 + hash_Icmp6OutParmProblems = simple_hash("Icmp6OutParmProblems");
179 + hash_Icmp6OutEchos = simple_hash("Icmp6OutEchos");
180 + hash_Icmp6OutEchoReplies = simple_hash("Icmp6OutEchoReplies");
181 + hash_Icmp6OutGroupMembQueries = simple_hash("Icmp6OutGroupMembQueries");
182 + hash_Icmp6OutGroupMembResponses = simple_hash("Icmp6OutGroupMembResponses");
183 + hash_Icmp6OutGroupMembReductions = simple_hash("Icmp6OutGroupMembReductions");
184 + hash_Icmp6OutRouterSolicits = simple_hash("Icmp6OutRouterSolicits");
185 + hash_Icmp6OutRouterAdvertisements = simple_hash("Icmp6OutRouterAdvertisements");
186 + hash_Icmp6OutNeighborSolicits = simple_hash("Icmp6OutNeighborSolicits");
187 + hash_Icmp6OutNeighborAdvertisements = simple_hash("Icmp6OutNeighborAdvertisements");
188 + hash_Icmp6OutRedirects = simple_hash("Icmp6OutRedirects");
189 + hash_Icmp6OutMLDv2Reports = simple_hash("Icmp6OutMLDv2Reports");
190 + hash_Icmp6InType1 = simple_hash("Icmp6InType1");
191 + hash_Icmp6InType128 = simple_hash("Icmp6InType128");
192 + hash_Icmp6InType129 = simple_hash("Icmp6InType129");
193 + hash_Icmp6InType136 = simple_hash("Icmp6InType136");
194 + hash_Icmp6OutType1 = simple_hash("Icmp6OutType1");
195 + hash_Icmp6OutType128 = simple_hash("Icmp6OutType128");
196 + hash_Icmp6OutType129 = simple_hash("Icmp6OutType129");
197 + hash_Icmp6OutType133 = simple_hash("Icmp6OutType133");
198 + hash_Icmp6OutType135 = simple_hash("Icmp6OutType135");
199 + hash_Icmp6OutType143 = simple_hash("Icmp6OutType143");
200 + hash_Udp6InDatagrams = simple_hash("Udp6InDatagrams");
201 + hash_Udp6NoPorts = simple_hash("Udp6NoPorts");
202 + hash_Udp6InErrors = simple_hash("Udp6InErrors");
203 + hash_Udp6OutDatagrams = simple_hash("Udp6OutDatagrams");
204 + hash_Udp6RcvbufErrors = simple_hash("Udp6RcvbufErrors");
205 + hash_Udp6SndbufErrors = simple_hash("Udp6SndbufErrors");
206 + hash_Udp6InCsumErrors = simple_hash("Udp6InCsumErrors");
207 + hash_Udp6IgnoredMulti = simple_hash("Udp6IgnoredMulti");
208 + hash_UdpLite6InDatagrams = simple_hash("UdpLite6InDatagrams");
209 + hash_UdpLite6NoPorts = simple_hash("UdpLite6NoPorts");
210 + hash_UdpLite6InErrors = simple_hash("UdpLite6InErrors");
211 + hash_UdpLite6OutDatagrams = simple_hash("UdpLite6OutDatagrams");
212 + hash_UdpLite6RcvbufErrors = simple_hash("UdpLite6RcvbufErrors");
213 + hash_UdpLite6SndbufErrors = simple_hash("UdpLite6SndbufErrors");
214 + hash_UdpLite6InCsumErrors = simple_hash("UdpLite6InCsumErrors");
215 + }
216 +
217 + if(do_ip_packets == -1) do_ip_packets = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "ipv6 packets", CONFIG_ONDEMAND_ONDEMAND);
218 + if(do_ip_fragsout == -1) do_ip_fragsout = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "ipv6 fragments sent", CONFIG_ONDEMAND_ONDEMAND);
219 + if(do_ip_fragsin == -1) do_ip_fragsin = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "ipv6 fragments assembly", CONFIG_ONDEMAND_ONDEMAND);
220 + if(do_ip_errors == -1) do_ip_errors = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "ipv6 errors", CONFIG_ONDEMAND_ONDEMAND);
221 + if(do_udp_packets == -1) do_udp_packets = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "ipv6 UDP packets", CONFIG_ONDEMAND_ONDEMAND);
222 + if(do_udp_errors == -1) do_udp_errors = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "ipv6 UDP errors", CONFIG_ONDEMAND_ONDEMAND);
223 + if(do_udplite_packets == -1) do_udplite_packets = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "ipv6 UDPlite packets", CONFIG_ONDEMAND_ONDEMAND);
224 + if(do_udplite_errors == -1) do_udplite_errors = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "ipv6 UDPlite errors", CONFIG_ONDEMAND_ONDEMAND);
225 + if(do_bandwidth == -1) do_bandwidth = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "bandwidth", CONFIG_ONDEMAND_ONDEMAND);
226 + if(do_mcast == -1) do_mcast = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "multicast bandwidth", CONFIG_ONDEMAND_ONDEMAND);
227 + if(do_bcast == -1) do_bcast = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "broadcast bandwidth", CONFIG_ONDEMAND_ONDEMAND);
228 + if(do_mcast_p == -1) do_mcast_p = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "multicast packets", CONFIG_ONDEMAND_ONDEMAND);
229 + if(do_icmp == -1) do_icmp = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "icmp", CONFIG_ONDEMAND_ONDEMAND);
230 + if(do_icmp_redir == -1) do_icmp_redir = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "icmp redirects", CONFIG_ONDEMAND_ONDEMAND);
231 + if(do_icmp_errors == -1) do_icmp_errors = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "icmp errors", CONFIG_ONDEMAND_ONDEMAND);
232 + if(do_icmp_echos == -1) do_icmp_echos = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "icmp echos", CONFIG_ONDEMAND_ONDEMAND);
233 + if(do_icmp_groupmemb == -1) do_icmp_groupmemb = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "icmp group membership", CONFIG_ONDEMAND_ONDEMAND);
234 + if(do_icmp_router == -1) do_icmp_router = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "icmp router", CONFIG_ONDEMAND_ONDEMAND);
235 + if(do_icmp_neighbor == -1) do_icmp_neighbor = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "icmp neighbor", CONFIG_ONDEMAND_ONDEMAND);
236 + if(do_icmp_mldv2 == -1) do_icmp_mldv2 = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "icmp mldv2", CONFIG_ONDEMAND_ONDEMAND);
237 + if(do_icmp_types == -1) do_icmp_types = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "icmp types", CONFIG_ONDEMAND_ONDEMAND);
238 + if(do_ect == -1) do_ect = config_get_boolean_ondemand("plugin:proc:/proc/net/snmp6", "ect", CONFIG_ONDEMAND_ONDEMAND);
239 +
240 + if(dt) {};
241 +
242 + if(!ff) {
243 + char filename[FILENAME_MAX + 1];
244 + snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/net/snmp6");
245 + ff = procfile_open(config_get("plugin:proc:/proc/net/snmp6", "filename to monitor", filename), " \t:", PROCFILE_FLAG_DEFAULT);
246 + }
247 + if(!ff) return 1;
248 +
249 + ff = procfile_readall(ff);
250 + if(!ff) return 0; // we return 0, so that we will retry to open it next time
251 +
252 + uint32_t lines = procfile_lines(ff), l;
253 + uint32_t words;
254 +
255 + unsigned long long Ip6InReceives = 0ULL;
256 + unsigned long long Ip6InHdrErrors = 0ULL;
257 + unsigned long long Ip6InTooBigErrors = 0ULL;
258 + unsigned long long Ip6InNoRoutes = 0ULL;
259 + unsigned long long Ip6InAddrErrors = 0ULL;
260 + unsigned long long Ip6InUnknownProtos = 0ULL;
261 + unsigned long long Ip6InTruncatedPkts = 0ULL;
262 + unsigned long long Ip6InDiscards = 0ULL;
263 + unsigned long long Ip6InDelivers = 0ULL;
264 + unsigned long long Ip6OutForwDatagrams = 0ULL;
265 + unsigned long long Ip6OutRequests = 0ULL;
266 + unsigned long long Ip6OutDiscards = 0ULL;
267 + unsigned long long Ip6OutNoRoutes = 0ULL;
268 + unsigned long long Ip6ReasmTimeout = 0ULL;
269 + unsigned long long Ip6ReasmReqds = 0ULL;
270 + unsigned long long Ip6ReasmOKs = 0ULL;
271 + unsigned long long Ip6ReasmFails = 0ULL;
272 + unsigned long long Ip6FragOKs = 0ULL;
273 + unsigned long long Ip6FragFails = 0ULL;
274 + unsigned long long Ip6FragCreates = 0ULL;
275 + unsigned long long Ip6InMcastPkts = 0ULL;
276 + unsigned long long Ip6OutMcastPkts = 0ULL;
277 + unsigned long long Ip6InOctets = 0ULL;
278 + unsigned long long Ip6OutOctets = 0ULL;
279 + unsigned long long Ip6InMcastOctets = 0ULL;
280 + unsigned long long Ip6OutMcastOctets = 0ULL;
281 + unsigned long long Ip6InBcastOctets = 0ULL;
282 + unsigned long long Ip6OutBcastOctets = 0ULL;
283 + unsigned long long Ip6InNoECTPkts = 0ULL;
284 + unsigned long long Ip6InECT1Pkts = 0ULL;
285 + unsigned long long Ip6InECT0Pkts = 0ULL;
286 + unsigned long long Ip6InCEPkts = 0ULL;
287 + unsigned long long Icmp6InMsgs = 0ULL;
288 + unsigned long long Icmp6InErrors = 0ULL;
289 + unsigned long long Icmp6OutMsgs = 0ULL;
290 + unsigned long long Icmp6OutErrors = 0ULL;
291 + unsigned long long Icmp6InCsumErrors = 0ULL;
292 + unsigned long long Icmp6InDestUnreachs = 0ULL;
293 + unsigned long long Icmp6InPktTooBigs = 0ULL;
294 + unsigned long long Icmp6InTimeExcds = 0ULL;
295 + unsigned long long Icmp6InParmProblems = 0ULL;
296 + unsigned long long Icmp6InEchos = 0ULL;
297 + unsigned long long Icmp6InEchoReplies = 0ULL;
298 + unsigned long long Icmp6InGroupMembQueries = 0ULL;
299 + unsigned long long Icmp6InGroupMembResponses = 0ULL;
300 + unsigned long long Icmp6InGroupMembReductions = 0ULL;
301 + unsigned long long Icmp6InRouterSolicits = 0ULL;
302 + unsigned long long Icmp6InRouterAdvertisements = 0ULL;
303 + unsigned long long Icmp6InNeighborSolicits = 0ULL;
304 + unsigned long long Icmp6InNeighborAdvertisements = 0ULL;
305 + unsigned long long Icmp6InRedirects = 0ULL;
306 + unsigned long long Icmp6InMLDv2Reports = 0ULL;
307 + unsigned long long Icmp6OutDestUnreachs = 0ULL;
308 + unsigned long long Icmp6OutPktTooBigs = 0ULL;
309 + unsigned long long Icmp6OutTimeExcds = 0ULL;
310 + unsigned long long Icmp6OutParmProblems = 0ULL;
311 + unsigned long long Icmp6OutEchos = 0ULL;
312 + unsigned long long Icmp6OutEchoReplies = 0ULL;
313 + unsigned long long Icmp6OutGroupMembQueries = 0ULL;
314 + unsigned long long Icmp6OutGroupMembResponses = 0ULL;
315 + unsigned long long Icmp6OutGroupMembReductions = 0ULL;
316 + unsigned long long Icmp6OutRouterSolicits = 0ULL;
317 + unsigned long long Icmp6OutRouterAdvertisements = 0ULL;
318 + unsigned long long Icmp6OutNeighborSolicits = 0ULL;
319 + unsigned long long Icmp6OutNeighborAdvertisements = 0ULL;
320 + unsigned long long Icmp6OutRedirects = 0ULL;
321 + unsigned long long Icmp6OutMLDv2Reports = 0ULL;
322 + unsigned long long Icmp6InType1 = 0ULL;
323 + unsigned long long Icmp6InType128 = 0ULL;
324 + unsigned long long Icmp6InType129 = 0ULL;
325 + unsigned long long Icmp6InType136 = 0ULL;
326 + unsigned long long Icmp6OutType1 = 0ULL;
327 + unsigned long long Icmp6OutType128 = 0ULL;
328 + unsigned long long Icmp6OutType129 = 0ULL;
329 + unsigned long long Icmp6OutType133 = 0ULL;
330 + unsigned long long Icmp6OutType135 = 0ULL;
331 + unsigned long long Icmp6OutType143 = 0ULL;
332 + unsigned long long Udp6InDatagrams = 0ULL;
333 + unsigned long long Udp6NoPorts = 0ULL;
334 + unsigned long long Udp6InErrors = 0ULL;
335 + unsigned long long Udp6OutDatagrams = 0ULL;
336 + unsigned long long Udp6RcvbufErrors = 0ULL;
337 + unsigned long long Udp6SndbufErrors = 0ULL;
338 + unsigned long long Udp6InCsumErrors = 0ULL;
339 + unsigned long long Udp6IgnoredMulti = 0ULL;
340 + unsigned long long UdpLite6InDatagrams = 0ULL;
341 + unsigned long long UdpLite6NoPorts = 0ULL;
342 + unsigned long long UdpLite6InErrors = 0ULL;
343 + unsigned long long UdpLite6OutDatagrams = 0ULL;
344 + unsigned long long UdpLite6RcvbufErrors = 0ULL;
345 + unsigned long long UdpLite6SndbufErrors = 0ULL;
346 + unsigned long long UdpLite6InCsumErrors = 0ULL;
347 +
348 + for(l = 0; l < lines ;l++) {
349 + words = procfile_linewords(ff, l);
350 + if(words < 2) {
351 + if(words) error("Cannot read /proc/net/snmp6 line %u. Expected 2 params, read %u.", l, words);
352 + continue;
353 + }
354 +
355 + char *name = procfile_lineword(ff, l, 0);
356 + char * value = procfile_lineword(ff, l, 1);
357 + if(!name || !*name || !value || !*value) continue;
358 +
359 + uint32_t hash = simple_hash(name);
360 +
361 + if(0) ;
362 + else if(hash == hash_Ip6InReceives && strcmp(name, "Ip6InReceives") == 0) Ip6InReceives = strtoull(value, NULL, 10);
363 + else if(hash == hash_Ip6InHdrErrors && strcmp(name, "Ip6InHdrErrors") == 0) Ip6InHdrErrors = strtoull(value, NULL, 10);
364 + else if(hash == hash_Ip6InTooBigErrors && strcmp(name, "Ip6InTooBigErrors") == 0) Ip6InTooBigErrors = strtoull(value, NULL, 10);
365 + else if(hash == hash_Ip6InNoRoutes && strcmp(name, "Ip6InNoRoutes") == 0) Ip6InNoRoutes = strtoull(value, NULL, 10);
366 + else if(hash == hash_Ip6InAddrErrors && strcmp(name, "Ip6InAddrErrors") == 0) Ip6InAddrErrors = strtoull(value, NULL, 10);
367 + else if(hash == hash_Ip6InUnknownProtos && strcmp(name, "Ip6InUnknownProtos") == 0) Ip6InUnknownProtos = strtoull(value, NULL, 10);
368 + else if(hash == hash_Ip6InTruncatedPkts && strcmp(name, "Ip6InTruncatedPkts") == 0) Ip6InTruncatedPkts = strtoull(value, NULL, 10);
369 + else if(hash == hash_Ip6InDiscards && strcmp(name, "Ip6InDiscards") == 0) Ip6InDiscards = strtoull(value, NULL, 10);
370 + else if(hash == hash_Ip6InDelivers && strcmp(name, "Ip6InDelivers") == 0) Ip6InDelivers = strtoull(value, NULL, 10);
371 + else if(hash == hash_Ip6OutForwDatagrams && strcmp(name, "Ip6OutForwDatagrams") == 0) Ip6OutForwDatagrams = strtoull(value, NULL, 10);
372 + else if(hash == hash_Ip6OutRequests && strcmp(name, "Ip6OutRequests") == 0) Ip6OutRequests = strtoull(value, NULL, 10);
373 + else if(hash == hash_Ip6OutDiscards && strcmp(name, "Ip6OutDiscards") == 0) Ip6OutDiscards = strtoull(value, NULL, 10);
374 + else if(hash == hash_Ip6OutNoRoutes && strcmp(name, "Ip6OutNoRoutes") == 0) Ip6OutNoRoutes = strtoull(value, NULL, 10);
375 + else if(hash == hash_Ip6ReasmTimeout && strcmp(name, "Ip6ReasmTimeout") == 0) Ip6ReasmTimeout = strtoull(value, NULL, 10);
376 + else if(hash == hash_Ip6ReasmReqds && strcmp(name, "Ip6ReasmReqds") == 0) Ip6ReasmReqds = strtoull(value, NULL, 10);
377 + else if(hash == hash_Ip6ReasmOKs && strcmp(name, "Ip6ReasmOKs") == 0) Ip6ReasmOKs = strtoull(value, NULL, 10);
378 + else if(hash == hash_Ip6ReasmFails && strcmp(name, "Ip6ReasmFails") == 0) Ip6ReasmFails = strtoull(value, NULL, 10);
379 + else if(hash == hash_Ip6FragOKs && strcmp(name, "Ip6FragOKs") == 0) Ip6FragOKs = strtoull(value, NULL, 10);
380 + else if(hash == hash_Ip6FragFails && strcmp(name, "Ip6FragFails") == 0) Ip6FragFails = strtoull(value, NULL, 10);
381 + else if(hash == hash_Ip6FragCreates && strcmp(name, "Ip6FragCreates") == 0) Ip6FragCreates = strtoull(value, NULL, 10);
382 + else if(hash == hash_Ip6InMcastPkts && strcmp(name, "Ip6InMcastPkts") == 0) Ip6InMcastPkts = strtoull(value, NULL, 10);
383 + else if(hash == hash_Ip6OutMcastPkts && strcmp(name, "Ip6OutMcastPkts") == 0) Ip6OutMcastPkts = strtoull(value, NULL, 10);
384 + else if(hash == hash_Ip6InOctets && strcmp(name, "Ip6InOctets") == 0) Ip6InOctets = strtoull(value, NULL, 10);
385 + else if(hash == hash_Ip6OutOctets && strcmp(name, "Ip6OutOctets") == 0) Ip6OutOctets = strtoull(value, NULL, 10);
386 + else if(hash == hash_Ip6InMcastOctets && strcmp(name, "Ip6InMcastOctets") == 0) Ip6InMcastOctets = strtoull(value, NULL, 10);
387 + else if(hash == hash_Ip6OutMcastOctets && strcmp(name, "Ip6OutMcastOctets") == 0) Ip6OutMcastOctets = strtoull(value, NULL, 10);
388 + else if(hash == hash_Ip6InBcastOctets && strcmp(name, "Ip6InBcastOctets") == 0) Ip6InBcastOctets = strtoull(value, NULL, 10);
389 + else if(hash == hash_Ip6OutBcastOctets && strcmp(name, "Ip6OutBcastOctets") == 0) Ip6OutBcastOctets = strtoull(value, NULL, 10);
390 + else if(hash == hash_Ip6InNoECTPkts && strcmp(name, "Ip6InNoECTPkts") == 0) Ip6InNoECTPkts = strtoull(value, NULL, 10);
391 + else if(hash == hash_Ip6InECT1Pkts && strcmp(name, "Ip6InECT1Pkts") == 0) Ip6InECT1Pkts = strtoull(value, NULL, 10);
392 + else if(hash == hash_Ip6InECT0Pkts && strcmp(name, "Ip6InECT0Pkts") == 0) Ip6InECT0Pkts = strtoull(value, NULL, 10);
393 + else if(hash == hash_Ip6InCEPkts && strcmp(name, "Ip6InCEPkts") == 0) Ip6InCEPkts = strtoull(value, NULL, 10);
394 + else if(hash == hash_Icmp6InMsgs && strcmp(name, "Icmp6InMsgs") == 0) Icmp6InMsgs = strtoull(value, NULL, 10);
395 + else if(hash == hash_Icmp6InErrors && strcmp(name, "Icmp6InErrors") == 0) Icmp6InErrors = strtoull(value, NULL, 10);
396 + else if(hash == hash_Icmp6OutMsgs && strcmp(name, "Icmp6OutMsgs") == 0) Icmp6OutMsgs = strtoull(value, NULL, 10);
397 + else if(hash == hash_Icmp6OutErrors && strcmp(name, "Icmp6OutErrors") == 0) Icmp6OutErrors = strtoull(value, NULL, 10);
398 + else if(hash == hash_Icmp6InCsumErrors && strcmp(name, "Icmp6InCsumErrors") == 0) Icmp6InCsumErrors = strtoull(value, NULL, 10);
399 + else if(hash == hash_Icmp6InDestUnreachs && strcmp(name, "Icmp6InDestUnreachs") == 0) Icmp6InDestUnreachs = strtoull(value, NULL, 10);
400 + else if(hash == hash_Icmp6InPktTooBigs && strcmp(name, "Icmp6InPktTooBigs") == 0) Icmp6InPktTooBigs = strtoull(value, NULL, 10);
401 + else if(hash == hash_Icmp6InTimeExcds && strcmp(name, "Icmp6InTimeExcds") == 0) Icmp6InTimeExcds = strtoull(value, NULL, 10);
402 + else if(hash == hash_Icmp6InParmProblems && strcmp(name, "Icmp6InParmProblems") == 0) Icmp6InParmProblems = strtoull(value, NULL, 10);
403 + else if(hash == hash_Icmp6InEchos && strcmp(name, "Icmp6InEchos") == 0) Icmp6InEchos = strtoull(value, NULL, 10);
404 + else if(hash == hash_Icmp6InEchoReplies && strcmp(name, "Icmp6InEchoReplies") == 0) Icmp6InEchoReplies = strtoull(value, NULL, 10);
405 + else if(hash == hash_Icmp6InGroupMembQueries && strcmp(name, "Icmp6InGroupMembQueries") == 0) Icmp6InGroupMembQueries = strtoull(value, NULL, 10);
406 + else if(hash == hash_Icmp6InGroupMembResponses && strcmp(name, "Icmp6InGroupMembResponses") == 0) Icmp6InGroupMembResponses = strtoull(value, NULL, 10);
407 + else if(hash == hash_Icmp6InGroupMembReductions && strcmp(name, "Icmp6InGroupMembReductions") == 0) Icmp6InGroupMembReductions = strtoull(value, NULL, 10);
408 + else if(hash == hash_Icmp6InRouterSolicits && strcmp(name, "Icmp6InRouterSolicits") == 0) Icmp6InRouterSolicits = strtoull(value, NULL, 10);
409 + else if(hash == hash_Icmp6InRouterAdvertisements && strcmp(name, "Icmp6InRouterAdvertisements") == 0) Icmp6InRouterAdvertisements = strtoull(value, NULL, 10);
410 + else if(hash == hash_Icmp6InNeighborSolicits && strcmp(name, "Icmp6InNeighborSolicits") == 0) Icmp6InNeighborSolicits = strtoull(value, NULL, 10);
411 + else if(hash == hash_Icmp6InNeighborAdvertisements && strcmp(name, "Icmp6InNeighborAdvertisements") == 0) Icmp6InNeighborAdvertisements = strtoull(value, NULL, 10);
412 + else if(hash == hash_Icmp6InRedirects && strcmp(name, "Icmp6InRedirects") == 0) Icmp6InRedirects = strtoull(value, NULL, 10);
413 + else if(hash == hash_Icmp6InMLDv2Reports && strcmp(name, "Icmp6InMLDv2Reports") == 0) Icmp6InMLDv2Reports = strtoull(value, NULL, 10);
414 + else if(hash == hash_Icmp6OutDestUnreachs && strcmp(name, "Icmp6OutDestUnreachs") == 0) Icmp6OutDestUnreachs = strtoull(value, NULL, 10);
415 + else if(hash == hash_Icmp6OutPktTooBigs && strcmp(name, "Icmp6OutPktTooBigs") == 0) Icmp6OutPktTooBigs = strtoull(value, NULL, 10);
416 + else if(hash == hash_Icmp6OutTimeExcds && strcmp(name, "Icmp6OutTimeExcds") == 0) Icmp6OutTimeExcds = strtoull(value, NULL, 10);
417 + else if(hash == hash_Icmp6OutParmProblems && strcmp(name, "Icmp6OutParmProblems") == 0) Icmp6OutParmProblems = strtoull(value, NULL, 10);
418 + else if(hash == hash_Icmp6OutEchos && strcmp(name, "Icmp6OutEchos") == 0) Icmp6OutEchos = strtoull(value, NULL, 10);
419 + else if(hash == hash_Icmp6OutEchoReplies && strcmp(name, "Icmp6OutEchoReplies") == 0) Icmp6OutEchoReplies = strtoull(value, NULL, 10);
420 + else if(hash == hash_Icmp6OutGroupMembQueries && strcmp(name, "Icmp6OutGroupMembQueries") == 0) Icmp6OutGroupMembQueries = strtoull(value, NULL, 10);
421 + else if(hash == hash_Icmp6OutGroupMembResponses && strcmp(name, "Icmp6OutGroupMembResponses") == 0) Icmp6OutGroupMembResponses = strtoull(value, NULL, 10);
422 + else if(hash == hash_Icmp6OutGroupMembReductions && strcmp(name, "Icmp6OutGroupMembReductions") == 0) Icmp6OutGroupMembReductions = strtoull(value, NULL, 10);
423 + else if(hash == hash_Icmp6OutRouterSolicits && strcmp(name, "Icmp6OutRouterSolicits") == 0) Icmp6OutRouterSolicits = strtoull(value, NULL, 10);
424 + else if(hash == hash_Icmp6OutRouterAdvertisements && strcmp(name, "Icmp6OutRouterAdvertisements") == 0) Icmp6OutRouterAdvertisements = strtoull(value, NULL, 10);
425 + else if(hash == hash_Icmp6OutNeighborSolicits && strcmp(name, "Icmp6OutNeighborSolicits") == 0) Icmp6OutNeighborSolicits = strtoull(value, NULL, 10);
426 + else if(hash == hash_Icmp6OutNeighborAdvertisements && strcmp(name, "Icmp6OutNeighborAdvertisements") == 0) Icmp6OutNeighborAdvertisements = strtoull(value, NULL, 10);
427 + else if(hash == hash_Icmp6OutRedirects && strcmp(name, "Icmp6OutRedirects") == 0) Icmp6OutRedirects = strtoull(value, NULL, 10);
428 + else if(hash == hash_Icmp6OutMLDv2Reports && strcmp(name, "Icmp6OutMLDv2Reports") == 0) Icmp6OutMLDv2Reports = strtoull(value, NULL, 10);
429 + else if(hash == hash_Icmp6InType1 && strcmp(name, "Icmp6InType1") == 0) Icmp6InType1 = strtoull(value, NULL, 10);
430 + else if(hash == hash_Icmp6InType128 && strcmp(name, "Icmp6InType128") == 0) Icmp6InType128 = strtoull(value, NULL, 10);
431 + else if(hash == hash_Icmp6InType129 && strcmp(name, "Icmp6InType129") == 0) Icmp6InType129 = strtoull(value, NULL, 10);
432 + else if(hash == hash_Icmp6InType136 && strcmp(name, "Icmp6InType136") == 0) Icmp6InType136 = strtoull(value, NULL, 10);
433 + else if(hash == hash_Icmp6OutType1 && strcmp(name, "Icmp6OutType1") == 0) Icmp6OutType1 = strtoull(value, NULL, 10);
434 + else if(hash == hash_Icmp6OutType128 && strcmp(name, "Icmp6OutType128") == 0) Icmp6OutType128 = strtoull(value, NULL, 10);
435 + else if(hash == hash_Icmp6OutType129 && strcmp(name, "Icmp6OutType129") == 0) Icmp6OutType129 = strtoull(value, NULL, 10);
436 + else if(hash == hash_Icmp6OutType133 && strcmp(name, "Icmp6OutType133") == 0) Icmp6OutType133 = strtoull(value, NULL, 10);
437 + else if(hash == hash_Icmp6OutType135 && strcmp(name, "Icmp6OutType135") == 0) Icmp6OutType135 = strtoull(value, NULL, 10);
438 + else if(hash == hash_Icmp6OutType143 && strcmp(name, "Icmp6OutType143") == 0) Icmp6OutType143 = strtoull(value, NULL, 10);
439 + else if(hash == hash_Udp6InDatagrams && strcmp(name, "Udp6InDatagrams") == 0) Udp6InDatagrams = strtoull(value, NULL, 10);
440 + else if(hash == hash_Udp6NoPorts && strcmp(name, "Udp6NoPorts") == 0) Udp6NoPorts = strtoull(value, NULL, 10);
441 + else if(hash == hash_Udp6InErrors && strcmp(name, "Udp6InErrors") == 0) Udp6InErrors = strtoull(value, NULL, 10);
442 + else if(hash == hash_Udp6OutDatagrams && strcmp(name, "Udp6OutDatagrams") == 0) Udp6OutDatagrams = strtoull(value, NULL, 10);
443 + else if(hash == hash_Udp6RcvbufErrors && strcmp(name, "Udp6RcvbufErrors") == 0) Udp6RcvbufErrors = strtoull(value, NULL, 10);
444 + else if(hash == hash_Udp6SndbufErrors && strcmp(name, "Udp6SndbufErrors") == 0) Udp6SndbufErrors = strtoull(value, NULL, 10);
445 + else if(hash == hash_Udp6InCsumErrors && strcmp(name, "Udp6InCsumErrors") == 0) Udp6InCsumErrors = strtoull(value, NULL, 10);
446 + else if(hash == hash_Udp6IgnoredMulti && strcmp(name, "Udp6IgnoredMulti") == 0) Udp6IgnoredMulti = strtoull(value, NULL, 10);
447 + else if(hash == hash_UdpLite6InDatagrams && strcmp(name, "UdpLite6InDatagrams") == 0) UdpLite6InDatagrams = strtoull(value, NULL, 10);
448 + else if(hash == hash_UdpLite6NoPorts && strcmp(name, "UdpLite6NoPorts") == 0) UdpLite6NoPorts = strtoull(value, NULL, 10);
449 + else if(hash == hash_UdpLite6InErrors && strcmp(name, "UdpLite6InErrors") == 0) UdpLite6InErrors = strtoull(value, NULL, 10);
450 + else if(hash == hash_UdpLite6OutDatagrams && strcmp(name, "UdpLite6OutDatagrams") == 0) UdpLite6OutDatagrams = strtoull(value, NULL, 10);
451 + else if(hash == hash_UdpLite6RcvbufErrors && strcmp(name, "UdpLite6RcvbufErrors") == 0) UdpLite6RcvbufErrors = strtoull(value, NULL, 10);
452 + else if(hash == hash_UdpLite6SndbufErrors && strcmp(name, "UdpLite6SndbufErrors") == 0) UdpLite6SndbufErrors = strtoull(value, NULL, 10);
453 + else if(hash == hash_UdpLite6InCsumErrors && strcmp(name, "UdpLite6InCsumErrors") == 0) UdpLite6InCsumErrors = strtoull(value, NULL, 10);
454 + }
455 +
456 + RRDSET *st;
457 +
458 + // --------------------------------------------------------------------
459 +
460 + if(do_bandwidth == CONFIG_ONDEMAND_YES || (do_bandwidth == CONFIG_ONDEMAND_ONDEMAND && (Ip6InOctets || Ip6OutOctets))) {
461 + do_bandwidth = CONFIG_ONDEMAND_YES;
462 + st = rrdset_find("system.ipv6");
463 + if(!st) {
464 + st = rrdset_create("system", "ipv6", NULL, "network", NULL, "IPv6 Bandwidth", "kilobits/s", 500, update_every, RRDSET_TYPE_AREA);
465 +
466 + rrddim_add(st, "received", NULL, 8, 1024, RRDDIM_INCREMENTAL);
467 + rrddim_add(st, "sent", NULL, -8, 1024, RRDDIM_INCREMENTAL);
468 + }
469 + else rrdset_next(st);
470 +
471 + rrddim_set(st, "sent", Ip6OutOctets);
472 + rrddim_set(st, "received", Ip6InOctets);
473 + rrdset_done(st);
474 + }
475 +
476 + // --------------------------------------------------------------------
477 +
478 + if(do_ip_packets == CONFIG_ONDEMAND_YES || (do_ip_packets == CONFIG_ONDEMAND_ONDEMAND && (Ip6InReceives || Ip6OutRequests || Ip6InDelivers || Ip6OutForwDatagrams))) {
479 + do_ip_packets = CONFIG_ONDEMAND_YES;
480 + st = rrdset_find(RRD_TYPE_NET_SNMP6 ".packets");
481 + if(!st) {
482 + st = rrdset_create(RRD_TYPE_NET_SNMP6, "packets", NULL, "packets", NULL, "IPv6 Packets", "packets/s", 3000, update_every, RRDSET_TYPE_LINE);
483 +
484 + rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
485 + rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
486 + rrddim_add(st, "forwarded", NULL, 1, 1, RRDDIM_INCREMENTAL);
487 + rrddim_add(st, "delivers", NULL, -1, 1, RRDDIM_INCREMENTAL);
488 + }
489 + else rrdset_next(st);
490 +
491 + rrddim_set(st, "sent", Ip6OutRequests);
492 + rrddim_set(st, "received", Ip6InReceives);
493 + rrddim_set(st, "forwarded", Ip6InDelivers);
494 + rrddim_set(st, "delivers", Ip6OutForwDatagrams);
495 + rrdset_done(st);
496 + }
497 +
498 + // --------------------------------------------------------------------
499 +
500 + if(do_ip_fragsout == CONFIG_ONDEMAND_YES || (do_ip_fragsout == CONFIG_ONDEMAND_ONDEMAND && (Ip6FragOKs || Ip6FragFails || Ip6FragCreates))) {
501 + do_ip_fragsout = CONFIG_ONDEMAND_YES;
502 + st = rrdset_find(RRD_TYPE_NET_SNMP6 ".fragsout");
503 + if(!st) {
504 + st = rrdset_create(RRD_TYPE_NET_SNMP6, "fragsout", NULL, "fragments", NULL, "IPv6 Fragments Sent", "packets/s", 3010, update_every, RRDSET_TYPE_LINE);
505 + st->isdetail = 1;
506 +
507 + rrddim_add(st, "ok", NULL, 1, 1, RRDDIM_INCREMENTAL);
508 + rrddim_add(st, "failed", NULL, -1, 1, RRDDIM_INCREMENTAL);
509 + rrddim_add(st, "all", NULL, 1, 1, RRDDIM_INCREMENTAL);
510 + }
511 + else rrdset_next(st);
512 +
513 + rrddim_set(st, "ok", Ip6FragOKs);
514 + rrddim_set(st, "failed", Ip6FragFails);
515 + rrddim_set(st, "all", Ip6FragCreates);
516 + rrdset_done(st);
517 + }
518 +
519 + // --------------------------------------------------------------------
520 +
521 + if(do_ip_fragsin == CONFIG_ONDEMAND_YES || (do_ip_fragsin == CONFIG_ONDEMAND_ONDEMAND
522 + && (
523 + Ip6ReasmOKs
524 + || Ip6ReasmFails
525 + || Ip6ReasmTimeout
526 + || Ip6ReasmReqds
527 + ))) {
528 + do_ip_fragsin = CONFIG_ONDEMAND_YES;
529 + st = rrdset_find(RRD_TYPE_NET_SNMP6 ".fragsin");
530 + if(!st) {
531 + st = rrdset_create(RRD_TYPE_NET_SNMP6, "fragsin", NULL, "fragments", NULL, "IPv6 Fragments Reassembly", "packets/s", 3011, update_every, RRDSET_TYPE_LINE);
532 + st->isdetail = 1;
533 +
534 + rrddim_add(st, "ok", NULL, 1, 1, RRDDIM_INCREMENTAL);
535 + rrddim_add(st, "failed", NULL, -1, 1, RRDDIM_INCREMENTAL);
536 + rrddim_add(st, "timeout", NULL, -1, 1, RRDDIM_INCREMENTAL);
537 + rrddim_add(st, "all", NULL, 1, 1, RRDDIM_INCREMENTAL);
538 + }
539 + else rrdset_next(st);
540 +
541 + rrddim_set(st, "ok", Ip6ReasmOKs);
542 + rrddim_set(st, "failed", Ip6ReasmFails);
543 + rrddim_set(st, "timeout", Ip6ReasmTimeout);
544 + rrddim_set(st, "all", Ip6ReasmReqds);
545 + rrdset_done(st);
546 + }
547 +
548 + // --------------------------------------------------------------------
549 +
550 + if(do_ip_errors == CONFIG_ONDEMAND_YES || (do_ip_errors == CONFIG_ONDEMAND_ONDEMAND
551 + && (
552 + Ip6InDiscards
553 + || Ip6OutDiscards
554 + || Ip6InHdrErrors
555 + || Ip6InAddrErrors
556 + || Ip6InUnknownProtos
557 + || Ip6InTooBigErrors
558 + || Ip6InTruncatedPkts
559 + || Ip6InNoRoutes
560 + ))) {
561 + do_ip_errors = CONFIG_ONDEMAND_YES;
562 + st = rrdset_find(RRD_TYPE_NET_SNMP6 ".errors");
563 + if(!st) {
564 + st = rrdset_create(RRD_TYPE_NET_SNMP6, "errors", NULL, "errors", NULL, "IPv6 Errors", "packets/s", 3002, update_every, RRDSET_TYPE_LINE);
565 + st->isdetail = 1;
566 +
567 + rrddim_add(st, "InDiscards", NULL, 1, 1, RRDDIM_INCREMENTAL);
568 + rrddim_add(st, "OutDiscards", NULL, -1, 1, RRDDIM_INCREMENTAL);
569 +
570 + rrddim_add(st, "InHdrErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
571 + rrddim_add(st, "InAddrErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
572 + rrddim_add(st, "InUnknownProtos", NULL, 1, 1, RRDDIM_INCREMENTAL);
573 + rrddim_add(st, "InTooBigErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
574 + rrddim_add(st, "InTruncatedPkts", NULL, 1, 1, RRDDIM_INCREMENTAL);
575 + rrddim_add(st, "InNoRoutes", NULL, 1, 1, RRDDIM_INCREMENTAL);
576 +
577 + rrddim_add(st, "OutNoRoutes", NULL, -1, 1, RRDDIM_INCREMENTAL);
578 + }
579 + else rrdset_next(st);
580 +
581 + rrddim_set(st, "InDiscards", Ip6InDiscards);
582 + rrddim_set(st, "OutDiscards", Ip6OutDiscards);
583 +
584 + rrddim_set(st, "InHdrErrors", Ip6InHdrErrors);
585 + rrddim_set(st, "InAddrErrors", Ip6InAddrErrors);
586 + rrddim_set(st, "InUnknownProtos", Ip6InUnknownProtos);
587 + rrddim_set(st, "InTooBigErrors", Ip6InTooBigErrors);
588 + rrddim_set(st, "InTruncatedPkts", Ip6InTruncatedPkts);
589 + rrddim_set(st, "InNoRoutes", Ip6InNoRoutes);
590 +
591 + rrddim_set(st, "OutNoRoutes", Ip6OutNoRoutes);
592 + rrdset_done(st);
593 + }
594 +
595 + // --------------------------------------------------------------------
596 +
597 + if(do_udp_packets == CONFIG_ONDEMAND_YES || (do_udp_packets == CONFIG_ONDEMAND_ONDEMAND && (Udp6InDatagrams || Udp6OutDatagrams))) {
598 + do_udp_packets = CONFIG_ONDEMAND_YES;
599 + st = rrdset_find(RRD_TYPE_NET_SNMP6 ".udppackets");
600 + if(!st) {
601 + st = rrdset_create(RRD_TYPE_NET_SNMP6, "udppackets", NULL, "udp", NULL, "IPv6 UDP Packets", "packets/s", 3601, update_every, RRDSET_TYPE_LINE);
602 +
603 + rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
604 + rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
605 + }
606 + else rrdset_next(st);
607 +
608 + rrddim_set(st, "received", Udp6InDatagrams);
609 + rrddim_set(st, "sent", Udp6OutDatagrams);
610 + rrdset_done(st);
611 + }
612 +
613 + // --------------------------------------------------------------------
614 +
615 + if(do_udp_errors == CONFIG_ONDEMAND_YES || (do_udp_errors == CONFIG_ONDEMAND_ONDEMAND
616 + && (
617 + Udp6InErrors
618 + || Udp6NoPorts
619 + || Udp6RcvbufErrors
620 + || Udp6SndbufErrors
621 + || Udp6InCsumErrors
622 + || Udp6IgnoredMulti
623 + ))) {
624 + do_udp_errors = CONFIG_ONDEMAND_YES;
625 + st = rrdset_find(RRD_TYPE_NET_SNMP6 ".udperrors");
626 + if(!st) {
627 + st = rrdset_create(RRD_TYPE_NET_SNMP6, "udperrors", NULL, "udp", NULL, "IPv6 UDP Errors", "events/s", 3701, update_every, RRDSET_TYPE_LINE);
628 + st->isdetail = 1;
629 +
630 + rrddim_add(st, "RcvbufErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
631 + rrddim_add(st, "SndbufErrors", NULL, -1, 1, RRDDIM_INCREMENTAL);
632 + rrddim_add(st, "InErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
633 + rrddim_add(st, "NoPorts", NULL, 1, 1, RRDDIM_INCREMENTAL);
634 + rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
635 + rrddim_add(st, "IgnoredMulti", NULL, 1, 1, RRDDIM_INCREMENTAL);
636 + }
637 + else rrdset_next(st);
638 +
639 + rrddim_set(st, "InErrors", Udp6InErrors);
640 + rrddim_set(st, "NoPorts", Udp6NoPorts);
641 + rrddim_set(st, "RcvbufErrors", Udp6RcvbufErrors);
642 + rrddim_set(st, "SndbufErrors", Udp6SndbufErrors);
643 + rrddim_set(st, "InCsumErrors", Udp6InCsumErrors);
644 + rrddim_set(st, "IgnoredMulti", Udp6IgnoredMulti);
645 + rrdset_done(st);
646 + }
647 +
648 + // --------------------------------------------------------------------
649 +
650 + if(do_udplite_packets == CONFIG_ONDEMAND_YES || (do_udplite_packets == CONFIG_ONDEMAND_ONDEMAND && (UdpLite6InDatagrams || UdpLite6OutDatagrams))) {
651 + do_udplite_packets = CONFIG_ONDEMAND_YES;
652 + st = rrdset_find(RRD_TYPE_NET_SNMP6 ".udplitepackets");
653 + if(!st) {
654 + st = rrdset_create(RRD_TYPE_NET_SNMP6, "udplitepackets", NULL, "udplite", NULL, "IPv6 UDPlite Packets", "packets/s", 3601, update_every, RRDSET_TYPE_LINE);
655 +
656 + rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
657 + rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
658 + }
659 + else rrdset_next(st);
660 +
661 + rrddim_set(st, "received", UdpLite6InDatagrams);
662 + rrddim_set(st, "sent", UdpLite6OutDatagrams);
663 + rrdset_done(st);
664 + }
665 +
666 + // --------------------------------------------------------------------
667 +
668 + if(do_udplite_errors == CONFIG_ONDEMAND_YES || (do_udplite_errors == CONFIG_ONDEMAND_ONDEMAND
669 + && (
670 + UdpLite6InErrors
671 + || UdpLite6NoPorts
672 + || UdpLite6RcvbufErrors
673 + || UdpLite6SndbufErrors
674 + || Udp6InCsumErrors
675 + || UdpLite6InCsumErrors
676 + ))) {
677 + do_udplite_errors = CONFIG_ONDEMAND_YES;
678 + st = rrdset_find(RRD_TYPE_NET_SNMP6 ".udpliteerrors");
679 + if(!st) {
680 + st = rrdset_create(RRD_TYPE_NET_SNMP6, "udpliteerrors", NULL, "udplite", NULL, "IPv6 UDP Lite Errors", "events/s", 3701, update_every, RRDSET_TYPE_LINE);
681 + st->isdetail = 1;
682 +
683 + rrddim_add(st, "RcvbufErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
684 + rrddim_add(st, "SndbufErrors", NULL, -1, 1, RRDDIM_INCREMENTAL);
685 + rrddim_add(st, "InErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
686 + rrddim_add(st, "NoPorts", NULL, 1, 1, RRDDIM_INCREMENTAL);
687 + rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
688 + }
689 + else rrdset_next(st);
690 +
691 + rrddim_set(st, "InErrors", UdpLite6InErrors);
692 + rrddim_set(st, "NoPorts", UdpLite6NoPorts);
693 + rrddim_set(st, "RcvbufErrors", UdpLite6RcvbufErrors);
694 + rrddim_set(st, "SndbufErrors", UdpLite6SndbufErrors);
695 + rrddim_set(st, "InCsumErrors", UdpLite6InCsumErrors);
696 + rrdset_done(st);
697 + }
698 +
699 + // --------------------------------------------------------------------
700 +
701 + if(do_mcast == CONFIG_ONDEMAND_YES || (do_mcast == CONFIG_ONDEMAND_ONDEMAND && (Ip6OutMcastOctets || Ip6InMcastOctets))) {
702 + do_mcast = CONFIG_ONDEMAND_YES;
703 + st = rrdset_find(RRD_TYPE_NET_SNMP6 ".mcast");
704 + if(!st) {
705 + st = rrdset_create(RRD_TYPE_NET_SNMP6, "mcast", NULL, "multicast", NULL, "IPv6 Multicast Bandwidth", "kilobits/s", 9000, update_every, RRDSET_TYPE_AREA);
706 + st->isdetail = 1;
707 +
708 + rrddim_add(st, "received", NULL, 8, 1024, RRDDIM_INCREMENTAL);
709 + rrddim_add(st, "sent", NULL, -8, 1024, RRDDIM_INCREMENTAL);
710 + }
711 + else rrdset_next(st);
712 +
713 + rrddim_set(st, "sent", Ip6OutMcastOctets);
714 + rrddim_set(st, "received", Ip6InMcastOctets);
715 + rrdset_done(st);
716 + }
717 +
718 + // --------------------------------------------------------------------
719 +
720 + if(do_bcast == CONFIG_ONDEMAND_YES || (do_bcast == CONFIG_ONDEMAND_ONDEMAND && (Ip6OutBcastOctets || Ip6InBcastOctets))) {
721 + do_bcast = CONFIG_ONDEMAND_YES;
722 + st = rrdset_find(RRD_TYPE_NET_SNMP6 ".bcast");
723 + if(!st) {
724 + st = rrdset_create(RRD_TYPE_NET_SNMP6, "bcast", NULL, "broadcast", NULL, "IPv6 Broadcast Bandwidth", "kilobits/s", 8000, update_every, RRDSET_TYPE_AREA);
725 + st->isdetail = 1;
726 +
727 + rrddim_add(st, "received", NULL, 8, 1024, RRDDIM_INCREMENTAL);
728 + rrddim_add(st, "sent", NULL, -8, 1024, RRDDIM_INCREMENTAL);
729 + }
730 + else rrdset_next(st);
731 +
732 + rrddim_set(st, "sent", Ip6OutBcastOctets);
733 + rrddim_set(st, "received", Ip6InBcastOctets);
734 + rrdset_done(st);
735 + }
736 +
737 + // --------------------------------------------------------------------
738 +
739 + if(do_mcast_p == CONFIG_ONDEMAND_YES || (do_mcast_p == CONFIG_ONDEMAND_ONDEMAND && (Ip6OutMcastPkts || Ip6InMcastPkts))) {
740 + do_mcast_p = CONFIG_ONDEMAND_YES;
741 + st = rrdset_find(RRD_TYPE_NET_SNMP6 ".mcastpkts");
742 + if(!st) {
743 + st = rrdset_create(RRD_TYPE_NET_SNMP6, "mcastpkts", NULL, "multicast", NULL, "IPv6 Multicast Packets", "packets/s", 9500, update_every, RRDSET_TYPE_LINE);
744 + st->isdetail = 1;
745 +
746 + rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
747 + rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
748 + }
749 + else rrdset_next(st);
750 +
751 + rrddim_set(st, "sent", Ip6OutMcastPkts);
752 + rrddim_set(st, "received", Ip6InMcastPkts);
753 + rrdset_done(st);
754 + }
755 +
756 + // --------------------------------------------------------------------
757 +
758 + if(do_icmp == CONFIG_ONDEMAND_YES || (do_icmp == CONFIG_ONDEMAND_ONDEMAND && (Icmp6InMsgs || Icmp6OutMsgs))) {
759 + do_icmp = CONFIG_ONDEMAND_YES;
760 + st = rrdset_find(RRD_TYPE_NET_SNMP6 ".icmp");
761 + if(!st) {
762 + st = rrdset_create(RRD_TYPE_NET_SNMP6, "icmp", NULL, "icmp", NULL, "IPv6 ICMP Messages", "messages/s", 10000, update_every, RRDSET_TYPE_LINE);
763 +
764 + rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
765 + rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
766 + }
767 + else rrdset_next(st);
768 +
769 + rrddim_set(st, "sent", Icmp6InMsgs);
770 + rrddim_set(st, "received", Icmp6OutMsgs);
771 + rrdset_done(st);
772 + }
773 +
774 + // --------------------------------------------------------------------
775 +
776 + if(do_icmp_redir == CONFIG_ONDEMAND_YES || (do_icmp_redir == CONFIG_ONDEMAND_ONDEMAND && (Icmp6InRedirects || Icmp6OutRedirects))) {
777 + do_icmp_redir = CONFIG_ONDEMAND_YES;
778 + st = rrdset_find(RRD_TYPE_NET_SNMP6 ".icmpredir");
779 + if(!st) {
780 + st = rrdset_create(RRD_TYPE_NET_SNMP6, "icmpredir", NULL, "icmp", NULL, "IPv6 ICMP Redirects", "redirects/s", 10050, update_every, RRDSET_TYPE_LINE);
781 +
782 + rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
783 + rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
784 + }
785 + else rrdset_next(st);
786 +
787 + rrddim_set(st, "sent", Icmp6InRedirects);
788 + rrddim_set(st, "received", Icmp6OutRedirects);
789 + rrdset_done(st);
790 + }
791 +
792 + // --------------------------------------------------------------------
793 +
794 + if(do_icmp_errors == CONFIG_ONDEMAND_YES || (do_icmp_errors == CONFIG_ONDEMAND_ONDEMAND
795 + && (
796 + Icmp6InErrors
797 + || Icmp6OutErrors
798 + || Icmp6InCsumErrors
799 + || Icmp6InDestUnreachs
800 + || Icmp6InPktTooBigs
801 + || Icmp6InTimeExcds
802 + || Icmp6InParmProblems
803 + || Icmp6OutDestUnreachs
804 + || Icmp6OutPktTooBigs
805 + || Icmp6OutTimeExcds
806 + || Icmp6OutParmProblems
807 + ))) {
808 + do_icmp_errors = CONFIG_ONDEMAND_YES;
809 + st = rrdset_find(RRD_TYPE_NET_SNMP6 ".icmperrors");
810 + if(!st) {
811 + st = rrdset_create(RRD_TYPE_NET_SNMP6, "icmperrors", NULL, "icmp", NULL, "IPv6 ICMP Errors", "errors/s", 10100, update_every, RRDSET_TYPE_LINE);
812 +
813 + rrddim_add(st, "InErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
814 + rrddim_add(st, "OutErrors", NULL, -1, 1, RRDDIM_INCREMENTAL);
815 +
816 + rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
817 + rrddim_add(st, "InDestUnreachs", NULL, 1, 1, RRDDIM_INCREMENTAL);
818 + rrddim_add(st, "InPktTooBigs", NULL, 1, 1, RRDDIM_INCREMENTAL);
819 + rrddim_add(st, "InTimeExcds", NULL, 1, 1, RRDDIM_INCREMENTAL);
820 + rrddim_add(st, "InParmProblems", NULL, 1, 1, RRDDIM_INCREMENTAL);
821 + rrddim_add(st, "OutDestUnreachs", NULL, -1, 1, RRDDIM_INCREMENTAL);
822 + rrddim_add(st, "OutPktTooBigs", NULL, -1, 1, RRDDIM_INCREMENTAL);
823 + rrddim_add(st, "OutTimeExcds", NULL, -1, 1, RRDDIM_INCREMENTAL);
824 + rrddim_add(st, "OutParmProblems", NULL, -1, 1, RRDDIM_INCREMENTAL);
825 + }
826 + else rrdset_next(st);
827 +
828 + rrddim_set(st, "InErrors", Icmp6InErrors);
829 + rrddim_set(st, "OutErrors", Icmp6OutErrors);
830 + rrddim_set(st, "InCsumErrors", Icmp6InCsumErrors);
831 + rrddim_set(st, "InDestUnreachs", Icmp6InDestUnreachs);
832 + rrddim_set(st, "InPktTooBigs", Icmp6InPktTooBigs);
833 + rrddim_set(st, "InTimeExcds", Icmp6InTimeExcds);
834 + rrddim_set(st, "InParmProblems", Icmp6InParmProblems);
835 + rrddim_set(st, "OutDestUnreachs", Icmp6OutDestUnreachs);
836 + rrddim_set(st, "OutPktTooBigs", Icmp6OutPktTooBigs);
837 + rrddim_set(st, "OutTimeExcds", Icmp6OutTimeExcds);
838 + rrddim_set(st, "OutParmProblems", Icmp6OutParmProblems);
839 + rrdset_done(st);
840 + }
841 +
842 + // --------------------------------------------------------------------
843 +
844 + if(do_icmp_echos == CONFIG_ONDEMAND_YES || (do_icmp_echos == CONFIG_ONDEMAND_ONDEMAND
845 + && (
846 + Icmp6InEchos
847 + || Icmp6OutEchos
848 + || Icmp6InEchoReplies
849 + || Icmp6OutEchoReplies
850 + ))) {
851 + do_icmp_echos = CONFIG_ONDEMAND_YES;
852 + st = rrdset_find(RRD_TYPE_NET_SNMP6 ".icmpechos");
853 + if(!st) {
854 + st = rrdset_create(RRD_TYPE_NET_SNMP6, "icmpechos", NULL, "icmp", NULL, "IPv6 ICMP Echo", "messages/s", 10200, update_every, RRDSET_TYPE_LINE);
855 +
856 + rrddim_add(st, "InEchos", NULL, 1, 1, RRDDIM_INCREMENTAL);
857 + rrddim_add(st, "OutEchos", NULL, -1, 1, RRDDIM_INCREMENTAL);
858 + rrddim_add(st, "InEchoReplies", NULL, 1, 1, RRDDIM_INCREMENTAL);
859 + rrddim_add(st, "OutEchoReplies", NULL, -1, 1, RRDDIM_INCREMENTAL);
860 + }
861 + else rrdset_next(st);
862 +
863 + rrddim_set(st, "InEchos", Icmp6InEchos);
864 + rrddim_set(st, "OutEchos", Icmp6OutEchos);
865 + rrddim_set(st, "InEchoReplies", Icmp6InEchoReplies);
866 + rrddim_set(st, "OutEchoReplies", Icmp6OutEchoReplies);
867 + rrdset_done(st);
868 + }
869 +
870 + // --------------------------------------------------------------------
871 +
872 + if(do_icmp_groupmemb == CONFIG_ONDEMAND_YES || (do_icmp_groupmemb == CONFIG_ONDEMAND_ONDEMAND
873 + && (
874 + Icmp6InGroupMembQueries
875 + || Icmp6OutGroupMembQueries
876 + || Icmp6InGroupMembResponses
877 + || Icmp6OutGroupMembResponses
878 + || Icmp6InGroupMembReductions
879 + || Icmp6OutGroupMembReductions
880 + ))) {
881 + do_icmp_groupmemb = CONFIG_ONDEMAND_YES;
882 + st = rrdset_find(RRD_TYPE_NET_SNMP6 ".groupmemb");
883 + if(!st) {
884 + st = rrdset_create(RRD_TYPE_NET_SNMP6, "groupmemb", NULL, "icmp", NULL, "IPv6 ICMP Group Membership", "messages/s", 10300, update_every, RRDSET_TYPE_LINE);
885 +
886 + rrddim_add(st, "InQueries", NULL, 1, 1, RRDDIM_INCREMENTAL);
887 + rrddim_add(st, "OutQueries", NULL, -1, 1, RRDDIM_INCREMENTAL);
888 + rrddim_add(st, "InResponses", NULL, 1, 1, RRDDIM_INCREMENTAL);
889 + rrddim_add(st, "OutResponses", NULL, -1, 1, RRDDIM_INCREMENTAL);
890 + rrddim_add(st, "InReductions", NULL, 1, 1, RRDDIM_INCREMENTAL);
891 + rrddim_add(st, "OutReductions", NULL, -1, 1, RRDDIM_INCREMENTAL);
892 + }
893 + else rrdset_next(st);
894 +
895 + rrddim_set(st, "InQueries", Icmp6InGroupMembQueries);
896 + rrddim_set(st, "OutQueries", Icmp6OutGroupMembQueries);
897 + rrddim_set(st, "InResponses", Icmp6InGroupMembResponses);
898 + rrddim_set(st, "OutResponses", Icmp6OutGroupMembResponses);
899 + rrddim_set(st, "InReductions", Icmp6InGroupMembReductions);
900 + rrddim_set(st, "OutReductions", Icmp6OutGroupMembReductions);
901 + rrdset_done(st);
902 + }
903 +
904 + // --------------------------------------------------------------------
905 +
906 + if(do_icmp_router == CONFIG_ONDEMAND_YES || (do_icmp_router == CONFIG_ONDEMAND_ONDEMAND
907 + && (
908 + Icmp6InRouterSolicits
909 + || Icmp6OutRouterSolicits
910 + || Icmp6InRouterAdvertisements
911 + || Icmp6OutRouterAdvertisements
912 + ))) {
913 + do_icmp_router = CONFIG_ONDEMAND_YES;
914 + st = rrdset_find(RRD_TYPE_NET_SNMP6 ".icmprouter");
915 + if(!st) {
916 + st = rrdset_create(RRD_TYPE_NET_SNMP6, "icmprouter", NULL, "icmp", NULL, "IPv6 Router Messages", "messages/s", 10400, update_every, RRDSET_TYPE_LINE);
917 +
918 + rrddim_add(st, "InSolicits", NULL, 1, 1, RRDDIM_INCREMENTAL);
919 + rrddim_add(st, "OutSolicits", NULL, -1, 1, RRDDIM_INCREMENTAL);
920 + rrddim_add(st, "InAdvertisements", NULL, 1, 1, RRDDIM_INCREMENTAL);
921 + rrddim_add(st, "OutAdvertisements", NULL, -1, 1, RRDDIM_INCREMENTAL);
922 + }
923 + else rrdset_next(st);
924 +
925 + rrddim_set(st, "InSolicits", Icmp6InRouterSolicits);
926 + rrddim_set(st, "OutSolicits", Icmp6OutRouterSolicits);
927 + rrddim_set(st, "InAdvertisements", Icmp6InRouterAdvertisements);
928 + rrddim_set(st, "OutAdvertisements", Icmp6OutRouterAdvertisements);
929 + rrdset_done(st);
930 + }
931 +
932 + // --------------------------------------------------------------------
933 +
934 + if(do_icmp_neighbor == CONFIG_ONDEMAND_YES || (do_icmp_neighbor == CONFIG_ONDEMAND_ONDEMAND
935 + && (
936 + Icmp6InNeighborSolicits
937 + || Icmp6OutNeighborSolicits
938 + || Icmp6InNeighborAdvertisements
939 + || Icmp6OutNeighborAdvertisements
940 + ))) {
941 + do_icmp_neighbor = CONFIG_ONDEMAND_YES;
942 + st = rrdset_find(RRD_TYPE_NET_SNMP6 ".icmpneighbor");
943 + if(!st) {
944 + st = rrdset_create(RRD_TYPE_NET_SNMP6, "icmpneighbor", NULL, "icmp", NULL, "IPv6 Neighbor Messages", "messages/s", 10500, update_every, RRDSET_TYPE_LINE);
945 +
946 + rrddim_add(st, "InSolicits", NULL, 1, 1, RRDDIM_INCREMENTAL);
947 + rrddim_add(st, "OutSolicits", NULL, -1, 1, RRDDIM_INCREMENTAL);
948 + rrddim_add(st, "InAdvertisements", NULL, 1, 1, RRDDIM_INCREMENTAL);
949 + rrddim_add(st, "OutAdvertisements", NULL, -1, 1, RRDDIM_INCREMENTAL);
950 + }
951 + else rrdset_next(st);
952 +
953 + rrddim_set(st, "InSolicits", Icmp6InNeighborSolicits);
954 + rrddim_set(st, "OutSolicits", Icmp6OutNeighborSolicits);
955 + rrddim_set(st, "InAdvertisements", Icmp6InNeighborAdvertisements);
956 + rrddim_set(st, "OutAdvertisements", Icmp6OutNeighborAdvertisements);
957 + rrdset_done(st);
958 + }
959 +
960 + // --------------------------------------------------------------------
961 +
962 + if(do_icmp_mldv2 == CONFIG_ONDEMAND_YES || (do_icmp_mldv2 == CONFIG_ONDEMAND_ONDEMAND && (Icmp6InMLDv2Reports || Icmp6OutMLDv2Reports))) {
963 + do_icmp_mldv2 = CONFIG_ONDEMAND_YES;
964 + st = rrdset_find(RRD_TYPE_NET_SNMP6 ".icmpmldv2");
965 + if(!st) {
966 + st = rrdset_create(RRD_TYPE_NET_SNMP6, "icmpmldv2", NULL, "icmp", NULL, "IPv6 ICMP MLDv2 Reports", "reports/s", 10600, update_every, RRDSET_TYPE_LINE);
967 +
968 + rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
969 + rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
970 + }
971 + else rrdset_next(st);
972 +
973 + rrddim_set(st, "sent", Icmp6InMLDv2Reports);
974 + rrddim_set(st, "received", Icmp6OutMLDv2Reports);
975 + rrdset_done(st);
976 + }
977 +
978 + // --------------------------------------------------------------------
979 +
980 + if(do_icmp_types == CONFIG_ONDEMAND_YES || (do_icmp_types == CONFIG_ONDEMAND_ONDEMAND
981 + && (
982 + Icmp6InType1
983 + || Icmp6InType128
984 + || Icmp6InType129
985 + || Icmp6InType136
986 + || Icmp6OutType1
987 + || Icmp6OutType128
988 + || Icmp6OutType129
989 + || Icmp6OutType133
990 + || Icmp6OutType135
991 + || Icmp6OutType143
992 + ))) {
993 + do_icmp_types = CONFIG_ONDEMAND_YES;
994 + st = rrdset_find(RRD_TYPE_NET_SNMP6 ".icmptypes");
995 + if(!st) {
996 + st = rrdset_create(RRD_TYPE_NET_SNMP6, "icmptypes", NULL, "icmp", NULL, "IPv6 ICMP Types", "messages/s", 10700, update_every, RRDSET_TYPE_LINE);
997 +
998 + rrddim_add(st, "InType1", NULL, 1, 1, RRDDIM_INCREMENTAL);
999 + rrddim_add(st, "InType128", NULL, 1, 1, RRDDIM_INCREMENTAL);
1000 + rrddim_add(st, "InType129", NULL, 1, 1, RRDDIM_INCREMENTAL);
1001 + rrddim_add(st, "InType136", NULL, 1, 1, RRDDIM_INCREMENTAL);
1002 + rrddim_add(st, "OutType1", NULL, -1, 1, RRDDIM_INCREMENTAL);
1003 + rrddim_add(st, "OutType128", NULL, -1, 1, RRDDIM_INCREMENTAL);
1004 + rrddim_add(st, "OutType129", NULL, -1, 1, RRDDIM_INCREMENTAL);
1005 + rrddim_add(st, "OutType133", NULL, -1, 1, RRDDIM_INCREMENTAL);
1006 + rrddim_add(st, "OutType135", NULL, -1, 1, RRDDIM_INCREMENTAL);
1007 + rrddim_add(st, "OutType143", NULL, -1, 1, RRDDIM_INCREMENTAL);
1008 + }
1009 + else rrdset_next(st);
1010 +
1011 + rrddim_set(st, "InType1", Icmp6InType1);
1012 + rrddim_set(st, "InType128", Icmp6InType128);
1013 + rrddim_set(st, "InType129", Icmp6InType129);
1014 + rrddim_set(st, "InType136", Icmp6InType136);
1015 + rrddim_set(st, "OutType1", Icmp6OutType1);
1016 + rrddim_set(st, "OutType128", Icmp6OutType128);
1017 + rrddim_set(st, "OutType129", Icmp6OutType129);
1018 + rrddim_set(st, "OutType133", Icmp6OutType133);
1019 + rrddim_set(st, "OutType135", Icmp6OutType135);
1020 + rrddim_set(st, "OutType143", Icmp6OutType143);
1021 + rrdset_done(st);
1022 + }
1023 +
1024 + // --------------------------------------------------------------------
1025 +
1026 + if(do_ect == CONFIG_ONDEMAND_YES || (do_ect == CONFIG_ONDEMAND_ONDEMAND
1027 + && (
1028 + Ip6InNoECTPkts
1029 + || Ip6InECT1Pkts
1030 + || Ip6InECT0Pkts
1031 + || Ip6InCEPkts
1032 + ))) {
1033 + do_ect = CONFIG_ONDEMAND_YES;
1034 + st = rrdset_find(RRD_TYPE_NET_SNMP6 ".ect");
1035 + if(!st) {
1036 + st = rrdset_create(RRD_TYPE_NET_SNMP6, "ect", NULL, "packets", NULL, "IPv6 ECT Packets", "packets/s", 10800, update_every, RRDSET_TYPE_LINE);
1037 +
1038 + rrddim_add(st, "InNoECTPkts", NULL, 1, 1, RRDDIM_INCREMENTAL);
1039 + rrddim_add(st, "InECT1Pkts", NULL, 1, 1, RRDDIM_INCREMENTAL);
1040 + rrddim_add(st, "InECT0Pkts", NULL, 1, 1, RRDDIM_INCREMENTAL);
1041 + rrddim_add(st, "InCEPkts", NULL, 1, 1, RRDDIM_INCREMENTAL);
1042 + }
1043 + else rrdset_next(st);
1044 +
1045 + rrddim_set(st, "InNoECTPkts", Ip6InNoECTPkts);
1046 + rrddim_set(st, "InECT1Pkts", Ip6InECT1Pkts);
1047 + rrddim_set(st, "InECT0Pkts", Ip6InECT0Pkts);
1048 + rrddim_set(st, "InCEPkts", Ip6InCEPkts);
1049 + rrdset_done(st);
1050 + }
1051 +
1052 + return 0;
1053 }
1054
src/proc_net_stat_conntrack.c
+198 -198
@@ -1,203 +1,203 @@
1 #include "common.h"
2
3 -#define RRD_TYPE_NET_STAT_NETFILTER "netfilter"
4 -#define RRD_TYPE_NET_STAT_CONNTRACK "conntrack"
5 -#define RRD_TYPE_NET_STAT_CONNTRACK_LEN strlen(RRD_TYPE_NET_STAT_CONNTRACK)
3 +#define RRD_TYPE_NET_STAT_NETFILTER "netfilter"
4 +#define RRD_TYPE_NET_STAT_CONNTRACK "conntrack"
5 +#define RRD_TYPE_NET_STAT_CONNTRACK_LEN strlen(RRD_TYPE_NET_STAT_CONNTRACK)
6
7 int do_proc_net_stat_conntrack(int update_every, unsigned long long dt) {
8 - static procfile *ff = NULL;
9 - static int do_sockets = -1, do_new = -1, do_changes = -1, do_expect = -1, do_search = -1, do_errors = -1;
10 -
11 - if(do_sockets == -1) do_sockets = config_get_boolean("plugin:proc:/proc/net/stat/nf_conntrack", "netfilter connections", 1);
12 - if(do_new == -1) do_new = config_get_boolean("plugin:proc:/proc/net/stat/nf_conntrack", "netfilter new connections", 1);
13 - if(do_changes == -1) do_changes = config_get_boolean("plugin:proc:/proc/net/stat/nf_conntrack", "netfilter connection changes", 1);
14 - if(do_expect == -1) do_expect = config_get_boolean("plugin:proc:/proc/net/stat/nf_conntrack", "netfilter connection expectations", 1);
15 - if(do_search == -1) do_search = config_get_boolean("plugin:proc:/proc/net/stat/nf_conntrack", "netfilter connection searches", 1);
16 - if(do_errors == -1) do_errors = config_get_boolean("plugin:proc:/proc/net/stat/nf_conntrack", "netfilter errors", 1);
17 -
18 - if(dt) {};
19 -
20 - if(!ff) {
21 - char filename[FILENAME_MAX + 1];
22 - snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/net/stat/nf_conntrack");
23 - ff = procfile_open(config_get("plugin:proc:/proc/net/stat/nf_conntrack", "filename to monitor", filename), " \t:", PROCFILE_FLAG_DEFAULT);
24 - }
25 - if(!ff) return 1;
26 -
27 - ff = procfile_readall(ff);
28 - if(!ff) return 0; // we return 0, so that we will retry to open it next time
29 -
30 - uint32_t lines = procfile_lines(ff), l;
31 - uint32_t words;
32 -
33 - unsigned long long aentries = 0, asearched = 0, afound = 0, anew = 0, ainvalid = 0, aignore = 0, adelete = 0, adelete_list = 0,
34 - ainsert = 0, ainsert_failed = 0, adrop = 0, aearly_drop = 0, aicmp_error = 0, aexpect_new = 0, aexpect_create = 0, aexpect_delete = 0, asearch_restart = 0;
35 -
36 - for(l = 1; l < lines ;l++) {
37 - words = procfile_linewords(ff, l);
38 - if(words < 17) {
39 - if(words) error("Cannot read /proc/net/stat/nf_conntrack line. Expected 17 params, read %u.", words);
40 - continue;
41 - }
42 -
43 - unsigned long long tentries = 0, tsearched = 0, tfound = 0, tnew = 0, tinvalid = 0, tignore = 0, tdelete = 0, tdelete_list = 0, tinsert = 0, tinsert_failed = 0, tdrop = 0, tearly_drop = 0, ticmp_error = 0, texpect_new = 0, texpect_create = 0, texpect_delete = 0, tsearch_restart = 0;
44 -
45 - tentries = strtoull(procfile_lineword(ff, l, 0), NULL, 16);
46 - tsearched = strtoull(procfile_lineword(ff, l, 1), NULL, 16);
47 - tfound = strtoull(procfile_lineword(ff, l, 2), NULL, 16);
48 - tnew = strtoull(procfile_lineword(ff, l, 3), NULL, 16);
49 - tinvalid = strtoull(procfile_lineword(ff, l, 4), NULL, 16);
50 - tignore = strtoull(procfile_lineword(ff, l, 5), NULL, 16);
51 - tdelete = strtoull(procfile_lineword(ff, l, 6), NULL, 16);
52 - tdelete_list = strtoull(procfile_lineword(ff, l, 7), NULL, 16);
53 - tinsert = strtoull(procfile_lineword(ff, l, 8), NULL, 16);
54 - tinsert_failed = strtoull(procfile_lineword(ff, l, 9), NULL, 16);
55 - tdrop = strtoull(procfile_lineword(ff, l, 10), NULL, 16);
56 - tearly_drop = strtoull(procfile_lineword(ff, l, 11), NULL, 16);
57 - ticmp_error = strtoull(procfile_lineword(ff, l, 12), NULL, 16);
58 - texpect_new = strtoull(procfile_lineword(ff, l, 13), NULL, 16);
59 - texpect_create = strtoull(procfile_lineword(ff, l, 14), NULL, 16);
60 - texpect_delete = strtoull(procfile_lineword(ff, l, 15), NULL, 16);
61 - tsearch_restart = strtoull(procfile_lineword(ff, l, 16), NULL, 16);
62 -
63 - if(!aentries) aentries = tentries;
64 -
65 - // sum all the cpus together
66 - asearched += tsearched; // conntrack.search
67 - afound += tfound; // conntrack.search
68 - anew += tnew; // conntrack.new
69 - ainvalid += tinvalid; // conntrack.new
70 - aignore += tignore; // conntrack.new
71 - adelete += tdelete; // conntrack.changes
72 - adelete_list += tdelete_list; // conntrack.changes
73 - ainsert += tinsert; // conntrack.changes
74 - ainsert_failed += tinsert_failed; // conntrack.errors
75 - adrop += tdrop; // conntrack.errors
76 - aearly_drop += tearly_drop; // conntrack.errors
77 - aicmp_error += ticmp_error; // conntrack.errors
78 - aexpect_new += texpect_new; // conntrack.expect
79 - aexpect_create += texpect_create; // conntrack.expect
80 - aexpect_delete += texpect_delete; // conntrack.expect
81 - asearch_restart += tsearch_restart; // conntrack.search
82 - }
83 -
84 - RRDSET *st;
85 -
86 - // --------------------------------------------------------------------
87 -
88 - if(do_sockets) {
89 - st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_CONNTRACK "_sockets");
90 - if(!st) {
91 - st = rrdset_create(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_CONNTRACK "_sockets", NULL, RRD_TYPE_NET_STAT_CONNTRACK, NULL, "Connection Tracker Connections", "active connections", 1000, update_every, RRDSET_TYPE_LINE);
92 -
93 - rrddim_add(st, "connections", NULL, 1, 1, RRDDIM_ABSOLUTE);
94 - }
95 - else rrdset_next(st);
96 -
97 - rrddim_set(st, "connections", aentries);
98 - rrdset_done(st);
99 - }
100 -
101 - // --------------------------------------------------------------------
102 -
103 - if(do_new) {
104 - st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_CONNTRACK "_new");
105 - if(!st) {
106 - st = rrdset_create(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_CONNTRACK "_new", NULL, RRD_TYPE_NET_STAT_CONNTRACK, NULL, "Connection Tracker New Connections", "connections/s", 1001, update_every, RRDSET_TYPE_LINE);
107 -
108 - rrddim_add(st, "new", NULL, 1, 1, RRDDIM_INCREMENTAL);
109 - rrddim_add(st, "ignore", NULL, -1, 1, RRDDIM_INCREMENTAL);
110 - rrddim_add(st, "invalid", NULL, -1, 1, RRDDIM_INCREMENTAL);
111 - }
112 - else rrdset_next(st);
113 -
114 - rrddim_set(st, "new", anew);
115 - rrddim_set(st, "ignore", aignore);
116 - rrddim_set(st, "invalid", ainvalid);
117 - rrdset_done(st);
118 - }
119 -
120 - // --------------------------------------------------------------------
121 -
122 - if(do_changes) {
123 - st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_CONNTRACK "_changes");
124 - if(!st) {
125 - st = rrdset_create(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_CONNTRACK "_changes", NULL, RRD_TYPE_NET_STAT_CONNTRACK, NULL, "Connection Tracker Changes", "changes/s", 1002, update_every, RRDSET_TYPE_LINE);
126 - st->isdetail = 1;
127 -
128 - rrddim_add(st, "inserted", NULL, 1, 1, RRDDIM_INCREMENTAL);
129 - rrddim_add(st, "deleted", NULL, -1, 1, RRDDIM_INCREMENTAL);
130 - rrddim_add(st, "delete_list", NULL, -1, 1, RRDDIM_INCREMENTAL);
131 - }
132 - else rrdset_next(st);
133 -
134 - rrddim_set(st, "inserted", ainsert);
135 - rrddim_set(st, "deleted", adelete);
136 - rrddim_set(st, "delete_list", adelete_list);
137 - rrdset_done(st);
138 - }
139 -
140 - // --------------------------------------------------------------------
141 -
142 - if(do_expect) {
143 - st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_CONNTRACK "_expect");
144 - if(!st) {
145 - st = rrdset_create(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_CONNTRACK "_expect", NULL, RRD_TYPE_NET_STAT_CONNTRACK, NULL, "Connection Tracker Expectations", "expectations/s", 1003, update_every, RRDSET_TYPE_LINE);
146 - st->isdetail = 1;
147 -
148 - rrddim_add(st, "created", NULL, 1, 1, RRDDIM_INCREMENTAL);
149 - rrddim_add(st, "deleted", NULL, -1, 1, RRDDIM_INCREMENTAL);
150 - rrddim_add(st, "new", NULL, 1, 1, RRDDIM_INCREMENTAL);
151 - }
152 - else rrdset_next(st);
153 -
154 - rrddim_set(st, "created", aexpect_create);
155 - rrddim_set(st, "deleted", aexpect_delete);
156 - rrddim_set(st, "new", aexpect_new);
157 - rrdset_done(st);
158 - }
159 -
160 - // --------------------------------------------------------------------
161 -
162 - if(do_search) {
163 - st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_CONNTRACK "_search");
164 - if(!st) {
165 - st = rrdset_create(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_CONNTRACK "_search", NULL, RRD_TYPE_NET_STAT_CONNTRACK, NULL, "Connection Tracker Searches", "searches/s", 1010, update_every, RRDSET_TYPE_LINE);
166 - st->isdetail = 1;
167 -
168 - rrddim_add(st, "searched", NULL, 1, 1, RRDDIM_INCREMENTAL);
169 - rrddim_add(st, "restarted", NULL, -1, 1, RRDDIM_INCREMENTAL);
170 - rrddim_add(st, "found", NULL, 1, 1, RRDDIM_INCREMENTAL);
171 - }
172 - else rrdset_next(st);
173 -
174 - rrddim_set(st, "searched", asearched);
175 - rrddim_set(st, "restarted", asearch_restart);
176 - rrddim_set(st, "found", afound);
177 - rrdset_done(st);
178 - }
179 -
180 - // --------------------------------------------------------------------
181 -
182 - if(do_errors) {
183 - st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_CONNTRACK "_errors");
184 - if(!st) {
185 - st = rrdset_create(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_CONNTRACK "_errors", NULL, RRD_TYPE_NET_STAT_CONNTRACK, NULL, "Connection Tracker Errors", "events/s", 1005, update_every, RRDSET_TYPE_LINE);
186 - st->isdetail = 1;
187 -
188 - rrddim_add(st, "icmp_error", NULL, 1, 1, RRDDIM_INCREMENTAL);
189 - rrddim_add(st, "insert_failed", NULL, -1, 1, RRDDIM_INCREMENTAL);
190 - rrddim_add(st, "drop", NULL, -1, 1, RRDDIM_INCREMENTAL);
191 - rrddim_add(st, "early_drop", NULL, -1, 1, RRDDIM_INCREMENTAL);
192 - }
193 - else rrdset_next(st);
194 -
195 - rrddim_set(st, "icmp_error", aicmp_error);
196 - rrddim_set(st, "insert_failed", ainsert_failed);
197 - rrddim_set(st, "drop", adrop);
198 - rrddim_set(st, "early_drop", aearly_drop);
199 - rrdset_done(st);
200 - }
201 -
202 - return 0;
8 + static procfile *ff = NULL;
9 + static int do_sockets = -1, do_new = -1, do_changes = -1, do_expect = -1, do_search = -1, do_errors = -1;
10 +
11 + if(do_sockets == -1) do_sockets = config_get_boolean("plugin:proc:/proc/net/stat/nf_conntrack", "netfilter connections", 1);
12 + if(do_new == -1) do_new = config_get_boolean("plugin:proc:/proc/net/stat/nf_conntrack", "netfilter new connections", 1);
13 + if(do_changes == -1) do_changes = config_get_boolean("plugin:proc:/proc/net/stat/nf_conntrack", "netfilter connection changes", 1);
14 + if(do_expect == -1) do_expect = config_get_boolean("plugin:proc:/proc/net/stat/nf_conntrack", "netfilter connection expectations", 1);
15 + if(do_search == -1) do_search = config_get_boolean("plugin:proc:/proc/net/stat/nf_conntrack", "netfilter connection searches", 1);
16 + if(do_errors == -1) do_errors = config_get_boolean("plugin:proc:/proc/net/stat/nf_conntrack", "netfilter errors", 1);
17 +
18 + if(dt) {};
19 +
20 + if(!ff) {
21 + char filename[FILENAME_MAX + 1];
22 + snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/net/stat/nf_conntrack");
23 + ff = procfile_open(config_get("plugin:proc:/proc/net/stat/nf_conntrack", "filename to monitor", filename), " \t:", PROCFILE_FLAG_DEFAULT);
24 + }
25 + if(!ff) return 1;
26 +
27 + ff = procfile_readall(ff);
28 + if(!ff) return 0; // we return 0, so that we will retry to open it next time
29 +
30 + uint32_t lines = procfile_lines(ff), l;
31 + uint32_t words;
32 +
33 + unsigned long long aentries = 0, asearched = 0, afound = 0, anew = 0, ainvalid = 0, aignore = 0, adelete = 0, adelete_list = 0,
34 + ainsert = 0, ainsert_failed = 0, adrop = 0, aearly_drop = 0, aicmp_error = 0, aexpect_new = 0, aexpect_create = 0, aexpect_delete = 0, asearch_restart = 0;
35 +
36 + for(l = 1; l < lines ;l++) {
37 + words = procfile_linewords(ff, l);
38 + if(words < 17) {
39 + if(words) error("Cannot read /proc/net/stat/nf_conntrack line. Expected 17 params, read %u.", words);
40 + continue;
41 + }
42 +
43 + unsigned long long tentries = 0, tsearched = 0, tfound = 0, tnew = 0, tinvalid = 0, tignore = 0, tdelete = 0, tdelete_list = 0, tinsert = 0, tinsert_failed = 0, tdrop = 0, tearly_drop = 0, ticmp_error = 0, texpect_new = 0, texpect_create = 0, texpect_delete = 0, tsearch_restart = 0;
44 +
45 + tentries = strtoull(procfile_lineword(ff, l, 0), NULL, 16);
46 + tsearched = strtoull(procfile_lineword(ff, l, 1), NULL, 16);
47 + tfound = strtoull(procfile_lineword(ff, l, 2), NULL, 16);
48 + tnew = strtoull(procfile_lineword(ff, l, 3), NULL, 16);
49 + tinvalid = strtoull(procfile_lineword(ff, l, 4), NULL, 16);
50 + tignore = strtoull(procfile_lineword(ff, l, 5), NULL, 16);
51 + tdelete = strtoull(procfile_lineword(ff, l, 6), NULL, 16);
52 + tdelete_list = strtoull(procfile_lineword(ff, l, 7), NULL, 16);
53 + tinsert = strtoull(procfile_lineword(ff, l, 8), NULL, 16);
54 + tinsert_failed = strtoull(procfile_lineword(ff, l, 9), NULL, 16);
55 + tdrop = strtoull(procfile_lineword(ff, l, 10), NULL, 16);
56 + tearly_drop = strtoull(procfile_lineword(ff, l, 11), NULL, 16);
57 + ticmp_error = strtoull(procfile_lineword(ff, l, 12), NULL, 16);
58 + texpect_new = strtoull(procfile_lineword(ff, l, 13), NULL, 16);
59 + texpect_create = strtoull(procfile_lineword(ff, l, 14), NULL, 16);
60 + texpect_delete = strtoull(procfile_lineword(ff, l, 15), NULL, 16);
61 + tsearch_restart = strtoull(procfile_lineword(ff, l, 16), NULL, 16);
62 +
63 + if(!aentries) aentries = tentries;
64 +
65 + // sum all the cpus together
66 + asearched += tsearched; // conntrack.search
67 + afound += tfound; // conntrack.search
68 + anew += tnew; // conntrack.new
69 + ainvalid += tinvalid; // conntrack.new
70 + aignore += tignore; // conntrack.new
71 + adelete += tdelete; // conntrack.changes
72 + adelete_list += tdelete_list; // conntrack.changes
73 + ainsert += tinsert; // conntrack.changes
74 + ainsert_failed += tinsert_failed; // conntrack.errors
75 + adrop += tdrop; // conntrack.errors
76 + aearly_drop += tearly_drop; // conntrack.errors
77 + aicmp_error += ticmp_error; // conntrack.errors
78 + aexpect_new += texpect_new; // conntrack.expect
79 + aexpect_create += texpect_create; // conntrack.expect
80 + aexpect_delete += texpect_delete; // conntrack.expect
81 + asearch_restart += tsearch_restart; // conntrack.search
82 + }
83 +
84 + RRDSET *st;
85 +
86 + // --------------------------------------------------------------------
87 +
88 + if(do_sockets) {
89 + st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_CONNTRACK "_sockets");
90 + if(!st) {
91 + st = rrdset_create(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_CONNTRACK "_sockets", NULL, RRD_TYPE_NET_STAT_CONNTRACK, NULL, "Connection Tracker Connections", "active connections", 1000, update_every, RRDSET_TYPE_LINE);
92 +
93 + rrddim_add(st, "connections", NULL, 1, 1, RRDDIM_ABSOLUTE);
94 + }
95 + else rrdset_next(st);
96 +
97 + rrddim_set(st, "connections", aentries);
98 + rrdset_done(st);
99 + }
100 +
101 + // --------------------------------------------------------------------
102 +
103 + if(do_new) {
104 + st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_CONNTRACK "_new");
105 + if(!st) {
106 + st = rrdset_create(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_CONNTRACK "_new", NULL, RRD_TYPE_NET_STAT_CONNTRACK, NULL, "Connection Tracker New Connections", "connections/s", 1001, update_every, RRDSET_TYPE_LINE);
107 +
108 + rrddim_add(st, "new", NULL, 1, 1, RRDDIM_INCREMENTAL);
109 + rrddim_add(st, "ignore", NULL, -1, 1, RRDDIM_INCREMENTAL);
110 + rrddim_add(st, "invalid", NULL, -1, 1, RRDDIM_INCREMENTAL);
111 + }
112 + else rrdset_next(st);
113 +
114 + rrddim_set(st, "new", anew);
115 + rrddim_set(st, "ignore", aignore);
116 + rrddim_set(st, "invalid", ainvalid);
117 + rrdset_done(st);
118 + }
119 +
120 + // --------------------------------------------------------------------
121 +
122 + if(do_changes) {
123 + st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_CONNTRACK "_changes");
124 + if(!st) {
125 + st = rrdset_create(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_CONNTRACK "_changes", NULL, RRD_TYPE_NET_STAT_CONNTRACK, NULL, "Connection Tracker Changes", "changes/s", 1002, update_every, RRDSET_TYPE_LINE);
126 + st->isdetail = 1;
127 +
128 + rrddim_add(st, "inserted", NULL, 1, 1, RRDDIM_INCREMENTAL);
129 + rrddim_add(st, "deleted", NULL, -1, 1, RRDDIM_INCREMENTAL);
130 + rrddim_add(st, "delete_list", NULL, -1, 1, RRDDIM_INCREMENTAL);
131 + }
132 + else rrdset_next(st);
133 +
134 + rrddim_set(st, "inserted", ainsert);
135 + rrddim_set(st, "deleted", adelete);
136 + rrddim_set(st, "delete_list", adelete_list);
137 + rrdset_done(st);
138 + }
139 +
140 + // --------------------------------------------------------------------
141 +
142 + if(do_expect) {
143 + st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_CONNTRACK "_expect");
144 + if(!st) {
145 + st = rrdset_create(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_CONNTRACK "_expect", NULL, RRD_TYPE_NET_STAT_CONNTRACK, NULL, "Connection Tracker Expectations", "expectations/s", 1003, update_every, RRDSET_TYPE_LINE);
146 + st->isdetail = 1;
147 +
148 + rrddim_add(st, "created", NULL, 1, 1, RRDDIM_INCREMENTAL);
149 + rrddim_add(st, "deleted", NULL, -1, 1, RRDDIM_INCREMENTAL);
150 + rrddim_add(st, "new", NULL, 1, 1, RRDDIM_INCREMENTAL);
151 + }
152 + else rrdset_next(st);
153 +
154 + rrddim_set(st, "created", aexpect_create);
155 + rrddim_set(st, "deleted", aexpect_delete);
156 + rrddim_set(st, "new", aexpect_new);
157 + rrdset_done(st);
158 + }
159 +
160 + // --------------------------------------------------------------------
161 +
162 + if(do_search) {
163 + st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_CONNTRACK "_search");
164 + if(!st) {
165 + st = rrdset_create(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_CONNTRACK "_search", NULL, RRD_TYPE_NET_STAT_CONNTRACK, NULL, "Connection Tracker Searches", "searches/s", 1010, update_every, RRDSET_TYPE_LINE);
166 + st->isdetail = 1;
167 +
168 + rrddim_add(st, "searched", NULL, 1, 1, RRDDIM_INCREMENTAL);
169 + rrddim_add(st, "restarted", NULL, -1, 1, RRDDIM_INCREMENTAL);
170 + rrddim_add(st, "found", NULL, 1, 1, RRDDIM_INCREMENTAL);
171 + }
172 + else rrdset_next(st);
173 +
174 + rrddim_set(st, "searched", asearched);
175 + rrddim_set(st, "restarted", asearch_restart);
176 + rrddim_set(st, "found", afound);
177 + rrdset_done(st);
178 + }
179 +
180 + // --------------------------------------------------------------------
181 +
182 + if(do_errors) {
183 + st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_CONNTRACK "_errors");
184 + if(!st) {
185 + st = rrdset_create(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_CONNTRACK "_errors", NULL, RRD_TYPE_NET_STAT_CONNTRACK, NULL, "Connection Tracker Errors", "events/s", 1005, update_every, RRDSET_TYPE_LINE);
186 + st->isdetail = 1;
187 +
188 + rrddim_add(st, "icmp_error", NULL, 1, 1, RRDDIM_INCREMENTAL);
189 + rrddim_add(st, "insert_failed", NULL, -1, 1, RRDDIM_INCREMENTAL);
190 + rrddim_add(st, "drop", NULL, -1, 1, RRDDIM_INCREMENTAL);
191 + rrddim_add(st, "early_drop", NULL, -1, 1, RRDDIM_INCREMENTAL);
192 + }
193 + else rrdset_next(st);
194 +
195 + rrddim_set(st, "icmp_error", aicmp_error);
196 + rrddim_set(st, "insert_failed", ainsert_failed);
197 + rrddim_set(st, "drop", adrop);
198 + rrddim_set(st, "early_drop", aearly_drop);
199 + rrdset_done(st);
200 + }
201 +
202 + return 0;
203 }
src/proc_net_stat_synproxy.c
+91 -91
@@ -1,127 +1,127 @@
1 #include "common.h"
2
3 -#define RRD_TYPE_NET_STAT_NETFILTER "netfilter"
4 -#define RRD_TYPE_NET_STAT_SYNPROXY "synproxy"
5 -#define RRD_TYPE_NET_STAT_SYNPROXY_LEN strlen(RRD_TYPE_NET_STAT_SYNPROXY)
3 +#define RRD_TYPE_NET_STAT_NETFILTER "netfilter"
4 +#define RRD_TYPE_NET_STAT_SYNPROXY "synproxy"
5 +#define RRD_TYPE_NET_STAT_SYNPROXY_LEN strlen(RRD_TYPE_NET_STAT_SYNPROXY)
6
7 int do_proc_net_stat_synproxy(int update_every, unsigned long long dt) {
8 - static int do_entries = -1, do_cookies = -1, do_syns = -1, do_reopened = -1;
9 - static procfile *ff = NULL;
8 + static int do_entries = -1, do_cookies = -1, do_syns = -1, do_reopened = -1;
9 + static procfile *ff = NULL;
10
11 - if(do_entries == -1) do_entries = config_get_boolean_ondemand("plugin:proc:/proc/net/stat/synproxy", "SYNPROXY entries", CONFIG_ONDEMAND_ONDEMAND);
12 - if(do_cookies == -1) do_cookies = config_get_boolean_ondemand("plugin:proc:/proc/net/stat/synproxy", "SYNPROXY cookies", CONFIG_ONDEMAND_ONDEMAND);
13 - if(do_syns == -1) do_syns = config_get_boolean_ondemand("plugin:proc:/proc/net/stat/synproxy", "SYNPROXY SYN received", CONFIG_ONDEMAND_ONDEMAND);
14 - if(do_reopened == -1) do_reopened = config_get_boolean_ondemand("plugin:proc:/proc/net/stat/synproxy", "SYNPROXY connections reopened", CONFIG_ONDEMAND_ONDEMAND);
11 + if(do_entries == -1) do_entries = config_get_boolean_ondemand("plugin:proc:/proc/net/stat/synproxy", "SYNPROXY entries", CONFIG_ONDEMAND_ONDEMAND);
12 + if(do_cookies == -1) do_cookies = config_get_boolean_ondemand("plugin:proc:/proc/net/stat/synproxy", "SYNPROXY cookies", CONFIG_ONDEMAND_ONDEMAND);
13 + if(do_syns == -1) do_syns = config_get_boolean_ondemand("plugin:proc:/proc/net/stat/synproxy", "SYNPROXY SYN received", CONFIG_ONDEMAND_ONDEMAND);
14 + if(do_reopened == -1) do_reopened = config_get_boolean_ondemand("plugin:proc:/proc/net/stat/synproxy", "SYNPROXY connections reopened", CONFIG_ONDEMAND_ONDEMAND);
15
16 - if(dt) {};
16 + if(dt) {};
17
18 - if(!ff) {
19 - char filename[FILENAME_MAX + 1];
20 - snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/net/stat/synproxy");
21 - ff = procfile_open(config_get("plugin:proc:/proc/net/stat/synproxy", "filename to monitor", filename), " \t,:|", PROCFILE_FLAG_DEFAULT);
22 - }
23 - if(!ff) return 1;
18 + if(!ff) {
19 + char filename[FILENAME_MAX + 1];
20 + snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/net/stat/synproxy");
21 + ff = procfile_open(config_get("plugin:proc:/proc/net/stat/synproxy", "filename to monitor", filename), " \t,:|", PROCFILE_FLAG_DEFAULT);
22 + }
23 + if(!ff) return 1;
24
25 - ff = procfile_readall(ff);
26 - if(!ff) return 0; // we return 0, so that we will retry to open it next time
25 + ff = procfile_readall(ff);
26 + if(!ff) return 0; // we return 0, so that we will retry to open it next time
27
28 - // make sure we have 3 lines
29 - size_t lines = procfile_lines(ff), l;
30 - if(lines < 2) {
31 - error("/proc/net/stat/synproxy has %zu lines, expected no less than 2. Disabling it.", lines);
32 - return 1;
33 - }
28 + // make sure we have 3 lines
29 + size_t lines = procfile_lines(ff), l;
30 + if(lines < 2) {
31 + error("/proc/net/stat/synproxy has %zu lines, expected no less than 2. Disabling it.", lines);
32 + return 1;
33 + }
34
35 - unsigned long long entries = 0, syn_received = 0, cookie_invalid = 0, cookie_valid = 0, cookie_retrans = 0, conn_reopened = 0;
35 + unsigned long long entries = 0, syn_received = 0, cookie_invalid = 0, cookie_valid = 0, cookie_retrans = 0, conn_reopened = 0;
36
37 - // synproxy gives its values per CPU
38 - for(l = 1; l < lines ;l++) {
39 - int words = procfile_linewords(ff, l);
40 - if(words < 6) continue;
37 + // synproxy gives its values per CPU
38 + for(l = 1; l < lines ;l++) {
39 + int words = procfile_linewords(ff, l);
40 + if(words < 6) continue;
41
42 - entries += strtoull(procfile_lineword(ff, l, 0), NULL, 16);
43 - syn_received += strtoull(procfile_lineword(ff, l, 1), NULL, 16);
44 - cookie_invalid += strtoull(procfile_lineword(ff, l, 2), NULL, 16);
45 - cookie_valid += strtoull(procfile_lineword(ff, l, 3), NULL, 16);
46 - cookie_retrans += strtoull(procfile_lineword(ff, l, 4), NULL, 16);
47 - conn_reopened += strtoull(procfile_lineword(ff, l, 5), NULL, 16);
48 - }
42 + entries += strtoull(procfile_lineword(ff, l, 0), NULL, 16);
43 + syn_received += strtoull(procfile_lineword(ff, l, 1), NULL, 16);
44 + cookie_invalid += strtoull(procfile_lineword(ff, l, 2), NULL, 16);
45 + cookie_valid += strtoull(procfile_lineword(ff, l, 3), NULL, 16);
46 + cookie_retrans += strtoull(procfile_lineword(ff, l, 4), NULL, 16);
47 + conn_reopened += strtoull(procfile_lineword(ff, l, 5), NULL, 16);
48 + }
49
50 - unsigned long long events = entries + syn_received + cookie_invalid + cookie_valid + cookie_retrans + conn_reopened;
50 + unsigned long long events = entries + syn_received + cookie_invalid + cookie_valid + cookie_retrans + conn_reopened;
51
52 - RRDSET *st;
52 + RRDSET *st;
53
54 - // --------------------------------------------------------------------
54 + // --------------------------------------------------------------------
55
56 - if((do_entries == CONFIG_ONDEMAND_ONDEMAND && events) || do_entries == CONFIG_ONDEMAND_YES) {
57 - do_entries = CONFIG_ONDEMAND_YES;
56 + if((do_entries == CONFIG_ONDEMAND_ONDEMAND && events) || do_entries == CONFIG_ONDEMAND_YES) {
57 + do_entries = CONFIG_ONDEMAND_YES;
58
59 - st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_SYNPROXY "_entries");
60 - if(!st) {
61 - st = rrdset_create(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_SYNPROXY "_entries", NULL, RRD_TYPE_NET_STAT_SYNPROXY, NULL, "SYNPROXY Entries Used", "entries", 1004, update_every, RRDSET_TYPE_LINE);
59 + st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_SYNPROXY "_entries");
60 + if(!st) {
61 + st = rrdset_create(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_SYNPROXY "_entries", NULL, RRD_TYPE_NET_STAT_SYNPROXY, NULL, "SYNPROXY Entries Used", "entries", 1004, update_every, RRDSET_TYPE_LINE);
62
63 - rrddim_add(st, "entries", NULL, 1, 1, RRDDIM_ABSOLUTE);
64 - }
65 - else rrdset_next(st);
63 + rrddim_add(st, "entries", NULL, 1, 1, RRDDIM_ABSOLUTE);
64 + }
65 + else rrdset_next(st);
66
67 - rrddim_set(st, "entries", entries);
68 - rrdset_done(st);
69 - }
67 + rrddim_set(st, "entries", entries);
68 + rrdset_done(st);
69 + }
70
71 - // --------------------------------------------------------------------
71 + // --------------------------------------------------------------------
72
73 - if((do_syns == CONFIG_ONDEMAND_ONDEMAND && events) || do_syns == CONFIG_ONDEMAND_YES) {
74 - do_syns = CONFIG_ONDEMAND_YES;
73 + if((do_syns == CONFIG_ONDEMAND_ONDEMAND && events) || do_syns == CONFIG_ONDEMAND_YES) {
74 + do_syns = CONFIG_ONDEMAND_YES;
75
76 - st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_SYNPROXY "_syn_received");
77 - if(!st) {
78 - st = rrdset_create(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_SYNPROXY "_syn_received", NULL, RRD_TYPE_NET_STAT_SYNPROXY, NULL, "SYNPROXY SYN Packets received", "SYN/s", 1001, update_every, RRDSET_TYPE_LINE);
76 + st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_SYNPROXY "_syn_received");
77 + if(!st) {
78 + st = rrdset_create(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_SYNPROXY "_syn_received", NULL, RRD_TYPE_NET_STAT_SYNPROXY, NULL, "SYNPROXY SYN Packets received", "SYN/s", 1001, update_every, RRDSET_TYPE_LINE);
79
80 - rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
81 - }
82 - else rrdset_next(st);
80 + rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
81 + }
82 + else rrdset_next(st);
83
84 - rrddim_set(st, "received", syn_received);
85 - rrdset_done(st);
86 - }
84 + rrddim_set(st, "received", syn_received);
85 + rrdset_done(st);
86 + }
87
88 - // --------------------------------------------------------------------
88 + // --------------------------------------------------------------------
89
90 - if((do_reopened == CONFIG_ONDEMAND_ONDEMAND && events) || do_reopened == CONFIG_ONDEMAND_YES) {
91 - do_reopened = CONFIG_ONDEMAND_YES;
90 + if((do_reopened == CONFIG_ONDEMAND_ONDEMAND && events) || do_reopened == CONFIG_ONDEMAND_YES) {
91 + do_reopened = CONFIG_ONDEMAND_YES;
92
93 - st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_SYNPROXY "_conn_reopened");
94 - if(!st) {
95 - st = rrdset_create(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_SYNPROXY "_conn_reopened", NULL, RRD_TYPE_NET_STAT_SYNPROXY, NULL, "SYNPROXY Connections Reopened", "connections/s", 1003, update_every, RRDSET_TYPE_LINE);
93 + st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_SYNPROXY "_conn_reopened");
94 + if(!st) {
95 + st = rrdset_create(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_SYNPROXY "_conn_reopened", NULL, RRD_TYPE_NET_STAT_SYNPROXY, NULL, "SYNPROXY Connections Reopened", "connections/s", 1003, update_every, RRDSET_TYPE_LINE);
96
97 - rrddim_add(st, "reopened", NULL, 1, 1, RRDDIM_INCREMENTAL);
98 - }
99 - else rrdset_next(st);
97 + rrddim_add(st, "reopened", NULL, 1, 1, RRDDIM_INCREMENTAL);
98 + }
99 + else rrdset_next(st);
100
101 - rrddim_set(st, "reopened", conn_reopened);
102 - rrdset_done(st);
103 - }
101 + rrddim_set(st, "reopened", conn_reopened);
102 + rrdset_done(st);
103 + }
104
105 - // --------------------------------------------------------------------
105 + // --------------------------------------------------------------------
106
107 - if((do_cookies == CONFIG_ONDEMAND_ONDEMAND && events) || do_cookies == CONFIG_ONDEMAND_YES) {
108 - do_cookies = CONFIG_ONDEMAND_YES;
107 + if((do_cookies == CONFIG_ONDEMAND_ONDEMAND && events) || do_cookies == CONFIG_ONDEMAND_YES) {
108 + do_cookies = CONFIG_ONDEMAND_YES;
109
110 - st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_SYNPROXY "_cookies");
111 - if(!st) {
112 - st = rrdset_create(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_SYNPROXY "_cookies", NULL, RRD_TYPE_NET_STAT_SYNPROXY, NULL, "SYNPROXY TCP Cookies", "cookies/s", 1002, update_every, RRDSET_TYPE_LINE);
110 + st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_SYNPROXY "_cookies");
111 + if(!st) {
112 + st = rrdset_create(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_SYNPROXY "_cookies", NULL, RRD_TYPE_NET_STAT_SYNPROXY, NULL, "SYNPROXY TCP Cookies", "cookies/s", 1002, update_every, RRDSET_TYPE_LINE);
113
114 - rrddim_add(st, "valid", NULL, 1, 1, RRDDIM_INCREMENTAL);
115 - rrddim_add(st, "invalid", NULL, -1, 1, RRDDIM_INCREMENTAL);
116 - rrddim_add(st, "retransmits", NULL, 1, 1, RRDDIM_INCREMENTAL);
117 - }
118 - else rrdset_next(st);
114 + rrddim_add(st, "valid", NULL, 1, 1, RRDDIM_INCREMENTAL);
115 + rrddim_add(st, "invalid", NULL, -1, 1, RRDDIM_INCREMENTAL);
116 + rrddim_add(st, "retransmits", NULL, 1, 1, RRDDIM_INCREMENTAL);
117 + }
118 + else rrdset_next(st);
119
120 - rrddim_set(st, "valid", cookie_valid);
121 - rrddim_set(st, "invalid", cookie_invalid);
122 - rrddim_set(st, "retransmits", cookie_retrans);
123 - rrdset_done(st);
124 - }
120 + rrddim_set(st, "valid", cookie_valid);
121 + rrddim_set(st, "invalid", cookie_invalid);
122 + rrddim_set(st, "retransmits", cookie_retrans);
123 + rrdset_done(st);
124 + }
125
126 - return 0;
126 + return 0;
127 }
src/proc_self_mountinfo.c
+170 -170
@@ -3,234 +3,234 @@
3 // find the mount info with the given major:minor
4 // in the supplied linked list of mountinfo structures
5 struct mountinfo *mountinfo_find(struct mountinfo *root, unsigned long major, unsigned long minor) {
6 - struct mountinfo *mi;
6 + struct mountinfo *mi;
7
8 - for(mi = root; mi ; mi = mi->next)
9 - if(mi->major == major && mi->minor == minor)
10 - return mi;
8 + for(mi = root; mi ; mi = mi->next)
9 + if(mi->major == major && mi->minor == minor)
10 + return mi;
11
12 - return NULL;
12 + return NULL;
13 }
14
15 // find the mount info with the given filesystem and mount_source
16 // in the supplied linked list of mountinfo structures
17 struct mountinfo *mountinfo_find_by_filesystem_mount_source(struct mountinfo *root, const char *filesystem, const char *mount_source) {
18 - struct mountinfo *mi;
19 - uint32_t filesystem_hash = simple_hash(filesystem), mount_source_hash = simple_hash(mount_source);
20 -
21 - for(mi = root; mi ; mi = mi->next)
22 - if(mi->filesystem
23 - && mi->mount_source
24 - && mi->filesystem_hash == filesystem_hash
25 - && mi->mount_source_hash == mount_source_hash
26 - && !strcmp(mi->filesystem, filesystem)
27 - && !strcmp(mi->mount_source, mount_source))
28 - return mi;
29 -
30 - return NULL;
18 + struct mountinfo *mi;
19 + uint32_t filesystem_hash = simple_hash(filesystem), mount_source_hash = simple_hash(mount_source);
20 +
21 + for(mi = root; mi ; mi = mi->next)
22 + if(mi->filesystem
23 + && mi->mount_source
24 + && mi->filesystem_hash == filesystem_hash
25 + && mi->mount_source_hash == mount_source_hash
26 + && !strcmp(mi->filesystem, filesystem)
27 + && !strcmp(mi->mount_source, mount_source))
28 + return mi;
29 +
30 + return NULL;
31 }
32
33 struct mountinfo *mountinfo_find_by_filesystem_super_option(struct mountinfo *root, const char *filesystem, const char *super_options) {
34 - struct mountinfo *mi;
35 - uint32_t filesystem_hash = simple_hash(filesystem);
34 + struct mountinfo *mi;
35 + uint32_t filesystem_hash = simple_hash(filesystem);
36
37 - size_t solen = strlen(super_options);
37 + size_t solen = strlen(super_options);
38
39 - for(mi = root; mi ; mi = mi->next)
40 - if(mi->filesystem
41 - && mi->super_options
42 - && mi->filesystem_hash == filesystem_hash
43 - && !strcmp(mi->filesystem, filesystem)) {
39 + for(mi = root; mi ; mi = mi->next)
40 + if(mi->filesystem
41 + && mi->super_options
42 + && mi->filesystem_hash == filesystem_hash
43 + && !strcmp(mi->filesystem, filesystem)) {
44
45 - // super_options is a comma separated list
46 - char *s = mi->super_options, *e;
47 - while(*s) {
48 - e = s + 1;
49 - while(*e && *e != ',') e++;
45 + // super_options is a comma separated list
46 + char *s = mi->super_options, *e;
47 + while(*s) {
48 + e = s + 1;
49 + while(*e && *e != ',') e++;
50
51 - size_t len = e - s;
52 - if(len == solen && !strncmp(s, super_options, len))
53 - return mi;
51 + size_t len = e - s;
52 + if(len == solen && !strncmp(s, super_options, len))
53 + return mi;
54
55 - if(*e == ',') s = ++e;
56 - else s = e;
57 - }
58 - }
55 + if(*e == ',') s = ++e;
56 + else s = e;
57 + }
58 + }
59
60 - return NULL;
60 + return NULL;
61 }
62
63
64 // free a linked list of mountinfo structures
65 void mountinfo_free(struct mountinfo *mi) {
66 - if(unlikely(!mi))
67 - return;
66 + if(unlikely(!mi))
67 + return;
68
69 - if(likely(mi->next))
70 - mountinfo_free(mi->next);
69 + if(likely(mi->next))
70 + mountinfo_free(mi->next);
71
72 - freez(mi->root);
73 - freez(mi->mount_point);
74 - freez(mi->mount_options);
72 + freez(mi->root);
73 + freez(mi->mount_point);
74 + freez(mi->mount_options);
75
76 /*
77 - if(mi->optional_fields_count) {
78 - int i;
79 - for(i = 0; i < mi->optional_fields_count ; i++)
80 - free(*mi->optional_fields[i]);
81 - }
82 - free(mi->optional_fields);
77 + if(mi->optional_fields_count) {
78 + int i;
79 + for(i = 0; i < mi->optional_fields_count ; i++)
80 + free(*mi->optional_fields[i]);
81 + }
82 + free(mi->optional_fields);
83 */
84 - freez(mi->filesystem);
85 - freez(mi->mount_source);
86 - freez(mi->super_options);
87 - freez(mi);
84 + freez(mi->filesystem);
85 + freez(mi->mount_source);
86 + freez(mi->super_options);
87 + freez(mi);
88 }
89
90 static char *strdupz_decoding_octal(const char *string) {
91 - char *buffer = strdupz(string);
92 -
93 - char *d = buffer;
94 - const char *s = string;
95 -
96 - while(*s) {
97 - if(unlikely(*s == '\\')) {
98 - s++;
99 - if(likely(isdigit(*s) && isdigit(s[1]) && isdigit(s[2]))) {
100 - char c = *s++ - '0';
101 - c <<= 3;
102 - c |= *s++ - '0';
103 - c <<= 3;
104 - c |= *s++ - '0';
105 - *d++ = c;
106 - }
107 - else *d++ = '_';
108 - }
109 - else *d++ = *s++;
110 - }
111 - *d = '\0';
112 -
113 - return buffer;
91 + char *buffer = strdupz(string);
92 +
93 + char *d = buffer;
94 + const char *s = string;
95 +
96 + while(*s) {
97 + if(unlikely(*s == '\\')) {
98 + s++;
99 + if(likely(isdigit(*s) && isdigit(s[1]) && isdigit(s[2]))) {
100 + char c = *s++ - '0';
101 + c <<= 3;
102 + c |= *s++ - '0';
103 + c <<= 3;
104 + c |= *s++ - '0';
105 + *d++ = c;
106 + }
107 + else *d++ = '_';
108 + }
109 + else *d++ = *s++;
110 + }
111 + *d = '\0';
112 +
113 + return buffer;
114 }
115
116 // read the whole mountinfo into a linked list
117 struct mountinfo *mountinfo_read() {
118 - procfile *ff = NULL;
118 + procfile *ff = NULL;
119
120 - char filename[FILENAME_MAX + 1];
121 - snprintfz(filename, FILENAME_MAX, "%s/proc/self/mountinfo", global_host_prefix);
122 - ff = procfile_open(filename, " \t", PROCFILE_FLAG_DEFAULT);
123 - if(!ff) {
124 - snprintfz(filename, FILENAME_MAX, "%s/proc/1/mountinfo", global_host_prefix);
125 - ff = procfile_open(filename, " \t", PROCFILE_FLAG_DEFAULT);
126 - if(!ff) return NULL;
127 - }
120 + char filename[FILENAME_MAX + 1];
121 + snprintfz(filename, FILENAME_MAX, "%s/proc/self/mountinfo", global_host_prefix);
122 + ff = procfile_open(filename, " \t", PROCFILE_FLAG_DEFAULT);
123 + if(!ff) {
124 + snprintfz(filename, FILENAME_MAX, "%s/proc/1/mountinfo", global_host_prefix);
125 + ff = procfile_open(filename, " \t", PROCFILE_FLAG_DEFAULT);
126 + if(!ff) return NULL;
127 + }
128
129 - ff = procfile_readall(ff);
130 - if(!ff) return NULL;
129 + ff = procfile_readall(ff);
130 + if(!ff) return NULL;
131
132 - struct mountinfo *root = NULL, *last = NULL, *mi = NULL;
132 + struct mountinfo *root = NULL, *last = NULL, *mi = NULL;
133
134 - unsigned long l, lines = procfile_lines(ff);
135 - for(l = 0; l < lines ;l++) {
136 - if(procfile_linewords(ff, l) < 5)
137 - continue;
134 + unsigned long l, lines = procfile_lines(ff);
135 + for(l = 0; l < lines ;l++) {
136 + if(procfile_linewords(ff, l) < 5)
137 + continue;
138
139 - mi = mallocz(sizeof(struct mountinfo));
139 + mi = mallocz(sizeof(struct mountinfo));
140
141 - if(unlikely(!root))
142 - root = last = mi;
143 - else
144 - last->next = mi;
141 + if(unlikely(!root))
142 + root = last = mi;
143 + else
144 + last->next = mi;
145
146 - last = mi;
147 - mi->next = NULL;
146 + last = mi;
147 + mi->next = NULL;
148
149 - unsigned long w = 0;
150 - mi->id = strtoul(procfile_lineword(ff, l, w), NULL, 10); w++;
151 - mi->parentid = strtoul(procfile_lineword(ff, l, w), NULL, 10); w++;
149 + unsigned long w = 0;
150 + mi->id = strtoul(procfile_lineword(ff, l, w), NULL, 10); w++;
151 + mi->parentid = strtoul(procfile_lineword(ff, l, w), NULL, 10); w++;
152
153 - char *major = procfile_lineword(ff, l, w), *minor; w++;
154 - for(minor = major; *minor && *minor != ':' ;minor++) ;
155 - *minor = '\0';
156 - minor++;
153 + char *major = procfile_lineword(ff, l, w), *minor; w++;
154 + for(minor = major; *minor && *minor != ':' ;minor++) ;
155 + *minor = '\0';
156 + minor++;
157
158 - mi->major = strtoul(major, NULL, 10);
159 - mi->minor = strtoul(minor, NULL, 10);
158 + mi->major = strtoul(major, NULL, 10);
159 + mi->minor = strtoul(minor, NULL, 10);
160
161 - mi->root = strdupz(procfile_lineword(ff, l, w)); w++;
162 - mi->root_hash = simple_hash(mi->root);
161 + mi->root = strdupz(procfile_lineword(ff, l, w)); w++;
162 + mi->root_hash = simple_hash(mi->root);
163
164 - mi->mount_point = strdupz_decoding_octal(procfile_lineword(ff, l, w)); w++;
165 - mi->mount_point_hash = simple_hash(mi->mount_point);
164 + mi->mount_point = strdupz_decoding_octal(procfile_lineword(ff, l, w)); w++;
165 + mi->mount_point_hash = simple_hash(mi->mount_point);
166
167 - mi->mount_options = strdupz(procfile_lineword(ff, l, w)); w++;
167 + mi->mount_options = strdupz(procfile_lineword(ff, l, w)); w++;
168
169 - // count the optional fields
169 + // count the optional fields
170 /*
171 - unsigned long wo = w;
171 + unsigned long wo = w;
172 */
173 - mi->optional_fields_count = 0;
174 - char *s = procfile_lineword(ff, l, w);
175 - while(*s && *s != '-') {
176 - w++;
177 - s = procfile_lineword(ff, l, w);
178 - mi->optional_fields_count++;
179 - }
173 + mi->optional_fields_count = 0;
174 + char *s = procfile_lineword(ff, l, w);
175 + while(*s && *s != '-') {
176 + w++;
177 + s = procfile_lineword(ff, l, w);
178 + mi->optional_fields_count++;
179 + }
180
181 /*
182 - if(unlikely(mi->optional_fields_count)) {
183 - // we have some optional fields
184 - // read them into a new array of pointers;
185 -
186 - mi->optional_fields = malloc(mi->optional_fields_count * sizeof(char *));
187 - if(unlikely(!mi->optional_fields))
188 - fatal("Cannot allocate memory for %d mountinfo optional fields", mi->optional_fields_count);
189 -
190 - int i;
191 - for(i = 0; i < mi->optional_fields_count ; i++) {
192 - *mi->optional_fields[wo] = strdup(procfile_lineword(ff, l, w));
193 - if(!mi->optional_fields[wo]) fatal("Cannot allocate memory");
194 - wo++;
195 - }
196 - }
197 - else
198 - mi->optional_fields = NULL;
182 + if(unlikely(mi->optional_fields_count)) {
183 + // we have some optional fields
184 + // read them into a new array of pointers;
185 +
186 + mi->optional_fields = malloc(mi->optional_fields_count * sizeof(char *));
187 + if(unlikely(!mi->optional_fields))
188 + fatal("Cannot allocate memory for %d mountinfo optional fields", mi->optional_fields_count);
189 +
190 + int i;
191 + for(i = 0; i < mi->optional_fields_count ; i++) {
192 + *mi->optional_fields[wo] = strdup(procfile_lineword(ff, l, w));
193 + if(!mi->optional_fields[wo]) fatal("Cannot allocate memory");
194 + wo++;
195 + }
196 + }
197 + else
198 + mi->optional_fields = NULL;
199 */
200
201 - if(likely(*s == '-')) {
202 - w++;
201 + if(likely(*s == '-')) {
202 + w++;
203
204 - mi->filesystem = strdupz(procfile_lineword(ff, l, w)); w++;
205 - mi->filesystem_hash = simple_hash(mi->filesystem);
204 + mi->filesystem = strdupz(procfile_lineword(ff, l, w)); w++;
205 + mi->filesystem_hash = simple_hash(mi->filesystem);
206
207 - mi->mount_source = strdupz(procfile_lineword(ff, l, w)); w++;
208 - mi->mount_source_hash = simple_hash(mi->mount_source);
207 + mi->mount_source = strdupz(procfile_lineword(ff, l, w)); w++;
208 + mi->mount_source_hash = simple_hash(mi->mount_source);
209
210 - mi->super_options = strdupz(procfile_lineword(ff, l, w)); w++;
211 - }
212 - else {
213 - mi->filesystem = NULL;
214 - mi->mount_source = NULL;
215 - mi->super_options = NULL;
216 - }
210 + mi->super_options = strdupz(procfile_lineword(ff, l, w)); w++;
211 + }
212 + else {
213 + mi->filesystem = NULL;
214 + mi->mount_source = NULL;
215 + mi->super_options = NULL;
216 + }
217
218 /*
219 - info("MOUNTINFO: %u %u %u:%u root '%s', mount point '%s', mount options '%s', filesystem '%s', mount source '%s', super options '%s'",
220 - mi->id,
221 - mi->parentid,
222 - mi->major,
223 - mi->minor,
224 - mi->root,
225 - mi->mount_point,
226 - mi->mount_options,
227 - mi->filesystem,
228 - mi->mount_source,
229 - mi->super_options
230 - );
219 + info("MOUNTINFO: %u %u %u:%u root '%s', mount point '%s', mount options '%s', filesystem '%s', mount source '%s', super options '%s'",
220 + mi->id,
221 + mi->parentid,
222 + mi->major,
223 + mi->minor,
224 + mi->root,
225 + mi->mount_point,
226 + mi->mount_options,
227 + mi->filesystem,
228 + mi->mount_source,
229 + mi->super_options
230 + );
231 */
232 - }
232 + }
233
234 - procfile_close(ff);
235 - return root;
234 + procfile_close(ff);
235 + return root;
236 }
src/proc_self_mountinfo.h
+17 -17
@@ -2,32 +2,32 @@
2 #define NETDATA_PROC_SELF_MOUNTINFO_H 1
3
4 struct mountinfo {
5 - long id; // mount ID: unique identifier of the mount (may be reused after umount(2)).
6 - long parentid; // parent ID: ID of parent mount (or of self for the top of the mount tree).
7 - unsigned long major; // major:minor: value of st_dev for files on filesystem (see stat(2)).
8 - unsigned long minor;
5 + long id; // mount ID: unique identifier of the mount (may be reused after umount(2)).
6 + long parentid; // parent ID: ID of parent mount (or of self for the top of the mount tree).
7 + unsigned long major; // major:minor: value of st_dev for files on filesystem (see stat(2)).
8 + unsigned long minor;
9
10 - char *root; // root: root of the mount within the filesystem.
11 - uint32_t root_hash;
10 + char *root; // root: root of the mount within the filesystem.
11 + uint32_t root_hash;
12
13 - char *mount_point; // mount point: mount point relative to the process's root.
14 - uint32_t mount_point_hash;
13 + char *mount_point; // mount point: mount point relative to the process's root.
14 + uint32_t mount_point_hash;
15
16 - char *mount_options; // mount options: per-mount options.
16 + char *mount_options; // mount options: per-mount options.
17
18 - int optional_fields_count;
18 + int optional_fields_count;
19 /*
20 - char ***optional_fields; // optional fields: zero or more fields of the form "tag[:value]".
20 + char ***optional_fields; // optional fields: zero or more fields of the form "tag[:value]".
21 */
22 - char *filesystem; // filesystem type: name of filesystem in the form "type[.subtype]".
23 - uint32_t filesystem_hash;
22 + char *filesystem; // filesystem type: name of filesystem in the form "type[.subtype]".
23 + uint32_t filesystem_hash;
24
25 - char *mount_source; // mount source: filesystem-specific information or "none".
26 - uint32_t mount_source_hash;
25 + char *mount_source; // mount source: filesystem-specific information or "none".
26 + uint32_t mount_source_hash;
27
28 - char *super_options; // super options: per-superblock options.
28 + char *super_options; // super options: per-superblock options.
29
30 - struct mountinfo *next;
30 + struct mountinfo *next;
31 };
32
33 extern struct mountinfo *mountinfo_find(struct mountinfo *root, unsigned long major, unsigned long minor);
src/proc_softirqs.c
+151 -151
@@ -3,11 +3,11 @@
3 #define MAX_INTERRUPT_NAME 50
4
5 struct interrupt {
6 - int used;
7 - char *id;
8 - char name[MAX_INTERRUPT_NAME + 1];
9 - unsigned long long total;
10 - unsigned long long value[];
6 + int used;
7 + char *id;
8 + char name[MAX_INTERRUPT_NAME + 1];
9 + unsigned long long total;
10 + unsigned long long value[];
11 };
12
13 // since each interrupt is variable in size
@@ -18,157 +18,157 @@ struct interrupt {
18 #define irrindex(base, line, cpus) ((struct interrupt *)&((char *)(base))[line * recordsize(cpus)])
19
20 static inline struct interrupt *get_interrupts_array(int lines, int cpus) {
21 - static struct interrupt *irrs = NULL;
22 - static int allocated = 0;
21 + static struct interrupt *irrs = NULL;
22 + static int allocated = 0;
23
24 - if(lines < allocated) return irrs;
25 - else {
26 - irrs = (struct interrupt *)reallocz(irrs, lines * recordsize(cpus));
27 - allocated = lines;
28 - }
24 + if(lines < allocated) return irrs;
25 + else {
26 + irrs = (struct interrupt *)reallocz(irrs, lines * recordsize(cpus));
27 + allocated = lines;
28 + }
29
30 - return irrs;
30 + return irrs;
31 }
32
33 int do_proc_softirqs(int update_every, unsigned long long dt) {
34 - static procfile *ff = NULL;
35 - static int cpus = -1, do_per_core = -1;
34 + static procfile *ff = NULL;
35 + static int cpus = -1, do_per_core = -1;
36
37 - struct interrupt *irrs = NULL;
38 -
39 - if(dt) {};
37 + struct interrupt *irrs = NULL;
38 +
39 + if(dt) {};
40
41 - if(do_per_core == -1) do_per_core = config_get_boolean("plugin:proc:/proc/softirqs", "interrupts per core", 1);
42 -
43 - if(!ff) {
44 - char filename[FILENAME_MAX + 1];
45 - snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/softirqs");
46 - ff = procfile_open(config_get("plugin:proc:/proc/softirqs", "filename to monitor", filename), " \t", PROCFILE_FLAG_DEFAULT);
47 - }
48 - if(!ff) return 1;
49 -
50 - ff = procfile_readall(ff);
51 - if(!ff) return 0; // we return 0, so that we will retry to open it next time
52 -
53 - uint32_t lines = procfile_lines(ff), l;
54 - uint32_t words = procfile_linewords(ff, 0), w;
55 -
56 - if(!lines) {
57 - error("Cannot read /proc/softirqs, zero lines reported.");
58 - return 1;
59 - }
60 -
61 - // find how many CPUs are there
62 - if(cpus == -1) {
63 - cpus = 0;
64 - for(w = 0; w < words ; w++) {
65 - if(strncmp(procfile_lineword(ff, 0, w), "CPU", 3) == 0)
66 - cpus++;
67 - }
68 - }
69 -
70 - if(!cpus) {
71 - error("PLUGIN: PROC_SOFTIRQS: Cannot find the number of CPUs in /proc/softirqs");
72 - return 1;
73 - }
74 -
75 - // allocate the size we need;
76 - irrs = get_interrupts_array(lines, cpus);
77 - irrs[0].used = 0;
78 -
79 - // loop through all lines
80 - for(l = 1; l < lines ;l++) {
81 - struct interrupt *irr = irrindex(irrs, l, cpus);
82 - irr->used = 0;
83 - irr->total = 0;
84 -
85 - words = procfile_linewords(ff, l);
86 - if(!words) continue;
87 -
88 - irr->id = procfile_lineword(ff, l, 0);
89 - if(!irr->id || !irr->id[0]) continue;
90 -
91 - int idlen = strlen(irr->id);
92 - if(irr->id[idlen - 1] == ':')
93 - irr->id[idlen - 1] = '\0';
94 -
95 - int c;
96 - for(c = 0; c < cpus ;c++) {
97 - if((c + 1) < (int)words)
98 - irr->value[c] = strtoull(procfile_lineword(ff, l, (uint32_t)(c + 1)), NULL, 10);
99 - else
100 - irr->value[c] = 0;
101 -
102 - irr->total += irr->value[c];
103 - }
104 -
105 - strncpyz(irr->name, irr->id, MAX_INTERRUPT_NAME);
106 -
107 - irr->used = 1;
108 - }
109 -
110 - RRDSET *st;
111 -
112 - // --------------------------------------------------------------------
113 -
114 - st = rrdset_find_bytype("system", "softirqs");
115 - if(!st) {
116 - st = rrdset_create("system", "softirqs", NULL, "softirqs", NULL, "System softirqs", "softirqs/s", 950, update_every, RRDSET_TYPE_STACKED);
117 -
118 - for(l = 0; l < lines ;l++) {
119 - struct interrupt *irr = irrindex(irrs, l, cpus);
120 - if(!irr->used) continue;
121 - rrddim_add(st, irr->id, irr->name, 1, 1, RRDDIM_INCREMENTAL);
122 - }
123 - }
124 - else rrdset_next(st);
125 -
126 - for(l = 0; l < lines ;l++) {
127 - struct interrupt *irr = irrindex(irrs, l, cpus);
128 - if(!irr->used) continue;
129 - rrddim_set(st, irr->id, irr->total);
130 - }
131 - rrdset_done(st);
132 -
133 - if(do_per_core) {
134 - int c;
135 -
136 - for(c = 0; c < cpus ; c++) {
137 - char id[256+1];
138 - snprintfz(id, 256, "cpu%d_softirqs", c);
139 -
140 - st = rrdset_find_bytype("cpu", id);
141 - if(!st) {
142 - // find if everything is zero
143 - unsigned long long core_sum = 0 ;
144 - for(l = 0; l < lines ;l++) {
145 - struct interrupt *irr = irrindex(irrs, l, cpus);
146 - if(!irr->used) continue;
147 - core_sum += irr->value[c];
148 - }
149 - if(core_sum == 0) continue; // try next core
150 -
151 - char name[256+1], title[256+1];
152 - snprintfz(name, 256, "cpu%d_softirqs", c);
153 - snprintfz(title, 256, "CPU%d softirqs", c);
154 - st = rrdset_create("cpu", id, name, "softirqs", "cpu.softirqs", title, "softirqs/s", 3000 + c, update_every, RRDSET_TYPE_STACKED);
155 -
156 - for(l = 0; l < lines ;l++) {
157 - struct interrupt *irr = irrindex(irrs, l, cpus);
158 - if(!irr->used) continue;
159 - rrddim_add(st, irr->id, irr->name, 1, 1, RRDDIM_INCREMENTAL);
160 - }
161 - }
162 - else rrdset_next(st);
163 -
164 - for(l = 0; l < lines ;l++) {
165 - struct interrupt *irr = irrindex(irrs, l, cpus);
166 - if(!irr->used) continue;
167 - rrddim_set(st, irr->id, irr->value[c]);
168 - }
169 - rrdset_done(st);
170 - }
171 - }
172 -
173 - return 0;
41 + if(do_per_core == -1) do_per_core = config_get_boolean("plugin:proc:/proc/softirqs", "interrupts per core", 1);
42 +
43 + if(!ff) {
44 + char filename[FILENAME_MAX + 1];
45 + snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/softirqs");
46 + ff = procfile_open(config_get("plugin:proc:/proc/softirqs", "filename to monitor", filename), " \t", PROCFILE_FLAG_DEFAULT);
47 + }
48 + if(!ff) return 1;
49 +
50 + ff = procfile_readall(ff);
51 + if(!ff) return 0; // we return 0, so that we will retry to open it next time
52 +
53 + uint32_t lines = procfile_lines(ff), l;
54 + uint32_t words = procfile_linewords(ff, 0), w;
55 +
56 + if(!lines) {
57 + error("Cannot read /proc/softirqs, zero lines reported.");
58 + return 1;
59 + }
60 +
61 + // find how many CPUs are there
62 + if(cpus == -1) {
63 + cpus = 0;
64 + for(w = 0; w < words ; w++) {
65 + if(strncmp(procfile_lineword(ff, 0, w), "CPU", 3) == 0)
66 + cpus++;
67 + }
68 + }
69 +
70 + if(!cpus) {
71 + error("PLUGIN: PROC_SOFTIRQS: Cannot find the number of CPUs in /proc/softirqs");
72 + return 1;
73 + }
74 +
75 + // allocate the size we need;
76 + irrs = get_interrupts_array(lines, cpus);
77 + irrs[0].used = 0;
78 +
79 + // loop through all lines
80 + for(l = 1; l < lines ;l++) {
81 + struct interrupt *irr = irrindex(irrs, l, cpus);
82 + irr->used = 0;
83 + irr->total = 0;
84 +
85 + words = procfile_linewords(ff, l);
86 + if(!words) continue;
87 +
88 + irr->id = procfile_lineword(ff, l, 0);
89 + if(!irr->id || !irr->id[0]) continue;
90 +
91 + int idlen = strlen(irr->id);
92 + if(irr->id[idlen - 1] == ':')
93 + irr->id[idlen - 1] = '\0';
94 +
95 + int c;
96 + for(c = 0; c < cpus ;c++) {
97 + if((c + 1) < (int)words)
98 + irr->value[c] = strtoull(procfile_lineword(ff, l, (uint32_t)(c + 1)), NULL, 10);
99 + else
100 + irr->value[c] = 0;
101 +
102 + irr->total += irr->value[c];
103 + }
104 +
105 + strncpyz(irr->name, irr->id, MAX_INTERRUPT_NAME);
106 +
107 + irr->used = 1;
108 + }
109 +
110 + RRDSET *st;
111 +
112 + // --------------------------------------------------------------------
113 +
114 + st = rrdset_find_bytype("system", "softirqs");
115 + if(!st) {
116 + st = rrdset_create("system", "softirqs", NULL, "softirqs", NULL, "System softirqs", "softirqs/s", 950, update_every, RRDSET_TYPE_STACKED);
117 +
118 + for(l = 0; l < lines ;l++) {
119 + struct interrupt *irr = irrindex(irrs, l, cpus);
120 + if(!irr->used) continue;
121 + rrddim_add(st, irr->id, irr->name, 1, 1, RRDDIM_INCREMENTAL);
122 + }
123 + }
124 + else rrdset_next(st);
125 +
126 + for(l = 0; l < lines ;l++) {
127 + struct interrupt *irr = irrindex(irrs, l, cpus);
128 + if(!irr->used) continue;
129 + rrddim_set(st, irr->id, irr->total);
130 + }
131 + rrdset_done(st);
132 +
133 + if(do_per_core) {
134 + int c;
135 +
136 + for(c = 0; c < cpus ; c++) {
137 + char id[256+1];
138 + snprintfz(id, 256, "cpu%d_softirqs", c);
139 +
140 + st = rrdset_find_bytype("cpu", id);
141 + if(!st) {
142 + // find if everything is zero
143 + unsigned long long core_sum = 0 ;
144 + for(l = 0; l < lines ;l++) {
145 + struct interrupt *irr = irrindex(irrs, l, cpus);
146 + if(!irr->used) continue;
147 + core_sum += irr->value[c];
148 + }
149 + if(core_sum == 0) continue; // try next core
150 +
151 + char name[256+1], title[256+1];
152 + snprintfz(name, 256, "cpu%d_softirqs", c);
153 + snprintfz(title, 256, "CPU%d softirqs", c);
154 + st = rrdset_create("cpu", id, name, "softirqs", "cpu.softirqs", title, "softirqs/s", 3000 + c, update_every, RRDSET_TYPE_STACKED);
155 +
156 + for(l = 0; l < lines ;l++) {
157 + struct interrupt *irr = irrindex(irrs, l, cpus);
158 + if(!irr->used) continue;
159 + rrddim_add(st, irr->id, irr->name, 1, 1, RRDDIM_INCREMENTAL);
160 + }
161 + }
162 + else rrdset_next(st);
163 +
164 + for(l = 0; l < lines ;l++) {
165 + struct interrupt *irr = irrindex(irrs, l, cpus);
166 + if(!irr->used) continue;
167 + rrddim_set(st, irr->id, irr->value[c]);
168 + }
169 + rrdset_done(st);
170 + }
171 + }
172 +
173 + return 0;
174 }
src/proc_stat.c
+207 -207
@@ -1,211 +1,211 @@
1 #include "common.h"
2
3 int do_proc_stat(int update_every, unsigned long long dt) {
4 - (void)dt;
5 -
6 - static procfile *ff = NULL;
7 - static int do_cpu = -1, do_cpu_cores = -1, do_interrupts = -1, do_context = -1, do_forks = -1, do_processes = -1;
8 - static uint32_t hash_intr, hash_ctxt, hash_processes, hash_procs_running, hash_procs_blocked;
9 -
10 - if(unlikely(do_cpu == -1)) {
11 - do_cpu = config_get_boolean("plugin:proc:/proc/stat", "cpu utilization", 1);
12 - do_cpu_cores = config_get_boolean("plugin:proc:/proc/stat", "per cpu core utilization", 1);
13 - do_interrupts = config_get_boolean("plugin:proc:/proc/stat", "cpu interrupts", 1);
14 - do_context = config_get_boolean("plugin:proc:/proc/stat", "context switches", 1);
15 - do_forks = config_get_boolean("plugin:proc:/proc/stat", "processes started", 1);
16 - do_processes = config_get_boolean("plugin:proc:/proc/stat", "processes running", 1);
17 -
18 - hash_intr = simple_hash("intr");
19 - hash_ctxt = simple_hash("ctxt");
20 - hash_processes = simple_hash("processes");
21 - hash_procs_running = simple_hash("procs_running");
22 - hash_procs_blocked = simple_hash("procs_blocked");
23 - }
24 -
25 - if(unlikely(!ff)) {
26 - char filename[FILENAME_MAX + 1];
27 - snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/stat");
28 - ff = procfile_open(config_get("plugin:proc:/proc/stat", "filename to monitor", filename), " \t:", PROCFILE_FLAG_DEFAULT);
29 - if(unlikely(!ff)) return 1;
30 - }
31 -
32 - ff = procfile_readall(ff);
33 - if(unlikely(!ff)) return 0; // we return 0, so that we will retry to open it next time
34 -
35 - uint32_t lines = procfile_lines(ff), l;
36 - uint32_t words;
37 -
38 - unsigned long long processes = 0, running = 0 , blocked = 0;
39 - RRDSET *st;
40 -
41 - for(l = 0; l < lines ;l++) {
42 - char *row_key = procfile_lineword(ff, l, 0);
43 - uint32_t hash = simple_hash(row_key);
44 -
45 - // faster strncmp(row_key, "cpu", 3) == 0
46 - if(likely(row_key[0] == 'c' && row_key[1] == 'p' && row_key[2] == 'u')) {
47 - words = procfile_linewords(ff, l);
48 - if(unlikely(words < 9)) {
49 - error("Cannot read /proc/stat cpu line. Expected 9 params, read %u.", words);
50 - continue;
51 - }
52 -
53 - char *id;
54 - unsigned long long user = 0, nice = 0, system = 0, idle = 0, iowait = 0, irq = 0, softirq = 0, steal = 0, guest = 0, guest_nice = 0;
55 -
56 - id = row_key;
57 - user = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
58 - nice = strtoull(procfile_lineword(ff, l, 2), NULL, 10);
59 - system = strtoull(procfile_lineword(ff, l, 3), NULL, 10);
60 - idle = strtoull(procfile_lineword(ff, l, 4), NULL, 10);
61 - iowait = strtoull(procfile_lineword(ff, l, 5), NULL, 10);
62 - irq = strtoull(procfile_lineword(ff, l, 6), NULL, 10);
63 - softirq = strtoull(procfile_lineword(ff, l, 7), NULL, 10);
64 - steal = strtoull(procfile_lineword(ff, l, 8), NULL, 10);
65 -
66 - guest = strtoull(procfile_lineword(ff, l, 9), NULL, 10);
67 - user -= guest;
68 -
69 - guest_nice = strtoull(procfile_lineword(ff, l, 10), NULL, 10);
70 - nice -= guest_nice;
71 -
72 - char *title, *type, *context, *family;
73 - long priority;
74 - int isthistotal;
75 -
76 - if(unlikely(strcmp(id, "cpu")) == 0) {
77 - title = "Total CPU utilization";
78 - type = "system";
79 - context = "system.cpu";
80 - family = id;
81 - priority = 100;
82 - isthistotal = 1;
83 - }
84 - else {
85 - title = "Core utilization";
86 - type = "cpu";
87 - context = "cpu.cpu";
88 - family = "utilization";
89 - priority = 1000;
90 - isthistotal = 0;
91 - }
92 -
93 - if(likely((isthistotal && do_cpu) || (!isthistotal && do_cpu_cores))) {
94 - st = rrdset_find_bytype(type, id);
95 - if(unlikely(!st)) {
96 - st = rrdset_create(type, id, NULL, family, context, title, "percentage", priority, update_every, RRDSET_TYPE_STACKED);
97 -
98 - long multiplier = 1;
99 - long divisor = 1; // sysconf(_SC_CLK_TCK);
100 -
101 - rrddim_add(st, "guest_nice", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
102 - rrddim_add(st, "guest", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
103 - rrddim_add(st, "steal", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
104 - rrddim_add(st, "softirq", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
105 - rrddim_add(st, "irq", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
106 - rrddim_add(st, "user", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
107 - rrddim_add(st, "system", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
108 - rrddim_add(st, "nice", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
109 - rrddim_add(st, "iowait", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
110 -
111 - rrddim_add(st, "idle", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
112 - rrddim_hide(st, "idle");
113 - }
114 - else rrdset_next(st);
115 -
116 - rrddim_set(st, "user", user);
117 - rrddim_set(st, "nice", nice);
118 - rrddim_set(st, "system", system);
119 - rrddim_set(st, "idle", idle);
120 - rrddim_set(st, "iowait", iowait);
121 - rrddim_set(st, "irq", irq);
122 - rrddim_set(st, "softirq", softirq);
123 - rrddim_set(st, "steal", steal);
124 - rrddim_set(st, "guest", guest);
125 - rrddim_set(st, "guest_nice", guest_nice);
126 - rrdset_done(st);
127 - }
128 - }
129 - else if(hash == hash_intr && strcmp(row_key, "intr") == 0) {
130 - unsigned long long value = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
131 -
132 - // --------------------------------------------------------------------
133 -
134 - if(likely(do_interrupts)) {
135 - st = rrdset_find_bytype("system", "intr");
136 - if(unlikely(!st)) {
137 - st = rrdset_create("system", "intr", NULL, "interrupts", NULL, "CPU Interrupts", "interrupts/s", 900, update_every, RRDSET_TYPE_LINE);
138 - st->isdetail = 1;
139 -
140 - rrddim_add(st, "interrupts", NULL, 1, 1, RRDDIM_INCREMENTAL);
141 - }
142 - else rrdset_next(st);
143 -
144 - rrddim_set(st, "interrupts", value);
145 - rrdset_done(st);
146 - }
147 - }
148 - else if(hash == hash_ctxt && strcmp(row_key, "ctxt") == 0) {
149 - unsigned long long value = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
150 -
151 - // --------------------------------------------------------------------
152 -
153 - if(likely(do_context)) {
154 - st = rrdset_find_bytype("system", "ctxt");
155 - if(unlikely(!st)) {
156 - st = rrdset_create("system", "ctxt", NULL, "processes", NULL, "CPU Context Switches", "context switches/s", 800, update_every, RRDSET_TYPE_LINE);
157 -
158 - rrddim_add(st, "switches", NULL, 1, 1, RRDDIM_INCREMENTAL);
159 - }
160 - else rrdset_next(st);
161 -
162 - rrddim_set(st, "switches", value);
163 - rrdset_done(st);
164 - }
165 - }
166 - else if(hash == hash_processes && !processes && strcmp(row_key, "processes") == 0) {
167 - processes = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
168 - }
169 - else if(hash == hash_procs_running && !running && strcmp(row_key, "procs_running") == 0) {
170 - running = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
171 - }
172 - else if(hash == hash_procs_blocked && !blocked && strcmp(row_key, "procs_blocked") == 0) {
173 - blocked = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
174 - }
175 - }
176 -
177 - // --------------------------------------------------------------------
178 -
179 - if(likely(do_forks)) {
180 - st = rrdset_find_bytype("system", "forks");
181 - if(unlikely(!st)) {
182 - st = rrdset_create("system", "forks", NULL, "processes", NULL, "Started Processes", "processes/s", 700, update_every, RRDSET_TYPE_LINE);
183 - st->isdetail = 1;
184 -
185 - rrddim_add(st, "started", NULL, 1, 1, RRDDIM_INCREMENTAL);
186 - }
187 - else rrdset_next(st);
188 -
189 - rrddim_set(st, "started", processes);
190 - rrdset_done(st);
191 - }
192 -
193 - // --------------------------------------------------------------------
194 -
195 - if(likely(do_processes)) {
196 - st = rrdset_find_bytype("system", "processes");
197 - if(unlikely(!st)) {
198 - st = rrdset_create("system", "processes", NULL, "processes", NULL, "System Processes", "processes", 600, update_every, RRDSET_TYPE_LINE);
199 -
200 - rrddim_add(st, "running", NULL, 1, 1, RRDDIM_ABSOLUTE);
201 - rrddim_add(st, "blocked", NULL, -1, 1, RRDDIM_ABSOLUTE);
202 - }
203 - else rrdset_next(st);
204 -
205 - rrddim_set(st, "running", running);
206 - rrddim_set(st, "blocked", blocked);
207 - rrdset_done(st);
208 - }
209 -
210 - return 0;
4 + (void)dt;
5 +
6 + static procfile *ff = NULL;
7 + static int do_cpu = -1, do_cpu_cores = -1, do_interrupts = -1, do_context = -1, do_forks = -1, do_processes = -1;
8 + static uint32_t hash_intr, hash_ctxt, hash_processes, hash_procs_running, hash_procs_blocked;
9 +
10 + if(unlikely(do_cpu == -1)) {
11 + do_cpu = config_get_boolean("plugin:proc:/proc/stat", "cpu utilization", 1);
12 + do_cpu_cores = config_get_boolean("plugin:proc:/proc/stat", "per cpu core utilization", 1);
13 + do_interrupts = config_get_boolean("plugin:proc:/proc/stat", "cpu interrupts", 1);
14 + do_context = config_get_boolean("plugin:proc:/proc/stat", "context switches", 1);
15 + do_forks = config_get_boolean("plugin:proc:/proc/stat", "processes started", 1);
16 + do_processes = config_get_boolean("plugin:proc:/proc/stat", "processes running", 1);
17 +
18 + hash_intr = simple_hash("intr");
19 + hash_ctxt = simple_hash("ctxt");
20 + hash_processes = simple_hash("processes");
21 + hash_procs_running = simple_hash("procs_running");
22 + hash_procs_blocked = simple_hash("procs_blocked");
23 + }
24 +
25 + if(unlikely(!ff)) {
26 + char filename[FILENAME_MAX + 1];
27 + snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/stat");
28 + ff = procfile_open(config_get("plugin:proc:/proc/stat", "filename to monitor", filename), " \t:", PROCFILE_FLAG_DEFAULT);
29 + if(unlikely(!ff)) return 1;
30 + }
31 +
32 + ff = procfile_readall(ff);
33 + if(unlikely(!ff)) return 0; // we return 0, so that we will retry to open it next time
34 +
35 + uint32_t lines = procfile_lines(ff), l;
36 + uint32_t words;
37 +
38 + unsigned long long processes = 0, running = 0 , blocked = 0;
39 + RRDSET *st;
40 +
41 + for(l = 0; l < lines ;l++) {
42 + char *row_key = procfile_lineword(ff, l, 0);
43 + uint32_t hash = simple_hash(row_key);
44 +
45 + // faster strncmp(row_key, "cpu", 3) == 0
46 + if(likely(row_key[0] == 'c' && row_key[1] == 'p' && row_key[2] == 'u')) {
47 + words = procfile_linewords(ff, l);
48 + if(unlikely(words < 9)) {
49 + error("Cannot read /proc/stat cpu line. Expected 9 params, read %u.", words);
50 + continue;
51 + }
52 +
53 + char *id;
54 + unsigned long long user = 0, nice = 0, system = 0, idle = 0, iowait = 0, irq = 0, softirq = 0, steal = 0, guest = 0, guest_nice = 0;
55 +
56 + id = row_key;
57 + user = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
58 + nice = strtoull(procfile_lineword(ff, l, 2), NULL, 10);
59 + system = strtoull(procfile_lineword(ff, l, 3), NULL, 10);
60 + idle = strtoull(procfile_lineword(ff, l, 4), NULL, 10);
61 + iowait = strtoull(procfile_lineword(ff, l, 5), NULL, 10);
62 + irq = strtoull(procfile_lineword(ff, l, 6), NULL, 10);
63 + softirq = strtoull(procfile_lineword(ff, l, 7), NULL, 10);
64 + steal = strtoull(procfile_lineword(ff, l, 8), NULL, 10);
65 +
66 + guest = strtoull(procfile_lineword(ff, l, 9), NULL, 10);
67 + user -= guest;
68 +
69 + guest_nice = strtoull(procfile_lineword(ff, l, 10), NULL, 10);
70 + nice -= guest_nice;
71 +
72 + char *title, *type, *context, *family;
73 + long priority;
74 + int isthistotal;
75 +
76 + if(unlikely(strcmp(id, "cpu")) == 0) {
77 + title = "Total CPU utilization";
78 + type = "system";
79 + context = "system.cpu";
80 + family = id;
81 + priority = 100;
82 + isthistotal = 1;
83 + }
84 + else {
85 + title = "Core utilization";
86 + type = "cpu";
87 + context = "cpu.cpu";
88 + family = "utilization";
89 + priority = 1000;
90 + isthistotal = 0;
91 + }
92 +
93 + if(likely((isthistotal && do_cpu) || (!isthistotal && do_cpu_cores))) {
94 + st = rrdset_find_bytype(type, id);
95 + if(unlikely(!st)) {
96 + st = rrdset_create(type, id, NULL, family, context, title, "percentage", priority, update_every, RRDSET_TYPE_STACKED);
97 +
98 + long multiplier = 1;
99 + long divisor = 1; // sysconf(_SC_CLK_TCK);
100 +
101 + rrddim_add(st, "guest_nice", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
102 + rrddim_add(st, "guest", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
103 + rrddim_add(st, "steal", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
104 + rrddim_add(st, "softirq", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
105 + rrddim_add(st, "irq", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
106 + rrddim_add(st, "user", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
107 + rrddim_add(st, "system", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
108 + rrddim_add(st, "nice", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
109 + rrddim_add(st, "iowait", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
110 +
111 + rrddim_add(st, "idle", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
112 + rrddim_hide(st, "idle");
113 + }
114 + else rrdset_next(st);
115 +
116 + rrddim_set(st, "user", user);
117 + rrddim_set(st, "nice", nice);
118 + rrddim_set(st, "system", system);
119 + rrddim_set(st, "idle", idle);
120 + rrddim_set(st, "iowait", iowait);
121 + rrddim_set(st, "irq", irq);
122 + rrddim_set(st, "softirq", softirq);
123 + rrddim_set(st, "steal", steal);
124 + rrddim_set(st, "guest", guest);
125 + rrddim_set(st, "guest_nice", guest_nice);
126 + rrdset_done(st);
127 + }
128 + }
129 + else if(hash == hash_intr && strcmp(row_key, "intr") == 0) {
130 + unsigned long long value = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
131 +
132 + // --------------------------------------------------------------------
133 +
134 + if(likely(do_interrupts)) {
135 + st = rrdset_find_bytype("system", "intr");
136 + if(unlikely(!st)) {
137 + st = rrdset_create("system", "intr", NULL, "interrupts", NULL, "CPU Interrupts", "interrupts/s", 900, update_every, RRDSET_TYPE_LINE);
138 + st->isdetail = 1;
139 +
140 + rrddim_add(st, "interrupts", NULL, 1, 1, RRDDIM_INCREMENTAL);
141 + }
142 + else rrdset_next(st);
143 +
144 + rrddim_set(st, "interrupts", value);
145 + rrdset_done(st);
146 + }
147 + }
148 + else if(hash == hash_ctxt && strcmp(row_key, "ctxt") == 0) {
149 + unsigned long long value = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
150 +
151 + // --------------------------------------------------------------------
152 +
153 + if(likely(do_context)) {
154 + st = rrdset_find_bytype("system", "ctxt");
155 + if(unlikely(!st)) {
156 + st = rrdset_create("system", "ctxt", NULL, "processes", NULL, "CPU Context Switches", "context switches/s", 800, update_every, RRDSET_TYPE_LINE);
157 +
158 + rrddim_add(st, "switches", NULL, 1, 1, RRDDIM_INCREMENTAL);
159 + }
160 + else rrdset_next(st);
161 +
162 + rrddim_set(st, "switches", value);
163 + rrdset_done(st);
164 + }
165 + }
166 + else if(hash == hash_processes && !processes && strcmp(row_key, "processes") == 0) {
167 + processes = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
168 + }
169 + else if(hash == hash_procs_running && !running && strcmp(row_key, "procs_running") == 0) {
170 + running = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
171 + }
172 + else if(hash == hash_procs_blocked && !blocked && strcmp(row_key, "procs_blocked") == 0) {
173 + blocked = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
174 + }
175 + }
176 +
177 + // --------------------------------------------------------------------
178 +
179 + if(likely(do_forks)) {
180 + st = rrdset_find_bytype("system", "forks");
181 + if(unlikely(!st)) {
182 + st = rrdset_create("system", "forks", NULL, "processes", NULL, "Started Processes", "processes/s", 700, update_every, RRDSET_TYPE_LINE);
183 + st->isdetail = 1;
184 +
185 + rrddim_add(st, "started", NULL, 1, 1, RRDDIM_INCREMENTAL);
186 + }
187 + else rrdset_next(st);
188 +
189 + rrddim_set(st, "started", processes);
190 + rrdset_done(st);
191 + }
192 +
193 + // --------------------------------------------------------------------
194 +
195 + if(likely(do_processes)) {
196 + st = rrdset_find_bytype("system", "processes");
197 + if(unlikely(!st)) {
198 + st = rrdset_create("system", "processes", NULL, "processes", NULL, "System Processes", "processes", 600, update_every, RRDSET_TYPE_LINE);
199 +
200 + rrddim_add(st, "running", NULL, 1, 1, RRDDIM_ABSOLUTE);
201 + rrddim_add(st, "blocked", NULL, -1, 1, RRDDIM_ABSOLUTE);
202 + }
203 + else rrdset_next(st);
204 +
205 + rrddim_set(st, "running", running);
206 + rrddim_set(st, "blocked", blocked);
207 + rrdset_done(st);
208 + }
209 +
210 + return 0;
211 }
src/proc_sys_kernel_random_entropy_avail.c
+20 -20
@@ -1,31 +1,31 @@
1 #include "common.h"
2
3 int do_proc_sys_kernel_random_entropy_avail(int update_every, unsigned long long dt) {
4 - static procfile *ff = NULL;
4 + static procfile *ff = NULL;
5
6 - if(dt) {} ;
6 + if(dt) {} ;
7
8 - if(!ff) {
9 - char filename[FILENAME_MAX + 1];
10 - snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/sys/kernel/random/entropy_avail");
11 - ff = procfile_open(config_get("plugin:proc:/proc/sys/kernel/random/entropy_avail", "filename to monitor", filename), "", PROCFILE_FLAG_DEFAULT);
12 - }
13 - if(!ff) return 1;
8 + if(!ff) {
9 + char filename[FILENAME_MAX + 1];
10 + snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/sys/kernel/random/entropy_avail");
11 + ff = procfile_open(config_get("plugin:proc:/proc/sys/kernel/random/entropy_avail", "filename to monitor", filename), "", PROCFILE_FLAG_DEFAULT);
12 + }
13 + if(!ff) return 1;
14
15 - ff = procfile_readall(ff);
16 - if(!ff) return 0; // we return 0, so that we will retry to open it next time
15 + ff = procfile_readall(ff);
16 + if(!ff) return 0; // we return 0, so that we will retry to open it next time
17
18 - unsigned long long entropy = strtoull(procfile_lineword(ff, 0, 0), NULL, 10);
18 + unsigned long long entropy = strtoull(procfile_lineword(ff, 0, 0), NULL, 10);
19
20 - RRDSET *st = rrdset_find_bytype("system", "entropy");
21 - if(!st) {
22 - st = rrdset_create("system", "entropy", NULL, "entropy", NULL, "Available Entropy", "entropy", 1000, update_every, RRDSET_TYPE_LINE);
23 - rrddim_add(st, "entropy", NULL, 1, 1, RRDDIM_ABSOLUTE);
24 - }
25 - else rrdset_next(st);
20 + RRDSET *st = rrdset_find_bytype("system", "entropy");
21 + if(!st) {
22 + st = rrdset_create("system", "entropy", NULL, "entropy", NULL, "Available Entropy", "entropy", 1000, update_every, RRDSET_TYPE_LINE);
23 + rrddim_add(st, "entropy", NULL, 1, 1, RRDDIM_ABSOLUTE);
24 + }
25 + else rrdset_next(st);
26
27 - rrddim_set(st, "entropy", entropy);
28 - rrdset_done(st);
27 + rrddim_set(st, "entropy", entropy);
28 + rrdset_done(st);
29
30 - return 0;
30 + return 0;
31 }
src/proc_vmstat.c
+440 -440
@@ -1,470 +1,470 @@
1 #include "common.h"
2
3 int do_proc_vmstat(int update_every, unsigned long long dt) {
4 - static procfile *ff = NULL;
5 - static int do_swapio = -1, do_io = -1, do_pgfaults = -1, gen_hashes = -1;
4 + static procfile *ff = NULL;
5 + static int do_swapio = -1, do_io = -1, do_pgfaults = -1, gen_hashes = -1;
6
7 - // static uint32_t hash_allocstall = -1;
8 - // static uint32_t hash_compact_blocks_moved = -1;
9 - // static uint32_t hash_compact_fail = -1;
10 - // static uint32_t hash_compact_pagemigrate_failed = -1;
11 - // static uint32_t hash_compact_pages_moved = -1;
12 - // static uint32_t hash_compact_stall = -1;
13 - // static uint32_t hash_compact_success = -1;
14 - // static uint32_t hash_htlb_buddy_alloc_fail = -1;
15 - // static uint32_t hash_htlb_buddy_alloc_success = -1;
16 - // static uint32_t hash_kswapd_high_wmark_hit_quickly = -1;
17 - // static uint32_t hash_kswapd_inodesteal = -1;
18 - // static uint32_t hash_kswapd_low_wmark_hit_quickly = -1;
19 - // static uint32_t hash_kswapd_skip_congestion_wait = -1;
20 - // static uint32_t hash_nr_active_anon = -1;
21 - // static uint32_t hash_nr_active_file = -1;
22 - // static uint32_t hash_nr_anon_pages = -1;
23 - // static uint32_t hash_nr_anon_transparent_hugepages = -1;
24 - // static uint32_t hash_nr_bounce = -1;
25 - // static uint32_t hash_nr_dirtied = -1;
26 - // static uint32_t hash_nr_dirty = -1;
27 - // static uint32_t hash_nr_dirty_background_threshold = -1;
28 - // static uint32_t hash_nr_dirty_threshold = -1;
29 - // static uint32_t hash_nr_file_pages = -1;
30 - // static uint32_t hash_nr_free_pages = -1;
31 - // static uint32_t hash_nr_inactive_anon = -1;
32 - // static uint32_t hash_nr_inactive_file = -1;
33 - // static uint32_t hash_nr_isolated_anon = -1;
34 - // static uint32_t hash_nr_isolated_file = -1;
35 - // static uint32_t hash_nr_kernel_stack = -1;
36 - // static uint32_t hash_nr_mapped = -1;
37 - // static uint32_t hash_nr_mlock = -1;
38 - // static uint32_t hash_nr_page_table_pages = -1;
39 - // static uint32_t hash_nr_shmem = -1;
40 - // static uint32_t hash_nr_slab_reclaimable = -1;
41 - // static uint32_t hash_nr_slab_unreclaimable = -1;
42 - // static uint32_t hash_nr_unevictable = -1;
43 - // static uint32_t hash_nr_unstable = -1;
44 - // static uint32_t hash_nr_vmscan_immediate_reclaim = -1;
45 - // static uint32_t hash_nr_vmscan_write = -1;
46 - // static uint32_t hash_nr_writeback = -1;
47 - // static uint32_t hash_nr_writeback_temp = -1;
48 - // static uint32_t hash_nr_written = -1;
49 - // static uint32_t hash_pageoutrun = -1;
50 - // static uint32_t hash_pgactivate = -1;
51 - // static uint32_t hash_pgalloc_dma = -1;
52 - // static uint32_t hash_pgalloc_dma32 = -1;
53 - // static uint32_t hash_pgalloc_movable = -1;
54 - // static uint32_t hash_pgalloc_normal = -1;
55 - // static uint32_t hash_pgdeactivate = -1;
56 - static uint32_t hash_pgfault = -1;
57 - // static uint32_t hash_pgfree = -1;
58 - // static uint32_t hash_pginodesteal = -1;
59 - static uint32_t hash_pgmajfault = -1;
60 - static uint32_t hash_pgpgin = -1;
61 - static uint32_t hash_pgpgout = -1;
62 - // static uint32_t hash_pgrefill_dma = -1;
63 - // static uint32_t hash_pgrefill_dma32 = -1;
64 - // static uint32_t hash_pgrefill_movable = -1;
65 - // static uint32_t hash_pgrefill_normal = -1;
66 - // static uint32_t hash_pgrotated = -1;
67 - // static uint32_t hash_pgscan_direct_dma = -1;
68 - // static uint32_t hash_pgscan_direct_dma32 = -1;
69 - // static uint32_t hash_pgscan_direct_movable = -1;
70 - // static uint32_t hash_pgscan_direct_normal = -1;
71 - // static uint32_t hash_pgscan_kswapd_dma = -1;
72 - // static uint32_t hash_pgscan_kswapd_dma32 = -1;
73 - // static uint32_t hash_pgscan_kswapd_movable = -1;
74 - // static uint32_t hash_pgscan_kswapd_normal = -1;
75 - // static uint32_t hash_pgsteal_direct_dma = -1;
76 - // static uint32_t hash_pgsteal_direct_dma32 = -1;
77 - // static uint32_t hash_pgsteal_direct_movable = -1;
78 - // static uint32_t hash_pgsteal_direct_normal = -1;
79 - // static uint32_t hash_pgsteal_kswapd_dma = -1;
80 - // static uint32_t hash_pgsteal_kswapd_dma32 = -1;
81 - // static uint32_t hash_pgsteal_kswapd_movable = -1;
82 - // static uint32_t hash_pgsteal_kswapd_normal = -1;
83 - static uint32_t hash_pswpin = -1;
84 - static uint32_t hash_pswpout = -1;
85 - // static uint32_t hash_slabs_scanned = -1;
86 - // static uint32_t hash_thp_collapse_alloc = -1;
87 - // static uint32_t hash_thp_collapse_alloc_failed = -1;
88 - // static uint32_t hash_thp_fault_alloc = -1;
89 - // static uint32_t hash_thp_fault_fallback = -1;
90 - // static uint32_t hash_thp_split = -1;
91 - // static uint32_t hash_unevictable_pgs_cleared = -1;
92 - // static uint32_t hash_unevictable_pgs_culled = -1;
93 - // static uint32_t hash_unevictable_pgs_mlocked = -1;
94 - // static uint32_t hash_unevictable_pgs_mlockfreed = -1;
95 - // static uint32_t hash_unevictable_pgs_munlocked = -1;
96 - // static uint32_t hash_unevictable_pgs_rescued = -1;
97 - // static uint32_t hash_unevictable_pgs_scanned = -1;
98 - // static uint32_t hash_unevictable_pgs_stranded = -1;
7 + // static uint32_t hash_allocstall = -1;
8 + // static uint32_t hash_compact_blocks_moved = -1;
9 + // static uint32_t hash_compact_fail = -1;
10 + // static uint32_t hash_compact_pagemigrate_failed = -1;
11 + // static uint32_t hash_compact_pages_moved = -1;
12 + // static uint32_t hash_compact_stall = -1;
13 + // static uint32_t hash_compact_success = -1;
14 + // static uint32_t hash_htlb_buddy_alloc_fail = -1;
15 + // static uint32_t hash_htlb_buddy_alloc_success = -1;
16 + // static uint32_t hash_kswapd_high_wmark_hit_quickly = -1;
17 + // static uint32_t hash_kswapd_inodesteal = -1;
18 + // static uint32_t hash_kswapd_low_wmark_hit_quickly = -1;
19 + // static uint32_t hash_kswapd_skip_congestion_wait = -1;
20 + // static uint32_t hash_nr_active_anon = -1;
21 + // static uint32_t hash_nr_active_file = -1;
22 + // static uint32_t hash_nr_anon_pages = -1;
23 + // static uint32_t hash_nr_anon_transparent_hugepages = -1;
24 + // static uint32_t hash_nr_bounce = -1;
25 + // static uint32_t hash_nr_dirtied = -1;
26 + // static uint32_t hash_nr_dirty = -1;
27 + // static uint32_t hash_nr_dirty_background_threshold = -1;
28 + // static uint32_t hash_nr_dirty_threshold = -1;
29 + // static uint32_t hash_nr_file_pages = -1;
30 + // static uint32_t hash_nr_free_pages = -1;
31 + // static uint32_t hash_nr_inactive_anon = -1;
32 + // static uint32_t hash_nr_inactive_file = -1;
33 + // static uint32_t hash_nr_isolated_anon = -1;
34 + // static uint32_t hash_nr_isolated_file = -1;
35 + // static uint32_t hash_nr_kernel_stack = -1;
36 + // static uint32_t hash_nr_mapped = -1;
37 + // static uint32_t hash_nr_mlock = -1;
38 + // static uint32_t hash_nr_page_table_pages = -1;
39 + // static uint32_t hash_nr_shmem = -1;
40 + // static uint32_t hash_nr_slab_reclaimable = -1;
41 + // static uint32_t hash_nr_slab_unreclaimable = -1;
42 + // static uint32_t hash_nr_unevictable = -1;
43 + // static uint32_t hash_nr_unstable = -1;
44 + // static uint32_t hash_nr_vmscan_immediate_reclaim = -1;
45 + // static uint32_t hash_nr_vmscan_write = -1;
46 + // static uint32_t hash_nr_writeback = -1;
47 + // static uint32_t hash_nr_writeback_temp = -1;
48 + // static uint32_t hash_nr_written = -1;
49 + // static uint32_t hash_pageoutrun = -1;
50 + // static uint32_t hash_pgactivate = -1;
51 + // static uint32_t hash_pgalloc_dma = -1;
52 + // static uint32_t hash_pgalloc_dma32 = -1;
53 + // static uint32_t hash_pgalloc_movable = -1;
54 + // static uint32_t hash_pgalloc_normal = -1;
55 + // static uint32_t hash_pgdeactivate = -1;
56 + static uint32_t hash_pgfault = -1;
57 + // static uint32_t hash_pgfree = -1;
58 + // static uint32_t hash_pginodesteal = -1;
59 + static uint32_t hash_pgmajfault = -1;
60 + static uint32_t hash_pgpgin = -1;
61 + static uint32_t hash_pgpgout = -1;
62 + // static uint32_t hash_pgrefill_dma = -1;
63 + // static uint32_t hash_pgrefill_dma32 = -1;
64 + // static uint32_t hash_pgrefill_movable = -1;
65 + // static uint32_t hash_pgrefill_normal = -1;
66 + // static uint32_t hash_pgrotated = -1;
67 + // static uint32_t hash_pgscan_direct_dma = -1;
68 + // static uint32_t hash_pgscan_direct_dma32 = -1;
69 + // static uint32_t hash_pgscan_direct_movable = -1;
70 + // static uint32_t hash_pgscan_direct_normal = -1;
71 + // static uint32_t hash_pgscan_kswapd_dma = -1;
72 + // static uint32_t hash_pgscan_kswapd_dma32 = -1;
73 + // static uint32_t hash_pgscan_kswapd_movable = -1;
74 + // static uint32_t hash_pgscan_kswapd_normal = -1;
75 + // static uint32_t hash_pgsteal_direct_dma = -1;
76 + // static uint32_t hash_pgsteal_direct_dma32 = -1;
77 + // static uint32_t hash_pgsteal_direct_movable = -1;
78 + // static uint32_t hash_pgsteal_direct_normal = -1;
79 + // static uint32_t hash_pgsteal_kswapd_dma = -1;
80 + // static uint32_t hash_pgsteal_kswapd_dma32 = -1;
81 + // static uint32_t hash_pgsteal_kswapd_movable = -1;
82 + // static uint32_t hash_pgsteal_kswapd_normal = -1;
83 + static uint32_t hash_pswpin = -1;
84 + static uint32_t hash_pswpout = -1;
85 + // static uint32_t hash_slabs_scanned = -1;
86 + // static uint32_t hash_thp_collapse_alloc = -1;
87 + // static uint32_t hash_thp_collapse_alloc_failed = -1;
88 + // static uint32_t hash_thp_fault_alloc = -1;
89 + // static uint32_t hash_thp_fault_fallback = -1;
90 + // static uint32_t hash_thp_split = -1;
91 + // static uint32_t hash_unevictable_pgs_cleared = -1;
92 + // static uint32_t hash_unevictable_pgs_culled = -1;
93 + // static uint32_t hash_unevictable_pgs_mlocked = -1;
94 + // static uint32_t hash_unevictable_pgs_mlockfreed = -1;
95 + // static uint32_t hash_unevictable_pgs_munlocked = -1;
96 + // static uint32_t hash_unevictable_pgs_rescued = -1;
97 + // static uint32_t hash_unevictable_pgs_scanned = -1;
98 + // static uint32_t hash_unevictable_pgs_stranded = -1;
99
100 - if(gen_hashes != 1) {
101 - gen_hashes = 1;
102 - // hash_allocstall = simple_hash("allocstall");
103 - // hash_compact_blocks_moved = simple_hash("compact_blocks_moved");
104 - // hash_compact_fail = simple_hash("compact_fail");
105 - // hash_compact_pagemigrate_failed = simple_hash("compact_pagemigrate_failed");
106 - // hash_compact_pages_moved = simple_hash("compact_pages_moved");
107 - // hash_compact_stall = simple_hash("compact_stall");
108 - // hash_compact_success = simple_hash("compact_success");
109 - // hash_htlb_buddy_alloc_fail = simple_hash("htlb_buddy_alloc_fail");
110 - // hash_htlb_buddy_alloc_success = simple_hash("htlb_buddy_alloc_success");
111 - // hash_kswapd_high_wmark_hit_quickly = simple_hash("kswapd_high_wmark_hit_quickly");
112 - // hash_kswapd_inodesteal = simple_hash("kswapd_inodesteal");
113 - // hash_kswapd_low_wmark_hit_quickly = simple_hash("kswapd_low_wmark_hit_quickly");
114 - // hash_kswapd_skip_congestion_wait = simple_hash("kswapd_skip_congestion_wait");
115 - // hash_nr_active_anon = simple_hash("nr_active_anon");
116 - // hash_nr_active_file = simple_hash("nr_active_file");
117 - // hash_nr_anon_pages = simple_hash("nr_anon_pages");
118 - // hash_nr_anon_transparent_hugepages = simple_hash("nr_anon_transparent_hugepages");
119 - // hash_nr_bounce = simple_hash("nr_bounce");
120 - // hash_nr_dirtied = simple_hash("nr_dirtied");
121 - // hash_nr_dirty = simple_hash("nr_dirty");
122 - // hash_nr_dirty_background_threshold = simple_hash("nr_dirty_background_threshold");
123 - // hash_nr_dirty_threshold = simple_hash("nr_dirty_threshold");
124 - // hash_nr_file_pages = simple_hash("nr_file_pages");
125 - // hash_nr_free_pages = simple_hash("nr_free_pages");
126 - // hash_nr_inactive_anon = simple_hash("nr_inactive_anon");
127 - // hash_nr_inactive_file = simple_hash("nr_inactive_file");
128 - // hash_nr_isolated_anon = simple_hash("nr_isolated_anon");
129 - // hash_nr_isolated_file = simple_hash("nr_isolated_file");
130 - // hash_nr_kernel_stack = simple_hash("nr_kernel_stack");
131 - // hash_nr_mapped = simple_hash("nr_mapped");
132 - // hash_nr_mlock = simple_hash("nr_mlock");
133 - // hash_nr_page_table_pages = simple_hash("nr_page_table_pages");
134 - // hash_nr_shmem = simple_hash("nr_shmem");
135 - // hash_nr_slab_reclaimable = simple_hash("nr_slab_reclaimable");
136 - // hash_nr_slab_unreclaimable = simple_hash("nr_slab_unreclaimable");
137 - // hash_nr_unevictable = simple_hash("nr_unevictable");
138 - // hash_nr_unstable = simple_hash("nr_unstable");
139 - // hash_nr_vmscan_immediate_reclaim = simple_hash("nr_vmscan_immediate_reclaim");
140 - // hash_nr_vmscan_write = simple_hash("nr_vmscan_write");
141 - // hash_nr_writeback = simple_hash("nr_writeback");
142 - // hash_nr_writeback_temp = simple_hash("nr_writeback_temp");
143 - // hash_nr_written = simple_hash("nr_written");
144 - // hash_pageoutrun = simple_hash("pageoutrun");
145 - // hash_pgactivate = simple_hash("pgactivate");
146 - // hash_pgalloc_dma = simple_hash("pgalloc_dma");
147 - // hash_pgalloc_dma32 = simple_hash("pgalloc_dma32");
148 - // hash_pgalloc_movable = simple_hash("pgalloc_movable");
149 - // hash_pgalloc_normal = simple_hash("pgalloc_normal");
150 - // hash_pgdeactivate = simple_hash("pgdeactivate");
151 - hash_pgfault = simple_hash("pgfault");
152 - // hash_pgfree = simple_hash("pgfree");
153 - // hash_pginodesteal = simple_hash("pginodesteal");
154 - hash_pgmajfault = simple_hash("pgmajfault");
155 - hash_pgpgin = simple_hash("pgpgin");
156 - hash_pgpgout = simple_hash("pgpgout");
157 - // hash_pgrefill_dma = simple_hash("pgrefill_dma");
158 - // hash_pgrefill_dma32 = simple_hash("pgrefill_dma32");
159 - // hash_pgrefill_movable = simple_hash("pgrefill_movable");
160 - // hash_pgrefill_normal = simple_hash("pgrefill_normal");
161 - // hash_pgrotated = simple_hash("pgrotated");
162 - // hash_pgscan_direct_dma = simple_hash("pgscan_direct_dma");
163 - // hash_pgscan_direct_dma32 = simple_hash("pgscan_direct_dma32");
164 - // hash_pgscan_direct_movable = simple_hash("pgscan_direct_movable");
165 - // hash_pgscan_direct_normal = simple_hash("pgscan_direct_normal");
166 - // hash_pgscan_kswapd_dma = simple_hash("pgscan_kswapd_dma");
167 - // hash_pgscan_kswapd_dma32 = simple_hash("pgscan_kswapd_dma32");
168 - // hash_pgscan_kswapd_movable = simple_hash("pgscan_kswapd_movable");
169 - // hash_pgscan_kswapd_normal = simple_hash("pgscan_kswapd_normal");
170 - // hash_pgsteal_direct_dma = simple_hash("pgsteal_direct_dma");
171 - // hash_pgsteal_direct_dma32 = simple_hash("pgsteal_direct_dma32");
172 - // hash_pgsteal_direct_movable = simple_hash("pgsteal_direct_movable");
173 - // hash_pgsteal_direct_normal = simple_hash("pgsteal_direct_normal");
174 - // hash_pgsteal_kswapd_dma = simple_hash("pgsteal_kswapd_dma");
175 - // hash_pgsteal_kswapd_dma32 = simple_hash("pgsteal_kswapd_dma32");
176 - // hash_pgsteal_kswapd_movable = simple_hash("pgsteal_kswapd_movable");
177 - // hash_pgsteal_kswapd_normal = simple_hash("pgsteal_kswapd_normal");
178 - hash_pswpin = simple_hash("pswpin");
179 - hash_pswpout = simple_hash("pswpout");
180 - // hash_slabs_scanned = simple_hash("slabs_scanned");
181 - // hash_thp_collapse_alloc = simple_hash("thp_collapse_alloc");
182 - // hash_thp_collapse_alloc_failed = simple_hash("thp_collapse_alloc_failed");
183 - // hash_thp_fault_alloc = simple_hash("thp_fault_alloc");
184 - // hash_thp_fault_fallback = simple_hash("thp_fault_fallback");
185 - // hash_thp_split = simple_hash("thp_split");
186 - // hash_unevictable_pgs_cleared = simple_hash("unevictable_pgs_cleared");
187 - // hash_unevictable_pgs_culled = simple_hash("unevictable_pgs_culled");
188 - // hash_unevictable_pgs_mlocked = simple_hash("unevictable_pgs_mlocked");
189 - // hash_unevictable_pgs_mlockfreed = simple_hash("unevictable_pgs_mlockfreed");
190 - // hash_unevictable_pgs_munlocked = simple_hash("unevictable_pgs_munlocked");
191 - // hash_unevictable_pgs_rescued = simple_hash("unevictable_pgs_rescued");
192 - // hash_unevictable_pgs_scanned = simple_hash("unevictable_pgs_scanned");
193 - // hash_unevictable_pgs_stranded = simple_hash("unevictable_pgs_stranded");
194 - }
100 + if(gen_hashes != 1) {
101 + gen_hashes = 1;
102 + // hash_allocstall = simple_hash("allocstall");
103 + // hash_compact_blocks_moved = simple_hash("compact_blocks_moved");
104 + // hash_compact_fail = simple_hash("compact_fail");
105 + // hash_compact_pagemigrate_failed = simple_hash("compact_pagemigrate_failed");
106 + // hash_compact_pages_moved = simple_hash("compact_pages_moved");
107 + // hash_compact_stall = simple_hash("compact_stall");
108 + // hash_compact_success = simple_hash("compact_success");
109 + // hash_htlb_buddy_alloc_fail = simple_hash("htlb_buddy_alloc_fail");
110 + // hash_htlb_buddy_alloc_success = simple_hash("htlb_buddy_alloc_success");
111 + // hash_kswapd_high_wmark_hit_quickly = simple_hash("kswapd_high_wmark_hit_quickly");
112 + // hash_kswapd_inodesteal = simple_hash("kswapd_inodesteal");
113 + // hash_kswapd_low_wmark_hit_quickly = simple_hash("kswapd_low_wmark_hit_quickly");
114 + // hash_kswapd_skip_congestion_wait = simple_hash("kswapd_skip_congestion_wait");
115 + // hash_nr_active_anon = simple_hash("nr_active_anon");
116 + // hash_nr_active_file = simple_hash("nr_active_file");
117 + // hash_nr_anon_pages = simple_hash("nr_anon_pages");
118 + // hash_nr_anon_transparent_hugepages = simple_hash("nr_anon_transparent_hugepages");
119 + // hash_nr_bounce = simple_hash("nr_bounce");
120 + // hash_nr_dirtied = simple_hash("nr_dirtied");
121 + // hash_nr_dirty = simple_hash("nr_dirty");
122 + // hash_nr_dirty_background_threshold = simple_hash("nr_dirty_background_threshold");
123 + // hash_nr_dirty_threshold = simple_hash("nr_dirty_threshold");
124 + // hash_nr_file_pages = simple_hash("nr_file_pages");
125 + // hash_nr_free_pages = simple_hash("nr_free_pages");
126 + // hash_nr_inactive_anon = simple_hash("nr_inactive_anon");
127 + // hash_nr_inactive_file = simple_hash("nr_inactive_file");
128 + // hash_nr_isolated_anon = simple_hash("nr_isolated_anon");
129 + // hash_nr_isolated_file = simple_hash("nr_isolated_file");
130 + // hash_nr_kernel_stack = simple_hash("nr_kernel_stack");
131 + // hash_nr_mapped = simple_hash("nr_mapped");
132 + // hash_nr_mlock = simple_hash("nr_mlock");
133 + // hash_nr_page_table_pages = simple_hash("nr_page_table_pages");
134 + // hash_nr_shmem = simple_hash("nr_shmem");
135 + // hash_nr_slab_reclaimable = simple_hash("nr_slab_reclaimable");
136 + // hash_nr_slab_unreclaimable = simple_hash("nr_slab_unreclaimable");
137 + // hash_nr_unevictable = simple_hash("nr_unevictable");
138 + // hash_nr_unstable = simple_hash("nr_unstable");
139 + // hash_nr_vmscan_immediate_reclaim = simple_hash("nr_vmscan_immediate_reclaim");
140 + // hash_nr_vmscan_write = simple_hash("nr_vmscan_write");
141 + // hash_nr_writeback = simple_hash("nr_writeback");
142 + // hash_nr_writeback_temp = simple_hash("nr_writeback_temp");
143 + // hash_nr_written = simple_hash("nr_written");
144 + // hash_pageoutrun = simple_hash("pageoutrun");
145 + // hash_pgactivate = simple_hash("pgactivate");
146 + // hash_pgalloc_dma = simple_hash("pgalloc_dma");
147 + // hash_pgalloc_dma32 = simple_hash("pgalloc_dma32");
148 + // hash_pgalloc_movable = simple_hash("pgalloc_movable");
149 + // hash_pgalloc_normal = simple_hash("pgalloc_normal");
150 + // hash_pgdeactivate = simple_hash("pgdeactivate");
151 + hash_pgfault = simple_hash("pgfault");
152 + // hash_pgfree = simple_hash("pgfree");
153 + // hash_pginodesteal = simple_hash("pginodesteal");
154 + hash_pgmajfault = simple_hash("pgmajfault");
155 + hash_pgpgin = simple_hash("pgpgin");
156 + hash_pgpgout = simple_hash("pgpgout");
157 + // hash_pgrefill_dma = simple_hash("pgrefill_dma");
158 + // hash_pgrefill_dma32 = simple_hash("pgrefill_dma32");
159 + // hash_pgrefill_movable = simple_hash("pgrefill_movable");
160 + // hash_pgrefill_normal = simple_hash("pgrefill_normal");
161 + // hash_pgrotated = simple_hash("pgrotated");
162 + // hash_pgscan_direct_dma = simple_hash("pgscan_direct_dma");
163 + // hash_pgscan_direct_dma32 = simple_hash("pgscan_direct_dma32");
164 + // hash_pgscan_direct_movable = simple_hash("pgscan_direct_movable");
165 + // hash_pgscan_direct_normal = simple_hash("pgscan_direct_normal");
166 + // hash_pgscan_kswapd_dma = simple_hash("pgscan_kswapd_dma");
167 + // hash_pgscan_kswapd_dma32 = simple_hash("pgscan_kswapd_dma32");
168 + // hash_pgscan_kswapd_movable = simple_hash("pgscan_kswapd_movable");
169 + // hash_pgscan_kswapd_normal = simple_hash("pgscan_kswapd_normal");
170 + // hash_pgsteal_direct_dma = simple_hash("pgsteal_direct_dma");
171 + // hash_pgsteal_direct_dma32 = simple_hash("pgsteal_direct_dma32");
172 + // hash_pgsteal_direct_movable = simple_hash("pgsteal_direct_movable");
173 + // hash_pgsteal_direct_normal = simple_hash("pgsteal_direct_normal");
174 + // hash_pgsteal_kswapd_dma = simple_hash("pgsteal_kswapd_dma");
175 + // hash_pgsteal_kswapd_dma32 = simple_hash("pgsteal_kswapd_dma32");
176 + // hash_pgsteal_kswapd_movable = simple_hash("pgsteal_kswapd_movable");
177 + // hash_pgsteal_kswapd_normal = simple_hash("pgsteal_kswapd_normal");
178 + hash_pswpin = simple_hash("pswpin");
179 + hash_pswpout = simple_hash("pswpout");
180 + // hash_slabs_scanned = simple_hash("slabs_scanned");
181 + // hash_thp_collapse_alloc = simple_hash("thp_collapse_alloc");
182 + // hash_thp_collapse_alloc_failed = simple_hash("thp_collapse_alloc_failed");
183 + // hash_thp_fault_alloc = simple_hash("thp_fault_alloc");
184 + // hash_thp_fault_fallback = simple_hash("thp_fault_fallback");
185 + // hash_thp_split = simple_hash("thp_split");
186 + // hash_unevictable_pgs_cleared = simple_hash("unevictable_pgs_cleared");
187 + // hash_unevictable_pgs_culled = simple_hash("unevictable_pgs_culled");
188 + // hash_unevictable_pgs_mlocked = simple_hash("unevictable_pgs_mlocked");
189 + // hash_unevictable_pgs_mlockfreed = simple_hash("unevictable_pgs_mlockfreed");
190 + // hash_unevictable_pgs_munlocked = simple_hash("unevictable_pgs_munlocked");
191 + // hash_unevictable_pgs_rescued = simple_hash("unevictable_pgs_rescued");
192 + // hash_unevictable_pgs_scanned = simple_hash("unevictable_pgs_scanned");
193 + // hash_unevictable_pgs_stranded = simple_hash("unevictable_pgs_stranded");
194 + }
195
196 - if(do_swapio == -1) do_swapio = config_get_boolean("plugin:proc:/proc/vmstat", "swap i/o", 1);
197 - if(do_io == -1) do_io = config_get_boolean("plugin:proc:/proc/vmstat", "disk i/o", 1);
198 - if(do_pgfaults == -1) do_pgfaults = config_get_boolean("plugin:proc:/proc/vmstat", "memory page faults", 1);
196 + if(do_swapio == -1) do_swapio = config_get_boolean("plugin:proc:/proc/vmstat", "swap i/o", 1);
197 + if(do_io == -1) do_io = config_get_boolean("plugin:proc:/proc/vmstat", "disk i/o", 1);
198 + if(do_pgfaults == -1) do_pgfaults = config_get_boolean("plugin:proc:/proc/vmstat", "memory page faults", 1);
199
200 - if(dt) {};
200 + if(dt) {};
201
202 - if(!ff) {
203 - char filename[FILENAME_MAX + 1];
204 - snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/vmstat");
205 - ff = procfile_open(config_get("plugin:proc:/proc/vmstat", "filename to monitor", filename), " \t:", PROCFILE_FLAG_DEFAULT);
206 - }
207 - if(!ff) return 1;
202 + if(!ff) {
203 + char filename[FILENAME_MAX + 1];
204 + snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/vmstat");
205 + ff = procfile_open(config_get("plugin:proc:/proc/vmstat", "filename to monitor", filename), " \t:", PROCFILE_FLAG_DEFAULT);
206 + }
207 + if(!ff) return 1;
208
209 - ff = procfile_readall(ff);
210 - if(!ff) return 0; // we return 0, so that we will retry to open it next time
209 + ff = procfile_readall(ff);
210 + if(!ff) return 0; // we return 0, so that we will retry to open it next time
211
212 - uint32_t lines = procfile_lines(ff), l;
213 - uint32_t words;
212 + uint32_t lines = procfile_lines(ff), l;
213 + uint32_t words;
214
215 - // unsigned long long allocstall = 0ULL;
216 - // unsigned long long compact_blocks_moved = 0ULL;
217 - // unsigned long long compact_fail = 0ULL;
218 - // unsigned long long compact_pagemigrate_failed = 0ULL;
219 - // unsigned long long compact_pages_moved = 0ULL;
220 - // unsigned long long compact_stall = 0ULL;
221 - // unsigned long long compact_success = 0ULL;
222 - // unsigned long long htlb_buddy_alloc_fail = 0ULL;
223 - // unsigned long long htlb_buddy_alloc_success = 0ULL;
224 - // unsigned long long kswapd_high_wmark_hit_quickly = 0ULL;
225 - // unsigned long long kswapd_inodesteal = 0ULL;
226 - // unsigned long long kswapd_low_wmark_hit_quickly = 0ULL;
227 - // unsigned long long kswapd_skip_congestion_wait = 0ULL;
228 - // unsigned long long nr_active_anon = 0ULL;
229 - // unsigned long long nr_active_file = 0ULL;
230 - // unsigned long long nr_anon_pages = 0ULL;
231 - // unsigned long long nr_anon_transparent_hugepages = 0ULL;
232 - // unsigned long long nr_bounce = 0ULL;
233 - // unsigned long long nr_dirtied = 0ULL;
234 - // unsigned long long nr_dirty = 0ULL;
235 - // unsigned long long nr_dirty_background_threshold = 0ULL;
236 - // unsigned long long nr_dirty_threshold = 0ULL;
237 - // unsigned long long nr_file_pages = 0ULL;
238 - // unsigned long long nr_free_pages = 0ULL;
239 - // unsigned long long nr_inactive_anon = 0ULL;
240 - // unsigned long long nr_inactive_file = 0ULL;
241 - // unsigned long long nr_isolated_anon = 0ULL;
242 - // unsigned long long nr_isolated_file = 0ULL;
243 - // unsigned long long nr_kernel_stack = 0ULL;
244 - // unsigned long long nr_mapped = 0ULL;
245 - // unsigned long long nr_mlock = 0ULL;
246 - // unsigned long long nr_page_table_pages = 0ULL;
247 - // unsigned long long nr_shmem = 0ULL;
248 - // unsigned long long nr_slab_reclaimable = 0ULL;
249 - // unsigned long long nr_slab_unreclaimable = 0ULL;
250 - // unsigned long long nr_unevictable = 0ULL;
251 - // unsigned long long nr_unstable = 0ULL;
252 - // unsigned long long nr_vmscan_immediate_reclaim = 0ULL;
253 - // unsigned long long nr_vmscan_write = 0ULL;
254 - // unsigned long long nr_writeback = 0ULL;
255 - // unsigned long long nr_writeback_temp = 0ULL;
256 - // unsigned long long nr_written = 0ULL;
257 - // unsigned long long pageoutrun = 0ULL;
258 - // unsigned long long pgactivate = 0ULL;
259 - // unsigned long long pgalloc_dma = 0ULL;
260 - // unsigned long long pgalloc_dma32 = 0ULL;
261 - // unsigned long long pgalloc_movable = 0ULL;
262 - // unsigned long long pgalloc_normal = 0ULL;
263 - // unsigned long long pgdeactivate = 0ULL;
264 - unsigned long long pgfault = 0ULL;
265 - // unsigned long long pgfree = 0ULL;
266 - // unsigned long long pginodesteal = 0ULL;
267 - unsigned long long pgmajfault = 0ULL;
268 - unsigned long long pgpgin = 0ULL;
269 - unsigned long long pgpgout = 0ULL;
270 - // unsigned long long pgrefill_dma = 0ULL;
271 - // unsigned long long pgrefill_dma32 = 0ULL;
272 - // unsigned long long pgrefill_movable = 0ULL;
273 - // unsigned long long pgrefill_normal = 0ULL;
274 - // unsigned long long pgrotated = 0ULL;
275 - // unsigned long long pgscan_direct_dma = 0ULL;
276 - // unsigned long long pgscan_direct_dma32 = 0ULL;
277 - // unsigned long long pgscan_direct_movable = 0ULL;
278 - // unsigned long long pgscan_direct_normal = 0ULL;
279 - // unsigned long long pgscan_kswapd_dma = 0ULL;
280 - // unsigned long long pgscan_kswapd_dma32 = 0ULL;
281 - // unsigned long long pgscan_kswapd_movable = 0ULL;
282 - // unsigned long long pgscan_kswapd_normal = 0ULL;
283 - // unsigned long long pgsteal_direct_dma = 0ULL;
284 - // unsigned long long pgsteal_direct_dma32 = 0ULL;
285 - // unsigned long long pgsteal_direct_movable = 0ULL;
286 - // unsigned long long pgsteal_direct_normal = 0ULL;
287 - // unsigned long long pgsteal_kswapd_dma = 0ULL;
288 - // unsigned long long pgsteal_kswapd_dma32 = 0ULL;
289 - // unsigned long long pgsteal_kswapd_movable = 0ULL;
290 - // unsigned long long pgsteal_kswapd_normal = 0ULL;
291 - unsigned long long pswpin = 0ULL;
292 - unsigned long long pswpout = 0ULL;
293 - // unsigned long long slabs_scanned = 0ULL;
294 - // unsigned long long thp_collapse_alloc = 0ULL;
295 - // unsigned long long thp_collapse_alloc_failed = 0ULL;
296 - // unsigned long long thp_fault_alloc = 0ULL;
297 - // unsigned long long thp_fault_fallback = 0ULL;
298 - // unsigned long long thp_split = 0ULL;
299 - // unsigned long long unevictable_pgs_cleared = 0ULL;
300 - // unsigned long long unevictable_pgs_culled = 0ULL;
301 - // unsigned long long unevictable_pgs_mlocked = 0ULL;
302 - // unsigned long long unevictable_pgs_mlockfreed = 0ULL;
303 - // unsigned long long unevictable_pgs_munlocked = 0ULL;
304 - // unsigned long long unevictable_pgs_rescued = 0ULL;
305 - // unsigned long long unevictable_pgs_scanned = 0ULL;
306 - // unsigned long long unevictable_pgs_stranded = 0ULL;
215 + // unsigned long long allocstall = 0ULL;
216 + // unsigned long long compact_blocks_moved = 0ULL;
217 + // unsigned long long compact_fail = 0ULL;
218 + // unsigned long long compact_pagemigrate_failed = 0ULL;
219 + // unsigned long long compact_pages_moved = 0ULL;
220 + // unsigned long long compact_stall = 0ULL;
221 + // unsigned long long compact_success = 0ULL;
222 + // unsigned long long htlb_buddy_alloc_fail = 0ULL;
223 + // unsigned long long htlb_buddy_alloc_success = 0ULL;
224 + // unsigned long long kswapd_high_wmark_hit_quickly = 0ULL;
225 + // unsigned long long kswapd_inodesteal = 0ULL;
226 + // unsigned long long kswapd_low_wmark_hit_quickly = 0ULL;
227 + // unsigned long long kswapd_skip_congestion_wait = 0ULL;
228 + // unsigned long long nr_active_anon = 0ULL;
229 + // unsigned long long nr_active_file = 0ULL;
230 + // unsigned long long nr_anon_pages = 0ULL;
231 + // unsigned long long nr_anon_transparent_hugepages = 0ULL;
232 + // unsigned long long nr_bounce = 0ULL;
233 + // unsigned long long nr_dirtied = 0ULL;
234 + // unsigned long long nr_dirty = 0ULL;
235 + // unsigned long long nr_dirty_background_threshold = 0ULL;
236 + // unsigned long long nr_dirty_threshold = 0ULL;
237 + // unsigned long long nr_file_pages = 0ULL;
238 + // unsigned long long nr_free_pages = 0ULL;
239 + // unsigned long long nr_inactive_anon = 0ULL;
240 + // unsigned long long nr_inactive_file = 0ULL;
241 + // unsigned long long nr_isolated_anon = 0ULL;
242 + // unsigned long long nr_isolated_file = 0ULL;
243 + // unsigned long long nr_kernel_stack = 0ULL;
244 + // unsigned long long nr_mapped = 0ULL;
245 + // unsigned long long nr_mlock = 0ULL;
246 + // unsigned long long nr_page_table_pages = 0ULL;
247 + // unsigned long long nr_shmem = 0ULL;
248 + // unsigned long long nr_slab_reclaimable = 0ULL;
249 + // unsigned long long nr_slab_unreclaimable = 0ULL;
250 + // unsigned long long nr_unevictable = 0ULL;
251 + // unsigned long long nr_unstable = 0ULL;
252 + // unsigned long long nr_vmscan_immediate_reclaim = 0ULL;
253 + // unsigned long long nr_vmscan_write = 0ULL;
254 + // unsigned long long nr_writeback = 0ULL;
255 + // unsigned long long nr_writeback_temp = 0ULL;
256 + // unsigned long long nr_written = 0ULL;
257 + // unsigned long long pageoutrun = 0ULL;
258 + // unsigned long long pgactivate = 0ULL;
259 + // unsigned long long pgalloc_dma = 0ULL;
260 + // unsigned long long pgalloc_dma32 = 0ULL;
261 + // unsigned long long pgalloc_movable = 0ULL;
262 + // unsigned long long pgalloc_normal = 0ULL;
263 + // unsigned long long pgdeactivate = 0ULL;
264 + unsigned long long pgfault = 0ULL;
265 + // unsigned long long pgfree = 0ULL;
266 + // unsigned long long pginodesteal = 0ULL;
267 + unsigned long long pgmajfault = 0ULL;
268 + unsigned long long pgpgin = 0ULL;
269 + unsigned long long pgpgout = 0ULL;
270 + // unsigned long long pgrefill_dma = 0ULL;
271 + // unsigned long long pgrefill_dma32 = 0ULL;
272 + // unsigned long long pgrefill_movable = 0ULL;
273 + // unsigned long long pgrefill_normal = 0ULL;
274 + // unsigned long long pgrotated = 0ULL;
275 + // unsigned long long pgscan_direct_dma = 0ULL;
276 + // unsigned long long pgscan_direct_dma32 = 0ULL;
277 + // unsigned long long pgscan_direct_movable = 0ULL;
278 + // unsigned long long pgscan_direct_normal = 0ULL;
279 + // unsigned long long pgscan_kswapd_dma = 0ULL;
280 + // unsigned long long pgscan_kswapd_dma32 = 0ULL;
281 + // unsigned long long pgscan_kswapd_movable = 0ULL;
282 + // unsigned long long pgscan_kswapd_normal = 0ULL;
283 + // unsigned long long pgsteal_direct_dma = 0ULL;
284 + // unsigned long long pgsteal_direct_dma32 = 0ULL;
285 + // unsigned long long pgsteal_direct_movable = 0ULL;
286 + // unsigned long long pgsteal_direct_normal = 0ULL;
287 + // unsigned long long pgsteal_kswapd_dma = 0ULL;
288 + // unsigned long long pgsteal_kswapd_dma32 = 0ULL;
289 + // unsigned long long pgsteal_kswapd_movable = 0ULL;
290 + // unsigned long long pgsteal_kswapd_normal = 0ULL;
291 + unsigned long long pswpin = 0ULL;
292 + unsigned long long pswpout = 0ULL;
293 + // unsigned long long slabs_scanned = 0ULL;
294 + // unsigned long long thp_collapse_alloc = 0ULL;
295 + // unsigned long long thp_collapse_alloc_failed = 0ULL;
296 + // unsigned long long thp_fault_alloc = 0ULL;
297 + // unsigned long long thp_fault_fallback = 0ULL;
298 + // unsigned long long thp_split = 0ULL;
299 + // unsigned long long unevictable_pgs_cleared = 0ULL;
300 + // unsigned long long unevictable_pgs_culled = 0ULL;
301 + // unsigned long long unevictable_pgs_mlocked = 0ULL;
302 + // unsigned long long unevictable_pgs_mlockfreed = 0ULL;
303 + // unsigned long long unevictable_pgs_munlocked = 0ULL;
304 + // unsigned long long unevictable_pgs_rescued = 0ULL;
305 + // unsigned long long unevictable_pgs_scanned = 0ULL;
306 + // unsigned long long unevictable_pgs_stranded = 0ULL;
307
308 - for(l = 0; l < lines ;l++) {
309 - words = procfile_linewords(ff, l);
310 - if(words < 2) {
311 - if(words) error("Cannot read /proc/vmstat line %u. Expected 2 params, read %u.", l, words);
312 - continue;
313 - }
308 + for(l = 0; l < lines ;l++) {
309 + words = procfile_linewords(ff, l);
310 + if(words < 2) {
311 + if(words) error("Cannot read /proc/vmstat line %u. Expected 2 params, read %u.", l, words);
312 + continue;
313 + }
314
315 - char *name = procfile_lineword(ff, l, 0);
316 - char * value = procfile_lineword(ff, l, 1);
317 - if(!name || !*name || !value || !*value) continue;
315 + char *name = procfile_lineword(ff, l, 0);
316 + char * value = procfile_lineword(ff, l, 1);
317 + if(!name || !*name || !value || !*value) continue;
318
319 - uint32_t hash = simple_hash(name);
319 + uint32_t hash = simple_hash(name);
320
321 - if(0) ;
322 - // else if(hash == hash_allocstall && strcmp(name, "allocstall") == 0) allocstall = strtoull(value, NULL, 10);
323 - // else if(hash == hash_compact_blocks_moved && strcmp(name, "compact_blocks_moved") == 0) compact_blocks_moved = strtoull(value, NULL, 10);
324 - // else if(hash == hash_compact_fail && strcmp(name, "compact_fail") == 0) compact_fail = strtoull(value, NULL, 10);
325 - // else if(hash == hash_compact_pagemigrate_failed && strcmp(name, "compact_pagemigrate_failed") == 0) compact_pagemigrate_failed = strtoull(value, NULL, 10);
326 - // else if(hash == hash_compact_pages_moved && strcmp(name, "compact_pages_moved") == 0) compact_pages_moved = strtoull(value, NULL, 10);
327 - // else if(hash == hash_compact_stall && strcmp(name, "compact_stall") == 0) compact_stall = strtoull(value, NULL, 10);
328 - // else if(hash == hash_compact_success && strcmp(name, "compact_success") == 0) compact_success = strtoull(value, NULL, 10);
329 - // else if(hash == hash_htlb_buddy_alloc_fail && strcmp(name, "htlb_buddy_alloc_fail") == 0) htlb_buddy_alloc_fail = strtoull(value, NULL, 10);
330 - // else if(hash == hash_htlb_buddy_alloc_success && strcmp(name, "htlb_buddy_alloc_success") == 0) htlb_buddy_alloc_success = strtoull(value, NULL, 10);
331 - // else if(hash == hash_kswapd_high_wmark_hit_quickly && strcmp(name, "kswapd_high_wmark_hit_quickly") == 0) kswapd_high_wmark_hit_quickly = strtoull(value, NULL, 10);
332 - // else if(hash == hash_kswapd_inodesteal && strcmp(name, "kswapd_inodesteal") == 0) kswapd_inodesteal = strtoull(value, NULL, 10);
333 - // else if(hash == hash_kswapd_low_wmark_hit_quickly && strcmp(name, "kswapd_low_wmark_hit_quickly") == 0) kswapd_low_wmark_hit_quickly = strtoull(value, NULL, 10);
334 - // else if(hash == hash_kswapd_skip_congestion_wait && strcmp(name, "kswapd_skip_congestion_wait") == 0) kswapd_skip_congestion_wait = strtoull(value, NULL, 10);
335 - // else if(hash == hash_nr_active_anon && strcmp(name, "nr_active_anon") == 0) nr_active_anon = strtoull(value, NULL, 10);
336 - // else if(hash == hash_nr_active_file && strcmp(name, "nr_active_file") == 0) nr_active_file = strtoull(value, NULL, 10);
337 - // else if(hash == hash_nr_anon_pages && strcmp(name, "nr_anon_pages") == 0) nr_anon_pages = strtoull(value, NULL, 10);
338 - // else if(hash == hash_nr_anon_transparent_hugepages && strcmp(name, "nr_anon_transparent_hugepages") == 0) nr_anon_transparent_hugepages = strtoull(value, NULL, 10);
339 - // else if(hash == hash_nr_bounce && strcmp(name, "nr_bounce") == 0) nr_bounce = strtoull(value, NULL, 10);
340 - // else if(hash == hash_nr_dirtied && strcmp(name, "nr_dirtied") == 0) nr_dirtied = strtoull(value, NULL, 10);
341 - // else if(hash == hash_nr_dirty && strcmp(name, "nr_dirty") == 0) nr_dirty = strtoull(value, NULL, 10);
342 - // else if(hash == hash_nr_dirty_background_threshold && strcmp(name, "nr_dirty_background_threshold") == 0) nr_dirty_background_threshold = strtoull(value, NULL, 10);
343 - // else if(hash == hash_nr_dirty_threshold && strcmp(name, "nr_dirty_threshold") == 0) nr_dirty_threshold = strtoull(value, NULL, 10);
344 - // else if(hash == hash_nr_file_pages && strcmp(name, "nr_file_pages") == 0) nr_file_pages = strtoull(value, NULL, 10);
345 - // else if(hash == hash_nr_free_pages && strcmp(name, "nr_free_pages") == 0) nr_free_pages = strtoull(value, NULL, 10);
346 - // else if(hash == hash_nr_inactive_anon && strcmp(name, "nr_inactive_anon") == 0) nr_inactive_anon = strtoull(value, NULL, 10);
347 - // else if(hash == hash_nr_inactive_file && strcmp(name, "nr_inactive_file") == 0) nr_inactive_file = strtoull(value, NULL, 10);
348 - // else if(hash == hash_nr_isolated_anon && strcmp(name, "nr_isolated_anon") == 0) nr_isolated_anon = strtoull(value, NULL, 10);
349 - // else if(hash == hash_nr_isolated_file && strcmp(name, "nr_isolated_file") == 0) nr_isolated_file = strtoull(value, NULL, 10);
350 - // else if(hash == hash_nr_kernel_stack && strcmp(name, "nr_kernel_stack") == 0) nr_kernel_stack = strtoull(value, NULL, 10);
351 - // else if(hash == hash_nr_mapped && strcmp(name, "nr_mapped") == 0) nr_mapped = strtoull(value, NULL, 10);
352 - // else if(hash == hash_nr_mlock && strcmp(name, "nr_mlock") == 0) nr_mlock = strtoull(value, NULL, 10);
353 - // else if(hash == hash_nr_page_table_pages && strcmp(name, "nr_page_table_pages") == 0) nr_page_table_pages = strtoull(value, NULL, 10);
354 - // else if(hash == hash_nr_shmem && strcmp(name, "nr_shmem") == 0) nr_shmem = strtoull(value, NULL, 10);
355 - // else if(hash == hash_nr_slab_reclaimable && strcmp(name, "nr_slab_reclaimable") == 0) nr_slab_reclaimable = strtoull(value, NULL, 10);
356 - // else if(hash == hash_nr_slab_unreclaimable && strcmp(name, "nr_slab_unreclaimable") == 0) nr_slab_unreclaimable = strtoull(value, NULL, 10);
357 - // else if(hash == hash_nr_unevictable && strcmp(name, "nr_unevictable") == 0) nr_unevictable = strtoull(value, NULL, 10);
358 - // else if(hash == hash_nr_unstable && strcmp(name, "nr_unstable") == 0) nr_unstable = strtoull(value, NULL, 10);
359 - // else if(hash == hash_nr_vmscan_immediate_reclaim && strcmp(name, "nr_vmscan_immediate_reclaim") == 0) nr_vmscan_immediate_reclaim = strtoull(value, NULL, 10);
360 - // else if(hash == hash_nr_vmscan_write && strcmp(name, "nr_vmscan_write") == 0) nr_vmscan_write = strtoull(value, NULL, 10);
361 - // else if(hash == hash_nr_writeback && strcmp(name, "nr_writeback") == 0) nr_writeback = strtoull(value, NULL, 10);
362 - // else if(hash == hash_nr_writeback_temp && strcmp(name, "nr_writeback_temp") == 0) nr_writeback_temp = strtoull(value, NULL, 10);
363 - // else if(hash == hash_nr_written && strcmp(name, "nr_written") == 0) nr_written = strtoull(value, NULL, 10);
364 - // else if(hash == hash_pageoutrun && strcmp(name, "pageoutrun") == 0) pageoutrun = strtoull(value, NULL, 10);
365 - // else if(hash == hash_pgactivate && strcmp(name, "pgactivate") == 0) pgactivate = strtoull(value, NULL, 10);
366 - // else if(hash == hash_pgalloc_dma && strcmp(name, "pgalloc_dma") == 0) pgalloc_dma = strtoull(value, NULL, 10);
367 - // else if(hash == hash_pgalloc_dma32 && strcmp(name, "pgalloc_dma32") == 0) pgalloc_dma32 = strtoull(value, NULL, 10);
368 - // else if(hash == hash_pgalloc_movable && strcmp(name, "pgalloc_movable") == 0) pgalloc_movable = strtoull(value, NULL, 10);
369 - // else if(hash == hash_pgalloc_normal && strcmp(name, "pgalloc_normal") == 0) pgalloc_normal = strtoull(value, NULL, 10);
370 - // else if(hash == hash_pgdeactivate && strcmp(name, "pgdeactivate") == 0) pgdeactivate = strtoull(value, NULL, 10);
371 - else if(hash == hash_pgfault && strcmp(name, "pgfault") == 0) pgfault = strtoull(value, NULL, 10);
372 - // else if(hash == hash_pgfree && strcmp(name, "pgfree") == 0) pgfree = strtoull(value, NULL, 10);
373 - // else if(hash == hash_pginodesteal && strcmp(name, "pginodesteal") == 0) pginodesteal = strtoull(value, NULL, 10);
374 - else if(hash == hash_pgmajfault && strcmp(name, "pgmajfault") == 0) pgmajfault = strtoull(value, NULL, 10);
375 - else if(hash == hash_pgpgin && strcmp(name, "pgpgin") == 0) pgpgin = strtoull(value, NULL, 10);
376 - else if(hash == hash_pgpgout && strcmp(name, "pgpgout") == 0) pgpgout = strtoull(value, NULL, 10);
377 - // else if(hash == hash_pgrefill_dma && strcmp(name, "pgrefill_dma") == 0) pgrefill_dma = strtoull(value, NULL, 10);
378 - // else if(hash == hash_pgrefill_dma32 && strcmp(name, "pgrefill_dma32") == 0) pgrefill_dma32 = strtoull(value, NULL, 10);
379 - // else if(hash == hash_pgrefill_movable && strcmp(name, "pgrefill_movable") == 0) pgrefill_movable = strtoull(value, NULL, 10);
380 - // else if(hash == hash_pgrefill_normal && strcmp(name, "pgrefill_normal") == 0) pgrefill_normal = strtoull(value, NULL, 10);
381 - // else if(hash == hash_pgrotated && strcmp(name, "pgrotated") == 0) pgrotated = strtoull(value, NULL, 10);
382 - // else if(hash == hash_pgscan_direct_dma && strcmp(name, "pgscan_direct_dma") == 0) pgscan_direct_dma = strtoull(value, NULL, 10);
383 - // else if(hash == hash_pgscan_direct_dma32 && strcmp(name, "pgscan_direct_dma32") == 0) pgscan_direct_dma32 = strtoull(value, NULL, 10);
384 - // else if(hash == hash_pgscan_direct_movable && strcmp(name, "pgscan_direct_movable") == 0) pgscan_direct_movable = strtoull(value, NULL, 10);
385 - // else if(hash == hash_pgscan_direct_normal && strcmp(name, "pgscan_direct_normal") == 0) pgscan_direct_normal = strtoull(value, NULL, 10);
386 - // else if(hash == hash_pgscan_kswapd_dma && strcmp(name, "pgscan_kswapd_dma") == 0) pgscan_kswapd_dma = strtoull(value, NULL, 10);
387 - // else if(hash == hash_pgscan_kswapd_dma32 && strcmp(name, "pgscan_kswapd_dma32") == 0) pgscan_kswapd_dma32 = strtoull(value, NULL, 10);
388 - // else if(hash == hash_pgscan_kswapd_movable && strcmp(name, "pgscan_kswapd_movable") == 0) pgscan_kswapd_movable = strtoull(value, NULL, 10);
389 - // else if(hash == hash_pgscan_kswapd_normal && strcmp(name, "pgscan_kswapd_normal") == 0) pgscan_kswapd_normal = strtoull(value, NULL, 10);
390 - // else if(hash == hash_pgsteal_direct_dma && strcmp(name, "pgsteal_direct_dma") == 0) pgsteal_direct_dma = strtoull(value, NULL, 10);
391 - // else if(hash == hash_pgsteal_direct_dma32 && strcmp(name, "pgsteal_direct_dma32") == 0) pgsteal_direct_dma32 = strtoull(value, NULL, 10);
392 - // else if(hash == hash_pgsteal_direct_movable && strcmp(name, "pgsteal_direct_movable") == 0) pgsteal_direct_movable = strtoull(value, NULL, 10);
393 - // else if(hash == hash_pgsteal_direct_normal && strcmp(name, "pgsteal_direct_normal") == 0) pgsteal_direct_normal = strtoull(value, NULL, 10);
394 - // else if(hash == hash_pgsteal_kswapd_dma && strcmp(name, "pgsteal_kswapd_dma") == 0) pgsteal_kswapd_dma = strtoull(value, NULL, 10);
395 - // else if(hash == hash_pgsteal_kswapd_dma32 && strcmp(name, "pgsteal_kswapd_dma32") == 0) pgsteal_kswapd_dma32 = strtoull(value, NULL, 10);
396 - // else if(hash == hash_pgsteal_kswapd_movable && strcmp(name, "pgsteal_kswapd_movable") == 0) pgsteal_kswapd_movable = strtoull(value, NULL, 10);
397 - // else if(hash == hash_pgsteal_kswapd_normal && strcmp(name, "pgsteal_kswapd_normal") == 0) pgsteal_kswapd_normal = strtoull(value, NULL, 10);
398 - else if(hash == hash_pswpin && strcmp(name, "pswpin") == 0) pswpin = strtoull(value, NULL, 10);
399 - else if(hash == hash_pswpout && strcmp(name, "pswpout") == 0) pswpout = strtoull(value, NULL, 10);
400 - // else if(hash == hash_slabs_scanned && strcmp(name, "slabs_scanned") == 0) slabs_scanned = strtoull(value, NULL, 10);
401 - // else if(hash == hash_thp_collapse_alloc && strcmp(name, "thp_collapse_alloc") == 0) thp_collapse_alloc = strtoull(value, NULL, 10);
402 - // else if(hash == hash_thp_collapse_alloc_failed && strcmp(name, "thp_collapse_alloc_failed") == 0) thp_collapse_alloc_failed = strtoull(value, NULL, 10);
403 - // else if(hash == hash_thp_fault_alloc && strcmp(name, "thp_fault_alloc") == 0) thp_fault_alloc = strtoull(value, NULL, 10);
404 - // else if(hash == hash_thp_fault_fallback && strcmp(name, "thp_fault_fallback") == 0) thp_fault_fallback = strtoull(value, NULL, 10);
405 - // else if(hash == hash_thp_split && strcmp(name, "thp_split") == 0) thp_split = strtoull(value, NULL, 10);
406 - // else if(hash == hash_unevictable_pgs_cleared && strcmp(name, "unevictable_pgs_cleared") == 0) unevictable_pgs_cleared = strtoull(value, NULL, 10);
407 - // else if(hash == hash_unevictable_pgs_culled && strcmp(name, "unevictable_pgs_culled") == 0) unevictable_pgs_culled = strtoull(value, NULL, 10);
408 - // else if(hash == hash_unevictable_pgs_mlocked && strcmp(name, "unevictable_pgs_mlocked") == 0) unevictable_pgs_mlocked = strtoull(value, NULL, 10);
409 - // else if(hash == hash_unevictable_pgs_mlockfreed && strcmp(name, "unevictable_pgs_mlockfreed") == 0) unevictable_pgs_mlockfreed = strtoull(value, NULL, 10);
410 - // else if(hash == hash_unevictable_pgs_munlocked && strcmp(name, "unevictable_pgs_munlocked") == 0) unevictable_pgs_munlocked = strtoull(value, NULL, 10);
411 - // else if(hash == hash_unevictable_pgs_rescued && strcmp(name, "unevictable_pgs_rescued") == 0) unevictable_pgs_rescued = strtoull(value, NULL, 10);
412 - // else if(hash == hash_unevictable_pgs_scanned && strcmp(name, "unevictable_pgs_scanned") == 0) unevictable_pgs_scanned = strtoull(value, NULL, 10);
413 - // else if(hash == hash_unevictable_pgs_stranded && strcmp(name, "unevictable_pgs_stranded") == 0) unevictable_pgs_stranded = strtoull(value, NULL, 10);
414 - }
321 + if(0) ;
322 + // else if(hash == hash_allocstall && strcmp(name, "allocstall") == 0) allocstall = strtoull(value, NULL, 10);
323 + // else if(hash == hash_compact_blocks_moved && strcmp(name, "compact_blocks_moved") == 0) compact_blocks_moved = strtoull(value, NULL, 10);
324 + // else if(hash == hash_compact_fail && strcmp(name, "compact_fail") == 0) compact_fail = strtoull(value, NULL, 10);
325 + // else if(hash == hash_compact_pagemigrate_failed && strcmp(name, "compact_pagemigrate_failed") == 0) compact_pagemigrate_failed = strtoull(value, NULL, 10);
326 + // else if(hash == hash_compact_pages_moved && strcmp(name, "compact_pages_moved") == 0) compact_pages_moved = strtoull(value, NULL, 10);
327 + // else if(hash == hash_compact_stall && strcmp(name, "compact_stall") == 0) compact_stall = strtoull(value, NULL, 10);
328 + // else if(hash == hash_compact_success && strcmp(name, "compact_success") == 0) compact_success = strtoull(value, NULL, 10);
329 + // else if(hash == hash_htlb_buddy_alloc_fail && strcmp(name, "htlb_buddy_alloc_fail") == 0) htlb_buddy_alloc_fail = strtoull(value, NULL, 10);
330 + // else if(hash == hash_htlb_buddy_alloc_success && strcmp(name, "htlb_buddy_alloc_success") == 0) htlb_buddy_alloc_success = strtoull(value, NULL, 10);
331 + // else if(hash == hash_kswapd_high_wmark_hit_quickly && strcmp(name, "kswapd_high_wmark_hit_quickly") == 0) kswapd_high_wmark_hit_quickly = strtoull(value, NULL, 10);
332 + // else if(hash == hash_kswapd_inodesteal && strcmp(name, "kswapd_inodesteal") == 0) kswapd_inodesteal = strtoull(value, NULL, 10);
333 + // else if(hash == hash_kswapd_low_wmark_hit_quickly && strcmp(name, "kswapd_low_wmark_hit_quickly") == 0) kswapd_low_wmark_hit_quickly = strtoull(value, NULL, 10);
334 + // else if(hash == hash_kswapd_skip_congestion_wait && strcmp(name, "kswapd_skip_congestion_wait") == 0) kswapd_skip_congestion_wait = strtoull(value, NULL, 10);
335 + // else if(hash == hash_nr_active_anon && strcmp(name, "nr_active_anon") == 0) nr_active_anon = strtoull(value, NULL, 10);
336 + // else if(hash == hash_nr_active_file && strcmp(name, "nr_active_file") == 0) nr_active_file = strtoull(value, NULL, 10);
337 + // else if(hash == hash_nr_anon_pages && strcmp(name, "nr_anon_pages") == 0) nr_anon_pages = strtoull(value, NULL, 10);
338 + // else if(hash == hash_nr_anon_transparent_hugepages && strcmp(name, "nr_anon_transparent_hugepages") == 0) nr_anon_transparent_hugepages = strtoull(value, NULL, 10);
339 + // else if(hash == hash_nr_bounce && strcmp(name, "nr_bounce") == 0) nr_bounce = strtoull(value, NULL, 10);
340 + // else if(hash == hash_nr_dirtied && strcmp(name, "nr_dirtied") == 0) nr_dirtied = strtoull(value, NULL, 10);
341 + // else if(hash == hash_nr_dirty && strcmp(name, "nr_dirty") == 0) nr_dirty = strtoull(value, NULL, 10);
342 + // else if(hash == hash_nr_dirty_background_threshold && strcmp(name, "nr_dirty_background_threshold") == 0) nr_dirty_background_threshold = strtoull(value, NULL, 10);
343 + // else if(hash == hash_nr_dirty_threshold && strcmp(name, "nr_dirty_threshold") == 0) nr_dirty_threshold = strtoull(value, NULL, 10);
344 + // else if(hash == hash_nr_file_pages && strcmp(name, "nr_file_pages") == 0) nr_file_pages = strtoull(value, NULL, 10);
345 + // else if(hash == hash_nr_free_pages && strcmp(name, "nr_free_pages") == 0) nr_free_pages = strtoull(value, NULL, 10);
346 + // else if(hash == hash_nr_inactive_anon && strcmp(name, "nr_inactive_anon") == 0) nr_inactive_anon = strtoull(value, NULL, 10);
347 + // else if(hash == hash_nr_inactive_file && strcmp(name, "nr_inactive_file") == 0) nr_inactive_file = strtoull(value, NULL, 10);
348 + // else if(hash == hash_nr_isolated_anon && strcmp(name, "nr_isolated_anon") == 0) nr_isolated_anon = strtoull(value, NULL, 10);
349 + // else if(hash == hash_nr_isolated_file && strcmp(name, "nr_isolated_file") == 0) nr_isolated_file = strtoull(value, NULL, 10);
350 + // else if(hash == hash_nr_kernel_stack && strcmp(name, "nr_kernel_stack") == 0) nr_kernel_stack = strtoull(value, NULL, 10);
351 + // else if(hash == hash_nr_mapped && strcmp(name, "nr_mapped") == 0) nr_mapped = strtoull(value, NULL, 10);
352 + // else if(hash == hash_nr_mlock && strcmp(name, "nr_mlock") == 0) nr_mlock = strtoull(value, NULL, 10);
353 + // else if(hash == hash_nr_page_table_pages && strcmp(name, "nr_page_table_pages") == 0) nr_page_table_pages = strtoull(value, NULL, 10);
354 + // else if(hash == hash_nr_shmem && strcmp(name, "nr_shmem") == 0) nr_shmem = strtoull(value, NULL, 10);
355 + // else if(hash == hash_nr_slab_reclaimable && strcmp(name, "nr_slab_reclaimable") == 0) nr_slab_reclaimable = strtoull(value, NULL, 10);
356 + // else if(hash == hash_nr_slab_unreclaimable && strcmp(name, "nr_slab_unreclaimable") == 0) nr_slab_unreclaimable = strtoull(value, NULL, 10);
357 + // else if(hash == hash_nr_unevictable && strcmp(name, "nr_unevictable") == 0) nr_unevictable = strtoull(value, NULL, 10);
358 + // else if(hash == hash_nr_unstable && strcmp(name, "nr_unstable") == 0) nr_unstable = strtoull(value, NULL, 10);
359 + // else if(hash == hash_nr_vmscan_immediate_reclaim && strcmp(name, "nr_vmscan_immediate_reclaim") == 0) nr_vmscan_immediate_reclaim = strtoull(value, NULL, 10);
360 + // else if(hash == hash_nr_vmscan_write && strcmp(name, "nr_vmscan_write") == 0) nr_vmscan_write = strtoull(value, NULL, 10);
361 + // else if(hash == hash_nr_writeback && strcmp(name, "nr_writeback") == 0) nr_writeback = strtoull(value, NULL, 10);
362 + // else if(hash == hash_nr_writeback_temp && strcmp(name, "nr_writeback_temp") == 0) nr_writeback_temp = strtoull(value, NULL, 10);
363 + // else if(hash == hash_nr_written && strcmp(name, "nr_written") == 0) nr_written = strtoull(value, NULL, 10);
364 + // else if(hash == hash_pageoutrun && strcmp(name, "pageoutrun") == 0) pageoutrun = strtoull(value, NULL, 10);
365 + // else if(hash == hash_pgactivate && strcmp(name, "pgactivate") == 0) pgactivate = strtoull(value, NULL, 10);
366 + // else if(hash == hash_pgalloc_dma && strcmp(name, "pgalloc_dma") == 0) pgalloc_dma = strtoull(value, NULL, 10);
367 + // else if(hash == hash_pgalloc_dma32 && strcmp(name, "pgalloc_dma32") == 0) pgalloc_dma32 = strtoull(value, NULL, 10);
368 + // else if(hash == hash_pgalloc_movable && strcmp(name, "pgalloc_movable") == 0) pgalloc_movable = strtoull(value, NULL, 10);
369 + // else if(hash == hash_pgalloc_normal && strcmp(name, "pgalloc_normal") == 0) pgalloc_normal = strtoull(value, NULL, 10);
370 + // else if(hash == hash_pgdeactivate && strcmp(name, "pgdeactivate") == 0) pgdeactivate = strtoull(value, NULL, 10);
371 + else if(hash == hash_pgfault && strcmp(name, "pgfault") == 0) pgfault = strtoull(value, NULL, 10);
372 + // else if(hash == hash_pgfree && strcmp(name, "pgfree") == 0) pgfree = strtoull(value, NULL, 10);
373 + // else if(hash == hash_pginodesteal && strcmp(name, "pginodesteal") == 0) pginodesteal = strtoull(value, NULL, 10);
374 + else if(hash == hash_pgmajfault && strcmp(name, "pgmajfault") == 0) pgmajfault = strtoull(value, NULL, 10);
375 + else if(hash == hash_pgpgin && strcmp(name, "pgpgin") == 0) pgpgin = strtoull(value, NULL, 10);
376 + else if(hash == hash_pgpgout && strcmp(name, "pgpgout") == 0) pgpgout = strtoull(value, NULL, 10);
377 + // else if(hash == hash_pgrefill_dma && strcmp(name, "pgrefill_dma") == 0) pgrefill_dma = strtoull(value, NULL, 10);
378 + // else if(hash == hash_pgrefill_dma32 && strcmp(name, "pgrefill_dma32") == 0) pgrefill_dma32 = strtoull(value, NULL, 10);
379 + // else if(hash == hash_pgrefill_movable && strcmp(name, "pgrefill_movable") == 0) pgrefill_movable = strtoull(value, NULL, 10);
380 + // else if(hash == hash_pgrefill_normal && strcmp(name, "pgrefill_normal") == 0) pgrefill_normal = strtoull(value, NULL, 10);
381 + // else if(hash == hash_pgrotated && strcmp(name, "pgrotated") == 0) pgrotated = strtoull(value, NULL, 10);
382 + // else if(hash == hash_pgscan_direct_dma && strcmp(name, "pgscan_direct_dma") == 0) pgscan_direct_dma = strtoull(value, NULL, 10);
383 + // else if(hash == hash_pgscan_direct_dma32 && strcmp(name, "pgscan_direct_dma32") == 0) pgscan_direct_dma32 = strtoull(value, NULL, 10);
384 + // else if(hash == hash_pgscan_direct_movable && strcmp(name, "pgscan_direct_movable") == 0) pgscan_direct_movable = strtoull(value, NULL, 10);
385 + // else if(hash == hash_pgscan_direct_normal && strcmp(name, "pgscan_direct_normal") == 0) pgscan_direct_normal = strtoull(value, NULL, 10);
386 + // else if(hash == hash_pgscan_kswapd_dma && strcmp(name, "pgscan_kswapd_dma") == 0) pgscan_kswapd_dma = strtoull(value, NULL, 10);
387 + // else if(hash == hash_pgscan_kswapd_dma32 && strcmp(name, "pgscan_kswapd_dma32") == 0) pgscan_kswapd_dma32 = strtoull(value, NULL, 10);
388 + // else if(hash == hash_pgscan_kswapd_movable && strcmp(name, "pgscan_kswapd_movable") == 0) pgscan_kswapd_movable = strtoull(value, NULL, 10);
389 + // else if(hash == hash_pgscan_kswapd_normal && strcmp(name, "pgscan_kswapd_normal") == 0) pgscan_kswapd_normal = strtoull(value, NULL, 10);
390 + // else if(hash == hash_pgsteal_direct_dma && strcmp(name, "pgsteal_direct_dma") == 0) pgsteal_direct_dma = strtoull(value, NULL, 10);
391 + // else if(hash == hash_pgsteal_direct_dma32 && strcmp(name, "pgsteal_direct_dma32") == 0) pgsteal_direct_dma32 = strtoull(value, NULL, 10);
392 + // else if(hash == hash_pgsteal_direct_movable && strcmp(name, "pgsteal_direct_movable") == 0) pgsteal_direct_movable = strtoull(value, NULL, 10);
393 + // else if(hash == hash_pgsteal_direct_normal && strcmp(name, "pgsteal_direct_normal") == 0) pgsteal_direct_normal = strtoull(value, NULL, 10);
394 + // else if(hash == hash_pgsteal_kswapd_dma && strcmp(name, "pgsteal_kswapd_dma") == 0) pgsteal_kswapd_dma = strtoull(value, NULL, 10);
395 + // else if(hash == hash_pgsteal_kswapd_dma32 && strcmp(name, "pgsteal_kswapd_dma32") == 0) pgsteal_kswapd_dma32 = strtoull(value, NULL, 10);
396 + // else if(hash == hash_pgsteal_kswapd_movable && strcmp(name, "pgsteal_kswapd_movable") == 0) pgsteal_kswapd_movable = strtoull(value, NULL, 10);
397 + // else if(hash == hash_pgsteal_kswapd_normal && strcmp(name, "pgsteal_kswapd_normal") == 0) pgsteal_kswapd_normal = strtoull(value, NULL, 10);
398 + else if(hash == hash_pswpin && strcmp(name, "pswpin") == 0) pswpin = strtoull(value, NULL, 10);
399 + else if(hash == hash_pswpout && strcmp(name, "pswpout") == 0) pswpout = strtoull(value, NULL, 10);
400 + // else if(hash == hash_slabs_scanned && strcmp(name, "slabs_scanned") == 0) slabs_scanned = strtoull(value, NULL, 10);
401 + // else if(hash == hash_thp_collapse_alloc && strcmp(name, "thp_collapse_alloc") == 0) thp_collapse_alloc = strtoull(value, NULL, 10);
402 + // else if(hash == hash_thp_collapse_alloc_failed && strcmp(name, "thp_collapse_alloc_failed") == 0) thp_collapse_alloc_failed = strtoull(value, NULL, 10);
403 + // else if(hash == hash_thp_fault_alloc && strcmp(name, "thp_fault_alloc") == 0) thp_fault_alloc = strtoull(value, NULL, 10);
404 + // else if(hash == hash_thp_fault_fallback && strcmp(name, "thp_fault_fallback") == 0) thp_fault_fallback = strtoull(value, NULL, 10);
405 + // else if(hash == hash_thp_split && strcmp(name, "thp_split") == 0) thp_split = strtoull(value, NULL, 10);
406 + // else if(hash == hash_unevictable_pgs_cleared && strcmp(name, "unevictable_pgs_cleared") == 0) unevictable_pgs_cleared = strtoull(value, NULL, 10);
407 + // else if(hash == hash_unevictable_pgs_culled && strcmp(name, "unevictable_pgs_culled") == 0) unevictable_pgs_culled = strtoull(value, NULL, 10);
408 + // else if(hash == hash_unevictable_pgs_mlocked && strcmp(name, "unevictable_pgs_mlocked") == 0) unevictable_pgs_mlocked = strtoull(value, NULL, 10);
409 + // else if(hash == hash_unevictable_pgs_mlockfreed && strcmp(name, "unevictable_pgs_mlockfreed") == 0) unevictable_pgs_mlockfreed = strtoull(value, NULL, 10);
410 + // else if(hash == hash_unevictable_pgs_munlocked && strcmp(name, "unevictable_pgs_munlocked") == 0) unevictable_pgs_munlocked = strtoull(value, NULL, 10);
411 + // else if(hash == hash_unevictable_pgs_rescued && strcmp(name, "unevictable_pgs_rescued") == 0) unevictable_pgs_rescued = strtoull(value, NULL, 10);
412 + // else if(hash == hash_unevictable_pgs_scanned && strcmp(name, "unevictable_pgs_scanned") == 0) unevictable_pgs_scanned = strtoull(value, NULL, 10);
413 + // else if(hash == hash_unevictable_pgs_stranded && strcmp(name, "unevictable_pgs_stranded") == 0) unevictable_pgs_stranded = strtoull(value, NULL, 10);
414 + }
415
416 - // --------------------------------------------------------------------
416 + // --------------------------------------------------------------------
417
418 - if(do_swapio) {
419 - static RRDSET *st_swapio = NULL;
420 - if(!st_swapio) {
421 - st_swapio = rrdset_create("system", "swapio", NULL, "swap", NULL, "Swap I/O", "kilobytes/s", 250, update_every, RRDSET_TYPE_AREA);
418 + if(do_swapio) {
419 + static RRDSET *st_swapio = NULL;
420 + if(!st_swapio) {
421 + st_swapio = rrdset_create("system", "swapio", NULL, "swap", NULL, "Swap I/O", "kilobytes/s", 250, update_every, RRDSET_TYPE_AREA);
422
423 - rrddim_add(st_swapio, "in", NULL, sysconf(_SC_PAGESIZE), 1024, RRDDIM_INCREMENTAL);
424 - rrddim_add(st_swapio, "out", NULL, -sysconf(_SC_PAGESIZE), 1024, RRDDIM_INCREMENTAL);
425 - }
426 - else rrdset_next(st_swapio);
423 + rrddim_add(st_swapio, "in", NULL, sysconf(_SC_PAGESIZE), 1024, RRDDIM_INCREMENTAL);
424 + rrddim_add(st_swapio, "out", NULL, -sysconf(_SC_PAGESIZE), 1024, RRDDIM_INCREMENTAL);
425 + }
426 + else rrdset_next(st_swapio);
427
428 - rrddim_set(st_swapio, "in", pswpin);
429 - rrddim_set(st_swapio, "out", pswpout);
430 - rrdset_done(st_swapio);
431 - }
428 + rrddim_set(st_swapio, "in", pswpin);
429 + rrddim_set(st_swapio, "out", pswpout);
430 + rrdset_done(st_swapio);
431 + }
432
433 - // --------------------------------------------------------------------
433 + // --------------------------------------------------------------------
434
435 - if(do_io) {
436 - static RRDSET *st_io = NULL;
437 - if(!st_io) {
438 - st_io = rrdset_create("system", "io", NULL, "disk", NULL, "Disk I/O", "kilobytes/s", 150, update_every, RRDSET_TYPE_AREA);
435 + if(do_io) {
436 + static RRDSET *st_io = NULL;
437 + if(!st_io) {
438 + st_io = rrdset_create("system", "io", NULL, "disk", NULL, "Disk I/O", "kilobytes/s", 150, update_every, RRDSET_TYPE_AREA);
439
440 - rrddim_add(st_io, "in", NULL, 1, 1, RRDDIM_INCREMENTAL);
441 - rrddim_add(st_io, "out", NULL, -1, 1, RRDDIM_INCREMENTAL);
442 - }
443 - else rrdset_next(st_io);
440 + rrddim_add(st_io, "in", NULL, 1, 1, RRDDIM_INCREMENTAL);
441 + rrddim_add(st_io, "out", NULL, -1, 1, RRDDIM_INCREMENTAL);
442 + }
443 + else rrdset_next(st_io);
444
445 - rrddim_set(st_io, "in", pgpgin);
446 - rrddim_set(st_io, "out", pgpgout);
447 - rrdset_done(st_io);
448 - }
445 + rrddim_set(st_io, "in", pgpgin);
446 + rrddim_set(st_io, "out", pgpgout);
447 + rrdset_done(st_io);
448 + }
449
450 - // --------------------------------------------------------------------
450 + // --------------------------------------------------------------------
451
452 - if(do_pgfaults) {
453 - static RRDSET *st_pgfaults = NULL;
454 - if(!st_pgfaults) {
455 - st_pgfaults = rrdset_create("mem", "pgfaults", NULL, "system", NULL, "Memory Page Faults", "page faults/s", 500, update_every, RRDSET_TYPE_LINE);
456 - st_pgfaults->isdetail = 1;
452 + if(do_pgfaults) {
453 + static RRDSET *st_pgfaults = NULL;
454 + if(!st_pgfaults) {
455 + st_pgfaults = rrdset_create("mem", "pgfaults", NULL, "system", NULL, "Memory Page Faults", "page faults/s", 500, update_every, RRDSET_TYPE_LINE);
456 + st_pgfaults->isdetail = 1;
457
458 - rrddim_add(st_pgfaults, "minor", NULL, 1, 1, RRDDIM_INCREMENTAL);
459 - rrddim_add(st_pgfaults, "major", NULL, -1, 1, RRDDIM_INCREMENTAL);
460 - }
461 - else rrdset_next(st_pgfaults);
458 + rrddim_add(st_pgfaults, "minor", NULL, 1, 1, RRDDIM_INCREMENTAL);
459 + rrddim_add(st_pgfaults, "major", NULL, -1, 1, RRDDIM_INCREMENTAL);
460 + }
461 + else rrdset_next(st_pgfaults);
462
463 - rrddim_set(st_pgfaults, "minor", pgfault);
464 - rrddim_set(st_pgfaults, "major", pgmajfault);
465 - rrdset_done(st_pgfaults);
466 - }
463 + rrddim_set(st_pgfaults, "minor", pgfault);
464 + rrddim_set(st_pgfaults, "major", pgmajfault);
465 + rrdset_done(st_pgfaults);
466 + }
467
468 - return 0;
468 + return 0;
469 }
470
src/procfile.c
+329 -329
@@ -19,40 +19,40 @@ size_t procfile_max_allocation = PROCFILE_INCREMENT_BUFFER;
19
20
21 pfwords *pfwords_add(pfwords *fw, char *str) {
22 - // debug(D_PROCFILE, PF_PREFIX ": adding word No %d: '%s'", fw->len, str);
22 + // debug(D_PROCFILE, PF_PREFIX ": adding word No %d: '%s'", fw->len, str);
23
24 - if(unlikely(fw->len == fw->size)) {
25 - // debug(D_PROCFILE, PF_PREFIX ": expanding words");
24 + if(unlikely(fw->len == fw->size)) {
25 + // debug(D_PROCFILE, PF_PREFIX ": expanding words");
26
27 - fw = reallocz(fw, sizeof(pfwords) + (fw->size + PFWORDS_INCREASE_STEP) * sizeof(char *));
28 - fw->size += PFWORDS_INCREASE_STEP;
29 - }
27 + fw = reallocz(fw, sizeof(pfwords) + (fw->size + PFWORDS_INCREASE_STEP) * sizeof(char *));
28 + fw->size += PFWORDS_INCREASE_STEP;
29 + }
30
31 - fw->words[fw->len++] = str;
31 + fw->words[fw->len++] = str;
32
33 - return fw;
33 + return fw;
34 }
35
36 pfwords *pfwords_new(void) {
37 - // debug(D_PROCFILE, PF_PREFIX ": initializing words");
37 + // debug(D_PROCFILE, PF_PREFIX ": initializing words");
38
39 - uint32_t size = (procfile_adaptive_initial_allocation) ? procfile_max_words : PFWORDS_INCREASE_STEP;
39 + uint32_t size = (procfile_adaptive_initial_allocation) ? procfile_max_words : PFWORDS_INCREASE_STEP;
40
41 - pfwords *new = mallocz(sizeof(pfwords) + size * sizeof(char *));
42 - new->len = 0;
43 - new->size = size;
44 - return new;
41 + pfwords *new = mallocz(sizeof(pfwords) + size * sizeof(char *));
42 + new->len = 0;
43 + new->size = size;
44 + return new;
45 }
46
47 void pfwords_reset(pfwords *fw) {
48 - // debug(D_PROCFILE, PF_PREFIX ": reseting words");
49 - fw->len = 0;
48 + // debug(D_PROCFILE, PF_PREFIX ": reseting words");
49 + fw->len = 0;
50 }
51
52 void pfwords_free(pfwords *fw) {
53 - // debug(D_PROCFILE, PF_PREFIX ": freeing words");
53 + // debug(D_PROCFILE, PF_PREFIX ": freeing words");
54
55 - freez(fw);
55 + freez(fw);
56 }
57
58
@@ -60,402 +60,402 @@ void pfwords_free(pfwords *fw) {
60 // An array of lines
61
62 pflines *pflines_add(pflines *fl, uint32_t first_word) {
63 - // debug(D_PROCFILE, PF_PREFIX ": adding line %d at word %d", fl->len, first_word);
63 + // debug(D_PROCFILE, PF_PREFIX ": adding line %d at word %d", fl->len, first_word);
64
65 - if(unlikely(fl->len == fl->size)) {
66 - // debug(D_PROCFILE, PF_PREFIX ": expanding lines");
65 + if(unlikely(fl->len == fl->size)) {
66 + // debug(D_PROCFILE, PF_PREFIX ": expanding lines");
67
68 - fl = reallocz(fl, sizeof(pflines) + (fl->size + PFLINES_INCREASE_STEP) * sizeof(ffline));
69 - fl->size += PFLINES_INCREASE_STEP;
70 - }
68 + fl = reallocz(fl, sizeof(pflines) + (fl->size + PFLINES_INCREASE_STEP) * sizeof(ffline));
69 + fl->size += PFLINES_INCREASE_STEP;
70 + }
71
72 - fl->lines[fl->len].words = 0;
73 - fl->lines[fl->len++].first = first_word;
72 + fl->lines[fl->len].words = 0;
73 + fl->lines[fl->len++].first = first_word;
74
75 - return fl;
75 + return fl;
76 }
77
78 pflines *pflines_new(void) {
79 - // debug(D_PROCFILE, PF_PREFIX ": initializing lines");
79 + // debug(D_PROCFILE, PF_PREFIX ": initializing lines");
80
81 - uint32_t size = (unlikely(procfile_adaptive_initial_allocation)) ? procfile_max_words : PFLINES_INCREASE_STEP;
81 + uint32_t size = (unlikely(procfile_adaptive_initial_allocation)) ? procfile_max_words : PFLINES_INCREASE_STEP;
82
83 - pflines *new = mallocz(sizeof(pflines) + size * sizeof(ffline));
84 - new->len = 0;
85 - new->size = size;
86 - return new;
83 + pflines *new = mallocz(sizeof(pflines) + size * sizeof(ffline));
84 + new->len = 0;
85 + new->size = size;
86 + return new;
87 }
88
89 void pflines_reset(pflines *fl) {
90 - // debug(D_PROCFILE, PF_PREFIX ": reseting lines");
90 + // debug(D_PROCFILE, PF_PREFIX ": reseting lines");
91
92 - fl->len = 0;
92 + fl->len = 0;
93 }
94
95 void pflines_free(pflines *fl) {
96 - // debug(D_PROCFILE, PF_PREFIX ": freeing lines");
96 + // debug(D_PROCFILE, PF_PREFIX ": freeing lines");
97
98 - freez(fl);
98 + freez(fl);
99 }
100
101
102 // ----------------------------------------------------------------------------
103 // The procfile
104
105 -#define PF_CHAR_IS_SEPARATOR ' '
106 -#define PF_CHAR_IS_NEWLINE 'N'
107 -#define PF_CHAR_IS_WORD 'W'
105 +#define PF_CHAR_IS_SEPARATOR ' '
106 +#define PF_CHAR_IS_NEWLINE 'N'
107 +#define PF_CHAR_IS_WORD 'W'
108 #define PF_CHAR_IS_QUOTE 'Q'
109 #define PF_CHAR_IS_OPEN 'O'
110 #define PF_CHAR_IS_CLOSE 'C'
111
112 void procfile_close(procfile *ff) {
113 - debug(D_PROCFILE, PF_PREFIX ": Closing file '%s'", ff->filename);
113 + debug(D_PROCFILE, PF_PREFIX ": Closing file '%s'", ff->filename);
114
115 - if(likely(ff->lines)) pflines_free(ff->lines);
116 - if(likely(ff->words)) pfwords_free(ff->words);
115 + if(likely(ff->lines)) pflines_free(ff->lines);
116 + if(likely(ff->words)) pfwords_free(ff->words);
117
118 - if(likely(ff->fd != -1)) close(ff->fd);
119 - freez(ff);
118 + if(likely(ff->fd != -1)) close(ff->fd);
119 + freez(ff);
120 }
121
122 procfile *procfile_parser(procfile *ff) {
123 - debug(D_PROCFILE, PF_PREFIX ": Parsing file '%s'", ff->filename);
124 -
125 - char *s = ff->data, *e = &ff->data[ff->len], *t = ff->data, quote = 0;
126 - uint32_t l = 0, w = 0;
127 - int opened = 0;
128 -
129 - ff->lines = pflines_add(ff->lines, w);
130 - if(unlikely(!ff->lines)) goto cleanup;
131 -
132 - while(likely(s < e)) {
133 - // we are not at the end
134 -
135 - switch(ff->separators[(uint8_t)(*s)]) {
136 - case PF_CHAR_IS_OPEN:
137 - if(s == t) {
138 - opened++;
139 - t = ++s;
140 - }
141 - else if(opened) {
142 - opened++;
143 - s++;
144 - }
145 - else
146 - s++;
147 - continue;
148 -
149 - case PF_CHAR_IS_CLOSE:
150 - if(opened) {
151 - opened--;
152 -
153 - if(!opened) {
154 - *s = '\0';
155 - ff->words = pfwords_add(ff->words, t);
156 - if(unlikely(!ff->words)) goto cleanup;
157 -
158 - ff->lines->lines[l].words++;
159 - w++;
160 -
161 - t = ++s;
162 - }
163 - else
164 - s++;
165 - }
166 - else
167 - s++;
168 - continue;
169 -
170 - case PF_CHAR_IS_QUOTE:
171 - if(unlikely(!quote && s == t)) {
172 - // quote opened at the beginning
173 - quote = *s;
174 - t = ++s;
175 - }
176 - else if(unlikely(quote && quote == *s)) {
177 - // quote closed
178 - quote = 0;
179 -
180 - *s = '\0';
181 - ff->words = pfwords_add(ff->words, t);
182 - if(unlikely(!ff->words)) goto cleanup;
183 -
184 - ff->lines->lines[l].words++;
185 - w++;
186 -
187 - t = ++s;
188 - }
189 - else
190 - s++;
191 - continue;
192 -
193 - case PF_CHAR_IS_SEPARATOR:
194 - if(unlikely(quote || opened)) {
195 - // we are inside a quote
196 - s++;
197 - continue;
198 - }
199 -
200 - if(unlikely(s == t)) {
201 - // skip all leading white spaces
202 - t = ++s;
203 - continue;
204 - }
205 -
206 - // end of word
207 - *s = '\0';
208 -
209 - ff->words = pfwords_add(ff->words, t);
210 - if(unlikely(!ff->words)) goto cleanup;
211 -
212 - ff->lines->lines[l].words++;
213 - w++;
214 -
215 - t = ++s;
216 - continue;
217 -
218 - case PF_CHAR_IS_NEWLINE:
219 - // end of line
220 - *s = '\0';
221 -
222 - ff->words = pfwords_add(ff->words, t);
223 - if(unlikely(!ff->words)) goto cleanup;
224 -
225 - ff->lines->lines[l].words++;
226 - w++;
227 -
228 - // debug(D_PROCFILE, PF_PREFIX ": ended line %d with %d words", l, ff->lines->lines[l].words);
229 -
230 - ff->lines = pflines_add(ff->lines, w);
231 - if(unlikely(!ff->lines)) goto cleanup;
232 - l++;
233 -
234 - t = ++s;
235 - continue;
236 -
237 - default:
238 - s++;
239 - continue;
240 - }
241 - }
242 -
243 - if(likely(s > t && t < e)) {
244 - // the last word
245 - if(likely(ff->len < ff->size))
246 - *s = '\0';
247 - else {
248 - // we are going to loose the last byte
249 - ff->data[ff->size - 1] = '\0';
250 - }
251 -
252 - ff->words = pfwords_add(ff->words, t);
253 - if(unlikely(!ff->words)) goto cleanup;
254 -
255 - ff->lines->lines[l].words++;
256 - w++;
257 - }
258 -
259 - return ff;
123 + debug(D_PROCFILE, PF_PREFIX ": Parsing file '%s'", ff->filename);
124 +
125 + char *s = ff->data, *e = &ff->data[ff->len], *t = ff->data, quote = 0;
126 + uint32_t l = 0, w = 0;
127 + int opened = 0;
128 +
129 + ff->lines = pflines_add(ff->lines, w);
130 + if(unlikely(!ff->lines)) goto cleanup;
131 +
132 + while(likely(s < e)) {
133 + // we are not at the end
134 +
135 + switch(ff->separators[(uint8_t)(*s)]) {
136 + case PF_CHAR_IS_OPEN:
137 + if(s == t) {
138 + opened++;
139 + t = ++s;
140 + }
141 + else if(opened) {
142 + opened++;
143 + s++;
144 + }
145 + else
146 + s++;
147 + continue;
148 +
149 + case PF_CHAR_IS_CLOSE:
150 + if(opened) {
151 + opened--;
152 +
153 + if(!opened) {
154 + *s = '\0';
155 + ff->words = pfwords_add(ff->words, t);
156 + if(unlikely(!ff->words)) goto cleanup;
157 +
158 + ff->lines->lines[l].words++;
159 + w++;
160 +
161 + t = ++s;
162 + }
163 + else
164 + s++;
165 + }
166 + else
167 + s++;
168 + continue;
169 +
170 + case PF_CHAR_IS_QUOTE:
171 + if(unlikely(!quote && s == t)) {
172 + // quote opened at the beginning
173 + quote = *s;
174 + t = ++s;
175 + }
176 + else if(unlikely(quote && quote == *s)) {
177 + // quote closed
178 + quote = 0;
179 +
180 + *s = '\0';
181 + ff->words = pfwords_add(ff->words, t);
182 + if(unlikely(!ff->words)) goto cleanup;
183 +
184 + ff->lines->lines[l].words++;
185 + w++;
186 +
187 + t = ++s;
188 + }
189 + else
190 + s++;
191 + continue;
192 +
193 + case PF_CHAR_IS_SEPARATOR:
194 + if(unlikely(quote || opened)) {
195 + // we are inside a quote
196 + s++;
197 + continue;
198 + }
199 +
200 + if(unlikely(s == t)) {
201 + // skip all leading white spaces
202 + t = ++s;
203 + continue;
204 + }
205 +
206 + // end of word
207 + *s = '\0';
208 +
209 + ff->words = pfwords_add(ff->words, t);
210 + if(unlikely(!ff->words)) goto cleanup;
211 +
212 + ff->lines->lines[l].words++;
213 + w++;
214 +
215 + t = ++s;
216 + continue;
217 +
218 + case PF_CHAR_IS_NEWLINE:
219 + // end of line
220 + *s = '\0';
221 +
222 + ff->words = pfwords_add(ff->words, t);
223 + if(unlikely(!ff->words)) goto cleanup;
224 +
225 + ff->lines->lines[l].words++;
226 + w++;
227 +
228 + // debug(D_PROCFILE, PF_PREFIX ": ended line %d with %d words", l, ff->lines->lines[l].words);
229 +
230 + ff->lines = pflines_add(ff->lines, w);
231 + if(unlikely(!ff->lines)) goto cleanup;
232 + l++;
233 +
234 + t = ++s;
235 + continue;
236 +
237 + default:
238 + s++;
239 + continue;
240 + }
241 + }
242 +
243 + if(likely(s > t && t < e)) {
244 + // the last word
245 + if(likely(ff->len < ff->size))
246 + *s = '\0';
247 + else {
248 + // we are going to loose the last byte
249 + ff->data[ff->size - 1] = '\0';
250 + }
251 +
252 + ff->words = pfwords_add(ff->words, t);
253 + if(unlikely(!ff->words)) goto cleanup;
254 +
255 + ff->lines->lines[l].words++;
256 + w++;
257 + }
258 +
259 + return ff;
260
261 cleanup:
262 - error(PF_PREFIX ": Failed to parse file '%s'", ff->filename);
263 - procfile_close(ff);
264 - return NULL;
262 + error(PF_PREFIX ": Failed to parse file '%s'", ff->filename);
263 + procfile_close(ff);
264 + return NULL;
265 }
266
267 procfile *procfile_readall(procfile *ff) {
268 - debug(D_PROCFILE, PF_PREFIX ": Reading file '%s'.", ff->filename);
268 + debug(D_PROCFILE, PF_PREFIX ": Reading file '%s'.", ff->filename);
269
270 - ssize_t s, r = 1, x;
271 - ff->len = 0;
270 + ssize_t s, r = 1, x;
271 + ff->len = 0;
272
273 - while(likely(r > 0)) {
274 - s = ff->len;
275 - x = ff->size - s;
273 + while(likely(r > 0)) {
274 + s = ff->len;
275 + x = ff->size - s;
276
277 - if(!x) {
278 - debug(D_PROCFILE, PF_PREFIX ": Expanding data buffer for file '%s'.", ff->filename);
277 + if(!x) {
278 + debug(D_PROCFILE, PF_PREFIX ": Expanding data buffer for file '%s'.", ff->filename);
279
280 - ff = reallocz(ff, sizeof(procfile) + ff->size + PROCFILE_INCREMENT_BUFFER);
281 - ff->size += PROCFILE_INCREMENT_BUFFER;
282 - }
280 + ff = reallocz(ff, sizeof(procfile) + ff->size + PROCFILE_INCREMENT_BUFFER);
281 + ff->size += PROCFILE_INCREMENT_BUFFER;
282 + }
283
284 - debug(D_PROCFILE, "Reading file '%s', from position %ld with length %lu", ff->filename, s, ff->size - s);
285 - r = read(ff->fd, &ff->data[s], ff->size - s);
286 - if(unlikely(r == -1)) {
287 - if(unlikely(!(ff->flags & PROCFILE_FLAG_NO_ERROR_ON_FILE_IO))) error(PF_PREFIX ": Cannot read from file '%s'", ff->filename);
288 - procfile_close(ff);
289 - return NULL;
290 - }
284 + debug(D_PROCFILE, "Reading file '%s', from position %ld with length %lu", ff->filename, s, ff->size - s);
285 + r = read(ff->fd, &ff->data[s], ff->size - s);
286 + if(unlikely(r == -1)) {
287 + if(unlikely(!(ff->flags & PROCFILE_FLAG_NO_ERROR_ON_FILE_IO))) error(PF_PREFIX ": Cannot read from file '%s'", ff->filename);
288 + procfile_close(ff);
289 + return NULL;
290 + }
291
292 - ff->len += r;
293 - }
292 + ff->len += r;
293 + }
294
295 - debug(D_PROCFILE, "Rewinding file '%s'", ff->filename);
296 - if(unlikely(lseek(ff->fd, 0, SEEK_SET) == -1)) {
297 - if(unlikely(!(ff->flags & PROCFILE_FLAG_NO_ERROR_ON_FILE_IO))) error(PF_PREFIX ": Cannot rewind on file '%s'.", ff->filename);
298 - procfile_close(ff);
299 - return NULL;
300 - }
295 + debug(D_PROCFILE, "Rewinding file '%s'", ff->filename);
296 + if(unlikely(lseek(ff->fd, 0, SEEK_SET) == -1)) {
297 + if(unlikely(!(ff->flags & PROCFILE_FLAG_NO_ERROR_ON_FILE_IO))) error(PF_PREFIX ": Cannot rewind on file '%s'.", ff->filename);
298 + procfile_close(ff);
299 + return NULL;
300 + }
301
302 - pflines_reset(ff->lines);
303 - pfwords_reset(ff->words);
302 + pflines_reset(ff->lines);
303 + pfwords_reset(ff->words);
304
305 - ff = procfile_parser(ff);
305 + ff = procfile_parser(ff);
306
307 - if(unlikely(procfile_adaptive_initial_allocation)) {
308 - if(unlikely(ff->len > procfile_max_allocation)) procfile_max_allocation = ff->len;
309 - if(unlikely(ff->lines->len > procfile_max_lines)) procfile_max_lines = ff->lines->len;
310 - if(unlikely(ff->words->len > procfile_max_words)) procfile_max_words = ff->words->len;
311 - }
307 + if(unlikely(procfile_adaptive_initial_allocation)) {
308 + if(unlikely(ff->len > procfile_max_allocation)) procfile_max_allocation = ff->len;
309 + if(unlikely(ff->lines->len > procfile_max_lines)) procfile_max_lines = ff->lines->len;
310 + if(unlikely(ff->words->len > procfile_max_words)) procfile_max_words = ff->words->len;
311 + }
312
313 - debug(D_PROCFILE, "File '%s' updated.", ff->filename);
314 - return ff;
313 + debug(D_PROCFILE, "File '%s' updated.", ff->filename);
314 + return ff;
315 }
316
317 static void procfile_set_separators(procfile *ff, const char *separators) {
318 - static char def[256] = { [0 ... 255] = 0 };
319 - int i;
320 -
321 - if(unlikely(!def[255])) {
322 - // this is thread safe
323 - // we check that the last byte is non-zero
324 - // if it is zero, multiple threads may be executing this at the same time
325 - // setting in def[] the exact same values
326 - for(i = 0; likely(i < 256) ;i++) {
327 - if(unlikely(i == '\n' || i == '\r')) def[i] = PF_CHAR_IS_NEWLINE;
328 - else if(unlikely(isspace(i) || !isprint(i))) def[i] = PF_CHAR_IS_SEPARATOR;
329 - else def[i] = PF_CHAR_IS_WORD;
330 - }
331 - }
332 -
333 - // copy the default
334 - char *ffs = ff->separators, *ffd = def, *ffe = &def[256];
335 - while(likely(ffd != ffe)) *ffs++ = *ffd++;
336 -
337 - // set the separators
338 - if(unlikely(!separators))
339 - separators = " \t=|";
340 -
341 - ffs = ff->separators;
342 - const char *s = separators;
343 - while(likely(*s))
344 - ffs[(int)*s++] = PF_CHAR_IS_SEPARATOR;
318 + static char def[256] = { [0 ... 255] = 0 };
319 + int i;
320 +
321 + if(unlikely(!def[255])) {
322 + // this is thread safe
323 + // we check that the last byte is non-zero
324 + // if it is zero, multiple threads may be executing this at the same time
325 + // setting in def[] the exact same values
326 + for(i = 0; likely(i < 256) ;i++) {
327 + if(unlikely(i == '\n' || i == '\r')) def[i] = PF_CHAR_IS_NEWLINE;
328 + else if(unlikely(isspace(i) || !isprint(i))) def[i] = PF_CHAR_IS_SEPARATOR;
329 + else def[i] = PF_CHAR_IS_WORD;
330 + }
331 + }
332 +
333 + // copy the default
334 + char *ffs = ff->separators, *ffd = def, *ffe = &def[256];
335 + while(likely(ffd != ffe)) *ffs++ = *ffd++;
336 +
337 + // set the separators
338 + if(unlikely(!separators))
339 + separators = " \t=|";
340 +
341 + ffs = ff->separators;
342 + const char *s = separators;
343 + while(likely(*s))
344 + ffs[(int)*s++] = PF_CHAR_IS_SEPARATOR;
345 }
346
347 void procfile_set_quotes(procfile *ff, const char *quotes) {
348 - // remove all quotes
349 - int i;
350 - for(i = 0; i < 256 ; i++)
351 - if(ff->separators[i] == PF_CHAR_IS_QUOTE)
352 - ff->separators[i] = PF_CHAR_IS_WORD;
353 -
354 - // if nothing given, return
355 - if(unlikely(!quotes || !*quotes))
356 - return;
357 -
358 - // set the quotes
359 - char *ffs = ff->separators;
360 - const char *s = quotes;
361 - while(likely(*s))
362 - ffs[(int)*s++] = PF_CHAR_IS_QUOTE;
348 + // remove all quotes
349 + int i;
350 + for(i = 0; i < 256 ; i++)
351 + if(ff->separators[i] == PF_CHAR_IS_QUOTE)
352 + ff->separators[i] = PF_CHAR_IS_WORD;
353 +
354 + // if nothing given, return
355 + if(unlikely(!quotes || !*quotes))
356 + return;
357 +
358 + // set the quotes
359 + char *ffs = ff->separators;
360 + const char *s = quotes;
361 + while(likely(*s))
362 + ffs[(int)*s++] = PF_CHAR_IS_QUOTE;
363 }
364
365 void procfile_set_open_close(procfile *ff, const char *open, const char *close) {
366 - // remove all open/close
367 - int i;
368 - for(i = 0; i < 256 ; i++)
369 - if(ff->separators[i] == PF_CHAR_IS_OPEN || ff->separators[i] == PF_CHAR_IS_CLOSE)
370 - ff->separators[i] = PF_CHAR_IS_WORD;
371 -
372 - // if nothing given, return
373 - if(unlikely(!open || !*open || !close || !*close))
374 - return;
375 -
376 - // set the openings
377 - char *ffs = ff->separators;
378 - const char *s = open;
379 - while(likely(*s))
380 - ffs[(int)*s++] = PF_CHAR_IS_OPEN;
381 -
382 - s = close;
383 - while(likely(*s))
384 - ffs[(int)*s++] = PF_CHAR_IS_CLOSE;
366 + // remove all open/close
367 + int i;
368 + for(i = 0; i < 256 ; i++)
369 + if(ff->separators[i] == PF_CHAR_IS_OPEN || ff->separators[i] == PF_CHAR_IS_CLOSE)
370 + ff->separators[i] = PF_CHAR_IS_WORD;
371 +
372 + // if nothing given, return
373 + if(unlikely(!open || !*open || !close || !*close))
374 + return;
375 +
376 + // set the openings
377 + char *ffs = ff->separators;
378 + const char *s = open;
379 + while(likely(*s))
380 + ffs[(int)*s++] = PF_CHAR_IS_OPEN;
381 +
382 + s = close;
383 + while(likely(*s))
384 + ffs[(int)*s++] = PF_CHAR_IS_CLOSE;
385 }
386
387 procfile *procfile_open(const char *filename, const char *separators, uint32_t flags) {
388 - debug(D_PROCFILE, PF_PREFIX ": Opening file '%s'", filename);
388 + debug(D_PROCFILE, PF_PREFIX ": Opening file '%s'", filename);
389
390 - int fd = open(filename, O_RDONLY, 0666);
391 - if(unlikely(fd == -1)) {
392 - if(unlikely(!(flags & PROCFILE_FLAG_NO_ERROR_ON_FILE_IO))) error(PF_PREFIX ": Cannot open file '%s'", filename);
393 - return NULL;
394 - }
390 + int fd = open(filename, O_RDONLY, 0666);
391 + if(unlikely(fd == -1)) {
392 + if(unlikely(!(flags & PROCFILE_FLAG_NO_ERROR_ON_FILE_IO))) error(PF_PREFIX ": Cannot open file '%s'", filename);
393 + return NULL;
394 + }
395
396 - size_t size = (unlikely(procfile_adaptive_initial_allocation)) ? procfile_max_allocation : PROCFILE_INCREMENT_BUFFER;
397 - procfile *ff = mallocz(sizeof(procfile) + size);
398 - strncpyz(ff->filename, filename, FILENAME_MAX);
396 + size_t size = (unlikely(procfile_adaptive_initial_allocation)) ? procfile_max_allocation : PROCFILE_INCREMENT_BUFFER;
397 + procfile *ff = mallocz(sizeof(procfile) + size);
398 + strncpyz(ff->filename, filename, FILENAME_MAX);
399
400 - ff->fd = fd;
401 - ff->size = size;
402 - ff->len = 0;
403 - ff->flags = flags;
400 + ff->fd = fd;
401 + ff->size = size;
402 + ff->len = 0;
403 + ff->flags = flags;
404
405 - ff->lines = pflines_new();
406 - ff->words = pfwords_new();
405 + ff->lines = pflines_new();
406 + ff->words = pfwords_new();
407
408 - if(unlikely(!ff->lines || !ff->words)) {
409 - error(PF_PREFIX ": Cannot initialize parser for file '%s'", filename);
410 - procfile_close(ff);
411 - return NULL;
412 - }
408 + if(unlikely(!ff->lines || !ff->words)) {
409 + error(PF_PREFIX ": Cannot initialize parser for file '%s'", filename);
410 + procfile_close(ff);
411 + return NULL;
412 + }
413
414 - procfile_set_separators(ff, separators);
414 + procfile_set_separators(ff, separators);
415
416 - debug(D_PROCFILE, "File '%s' opened.", filename);
417 - return ff;
416 + debug(D_PROCFILE, "File '%s' opened.", filename);
417 + return ff;
418 }
419
420 procfile *procfile_reopen(procfile *ff, const char *filename, const char *separators, uint32_t flags) {
421 - if(unlikely(!ff)) return procfile_open(filename, separators, flags);
421 + if(unlikely(!ff)) return procfile_open(filename, separators, flags);
422
423 - if(likely(ff->fd != -1)) close(ff->fd);
423 + if(likely(ff->fd != -1)) close(ff->fd);
424
425 - ff->fd = open(filename, O_RDONLY, 0666);
426 - if(unlikely(ff->fd == -1)) {
427 - procfile_close(ff);
428 - return NULL;
429 - }
425 + ff->fd = open(filename, O_RDONLY, 0666);
426 + if(unlikely(ff->fd == -1)) {
427 + procfile_close(ff);
428 + return NULL;
429 + }
430
431 - strncpyz(ff->filename, filename, FILENAME_MAX);
431 + strncpyz(ff->filename, filename, FILENAME_MAX);
432
433 - ff->flags = flags;
433 + ff->flags = flags;
434
435 - // do not do the separators again if NULL is given
436 - if(likely(separators)) procfile_set_separators(ff, separators);
435 + // do not do the separators again if NULL is given
436 + if(likely(separators)) procfile_set_separators(ff, separators);
437
438 - return ff;
438 + return ff;
439 }
440
441 // ----------------------------------------------------------------------------
442 // example parsing of procfile data
443
444 void procfile_print(procfile *ff) {
445 - uint32_t lines = procfile_lines(ff), l;
446 - uint32_t words, w;
447 - char *s;
445 + uint32_t lines = procfile_lines(ff), l;
446 + uint32_t words, w;
447 + char *s;
448
449 - debug(D_PROCFILE, "File '%s' with %u lines and %u words", ff->filename, ff->lines->len, ff->words->len);
449 + debug(D_PROCFILE, "File '%s' with %u lines and %u words", ff->filename, ff->lines->len, ff->words->len);
450
451 - for(l = 0; likely(l < lines) ;l++) {
452 - words = procfile_linewords(ff, l);
451 + for(l = 0; likely(l < lines) ;l++) {
452 + words = procfile_linewords(ff, l);
453
454 - debug(D_PROCFILE, " line %u starts at word %u and has %u words", l, ff->lines->lines[l].first, ff->lines->lines[l].words);
454 + debug(D_PROCFILE, " line %u starts at word %u and has %u words", l, ff->lines->lines[l].first, ff->lines->lines[l].words);
455
456 - for(w = 0; likely(w < words) ;w++) {
457 - s = procfile_lineword(ff, l, w);
458 - debug(D_PROCFILE, " [%u.%u] '%s'", l, w, s);
459 - }
460 - }
456 + for(w = 0; likely(w < words) ;w++) {
457 + s = procfile_lineword(ff, l, w);
458 + debug(D_PROCFILE, " [%u.%u] '%s'", l, w, s);
459 + }
460 + }
461 }
src/procfile.h
+18 -18
@@ -30,9 +30,9 @@
30 // An array of words
31
32 typedef struct {
33 - uint32_t len; // used entries
34 - uint32_t size; // capacity
35 - char *words[]; // array of pointers
33 + uint32_t len; // used entries
34 + uint32_t size; // capacity
35 + char *words[]; // array of pointers
36 } pfwords;
37
38
@@ -40,15 +40,15 @@ typedef struct {
40 // An array of lines
41
42 typedef struct {
43 - uint32_t words; // how many words this line has
44 - uint32_t first; // the id of the first word of this line
45 - // in the words array
43 + uint32_t words; // how many words this line has
44 + uint32_t first; // the id of the first word of this line
45 + // in the words array
46 } ffline;
47
48 typedef struct {
49 - uint32_t len; // used entries
50 - uint32_t size; // capacity
51 - ffline lines[]; // array of lines
49 + uint32_t len; // used entries
50 + uint32_t size; // capacity
51 + ffline lines[]; // array of lines
52 } pflines;
53
54
@@ -59,15 +59,15 @@ typedef struct {
59 #define PROCFILE_FLAG_NO_ERROR_ON_FILE_IO 0x00000001
60
61 typedef struct {
62 - char filename[FILENAME_MAX + 1];
63 - uint32_t flags;
64 - int fd; // the file desriptor
65 - size_t len; // the bytes we have placed into data
66 - size_t size; // the bytes we have allocated for data
67 - pflines *lines;
68 - pfwords *words;
69 - char separators[256];
70 - char data[]; // allocated buffer to keep file contents
62 + char filename[FILENAME_MAX + 1];
63 + uint32_t flags;
64 + int fd; // the file desriptor
65 + size_t len; // the bytes we have placed into data
66 + size_t size; // the bytes we have allocated for data
67 + pflines *lines;
68 + pfwords *words;
69 + char separators[256];
70 + char data[]; // allocated buffer to keep file contents
71 } procfile;
72
73 // close the proc file and free all related memory
src/registry.c
+1267 -1267
@@ -39,60 +39,60 @@
39 // COMMON structures
40
41 struct registry {
42 - int enabled;
43 -
44 - char machine_guid[36 + 1];
45 -
46 - // entries counters / statistics
47 - unsigned long long persons_count;
48 - unsigned long long machines_count;
49 - unsigned long long usages_count;
50 - unsigned long long urls_count;
51 - unsigned long long persons_urls_count;
52 - unsigned long long machines_urls_count;
53 - unsigned long long log_count;
54 -
55 - // memory counters / statistics
56 - unsigned long long persons_memory;
57 - unsigned long long machines_memory;
58 - unsigned long long urls_memory;
59 - unsigned long long persons_urls_memory;
60 - unsigned long long machines_urls_memory;
61 -
62 - // configuration
63 - unsigned long long save_registry_every_entries;
64 - char *registry_domain;
65 - char *hostname;
66 - char *registry_to_announce;
67 - time_t persons_expiration; // seconds to expire idle persons
68 - int verify_cookies_redirects;
69 -
70 - size_t max_url_length;
71 - size_t max_name_length;
72 -
73 - // file/path names
74 - char *pathname;
75 - char *db_filename;
76 - char *log_filename;
77 - char *machine_guid_filename;
78 -
79 - // open files
80 - FILE *log_fp;
81 -
82 - // the database
83 - DICTIONARY *persons; // dictionary of PERSON *, with key the PERSON.guid
84 - DICTIONARY *machines; // dictionary of MACHINE *, with key the MACHINE.guid
85 - DICTIONARY *urls; // dictionary of URL *, with key the URL.url
86 -
87 - // concurrency locking
88 - // we keep different locks for different things
89 - // so that many tasks can be completed in parallel
90 - pthread_mutex_t persons_lock;
91 - pthread_mutex_t machines_lock;
92 - pthread_mutex_t urls_lock;
93 - pthread_mutex_t person_urls_lock;
94 - pthread_mutex_t machine_urls_lock;
95 - pthread_mutex_t log_lock;
42 + int enabled;
43 +
44 + char machine_guid[36 + 1];
45 +
46 + // entries counters / statistics
47 + unsigned long long persons_count;
48 + unsigned long long machines_count;
49 + unsigned long long usages_count;
50 + unsigned long long urls_count;
51 + unsigned long long persons_urls_count;
52 + unsigned long long machines_urls_count;
53 + unsigned long long log_count;
54 +
55 + // memory counters / statistics
56 + unsigned long long persons_memory;
57 + unsigned long long machines_memory;
58 + unsigned long long urls_memory;
59 + unsigned long long persons_urls_memory;
60 + unsigned long long machines_urls_memory;
61 +
62 + // configuration
63 + unsigned long long save_registry_every_entries;
64 + char *registry_domain;
65 + char *hostname;
66 + char *registry_to_announce;
67 + time_t persons_expiration; // seconds to expire idle persons
68 + int verify_cookies_redirects;
69 +
70 + size_t max_url_length;
71 + size_t max_name_length;
72 +
73 + // file/path names
74 + char *pathname;
75 + char *db_filename;
76 + char *log_filename;
77 + char *machine_guid_filename;
78 +
79 + // open files
80 + FILE *log_fp;
81 +
82 + // the database
83 + DICTIONARY *persons; // dictionary of PERSON *, with key the PERSON.guid
84 + DICTIONARY *machines; // dictionary of MACHINE *, with key the MACHINE.guid
85 + DICTIONARY *urls; // dictionary of URL *, with key the URL.url
86 +
87 + // concurrency locking
88 + // we keep different locks for different things
89 + // so that many tasks can be completed in parallel
90 + pthread_mutex_t persons_lock;
91 + pthread_mutex_t machines_lock;
92 + pthread_mutex_t urls_lock;
93 + pthread_mutex_t person_urls_lock;
94 + pthread_mutex_t machine_urls_lock;
95 + pthread_mutex_t log_lock;
96 } registry;
97
98
@@ -103,9 +103,9 @@ struct registry {
103 // we store them here and we keep pointers elsewhere
104
105 struct url {
106 - uint32_t links; // the number of links to this URL - when none is left, we free it
107 - uint16_t len; // the length of the URL in bytes
108 - char url[1]; // the URL - dynamically allocated to more size
106 + uint32_t links; // the number of links to this URL - when none is left, we free it
107 + uint16_t len; // the length of the URL in bytes
108 + char url[1]; // the URL - dynamically allocated to more size
109 };
110 typedef struct url URL;
111
@@ -115,27 +115,27 @@ typedef struct url URL;
115
116 // For each MACHINE-URL pair we keep this
117 struct machine_url {
118 - URL *url; // de-duplicated URL
119 -// DICTIONARY *persons; // dictionary of PERSON *
118 + URL *url; // de-duplicated URL
119 +// DICTIONARY *persons; // dictionary of PERSON *
120
121 - uint8_t flags;
122 - uint32_t first_t; // the first time we saw this
123 - uint32_t last_t; // the last time we saw this
124 - uint32_t usages; // how many times this has been accessed
121 + uint8_t flags;
122 + uint32_t first_t; // the first time we saw this
123 + uint32_t last_t; // the last time we saw this
124 + uint32_t usages; // how many times this has been accessed
125 };
126 typedef struct machine_url MACHINE_URL;
127
128 // A machine
129 struct machine {
130 - char guid[36 + 1]; // the GUID
130 + char guid[36 + 1]; // the GUID
131
132 - uint32_t links; // the number of PERSON_URLs linked to this machine
132 + uint32_t links; // the number of PERSON_URLs linked to this machine
133
134 - DICTIONARY *urls; // MACHINE_URL *
134 + DICTIONARY *urls; // MACHINE_URL *
135
136 - uint32_t first_t; // the first time we saw this
137 - uint32_t last_t; // the last time we saw this
138 - uint32_t usages; // how many times this has been accessed
136 + uint32_t first_t; // the first time we saw this
137 + uint32_t last_t; // the last time we saw this
138 + uint32_t usages; // how many times this has been accessed
139 };
140 typedef struct machine MACHINE;
141
@@ -145,28 +145,28 @@ typedef struct machine MACHINE;
145
146 // for each PERSON-URL pair we keep this
147 struct person_url {
148 - URL *url; // de-duplicated URL
149 - MACHINE *machine; // link the MACHINE of this URL
148 + URL *url; // de-duplicated URL
149 + MACHINE *machine; // link the MACHINE of this URL
150
151 - uint8_t flags;
152 - uint32_t first_t; // the first time we saw this
153 - uint32_t last_t; // the last time we saw this
154 - uint32_t usages; // how many times this has been accessed
151 + uint8_t flags;
152 + uint32_t first_t; // the first time we saw this
153 + uint32_t last_t; // the last time we saw this
154 + uint32_t usages; // how many times this has been accessed
155
156 - char name[1]; // the name of the URL, as known by the user
157 - // dynamically allocated to fit properly
156 + char name[1]; // the name of the URL, as known by the user
157 + // dynamically allocated to fit properly
158 };
159 typedef struct person_url PERSON_URL;
160
161 // A person
162 struct person {
163 - char guid[36 + 1]; // the person GUID
163 + char guid[36 + 1]; // the person GUID
164
165 - DICTIONARY *urls; // dictionary of PERSON_URL *
165 + DICTIONARY *urls; // dictionary of PERSON_URL *
166
167 - uint32_t first_t; // the first time we saw this
168 - uint32_t last_t; // the last time we saw this
169 - uint32_t usages; // how many times this has been accessed
167 + uint32_t first_t; // the first time we saw this
168 + uint32_t last_t; // the last time we saw this
169 + uint32_t usages; // how many times this has been accessed
170 };
171 typedef struct person PERSON;
172
@@ -175,27 +175,27 @@ typedef struct person PERSON;
175 // REGISTRY concurrency locking
176
177 static inline void registry_persons_lock(void) {
178 - pthread_mutex_lock(&registry.persons_lock);
178 + pthread_mutex_lock(&registry.persons_lock);
179 }
180
181 static inline void registry_persons_unlock(void) {
182 - pthread_mutex_unlock(&registry.persons_lock);
182 + pthread_mutex_unlock(&registry.persons_lock);
183 }
184
185 static inline void registry_machines_lock(void) {
186 - pthread_mutex_lock(&registry.machines_lock);
186 + pthread_mutex_lock(&registry.machines_lock);
187 }
188
189 static inline void registry_machines_unlock(void) {
190 - pthread_mutex_unlock(&registry.machines_lock);
190 + pthread_mutex_unlock(&registry.machines_lock);
191 }
192
193 static inline void registry_urls_lock(void) {
194 - pthread_mutex_lock(&registry.urls_lock);
194 + pthread_mutex_lock(&registry.urls_lock);
195 }
196
197 static inline void registry_urls_unlock(void) {
198 - pthread_mutex_unlock(&registry.urls_lock);
198 + pthread_mutex_unlock(&registry.urls_lock);
199 }
200
201 // ideally, we should not lock the whole registry for
@@ -203,13 +203,13 @@ static inline void registry_urls_unlock(void) {
203 // however, to save the memory required for keeping a
204 // mutex (40 bytes) per person, we do...
205 static inline void registry_person_urls_lock(PERSON *p) {
206 - (void)p;
207 - pthread_mutex_lock(&registry.person_urls_lock);
206 + (void)p;
207 + pthread_mutex_lock(&registry.person_urls_lock);
208 }
209
210 static inline void registry_person_urls_unlock(PERSON *p) {
211 - (void)p;
212 - pthread_mutex_unlock(&registry.person_urls_lock);
211 + (void)p;
212 + pthread_mutex_unlock(&registry.person_urls_lock);
213 }
214
215 // ideally, we should not lock the whole registry for
@@ -217,21 +217,21 @@ static inline void registry_person_urls_unlock(PERSON *p) {
217 // however, to save the memory required for keeping a
218 // mutex (40 bytes) per machine, we do...
219 static inline void registry_machine_urls_lock(MACHINE *m) {
220 - (void)m;
221 - pthread_mutex_lock(&registry.machine_urls_lock);
220 + (void)m;
221 + pthread_mutex_lock(&registry.machine_urls_lock);
222 }
223
224 static inline void registry_machine_urls_unlock(MACHINE *m) {
225 - (void)m;
226 - pthread_mutex_unlock(&registry.machine_urls_lock);
225 + (void)m;
226 + pthread_mutex_unlock(&registry.machine_urls_lock);
227 }
228
229 static inline void registry_log_lock(void) {
230 - pthread_mutex_lock(&registry.log_lock);
230 + pthread_mutex_lock(&registry.log_lock);
231 }
232
233 static inline void registry_log_unlock(void) {
234 - pthread_mutex_unlock(&registry.log_lock);
234 + pthread_mutex_unlock(&registry.log_lock);
235 }
236
237
@@ -241,58 +241,58 @@ static inline void registry_log_unlock(void) {
241 // parse a GUID and re-generated to be always lower case
242 // this is used as a protection against the variations of GUIDs
243 static inline int registry_regenerate_guid(const char *guid, char *result) {
244 - uuid_t uuid;
245 - if(unlikely(uuid_parse(guid, uuid) == -1)) {
246 - info("Registry: GUID '%s' is not a valid GUID.", guid);
247 - return -1;
248 - }
249 - else {
250 - uuid_unparse_lower(uuid, result);
244 + uuid_t uuid;
245 + if(unlikely(uuid_parse(guid, uuid) == -1)) {
246 + info("Registry: GUID '%s' is not a valid GUID.", guid);
247 + return -1;
248 + }
249 + else {
250 + uuid_unparse_lower(uuid, result);
251
252 #ifdef NETDATA_INTERNAL_CHECKS
253 - if(strcmp(guid, result))
254 - info("Registry: source GUID '%s' and re-generated GUID '%s' differ!", guid, result);
253 + if(strcmp(guid, result))
254 + info("Registry: source GUID '%s' and re-generated GUID '%s' differ!", guid, result);
255 #endif /* NETDATA_INTERNAL_CHECKS */
256 - }
256 + }
257
258 - return 0;
258 + return 0;
259 }
260
261 // make sure the names of the machines / URLs do not contain any tabs
262 // (which are used as our separator in the database files)
263 // and are properly trimmed (before and after)
264 static inline char *registry_fix_machine_name(char *name, size_t *len) {
265 - char *s = name?name:"";
265 + char *s = name?name:"";
266
267 - // skip leading spaces
268 - while(*s && isspace(*s)) s++;
267 + // skip leading spaces
268 + while(*s && isspace(*s)) s++;
269
270 - // make sure all spaces are a SPACE
271 - char *t = s;
272 - while(*t) {
273 - if(unlikely(isspace(*t)))
274 - *t = ' ';
270 + // make sure all spaces are a SPACE
271 + char *t = s;
272 + while(*t) {
273 + if(unlikely(isspace(*t)))
274 + *t = ' ';
275
276 - t++;
277 - }
276 + t++;
277 + }
278
279 - // remove trailing spaces
280 - while(--t >= s) {
281 - if(*t == ' ')
282 - *t = '\0';
283 - else
284 - break;
285 - }
286 - t++;
279 + // remove trailing spaces
280 + while(--t >= s) {
281 + if(*t == ' ')
282 + *t = '\0';
283 + else
284 + break;
285 + }
286 + t++;
287
288 - if(likely(len))
289 - *len = (t - s);
288 + if(likely(len))
289 + *len = (t - s);
290
291 - return s;
291 + return s;
292 }
293
294 static inline char *registry_fix_url(char *url, size_t *len) {
295 - return registry_fix_machine_name(url, len);
295 + return registry_fix_machine_name(url, len);
296 }
297
298
@@ -307,57 +307,57 @@ extern PERSON *registry_request_delete(char *person_guid, char *machine_guid, ch
307 // URL
308
309 static inline URL *registry_url_allocate_nolock(const char *url, size_t urllen) {
310 - // protection from too big URLs
311 - if(urllen > registry.max_url_length)
312 - urllen = registry.max_url_length;
310 + // protection from too big URLs
311 + if(urllen > registry.max_url_length)
312 + urllen = registry.max_url_length;
313
314 - debug(D_REGISTRY, "Registry: registry_url_allocate_nolock('%s'): allocating %zu bytes", url, sizeof(URL) + urllen);
315 - URL *u = mallocz(sizeof(URL) + urllen);
314 + debug(D_REGISTRY, "Registry: registry_url_allocate_nolock('%s'): allocating %zu bytes", url, sizeof(URL) + urllen);
315 + URL *u = mallocz(sizeof(URL) + urllen);
316
317 - // a simple strcpy() should do the job
318 - // but I prefer to be safe, since the caller specified urllen
319 - u->len = (uint16_t)urllen;
320 - strncpyz(u->url, url, u->len);
321 - u->links = 0;
317 + // a simple strcpy() should do the job
318 + // but I prefer to be safe, since the caller specified urllen
319 + u->len = (uint16_t)urllen;
320 + strncpyz(u->url, url, u->len);
321 + u->links = 0;
322
323 - registry.urls_memory += sizeof(URL) + urllen;
323 + registry.urls_memory += sizeof(URL) + urllen;
324
325 - debug(D_REGISTRY, "Registry: registry_url_allocate_nolock('%s'): indexing it", url);
326 - dictionary_set(registry.urls, u->url, u, sizeof(URL));
325 + debug(D_REGISTRY, "Registry: registry_url_allocate_nolock('%s'): indexing it", url);
326 + dictionary_set(registry.urls, u->url, u, sizeof(URL));
327
328 - return u;
328 + return u;
329 }
330
331 static inline URL *registry_url_get(const char *url, size_t urllen) {
332 - debug(D_REGISTRY, "Registry: registry_url_get('%s')", url);
332 + debug(D_REGISTRY, "Registry: registry_url_get('%s')", url);
333
334 - registry_urls_lock();
334 + registry_urls_lock();
335
336 - URL *u = dictionary_get(registry.urls, url);
337 - if(!u) {
338 - u = registry_url_allocate_nolock(url, urllen);
339 - registry.urls_count++;
340 - }
336 + URL *u = dictionary_get(registry.urls, url);
337 + if(!u) {
338 + u = registry_url_allocate_nolock(url, urllen);
339 + registry.urls_count++;
340 + }
341
342 - registry_urls_unlock();
342 + registry_urls_unlock();
343
344 - return u;
344 + return u;
345 }
346
347 static inline void registry_url_link_nolock(URL *u) {
348 - u->links++;
349 - debug(D_REGISTRY, "Registry: registry_url_link_nolock('%s'): URL has now %u links", u->url, u->links);
348 + u->links++;
349 + debug(D_REGISTRY, "Registry: registry_url_link_nolock('%s'): URL has now %u links", u->url, u->links);
350 }
351
352 static inline void registry_url_unlink_nolock(URL *u) {
353 - u->links--;
354 - if(!u->links) {
355 - debug(D_REGISTRY, "Registry: registry_url_unlink_nolock('%s'): No more links for this URL", u->url);
356 - dictionary_del(registry.urls, u->url);
357 - freez(u);
358 - }
359 - else
360 - debug(D_REGISTRY, "Registry: registry_url_unlink_nolock('%s'): URL has %u links left", u->url, u->links);
353 + u->links--;
354 + if(!u->links) {
355 + debug(D_REGISTRY, "Registry: registry_url_unlink_nolock('%s'): No more links for this URL", u->url);
356 + dictionary_del(registry.urls, u->url);
357 + freez(u);
358 + }
359 + else
360 + debug(D_REGISTRY, "Registry: registry_url_unlink_nolock('%s'): URL has %u links left", u->url, u->links);
361 }
362
363
@@ -365,76 +365,76 @@ static inline void registry_url_unlink_nolock(URL *u) {
365 // MACHINE
366
367 static inline MACHINE *registry_machine_find(const char *machine_guid) {
368 - debug(D_REGISTRY, "Registry: registry_machine_find('%s')", machine_guid);
369 - return dictionary_get(registry.machines, machine_guid);
368 + debug(D_REGISTRY, "Registry: registry_machine_find('%s')", machine_guid);
369 + return dictionary_get(registry.machines, machine_guid);
370 }
371
372 static inline MACHINE_URL *registry_machine_url_allocate(MACHINE *m, URL *u, time_t when) {
373 - debug(D_REGISTRY, "registry_machine_link_to_url('%s', '%s'): allocating %zu bytes", m->guid, u->url, sizeof(MACHINE_URL));
373 + debug(D_REGISTRY, "registry_machine_link_to_url('%s', '%s'): allocating %zu bytes", m->guid, u->url, sizeof(MACHINE_URL));
374
375 - MACHINE_URL *mu = mallocz(sizeof(MACHINE_URL));
375 + MACHINE_URL *mu = mallocz(sizeof(MACHINE_URL));
376
377 - // mu->persons = dictionary_create(DICTIONARY_FLAGS);
378 - // dictionary_set(mu->persons, p->guid, p, sizeof(PERSON));
377 + // mu->persons = dictionary_create(DICTIONARY_FLAGS);
378 + // dictionary_set(mu->persons, p->guid, p, sizeof(PERSON));
379
380 - mu->first_t = mu->last_t = (uint32_t)when;
381 - mu->usages = 1;
382 - mu->url = u;
383 - mu->flags = REGISTRY_URL_FLAGS_DEFAULT;
380 + mu->first_t = mu->last_t = (uint32_t)when;
381 + mu->usages = 1;
382 + mu->url = u;
383 + mu->flags = REGISTRY_URL_FLAGS_DEFAULT;
384
385 - registry.machines_urls_memory += sizeof(MACHINE_URL);
385 + registry.machines_urls_memory += sizeof(MACHINE_URL);
386
387 - debug(D_REGISTRY, "registry_machine_link_to_url('%s', '%s'): indexing URL in machine", m->guid, u->url);
388 - dictionary_set(m->urls, u->url, mu, sizeof(MACHINE_URL));
389 - registry_url_link_nolock(u);
387 + debug(D_REGISTRY, "registry_machine_link_to_url('%s', '%s'): indexing URL in machine", m->guid, u->url);
388 + dictionary_set(m->urls, u->url, mu, sizeof(MACHINE_URL));
389 + registry_url_link_nolock(u);
390
391 - return mu;
391 + return mu;
392 }
393
394 static inline MACHINE *registry_machine_allocate(const char *machine_guid, time_t when) {
395 - debug(D_REGISTRY, "Registry: registry_machine_allocate('%s'): creating new machine, sizeof(MACHINE)=%zu", machine_guid, sizeof(MACHINE));
395 + debug(D_REGISTRY, "Registry: registry_machine_allocate('%s'): creating new machine, sizeof(MACHINE)=%zu", machine_guid, sizeof(MACHINE));
396
397 - MACHINE *m = mallocz(sizeof(MACHINE));
397 + MACHINE *m = mallocz(sizeof(MACHINE));
398
399 - strncpyz(m->guid, machine_guid, 36);
399 + strncpyz(m->guid, machine_guid, 36);
400
401 - debug(D_REGISTRY, "Registry: registry_machine_allocate('%s'): creating dictionary of urls", machine_guid);
402 - m->urls = dictionary_create(DICTIONARY_FLAGS);
401 + debug(D_REGISTRY, "Registry: registry_machine_allocate('%s'): creating dictionary of urls", machine_guid);
402 + m->urls = dictionary_create(DICTIONARY_FLAGS);
403
404 - m->first_t = m->last_t = (uint32_t)when;
405 - m->usages = 0;
404 + m->first_t = m->last_t = (uint32_t)when;
405 + m->usages = 0;
406
407 - registry.machines_memory += sizeof(MACHINE);
407 + registry.machines_memory += sizeof(MACHINE);
408
409 - registry.machines_count++;
410 - dictionary_set(registry.machines, m->guid, m, sizeof(MACHINE));
409 + registry.machines_count++;
410 + dictionary_set(registry.machines, m->guid, m, sizeof(MACHINE));
411
412 - return m;
412 + return m;
413 }
414
415 // 1. validate machine GUID
416 // 2. if it is valid, find it or create it and return it
417 // 3. if it is not valid, return NULL
418 static inline MACHINE *registry_machine_get(const char *machine_guid, time_t when) {
419 - MACHINE *m = NULL;
419 + MACHINE *m = NULL;
420
421 - registry_machines_lock();
421 + registry_machines_lock();
422
423 - if(likely(machine_guid && *machine_guid)) {
424 - // validate it is a GUID
425 - char buf[36 + 1];
426 - if(unlikely(registry_regenerate_guid(machine_guid, buf) == -1))
427 - info("Registry: machine guid '%s' is not a valid guid. Ignoring it.", machine_guid);
428 - else {
429 - machine_guid = buf;
430 - m = registry_machine_find(machine_guid);
431 - if(!m) m = registry_machine_allocate(machine_guid, when);
432 - }
433 - }
423 + if(likely(machine_guid && *machine_guid)) {
424 + // validate it is a GUID
425 + char buf[36 + 1];
426 + if(unlikely(registry_regenerate_guid(machine_guid, buf) == -1))
427 + info("Registry: machine guid '%s' is not a valid guid. Ignoring it.", machine_guid);
428 + else {
429 + machine_guid = buf;
430 + m = registry_machine_find(machine_guid);
431 + if(!m) m = registry_machine_allocate(machine_guid, when);
432 + }
433 + }
434
435 - registry_machines_unlock();
435 + registry_machines_unlock();
436
437 - return m;
437 + return m;
438 }
439
440
@@ -442,99 +442,99 @@ static inline MACHINE *registry_machine_get(const char *machine_guid, time_t whe
442 // PERSON
443
444 static inline PERSON *registry_person_find(const char *person_guid) {
445 - debug(D_REGISTRY, "Registry: registry_person_find('%s')", person_guid);
446 - return dictionary_get(registry.persons, person_guid);
445 + debug(D_REGISTRY, "Registry: registry_person_find('%s')", person_guid);
446 + return dictionary_get(registry.persons, person_guid);
447 }
448
449 static inline PERSON_URL *registry_person_url_allocate(PERSON *p, MACHINE *m, URL *u, char *name, size_t namelen, time_t when) {
450 - // protection from too big names
451 - if(namelen > registry.max_name_length)
452 - namelen = registry.max_name_length;
450 + // protection from too big names
451 + if(namelen > registry.max_name_length)
452 + namelen = registry.max_name_length;
453
454 - debug(D_REGISTRY, "registry_person_url_allocate('%s', '%s', '%s'): allocating %zu bytes", p->guid, m->guid, u->url,
455 - sizeof(PERSON_URL) + namelen);
454 + debug(D_REGISTRY, "registry_person_url_allocate('%s', '%s', '%s'): allocating %zu bytes", p->guid, m->guid, u->url,
455 + sizeof(PERSON_URL) + namelen);
456
457 - PERSON_URL *pu = mallocz(sizeof(PERSON_URL) + namelen);
457 + PERSON_URL *pu = mallocz(sizeof(PERSON_URL) + namelen);
458
459 - // a simple strcpy() should do the job
460 - // but I prefer to be safe, since the caller specified urllen
461 - strncpyz(pu->name, name, namelen);
459 + // a simple strcpy() should do the job
460 + // but I prefer to be safe, since the caller specified urllen
461 + strncpyz(pu->name, name, namelen);
462
463 - pu->machine = m;
464 - pu->first_t = pu->last_t = when;
465 - pu->usages = 1;
466 - pu->url = u;
467 - pu->flags = REGISTRY_URL_FLAGS_DEFAULT;
468 - m->links++;
463 + pu->machine = m;
464 + pu->first_t = pu->last_t = when;
465 + pu->usages = 1;
466 + pu->url = u;
467 + pu->flags = REGISTRY_URL_FLAGS_DEFAULT;
468 + m->links++;
469
470 - registry.persons_urls_memory += sizeof(PERSON_URL) + namelen;
470 + registry.persons_urls_memory += sizeof(PERSON_URL) + namelen;
471
472 - debug(D_REGISTRY, "registry_person_url_allocate('%s', '%s', '%s'): indexing URL in person", p->guid, m->guid, u->url);
473 - dictionary_set(p->urls, u->url, pu, sizeof(PERSON_URL));
474 - registry_url_link_nolock(u);
472 + debug(D_REGISTRY, "registry_person_url_allocate('%s', '%s', '%s'): indexing URL in person", p->guid, m->guid, u->url);
473 + dictionary_set(p->urls, u->url, pu, sizeof(PERSON_URL));
474 + registry_url_link_nolock(u);
475
476 - return pu;
476 + return pu;
477 }
478
479 static inline PERSON_URL *registry_person_url_reallocate(PERSON *p, MACHINE *m, URL *u, char *name, size_t namelen, time_t when, PERSON_URL *pu) {
480 - // this function is needed to change the name of a PERSON_URL
480 + // this function is needed to change the name of a PERSON_URL
481
482 - debug(D_REGISTRY, "registry_person_url_reallocate('%s', '%s', '%s'): allocating %zu bytes", p->guid, m->guid, u->url,
483 - sizeof(PERSON_URL) + namelen);
482 + debug(D_REGISTRY, "registry_person_url_reallocate('%s', '%s', '%s'): allocating %zu bytes", p->guid, m->guid, u->url,
483 + sizeof(PERSON_URL) + namelen);
484
485 - PERSON_URL *tpu = registry_person_url_allocate(p, m, u, name, namelen, when);
486 - tpu->first_t = pu->first_t;
487 - tpu->last_t = pu->last_t;
488 - tpu->usages = pu->usages;
485 + PERSON_URL *tpu = registry_person_url_allocate(p, m, u, name, namelen, when);
486 + tpu->first_t = pu->first_t;
487 + tpu->last_t = pu->last_t;
488 + tpu->usages = pu->usages;
489
490 - // ok, these are a hack - since the registry_person_url_allocate() is
491 - // adding these, we have to subtract them
492 - tpu->machine->links--;
493 - registry.persons_urls_memory -= sizeof(PERSON_URL) + strlen(pu->name);
494 - registry_url_unlink_nolock(u);
490 + // ok, these are a hack - since the registry_person_url_allocate() is
491 + // adding these, we have to subtract them
492 + tpu->machine->links--;
493 + registry.persons_urls_memory -= sizeof(PERSON_URL) + strlen(pu->name);
494 + registry_url_unlink_nolock(u);
495
496 - freez(pu);
496 + freez(pu);
497
498 - return tpu;
498 + return tpu;
499 }
500
501 static inline PERSON *registry_person_allocate(const char *person_guid, time_t when) {
502 - PERSON *p = NULL;
502 + PERSON *p = NULL;
503
504 - debug(D_REGISTRY, "Registry: registry_person_allocate('%s'): allocating new person, sizeof(PERSON)=%zu", (person_guid)?person_guid:"", sizeof(PERSON));
504 + debug(D_REGISTRY, "Registry: registry_person_allocate('%s'): allocating new person, sizeof(PERSON)=%zu", (person_guid)?person_guid:"", sizeof(PERSON));
505
506 - p = mallocz(sizeof(PERSON));
506 + p = mallocz(sizeof(PERSON));
507
508 - if(!person_guid) {
509 - for (; ;) {
510 - uuid_t uuid;
511 - uuid_generate(uuid);
512 - uuid_unparse_lower(uuid, p->guid);
508 + if(!person_guid) {
509 + for (; ;) {
510 + uuid_t uuid;
511 + uuid_generate(uuid);
512 + uuid_unparse_lower(uuid, p->guid);
513
514 - debug(D_REGISTRY, "Registry: Checking if the generated person guid '%s' is unique", p->guid);
515 - if (!dictionary_get(registry.persons, p->guid)) {
516 - debug(D_REGISTRY, "Registry: generated person guid '%s' is unique", p->guid);
517 - break;
518 - }
519 - else
520 - info("Registry: generated person guid '%s' found in the registry. Retrying...", p->guid);
521 - }
522 - }
523 - else
524 - strncpyz(p->guid, person_guid, 36);
514 + debug(D_REGISTRY, "Registry: Checking if the generated person guid '%s' is unique", p->guid);
515 + if (!dictionary_get(registry.persons, p->guid)) {
516 + debug(D_REGISTRY, "Registry: generated person guid '%s' is unique", p->guid);
517 + break;
518 + }
519 + else
520 + info("Registry: generated person guid '%s' found in the registry. Retrying...", p->guid);
521 + }
522 + }
523 + else
524 + strncpyz(p->guid, person_guid, 36);
525
526 - debug(D_REGISTRY, "Registry: registry_person_allocate('%s'): creating dictionary of urls", p->guid);
527 - p->urls = dictionary_create(DICTIONARY_FLAGS);
526 + debug(D_REGISTRY, "Registry: registry_person_allocate('%s'): creating dictionary of urls", p->guid);
527 + p->urls = dictionary_create(DICTIONARY_FLAGS);
528
529 - p->first_t = p->last_t = when;
530 - p->usages = 0;
529 + p->first_t = p->last_t = when;
530 + p->usages = 0;
531
532 - registry.persons_memory += sizeof(PERSON);
532 + registry.persons_memory += sizeof(PERSON);
533
534 - registry.persons_count++;
535 - dictionary_set(registry.persons, p->guid, p, sizeof(PERSON));
534 + registry.persons_count++;
535 + dictionary_set(registry.persons, p->guid, p, sizeof(PERSON));
536
537 - return p;
537 + return p;
538 }
539
540
@@ -543,260 +543,260 @@ static inline PERSON *registry_person_allocate(const char *person_guid, time_t w
543 // 3. if it is not valid, create a new one
544 // 4. return it
545 static inline PERSON *registry_person_get(const char *person_guid, time_t when) {
546 - PERSON *p = NULL;
546 + PERSON *p = NULL;
547
548 - registry_persons_lock();
548 + registry_persons_lock();
549
550 - if(person_guid && *person_guid) {
551 - char buf[36 + 1];
552 - // validate it is a GUID
553 - if(unlikely(registry_regenerate_guid(person_guid, buf) == -1))
554 - info("Registry: person guid '%s' is not a valid guid. Ignoring it.", person_guid);
555 - else {
556 - person_guid = buf;
557 - p = registry_person_find(person_guid);
558 - if(!p) person_guid = NULL;
559 - }
560 - }
550 + if(person_guid && *person_guid) {
551 + char buf[36 + 1];
552 + // validate it is a GUID
553 + if(unlikely(registry_regenerate_guid(person_guid, buf) == -1))
554 + info("Registry: person guid '%s' is not a valid guid. Ignoring it.", person_guid);
555 + else {
556 + person_guid = buf;
557 + p = registry_person_find(person_guid);
558 + if(!p) person_guid = NULL;
559 + }
560 + }
561
562 - if(!p) p = registry_person_allocate(NULL, when);
562 + if(!p) p = registry_person_allocate(NULL, when);
563
564 - registry_persons_unlock();
564 + registry_persons_unlock();
565
566 - return p;
566 + return p;
567 }
568
569 // ----------------------------------------------------------------------------
570 // LINKING OF OBJECTS
571
572 static inline PERSON_URL *registry_person_link_to_url(PERSON *p, MACHINE *m, URL *u, char *name, size_t namelen, time_t when) {
573 - debug(D_REGISTRY, "registry_person_link_to_url('%s', '%s', '%s'): searching for URL in person", p->guid, m->guid, u->url);
574 -
575 - registry_person_urls_lock(p);
576 -
577 - PERSON_URL *pu = dictionary_get(p->urls, u->url);
578 - if(!pu) {
579 - debug(D_REGISTRY, "registry_person_link_to_url('%s', '%s', '%s'): not found", p->guid, m->guid, u->url);
580 - pu = registry_person_url_allocate(p, m, u, name, namelen, when);
581 - registry.persons_urls_count++;
582 - }
583 - else {
584 - debug(D_REGISTRY, "registry_person_link_to_url('%s', '%s', '%s'): found", p->guid, m->guid, u->url);
585 - pu->usages++;
586 - if(likely(pu->last_t < (uint32_t)when)) pu->last_t = when;
587 -
588 - if(pu->machine != m) {
589 - MACHINE_URL *mu = dictionary_get(pu->machine->urls, u->url);
590 - if(mu) {
591 - info("registry_person_link_to_url('%s', '%s', '%s'): URL switched machines (old was '%s') - expiring it from previous machine.",
592 - p->guid, m->guid, u->url, pu->machine->guid);
593 - mu->flags |= REGISTRY_URL_FLAGS_EXPIRED;
594 - }
595 - else {
596 - info("registry_person_link_to_url('%s', '%s', '%s'): URL switched machines (old was '%s') - but the URL is not linked to the old machine.",
597 - p->guid, m->guid, u->url, pu->machine->guid);
598 - }
599 -
600 - pu->machine->links--;
601 - pu->machine = m;
602 - }
603 -
604 - if(strcmp(pu->name, name)) {
605 - // the name of the PERSON_URL has changed !
606 - pu = registry_person_url_reallocate(p, m, u, name, namelen, when, pu);
607 - }
608 - }
609 -
610 - p->usages++;
611 - if(likely(p->last_t < (uint32_t)when)) p->last_t = when;
612 -
613 - if(pu->flags & REGISTRY_URL_FLAGS_EXPIRED) {
614 - info("registry_person_link_to_url('%s', '%s', '%s'): accessing an expired URL. Re-enabling URL.", p->guid, m->guid, u->url);
615 - pu->flags &= ~REGISTRY_URL_FLAGS_EXPIRED;
616 - }
617 -
618 - registry_person_urls_unlock(p);
619 -
620 - return pu;
573 + debug(D_REGISTRY, "registry_person_link_to_url('%s', '%s', '%s'): searching for URL in person", p->guid, m->guid, u->url);
574 +
575 + registry_person_urls_lock(p);
576 +
577 + PERSON_URL *pu = dictionary_get(p->urls, u->url);
578 + if(!pu) {
579 + debug(D_REGISTRY, "registry_person_link_to_url('%s', '%s', '%s'): not found", p->guid, m->guid, u->url);
580 + pu = registry_person_url_allocate(p, m, u, name, namelen, when);
581 + registry.persons_urls_count++;
582 + }
583 + else {
584 + debug(D_REGISTRY, "registry_person_link_to_url('%s', '%s', '%s'): found", p->guid, m->guid, u->url);
585 + pu->usages++;
586 + if(likely(pu->last_t < (uint32_t)when)) pu->last_t = when;
587 +
588 + if(pu->machine != m) {
589 + MACHINE_URL *mu = dictionary_get(pu->machine->urls, u->url);
590 + if(mu) {
591 + info("registry_person_link_to_url('%s', '%s', '%s'): URL switched machines (old was '%s') - expiring it from previous machine.",
592 + p->guid, m->guid, u->url, pu->machine->guid);
593 + mu->flags |= REGISTRY_URL_FLAGS_EXPIRED;
594 + }
595 + else {
596 + info("registry_person_link_to_url('%s', '%s', '%s'): URL switched machines (old was '%s') - but the URL is not linked to the old machine.",
597 + p->guid, m->guid, u->url, pu->machine->guid);
598 + }
599 +
600 + pu->machine->links--;
601 + pu->machine = m;
602 + }
603 +
604 + if(strcmp(pu->name, name)) {
605 + // the name of the PERSON_URL has changed !
606 + pu = registry_person_url_reallocate(p, m, u, name, namelen, when, pu);
607 + }
608 + }
609 +
610 + p->usages++;
611 + if(likely(p->last_t < (uint32_t)when)) p->last_t = when;
612 +
613 + if(pu->flags & REGISTRY_URL_FLAGS_EXPIRED) {
614 + info("registry_person_link_to_url('%s', '%s', '%s'): accessing an expired URL. Re-enabling URL.", p->guid, m->guid, u->url);
615 + pu->flags &= ~REGISTRY_URL_FLAGS_EXPIRED;
616 + }
617 +
618 + registry_person_urls_unlock(p);
619 +
620 + return pu;
621 }
622
623 static inline MACHINE_URL *registry_machine_link_to_url(PERSON *p, MACHINE *m, URL *u, time_t when) {
624 - debug(D_REGISTRY, "registry_machine_link_to_url('%s', '%s', '%s'): searching for URL in machine", p->guid, m->guid, u->url);
624 + debug(D_REGISTRY, "registry_machine_link_to_url('%s', '%s', '%s'): searching for URL in machine", p->guid, m->guid, u->url);
625
626 - registry_machine_urls_lock(m);
626 + registry_machine_urls_lock(m);
627
628 - MACHINE_URL *mu = dictionary_get(m->urls, u->url);
629 - if(!mu) {
630 - debug(D_REGISTRY, "registry_machine_link_to_url('%s', '%s', '%s'): not found", p->guid, m->guid, u->url);
631 - mu = registry_machine_url_allocate(m, u, when);
632 - registry.machines_urls_count++;
633 - }
634 - else {
635 - debug(D_REGISTRY, "registry_machine_link_to_url('%s', '%s', '%s'): found", p->guid, m->guid, u->url);
636 - mu->usages++;
637 - if(likely(mu->last_t < (uint32_t)when)) mu->last_t = when;
638 - }
628 + MACHINE_URL *mu = dictionary_get(m->urls, u->url);
629 + if(!mu) {
630 + debug(D_REGISTRY, "registry_machine_link_to_url('%s', '%s', '%s'): not found", p->guid, m->guid, u->url);
631 + mu = registry_machine_url_allocate(m, u, when);
632 + registry.machines_urls_count++;
633 + }
634 + else {
635 + debug(D_REGISTRY, "registry_machine_link_to_url('%s', '%s', '%s'): found", p->guid, m->guid, u->url);
636 + mu->usages++;
637 + if(likely(mu->last_t < (uint32_t)when)) mu->last_t = when;
638 + }
639
640 - //debug(D_REGISTRY, "registry_machine_link_to_url('%s', '%s', '%s'): indexing person in machine", p->guid, m->guid, u->url);
641 - //dictionary_set(mu->persons, p->guid, p, sizeof(PERSON));
640 + //debug(D_REGISTRY, "registry_machine_link_to_url('%s', '%s', '%s'): indexing person in machine", p->guid, m->guid, u->url);
641 + //dictionary_set(mu->persons, p->guid, p, sizeof(PERSON));
642
643 - m->usages++;
644 - if(likely(m->last_t < (uint32_t)when)) m->last_t = when;
643 + m->usages++;
644 + if(likely(m->last_t < (uint32_t)when)) m->last_t = when;
645
646 - if(mu->flags & REGISTRY_URL_FLAGS_EXPIRED) {
647 - info("registry_machine_link_to_url('%s', '%s', '%s'): accessing an expired URL.", p->guid, m->guid, u->url);
648 - mu->flags &= ~REGISTRY_URL_FLAGS_EXPIRED;
649 - }
646 + if(mu->flags & REGISTRY_URL_FLAGS_EXPIRED) {
647 + info("registry_machine_link_to_url('%s', '%s', '%s'): accessing an expired URL.", p->guid, m->guid, u->url);
648 + mu->flags &= ~REGISTRY_URL_FLAGS_EXPIRED;
649 + }
650
651 - registry_machine_urls_unlock(m);
651 + registry_machine_urls_unlock(m);
652
653 - return mu;
653 + return mu;
654 }
655
656 // ----------------------------------------------------------------------------
657 // REGISTRY LOG LOAD/SAVE
658
659 static inline int registry_should_save_db(void) {
660 - debug(D_REGISTRY, "log entries %llu, max %llu", registry.log_count, registry.save_registry_every_entries);
661 - return registry.log_count > registry.save_registry_every_entries;
660 + debug(D_REGISTRY, "log entries %llu, max %llu", registry.log_count, registry.save_registry_every_entries);
661 + return registry.log_count > registry.save_registry_every_entries;
662 }
663
664 static inline void registry_log(const char action, PERSON *p, MACHINE *m, URL *u, char *name) {
665 - if(likely(registry.log_fp)) {
666 - // we lock only if the file is open
667 - // to allow replaying the log at registry_log_load()
668 - registry_log_lock();
669 -
670 - if(unlikely(fprintf(registry.log_fp, "%c\t%08x\t%s\t%s\t%s\t%s\n",
671 - action,
672 - p->last_t,
673 - p->guid,
674 - m->guid,
675 - name,
676 - u->url) < 0))
677 - error("Registry: failed to save log. Registry data may be lost in case of abnormal restart.");
678 -
679 - // we increase the counter even on failures
680 - // so that the registry will be saved periodically
681 - registry.log_count++;
682 -
683 - registry_log_unlock();
684 -
685 - // this must be outside the log_lock(), or a deadlock will happen.
686 - // registry_save() checks the same inside the log_lock, so only
687 - // one thread will save the db
688 - if(unlikely(registry_should_save_db()))
689 - registry_save();
690 - }
665 + if(likely(registry.log_fp)) {
666 + // we lock only if the file is open
667 + // to allow replaying the log at registry_log_load()
668 + registry_log_lock();
669 +
670 + if(unlikely(fprintf(registry.log_fp, "%c\t%08x\t%s\t%s\t%s\t%s\n",
671 + action,
672 + p->last_t,
673 + p->guid,
674 + m->guid,
675 + name,
676 + u->url) < 0))
677 + error("Registry: failed to save log. Registry data may be lost in case of abnormal restart.");
678 +
679 + // we increase the counter even on failures
680 + // so that the registry will be saved periodically
681 + registry.log_count++;
682 +
683 + registry_log_unlock();
684 +
685 + // this must be outside the log_lock(), or a deadlock will happen.
686 + // registry_save() checks the same inside the log_lock, so only
687 + // one thread will save the db
688 + if(unlikely(registry_should_save_db()))
689 + registry_save();
690 + }
691 }
692
693 static inline int registry_log_open_nolock(void) {
694 - if(registry.log_fp)
695 - fclose(registry.log_fp);
694 + if(registry.log_fp)
695 + fclose(registry.log_fp);
696
697 - registry.log_fp = fopen(registry.log_filename, "a");
697 + registry.log_fp = fopen(registry.log_filename, "a");
698
699 - if(registry.log_fp) {
700 - if (setvbuf(registry.log_fp, NULL, _IOLBF, 0) != 0)
701 - error("Cannot set line buffering on registry log file.");
702 - return 0;
703 - }
699 + if(registry.log_fp) {
700 + if (setvbuf(registry.log_fp, NULL, _IOLBF, 0) != 0)
701 + error("Cannot set line buffering on registry log file.");
702 + return 0;
703 + }
704
705 - error("Cannot open registry log file '%s'. Registry data will be lost in case of netdata or server crash.", registry.log_filename);
706 - return -1;
705 + error("Cannot open registry log file '%s'. Registry data will be lost in case of netdata or server crash.", registry.log_filename);
706 + return -1;
707 }
708
709 static inline void registry_log_close_nolock(void) {
710 - if(registry.log_fp) {
711 - fclose(registry.log_fp);
712 - registry.log_fp = NULL;
713 - }
710 + if(registry.log_fp) {
711 + fclose(registry.log_fp);
712 + registry.log_fp = NULL;
713 + }
714 }
715
716 static inline void registry_log_recreate_nolock(void) {
717 - if(registry.log_fp != NULL) {
718 - registry_log_close_nolock();
717 + if(registry.log_fp != NULL) {
718 + registry_log_close_nolock();
719
720 - // open it with truncate
721 - registry.log_fp = fopen(registry.log_filename, "w");
722 - if(registry.log_fp) fclose(registry.log_fp);
723 - else error("Cannot truncate registry log '%s'", registry.log_filename);
720 + // open it with truncate
721 + registry.log_fp = fopen(registry.log_filename, "w");
722 + if(registry.log_fp) fclose(registry.log_fp);
723 + else error("Cannot truncate registry log '%s'", registry.log_filename);
724
725 - registry.log_fp = NULL;
725 + registry.log_fp = NULL;
726
727 - registry_log_open_nolock();
728 - }
727 + registry_log_open_nolock();
728 + }
729 }
730
731 int registry_log_load(void) {
732 - char *s, buf[4096 + 1];
733 - size_t line = -1;
734 -
735 - // closing the log is required here
736 - // otherwise we will append to it the values we read
737 - registry_log_close_nolock();
738 -
739 - debug(D_REGISTRY, "Registry: loading active db from: %s", registry.log_filename);
740 - FILE *fp = fopen(registry.log_filename, "r");
741 - if(!fp)
742 - error("Registry: cannot open registry file: %s", registry.log_filename);
743 - else {
744 - line = 0;
745 - size_t len = 0;
746 - while ((s = fgets_trim_len(buf, 4096, fp, &len))) {
747 - line++;
748 -
749 - switch (s[0]) {
750 - case 'A': // accesses
751 - case 'D': // deletes
752 -
753 - // verify it is valid
754 - if (unlikely(len < 85 || s[1] != '\t' || s[10] != '\t' || s[47] != '\t' || s[84] != '\t')) {
755 - error("Registry: log line %zu is wrong (len = %zu).", line, len);
756 - continue;
757 - }
758 - s[1] = s[10] = s[47] = s[84] = '\0';
759 -
760 - // get the variables
761 - time_t when = strtoul(&s[2], NULL, 16);
762 - char *person_guid = &s[11];
763 - char *machine_guid = &s[48];
764 - char *name = &s[85];
765 -
766 - // skip the name to find the url
767 - char *url = name;
768 - while(*url && *url != '\t') url++;
769 - if(!*url) {
770 - error("Registry: log line %zu does not have a url.", line);
771 - continue;
772 - }
773 - *url++ = '\0';
774 -
775 - // make sure the person exists
776 - // without this, a new person guid will be created
777 - PERSON *p = registry_person_find(person_guid);
778 - if(!p) p = registry_person_allocate(person_guid, when);
779 -
780 - if(s[0] == 'A')
781 - registry_request_access(p->guid, machine_guid, url, name, when);
782 - else
783 - registry_request_delete(p->guid, machine_guid, url, name, when);
784 -
785 - break;
786 -
787 - default:
788 - error("Registry: ignoring line %zu of filename '%s': %s.", line, registry.log_filename, s);
789 - break;
790 - }
791 - }
792 -
793 - fclose(fp);
794 - }
795 -
796 - // open the log again
797 - registry_log_open_nolock();
798 -
799 - return line;
732 + char *s, buf[4096 + 1];
733 + size_t line = -1;
734 +
735 + // closing the log is required here
736 + // otherwise we will append to it the values we read
737 + registry_log_close_nolock();
738 +
739 + debug(D_REGISTRY, "Registry: loading active db from: %s", registry.log_filename);
740 + FILE *fp = fopen(registry.log_filename, "r");
741 + if(!fp)
742 + error("Registry: cannot open registry file: %s", registry.log_filename);
743 + else {
744 + line = 0;
745 + size_t len = 0;
746 + while ((s = fgets_trim_len(buf, 4096, fp, &len))) {
747 + line++;
748 +
749 + switch (s[0]) {
750 + case 'A': // accesses
751 + case 'D': // deletes
752 +
753 + // verify it is valid
754 + if (unlikely(len < 85 || s[1] != '\t' || s[10] != '\t' || s[47] != '\t' || s[84] != '\t')) {
755 + error("Registry: log line %zu is wrong (len = %zu).", line, len);
756 + continue;
757 + }
758 + s[1] = s[10] = s[47] = s[84] = '\0';
759 +
760 + // get the variables
761 + time_t when = strtoul(&s[2], NULL, 16);
762 + char *person_guid = &s[11];
763 + char *machine_guid = &s[48];
764 + char *name = &s[85];
765 +
766 + // skip the name to find the url
767 + char *url = name;
768 + while(*url && *url != '\t') url++;
769 + if(!*url) {
770 + error("Registry: log line %zu does not have a url.", line);
771 + continue;
772 + }
773 + *url++ = '\0';
774 +
775 + // make sure the person exists
776 + // without this, a new person guid will be created
777 + PERSON *p = registry_person_find(person_guid);
778 + if(!p) p = registry_person_allocate(person_guid, when);
779 +
780 + if(s[0] == 'A')
781 + registry_request_access(p->guid, machine_guid, url, name, when);
782 + else
783 + registry_request_delete(p->guid, machine_guid, url, name, when);
784 +
785 + break;
786 +
787 + default:
788 + error("Registry: ignoring line %zu of filename '%s': %s.", line, registry.log_filename, s);
789 + break;
790 + }
791 + }
792 +
793 + fclose(fp);
794 + }
795 +
796 + // open the log again
797 + registry_log_open_nolock();
798 +
799 + return line;
800 }
801
802
@@ -804,176 +804,176 @@ int registry_log_load(void) {
804 // REGISTRY REQUESTS
805
806 PERSON *registry_request_access(char *person_guid, char *machine_guid, char *url, char *name, time_t when) {
807 - debug(D_REGISTRY, "registry_request_access('%s', '%s', '%s'): NEW REQUEST", (person_guid)?person_guid:"", machine_guid, url);
807 + debug(D_REGISTRY, "registry_request_access('%s', '%s', '%s'): NEW REQUEST", (person_guid)?person_guid:"", machine_guid, url);
808
809 - MACHINE *m = registry_machine_get(machine_guid, when);
810 - if(!m) return NULL;
809 + MACHINE *m = registry_machine_get(machine_guid, when);
810 + if(!m) return NULL;
811
812 - // make sure the name is valid
813 - size_t namelen;
814 - name = registry_fix_machine_name(name, &namelen);
812 + // make sure the name is valid
813 + size_t namelen;
814 + name = registry_fix_machine_name(name, &namelen);
815
816 - size_t urllen;
817 - url = registry_fix_url(url, &urllen);
816 + size_t urllen;
817 + url = registry_fix_url(url, &urllen);
818
819 - URL *u = registry_url_get(url, urllen);
820 - PERSON *p = registry_person_get(person_guid, when);
819 + URL *u = registry_url_get(url, urllen);
820 + PERSON *p = registry_person_get(person_guid, when);
821
822 - registry_person_link_to_url(p, m, u, name, namelen, when);
823 - registry_machine_link_to_url(p, m, u, when);
822 + registry_person_link_to_url(p, m, u, name, namelen, when);
823 + registry_machine_link_to_url(p, m, u, when);
824
825 - registry_log('A', p, m, u, name);
825 + registry_log('A', p, m, u, name);
826
827 - registry.usages_count++;
828 - return p;
827 + registry.usages_count++;
828 + return p;
829 }
830
831 // verify the person, the machine and the URL exist in our DB
832 PERSON_URL *registry_verify_request(char *person_guid, char *machine_guid, char *url, PERSON **pp, MACHINE **mm) {
833 - char pbuf[36 + 1], mbuf[36 + 1];
834 -
835 - if(!person_guid || !*person_guid || !machine_guid || !*machine_guid || !url || !*url) {
836 - info("Registry Request Verification: invalid request! person: '%s', machine '%s', url '%s'", person_guid?person_guid:"UNSET", machine_guid?machine_guid:"UNSET", url?url:"UNSET");
837 - return NULL;
838 - }
839 -
840 - // normalize the url
841 - url = registry_fix_url(url, NULL);
842 -
843 - // make sure the person GUID is valid
844 - if(registry_regenerate_guid(person_guid, pbuf) == -1) {
845 - info("Registry Request Verification: invalid person GUID, person: '%s', machine '%s', url '%s'", person_guid, machine_guid, url);
846 - return NULL;
847 - }
848 - person_guid = pbuf;
849 -
850 - // make sure the machine GUID is valid
851 - if(registry_regenerate_guid(machine_guid, mbuf) == -1) {
852 - info("Registry Request Verification: invalid machine GUID, person: '%s', machine '%s', url '%s'", person_guid, machine_guid, url);
853 - return NULL;
854 - }
855 - machine_guid = mbuf;
856 -
857 - // make sure the machine exists
858 - MACHINE *m = registry_machine_find(machine_guid);
859 - if(!m) {
860 - info("Registry Request Verification: machine not found, person: '%s', machine '%s', url '%s'", person_guid, machine_guid, url);
861 - return NULL;
862 - }
863 - if(mm) *mm = m;
864 -
865 - // make sure the person exist
866 - PERSON *p = registry_person_find(person_guid);
867 - if(!p) {
868 - info("Registry Request Verification: person not found, person: '%s', machine '%s', url '%s'", person_guid, machine_guid, url);
869 - return NULL;
870 - }
871 - if(pp) *pp = p;
872 -
873 - PERSON_URL *pu = dictionary_get(p->urls, url);
874 - if(!pu) {
875 - info("Registry Request Verification: URL not found for person, person: '%s', machine '%s', url '%s'", person_guid, machine_guid, url);
876 - return NULL;
877 - }
878 - return pu;
833 + char pbuf[36 + 1], mbuf[36 + 1];
834 +
835 + if(!person_guid || !*person_guid || !machine_guid || !*machine_guid || !url || !*url) {
836 + info("Registry Request Verification: invalid request! person: '%s', machine '%s', url '%s'", person_guid?person_guid:"UNSET", machine_guid?machine_guid:"UNSET", url?url:"UNSET");
837 + return NULL;
838 + }
839 +
840 + // normalize the url
841 + url = registry_fix_url(url, NULL);
842 +
843 + // make sure the person GUID is valid
844 + if(registry_regenerate_guid(person_guid, pbuf) == -1) {
845 + info("Registry Request Verification: invalid person GUID, person: '%s', machine '%s', url '%s'", person_guid, machine_guid, url);
846 + return NULL;
847 + }
848 + person_guid = pbuf;
849 +
850 + // make sure the machine GUID is valid
851 + if(registry_regenerate_guid(machine_guid, mbuf) == -1) {
852 + info("Registry Request Verification: invalid machine GUID, person: '%s', machine '%s', url '%s'", person_guid, machine_guid, url);
853 + return NULL;
854 + }
855 + machine_guid = mbuf;
856 +
857 + // make sure the machine exists
858 + MACHINE *m = registry_machine_find(machine_guid);
859 + if(!m) {
860 + info("Registry Request Verification: machine not found, person: '%s', machine '%s', url '%s'", person_guid, machine_guid, url);
861 + return NULL;
862 + }
863 + if(mm) *mm = m;
864 +
865 + // make sure the person exist
866 + PERSON *p = registry_person_find(person_guid);
867 + if(!p) {
868 + info("Registry Request Verification: person not found, person: '%s', machine '%s', url '%s'", person_guid, machine_guid, url);
869 + return NULL;
870 + }
871 + if(pp) *pp = p;
872 +
873 + PERSON_URL *pu = dictionary_get(p->urls, url);
874 + if(!pu) {
875 + info("Registry Request Verification: URL not found for person, person: '%s', machine '%s', url '%s'", person_guid, machine_guid, url);
876 + return NULL;
877 + }
878 + return pu;
879 }
880
881 PERSON *registry_request_delete(char *person_guid, char *machine_guid, char *url, char *delete_url, time_t when) {
882 - (void)when;
882 + (void)when;
883
884 - PERSON *p = NULL;
885 - MACHINE *m = NULL;
886 - PERSON_URL *pu = registry_verify_request(person_guid, machine_guid, url, &p, &m);
887 - if(!pu || !p || !m) return NULL;
884 + PERSON *p = NULL;
885 + MACHINE *m = NULL;
886 + PERSON_URL *pu = registry_verify_request(person_guid, machine_guid, url, &p, &m);
887 + if(!pu || !p || !m) return NULL;
888
889 - // normalize the url
890 - delete_url = registry_fix_url(delete_url, NULL);
889 + // normalize the url
890 + delete_url = registry_fix_url(delete_url, NULL);
891
892 - // make sure the user is not deleting the url it uses
893 - if(!strcmp(delete_url, pu->url->url)) {
894 - info("Registry Delete Request: delete URL is the one currently accessed, person: '%s', machine '%s', url '%s', delete url '%s'", p->guid, m->guid, pu->url->url, delete_url);
895 - return NULL;
896 - }
892 + // make sure the user is not deleting the url it uses
893 + if(!strcmp(delete_url, pu->url->url)) {
894 + info("Registry Delete Request: delete URL is the one currently accessed, person: '%s', machine '%s', url '%s', delete url '%s'", p->guid, m->guid, pu->url->url, delete_url);
895 + return NULL;
896 + }
897
898 - registry_person_urls_lock(p);
898 + registry_person_urls_lock(p);
899
900 - PERSON_URL *dpu = dictionary_get(p->urls, delete_url);
901 - if(!dpu) {
902 - info("Registry Delete Request: URL not found for person: '%s', machine '%s', url '%s', delete url '%s'", p->guid, m->guid, pu->url->url, delete_url);
903 - registry_person_urls_unlock(p);
904 - return NULL;
905 - }
900 + PERSON_URL *dpu = dictionary_get(p->urls, delete_url);
901 + if(!dpu) {
902 + info("Registry Delete Request: URL not found for person: '%s', machine '%s', url '%s', delete url '%s'", p->guid, m->guid, pu->url->url, delete_url);
903 + registry_person_urls_unlock(p);
904 + return NULL;
905 + }
906
907 - registry_log('D', p, m, pu->url, dpu->url->url);
907 + registry_log('D', p, m, pu->url, dpu->url->url);
908
909 - dictionary_del(p->urls, dpu->url->url);
910 - registry_url_unlink_nolock(dpu->url);
911 - freez(dpu);
909 + dictionary_del(p->urls, dpu->url->url);
910 + registry_url_unlink_nolock(dpu->url);
911 + freez(dpu);
912
913 - registry_person_urls_unlock(p);
914 - return p;
913 + registry_person_urls_unlock(p);
914 + return p;
915 }
916
917
918 // a structure to pass to the dictionary_get_all() callback handler
919 struct machine_request_callback_data {
920 - MACHINE *find_this_machine;
921 - PERSON_URL *result;
920 + MACHINE *find_this_machine;
921 + PERSON_URL *result;
922 };
923
924 // the callback function
925 // this will be run for every PERSON_URL of this PERSON
926 int machine_request_callback(void *entry, void *data) {
927 - PERSON_URL *mypu = (PERSON_URL *)entry;
928 - struct machine_request_callback_data *myrdata = (struct machine_request_callback_data *)data;
927 + PERSON_URL *mypu = (PERSON_URL *)entry;
928 + struct machine_request_callback_data *myrdata = (struct machine_request_callback_data *)data;
929
930 - if(mypu->machine == myrdata->find_this_machine) {
931 - myrdata->result = mypu;
932 - return -1; // this will also stop the walk through
933 - }
930 + if(mypu->machine == myrdata->find_this_machine) {
931 + myrdata->result = mypu;
932 + return -1; // this will also stop the walk through
933 + }
934
935 - return 0; // continue
935 + return 0; // continue
936 }
937
938 MACHINE *registry_request_machine(char *person_guid, char *machine_guid, char *url, char *request_machine, time_t when) {
939 - (void)when;
939 + (void)when;
940
941 - char mbuf[36 + 1];
941 + char mbuf[36 + 1];
942
943 - PERSON *p = NULL;
944 - MACHINE *m = NULL;
945 - PERSON_URL *pu = registry_verify_request(person_guid, machine_guid, url, &p, &m);
946 - if(!pu || !p || !m) return NULL;
943 + PERSON *p = NULL;
944 + MACHINE *m = NULL;
945 + PERSON_URL *pu = registry_verify_request(person_guid, machine_guid, url, &p, &m);
946 + if(!pu || !p || !m) return NULL;
947
948 - // make sure the machine GUID is valid
949 - if(registry_regenerate_guid(request_machine, mbuf) == -1) {
950 - info("Registry Machine URLs request: invalid machine GUID, person: '%s', machine '%s', url '%s', request machine '%s'", p->guid, m->guid, pu->url->url, request_machine);
951 - return NULL;
952 - }
953 - request_machine = mbuf;
948 + // make sure the machine GUID is valid
949 + if(registry_regenerate_guid(request_machine, mbuf) == -1) {
950 + info("Registry Machine URLs request: invalid machine GUID, person: '%s', machine '%s', url '%s', request machine '%s'", p->guid, m->guid, pu->url->url, request_machine);
951 + return NULL;
952 + }
953 + request_machine = mbuf;
954
955 - // make sure the machine exists
956 - m = registry_machine_find(request_machine);
957 - if(!m) {
958 - info("Registry Machine URLs request: machine not found, person: '%s', machine '%s', url '%s', request machine '%s'", p->guid, m->guid, pu->url->url, request_machine);
959 - return NULL;
960 - }
955 + // make sure the machine exists
956 + m = registry_machine_find(request_machine);
957 + if(!m) {
958 + info("Registry Machine URLs request: machine not found, person: '%s', machine '%s', url '%s', request machine '%s'", p->guid, m->guid, pu->url->url, request_machine);
959 + return NULL;
960 + }
961
962 - // Verify the user has in the past accessed this machine
963 - // We will walk through the PERSON_URLs to find the machine
964 - // linking to our machine
962 + // Verify the user has in the past accessed this machine
963 + // We will walk through the PERSON_URLs to find the machine
964 + // linking to our machine
965
966 - // a structure to pass to the dictionary_get_all() callback handler
967 - struct machine_request_callback_data rdata = { m, NULL };
966 + // a structure to pass to the dictionary_get_all() callback handler
967 + struct machine_request_callback_data rdata = { m, NULL };
968
969 - // request a walk through on the dictionary
970 - // no need for locking here, the underlying dictionary has its own
971 - dictionary_get_all(p->urls, machine_request_callback, &rdata);
969 + // request a walk through on the dictionary
970 + // no need for locking here, the underlying dictionary has its own
971 + dictionary_get_all(p->urls, machine_request_callback, &rdata);
972
973 - if(rdata.result)
974 - return m;
973 + if(rdata.result)
974 + return m;
975
976 - return NULL;
976 + return NULL;
977 }
978
979
@@ -985,242 +985,242 @@ MACHINE *registry_request_machine(char *person_guid, char *machine_guid, char *u
985 #define REGISTRY_STATUS_DISABLED "disabled"
986
987 int registry_verify_cookies_redirects(void) {
988 - return registry.verify_cookies_redirects;
988 + return registry.verify_cookies_redirects;
989 }
990
991 const char *registry_to_announce(void) {
992 - return registry.registry_to_announce;
992 + return registry.registry_to_announce;
993 }
994
995 void registry_set_cookie(struct web_client *w, const char *guid) {
996 - char edate[100];
997 - time_t et = time(NULL) + registry.persons_expiration;
998 - struct tm etmbuf, *etm = gmtime_r(&et, &etmbuf);
999 - strftime(edate, sizeof(edate), "%a, %d %b %Y %H:%M:%S %Z", etm);
996 + char edate[100];
997 + time_t et = time(NULL) + registry.persons_expiration;
998 + struct tm etmbuf, *etm = gmtime_r(&et, &etmbuf);
999 + strftime(edate, sizeof(edate), "%a, %d %b %Y %H:%M:%S %Z", etm);
1000
1001 - snprintfz(w->cookie1, COOKIE_MAX, NETDATA_REGISTRY_COOKIE_NAME "=%s; Expires=%s", guid, edate);
1001 + snprintfz(w->cookie1, COOKIE_MAX, NETDATA_REGISTRY_COOKIE_NAME "=%s; Expires=%s", guid, edate);
1002
1003 - if(registry.registry_domain && registry.registry_domain[0])
1004 - snprintfz(w->cookie2, COOKIE_MAX, NETDATA_REGISTRY_COOKIE_NAME "=%s; Domain=%s; Expires=%s", guid, registry.registry_domain, edate);
1003 + if(registry.registry_domain && registry.registry_domain[0])
1004 + snprintfz(w->cookie2, COOKIE_MAX, NETDATA_REGISTRY_COOKIE_NAME "=%s; Domain=%s; Expires=%s", guid, registry.registry_domain, edate);
1005 }
1006
1007 static inline void registry_set_person_cookie(struct web_client *w, PERSON *p) {
1008 - registry_set_cookie(w, p->guid);
1008 + registry_set_cookie(w, p->guid);
1009 }
1010
1011 static inline void registry_json_header(struct web_client *w, const char *action, const char *status) {
1012 - buffer_flush(w->response.data);
1013 - w->response.data->contenttype = CT_APPLICATION_JSON;
1014 - buffer_sprintf(w->response.data, "{\n\t\"action\": \"%s\",\n\t\"status\": \"%s\",\n\t\"hostname\": \"%s\",\n\t\"machine_guid\": \"%s\"",
1015 - action, status, registry.hostname, registry.machine_guid);
1012 + buffer_flush(w->response.data);
1013 + w->response.data->contenttype = CT_APPLICATION_JSON;
1014 + buffer_sprintf(w->response.data, "{\n\t\"action\": \"%s\",\n\t\"status\": \"%s\",\n\t\"hostname\": \"%s\",\n\t\"machine_guid\": \"%s\"",
1015 + action, status, registry.hostname, registry.machine_guid);
1016 }
1017
1018 static inline void registry_json_footer(struct web_client *w) {
1019 - buffer_strcat(w->response.data, "\n}\n");
1019 + buffer_strcat(w->response.data, "\n}\n");
1020 }
1021
1022 int registry_request_hello_json(struct web_client *w) {
1023 - registry_json_header(w, "hello", REGISTRY_STATUS_OK);
1023 + registry_json_header(w, "hello", REGISTRY_STATUS_OK);
1024
1025 - buffer_sprintf(w->response.data, ",\n\t\"registry\": \"%s\"",
1026 - registry.registry_to_announce);
1025 + buffer_sprintf(w->response.data, ",\n\t\"registry\": \"%s\"",
1026 + registry.registry_to_announce);
1027
1028 - registry_json_footer(w);
1029 - return 200;
1028 + registry_json_footer(w);
1029 + return 200;
1030 }
1031
1032 static inline int registry_json_disabled(struct web_client *w, const char *action) {
1033 - registry_json_header(w, action, REGISTRY_STATUS_DISABLED);
1033 + registry_json_header(w, action, REGISTRY_STATUS_DISABLED);
1034
1035 - buffer_sprintf(w->response.data, ",\n\t\"registry\": \"%s\"",
1036 - registry.registry_to_announce);
1035 + buffer_sprintf(w->response.data, ",\n\t\"registry\": \"%s\"",
1036 + registry.registry_to_announce);
1037
1038 - registry_json_footer(w);
1039 - return 200;
1038 + registry_json_footer(w);
1039 + return 200;
1040 }
1041
1042 // structure used be the callbacks below
1043 struct registry_json_walk_person_urls_callback {
1044 - PERSON *p;
1045 - MACHINE *m;
1046 - struct web_client *w;
1047 - int count;
1044 + PERSON *p;
1045 + MACHINE *m;
1046 + struct web_client *w;
1047 + int count;
1048 };
1049
1050 // callback for rendering PERSON_URLs
1051 static inline int registry_json_person_url_callback(void *entry, void *data) {
1052 - PERSON_URL *pu = (PERSON_URL *)entry;
1053 - struct registry_json_walk_person_urls_callback *c = (struct registry_json_walk_person_urls_callback *)data;
1054 - struct web_client *w = c->w;
1052 + PERSON_URL *pu = (PERSON_URL *)entry;
1053 + struct registry_json_walk_person_urls_callback *c = (struct registry_json_walk_person_urls_callback *)data;
1054 + struct web_client *w = c->w;
1055
1056 - if(unlikely(c->count++))
1057 - buffer_strcat(w->response.data, ",");
1056 + if(unlikely(c->count++))
1057 + buffer_strcat(w->response.data, ",");
1058
1059 - buffer_sprintf(w->response.data, "\n\t\t[ \"%s\", \"%s\", %u000, %u, \"%s\" ]",
1060 - pu->machine->guid, pu->url->url, pu->last_t, pu->usages, pu->name);
1059 + buffer_sprintf(w->response.data, "\n\t\t[ \"%s\", \"%s\", %u000, %u, \"%s\" ]",
1060 + pu->machine->guid, pu->url->url, pu->last_t, pu->usages, pu->name);
1061
1062 - return 1;
1062 + return 1;
1063 }
1064
1065 // callback for rendering MACHINE_URLs
1066 static inline int registry_json_machine_url_callback(void *entry, void *data) {
1067 - MACHINE_URL *mu = (MACHINE_URL *)entry;
1068 - struct registry_json_walk_person_urls_callback *c = (struct registry_json_walk_person_urls_callback *)data;
1069 - struct web_client *w = c->w;
1070 - MACHINE *m = c->m;
1067 + MACHINE_URL *mu = (MACHINE_URL *)entry;
1068 + struct registry_json_walk_person_urls_callback *c = (struct registry_json_walk_person_urls_callback *)data;
1069 + struct web_client *w = c->w;
1070 + MACHINE *m = c->m;
1071
1072 - if(unlikely(c->count++))
1073 - buffer_strcat(w->response.data, ",");
1072 + if(unlikely(c->count++))
1073 + buffer_strcat(w->response.data, ",");
1074
1075 - buffer_sprintf(w->response.data, "\n\t\t[ \"%s\", \"%s\", %u000, %u ]",
1076 - m->guid, mu->url->url, mu->last_t, mu->usages);
1075 + buffer_sprintf(w->response.data, "\n\t\t[ \"%s\", \"%s\", %u000, %u ]",
1076 + m->guid, mu->url->url, mu->last_t, mu->usages);
1077
1078 - return 1;
1078 + return 1;
1079 }
1080
1081
1082 // the main method for registering an access
1083 int registry_request_access_json(struct web_client *w, char *person_guid, char *machine_guid, char *url, char *name, time_t when) {
1084 - if(!registry.enabled)
1085 - return registry_json_disabled(w, "access");
1084 + if(!registry.enabled)
1085 + return registry_json_disabled(w, "access");
1086
1087 - PERSON *p = registry_request_access(person_guid, machine_guid, url, name, when);
1088 - if(!p) {
1089 - registry_json_header(w, "access", REGISTRY_STATUS_FAILED);
1090 - registry_json_footer(w);
1091 - return 412;
1092 - }
1087 + PERSON *p = registry_request_access(person_guid, machine_guid, url, name, when);
1088 + if(!p) {
1089 + registry_json_header(w, "access", REGISTRY_STATUS_FAILED);
1090 + registry_json_footer(w);
1091 + return 412;
1092 + }
1093
1094 - // set the cookie
1095 - registry_set_person_cookie(w, p);
1094 + // set the cookie
1095 + registry_set_person_cookie(w, p);
1096
1097 - // generate the response
1098 - registry_json_header(w, "access", REGISTRY_STATUS_OK);
1097 + // generate the response
1098 + registry_json_header(w, "access", REGISTRY_STATUS_OK);
1099
1100 - buffer_sprintf(w->response.data, ",\n\t\"person_guid\": \"%s\",\n\t\"urls\": [", p->guid);
1101 - struct registry_json_walk_person_urls_callback c = { p, NULL, w, 0 };
1102 - dictionary_get_all(p->urls, registry_json_person_url_callback, &c);
1103 - buffer_strcat(w->response.data, "\n\t]\n");
1100 + buffer_sprintf(w->response.data, ",\n\t\"person_guid\": \"%s\",\n\t\"urls\": [", p->guid);
1101 + struct registry_json_walk_person_urls_callback c = { p, NULL, w, 0 };
1102 + dictionary_get_all(p->urls, registry_json_person_url_callback, &c);
1103 + buffer_strcat(w->response.data, "\n\t]\n");
1104
1105 - registry_json_footer(w);
1106 - return 200;
1105 + registry_json_footer(w);
1106 + return 200;
1107 }
1108
1109 // the main method for deleting a URL from a person
1110 int registry_request_delete_json(struct web_client *w, char *person_guid, char *machine_guid, char *url, char *delete_url, time_t when) {
1111 - if(!registry.enabled)
1112 - return registry_json_disabled(w, "delete");
1111 + if(!registry.enabled)
1112 + return registry_json_disabled(w, "delete");
1113
1114 - PERSON *p = registry_request_delete(person_guid, machine_guid, url, delete_url, when);
1115 - if(!p) {
1116 - registry_json_header(w, "delete", REGISTRY_STATUS_FAILED);
1117 - registry_json_footer(w);
1118 - return 412;
1119 - }
1114 + PERSON *p = registry_request_delete(person_guid, machine_guid, url, delete_url, when);
1115 + if(!p) {
1116 + registry_json_header(w, "delete", REGISTRY_STATUS_FAILED);
1117 + registry_json_footer(w);
1118 + return 412;
1119 + }
1120
1121 - // generate the response
1122 - registry_json_header(w, "delete", REGISTRY_STATUS_OK);
1123 - registry_json_footer(w);
1124 - return 200;
1121 + // generate the response
1122 + registry_json_header(w, "delete", REGISTRY_STATUS_OK);
1123 + registry_json_footer(w);
1124 + return 200;
1125 }
1126
1127 // the main method for searching the URLs of a netdata
1128 int registry_request_search_json(struct web_client *w, char *person_guid, char *machine_guid, char *url, char *request_machine, time_t when) {
1129 - if(!registry.enabled)
1130 - return registry_json_disabled(w, "search");
1129 + if(!registry.enabled)
1130 + return registry_json_disabled(w, "search");
1131
1132 - MACHINE *m = registry_request_machine(person_guid, machine_guid, url, request_machine, when);
1133 - if(!m) {
1134 - registry_json_header(w, "search", REGISTRY_STATUS_FAILED);
1135 - registry_json_footer(w);
1136 - return 404;
1137 - }
1132 + MACHINE *m = registry_request_machine(person_guid, machine_guid, url, request_machine, when);
1133 + if(!m) {
1134 + registry_json_header(w, "search", REGISTRY_STATUS_FAILED);
1135 + registry_json_footer(w);
1136 + return 404;
1137 + }
1138
1139 - registry_json_header(w, "search", REGISTRY_STATUS_OK);
1139 + registry_json_header(w, "search", REGISTRY_STATUS_OK);
1140
1141 - buffer_strcat(w->response.data, ",\n\t\"urls\": [");
1142 - struct registry_json_walk_person_urls_callback c = { NULL, m, w, 0 };
1143 - dictionary_get_all(m->urls, registry_json_machine_url_callback, &c);
1144 - buffer_strcat(w->response.data, "\n\t]\n");
1141 + buffer_strcat(w->response.data, ",\n\t\"urls\": [");
1142 + struct registry_json_walk_person_urls_callback c = { NULL, m, w, 0 };
1143 + dictionary_get_all(m->urls, registry_json_machine_url_callback, &c);
1144 + buffer_strcat(w->response.data, "\n\t]\n");
1145
1146 - registry_json_footer(w);
1147 - return 200;
1146 + registry_json_footer(w);
1147 + return 200;
1148 }
1149
1150 // structure used be the callbacks below
1151 struct registry_person_url_callback_verify_machine_exists_data {
1152 - MACHINE *m;
1153 - int count;
1152 + MACHINE *m;
1153 + int count;
1154 };
1155
1156 int registry_person_url_callback_verify_machine_exists(void *entry, void *data) {
1157 - struct registry_person_url_callback_verify_machine_exists_data *d = (struct registry_person_url_callback_verify_machine_exists_data *)data;
1158 - PERSON_URL *pu = (PERSON_URL *)entry;
1159 - MACHINE *m = d->m;
1157 + struct registry_person_url_callback_verify_machine_exists_data *d = (struct registry_person_url_callback_verify_machine_exists_data *)data;
1158 + PERSON_URL *pu = (PERSON_URL *)entry;
1159 + MACHINE *m = d->m;
1160
1161 - if(pu->machine == m)
1162 - d->count++;
1161 + if(pu->machine == m)
1162 + d->count++;
1163
1164 - return 0;
1164 + return 0;
1165 }
1166
1167 // the main method for switching user identity
1168 int registry_request_switch_json(struct web_client *w, char *person_guid, char *machine_guid, char *url, char *new_person_guid, time_t when) {
1169 - (void)url;
1170 - (void)when;
1171 -
1172 - if(!registry.enabled)
1173 - return registry_json_disabled(w, "switch");
1174 -
1175 - PERSON *op = registry_person_find(person_guid);
1176 - if(!op) {
1177 - registry_json_header(w, "switch", REGISTRY_STATUS_FAILED);
1178 - registry_json_footer(w);
1179 - return 430;
1180 - }
1181 -
1182 - PERSON *np = registry_person_find(new_person_guid);
1183 - if(!np) {
1184 - registry_json_header(w, "switch", REGISTRY_STATUS_FAILED);
1185 - registry_json_footer(w);
1186 - return 431;
1187 - }
1188 -
1189 - MACHINE *m = registry_machine_find(machine_guid);
1190 - if(!m) {
1191 - registry_json_header(w, "switch", REGISTRY_STATUS_FAILED);
1192 - registry_json_footer(w);
1193 - return 432;
1194 - }
1195 -
1196 - struct registry_person_url_callback_verify_machine_exists_data data = { m, 0 };
1197 -
1198 - // verify the old person has access to this machine
1199 - dictionary_get_all(op->urls, registry_person_url_callback_verify_machine_exists, &data);
1200 - if(!data.count) {
1201 - registry_json_header(w, "switch", REGISTRY_STATUS_FAILED);
1202 - registry_json_footer(w);
1203 - return 433;
1204 - }
1205 -
1206 - // verify the new person has access to this machine
1207 - data.count = 0;
1208 - dictionary_get_all(np->urls, registry_person_url_callback_verify_machine_exists, &data);
1209 - if(!data.count) {
1210 - registry_json_header(w, "switch", REGISTRY_STATUS_FAILED);
1211 - registry_json_footer(w);
1212 - return 434;
1213 - }
1214 -
1215 - // set the cookie of the new person
1216 - // the user just switched identity
1217 - registry_set_person_cookie(w, np);
1218 -
1219 - // generate the response
1220 - registry_json_header(w, "switch", REGISTRY_STATUS_OK);
1221 - buffer_sprintf(w->response.data, ",\n\t\"person_guid\": \"%s\"", np->guid);
1222 - registry_json_footer(w);
1223 - return 200;
1169 + (void)url;
1170 + (void)when;
1171 +
1172 + if(!registry.enabled)
1173 + return registry_json_disabled(w, "switch");
1174 +
1175 + PERSON *op = registry_person_find(person_guid);
1176 + if(!op) {
1177 + registry_json_header(w, "switch", REGISTRY_STATUS_FAILED);
1178 + registry_json_footer(w);
1179 + return 430;
1180 + }
1181 +
1182 + PERSON *np = registry_person_find(new_person_guid);
1183 + if(!np) {
1184 + registry_json_header(w, "switch", REGISTRY_STATUS_FAILED);
1185 + registry_json_footer(w);
1186 + return 431;
1187 + }
1188 +
1189 + MACHINE *m = registry_machine_find(machine_guid);
1190 + if(!m) {
1191 + registry_json_header(w, "switch", REGISTRY_STATUS_FAILED);
1192 + registry_json_footer(w);
1193 + return 432;
1194 + }
1195 +
1196 + struct registry_person_url_callback_verify_machine_exists_data data = { m, 0 };
1197 +
1198 + // verify the old person has access to this machine
1199 + dictionary_get_all(op->urls, registry_person_url_callback_verify_machine_exists, &data);
1200 + if(!data.count) {
1201 + registry_json_header(w, "switch", REGISTRY_STATUS_FAILED);
1202 + registry_json_footer(w);
1203 + return 433;
1204 + }
1205 +
1206 + // verify the new person has access to this machine
1207 + data.count = 0;
1208 + dictionary_get_all(np->urls, registry_person_url_callback_verify_machine_exists, &data);
1209 + if(!data.count) {
1210 + registry_json_header(w, "switch", REGISTRY_STATUS_FAILED);
1211 + registry_json_footer(w);
1212 + return 434;
1213 + }
1214 +
1215 + // set the cookie of the new person
1216 + // the user just switched identity
1217 + registry_set_person_cookie(w, np);
1218 +
1219 + // generate the response
1220 + registry_json_header(w, "switch", REGISTRY_STATUS_OK);
1221 + buffer_sprintf(w->response.data, ",\n\t\"person_guid\": \"%s\"", np->guid);
1222 + registry_json_footer(w);
1223 + return 200;
1224 }
1225
1226
@@ -1228,47 +1228,47 @@ int registry_request_switch_json(struct web_client *w, char *person_guid, char *
1228 // REGISTRY THIS MACHINE UNIQUE ID
1229
1230 char *registry_get_this_machine_guid(void) {
1231 - if(likely(registry.machine_guid[0]))
1232 - return registry.machine_guid;
1231 + if(likely(registry.machine_guid[0]))
1232 + return registry.machine_guid;
1233
1234 - // read it from disk
1235 - int fd = open(registry.machine_guid_filename, O_RDONLY);
1236 - if(fd != -1) {
1237 - char buf[36 + 1];
1238 - if(read(fd, buf, 36) != 36)
1239 - error("Failed to read machine GUID from '%s'", registry.machine_guid_filename);
1240 - else {
1241 - buf[36] = '\0';
1242 - if(registry_regenerate_guid(buf, registry.machine_guid) == -1) {
1243 - error("Failed to validate machine GUID '%s' from '%s'. Ignoring it - this might mean this netdata will appear as duplicate in the registry.",
1244 - buf, registry.machine_guid_filename);
1234 + // read it from disk
1235 + int fd = open(registry.machine_guid_filename, O_RDONLY);
1236 + if(fd != -1) {
1237 + char buf[36 + 1];
1238 + if(read(fd, buf, 36) != 36)
1239 + error("Failed to read machine GUID from '%s'", registry.machine_guid_filename);
1240 + else {
1241 + buf[36] = '\0';
1242 + if(registry_regenerate_guid(buf, registry.machine_guid) == -1) {
1243 + error("Failed to validate machine GUID '%s' from '%s'. Ignoring it - this might mean this netdata will appear as duplicate in the registry.",
1244 + buf, registry.machine_guid_filename);
1245
1246 - registry.machine_guid[0] = '\0';
1247 - }
1248 - }
1249 - close(fd);
1250 - }
1246 + registry.machine_guid[0] = '\0';
1247 + }
1248 + }
1249 + close(fd);
1250 + }
1251
1252 - // generate a new one?
1253 - if(!registry.machine_guid[0]) {
1254 - uuid_t uuid;
1252 + // generate a new one?
1253 + if(!registry.machine_guid[0]) {
1254 + uuid_t uuid;
1255
1256 - uuid_generate_time(uuid);
1257 - uuid_unparse_lower(uuid, registry.machine_guid);
1258 - registry.machine_guid[36] = '\0';
1256 + uuid_generate_time(uuid);
1257 + uuid_unparse_lower(uuid, registry.machine_guid);
1258 + registry.machine_guid[36] = '\0';
1259
1260 - // save it
1261 - fd = open(registry.machine_guid_filename, O_WRONLY|O_CREAT|O_TRUNC, 444);
1262 - if(fd == -1)
1263 - fatal("Cannot create unique machine id file '%s'. Please fix this.", registry.machine_guid_filename);
1260 + // save it
1261 + fd = open(registry.machine_guid_filename, O_WRONLY|O_CREAT|O_TRUNC, 444);
1262 + if(fd == -1)
1263 + fatal("Cannot create unique machine id file '%s'. Please fix this.", registry.machine_guid_filename);
1264
1265 - if(write(fd, registry.machine_guid, 36) != 36)
1266 - fatal("Cannot write the unique machine id file '%s'. Please fix this.", registry.machine_guid_filename);
1265 + if(write(fd, registry.machine_guid, 36) != 36)
1266 + fatal("Cannot write the unique machine id file '%s'. Please fix this.", registry.machine_guid_filename);
1267
1268 - close(fd);
1269 - }
1268 + close(fd);
1269 + }
1270
1271 - return registry.machine_guid;
1271 + return registry.machine_guid;
1272 }
1273
1274
@@ -1276,560 +1276,560 @@ char *registry_get_this_machine_guid(void) {
1276 // REGISTRY LOAD/SAVE
1277
1278 int registry_machine_save_url(void *entry, void *file) {
1279 - MACHINE_URL *mu = entry;
1280 - FILE *fp = file;
1279 + MACHINE_URL *mu = entry;
1280 + FILE *fp = file;
1281
1282 - debug(D_REGISTRY, "Registry: registry_machine_save_url('%s')", mu->url->url);
1282 + debug(D_REGISTRY, "Registry: registry_machine_save_url('%s')", mu->url->url);
1283
1284 - int ret = fprintf(fp, "V\t%08x\t%08x\t%08x\t%02x\t%s\n",
1285 - mu->first_t,
1286 - mu->last_t,
1287 - mu->usages,
1288 - mu->flags,
1289 - mu->url->url
1290 - );
1284 + int ret = fprintf(fp, "V\t%08x\t%08x\t%08x\t%02x\t%s\n",
1285 + mu->first_t,
1286 + mu->last_t,
1287 + mu->usages,
1288 + mu->flags,
1289 + mu->url->url
1290 + );
1291
1292 - // error handling is done at registry_save()
1292 + // error handling is done at registry_save()
1293
1294 - return ret;
1294 + return ret;
1295 }
1296
1297 int registry_machine_save(void *entry, void *file) {
1298 - MACHINE *m = entry;
1299 - FILE *fp = file;
1298 + MACHINE *m = entry;
1299 + FILE *fp = file;
1300
1301 - debug(D_REGISTRY, "Registry: registry_machine_save('%s')", m->guid);
1301 + debug(D_REGISTRY, "Registry: registry_machine_save('%s')", m->guid);
1302
1303 - int ret = fprintf(fp, "M\t%08x\t%08x\t%08x\t%s\n",
1304 - m->first_t,
1305 - m->last_t,
1306 - m->usages,
1307 - m->guid
1308 - );
1303 + int ret = fprintf(fp, "M\t%08x\t%08x\t%08x\t%s\n",
1304 + m->first_t,
1305 + m->last_t,
1306 + m->usages,
1307 + m->guid
1308 + );
1309
1310 - if(ret >= 0) {
1311 - int ret2 = dictionary_get_all(m->urls, registry_machine_save_url, fp);
1312 - if(ret2 < 0) return ret2;
1313 - ret += ret2;
1314 - }
1310 + if(ret >= 0) {
1311 + int ret2 = dictionary_get_all(m->urls, registry_machine_save_url, fp);
1312 + if(ret2 < 0) return ret2;
1313 + ret += ret2;
1314 + }
1315
1316 - // error handling is done at registry_save()
1316 + // error handling is done at registry_save()
1317
1318 - return ret;
1318 + return ret;
1319 }
1320
1321 static inline int registry_person_save_url(void *entry, void *file) {
1322 - PERSON_URL *pu = entry;
1323 - FILE *fp = file;
1322 + PERSON_URL *pu = entry;
1323 + FILE *fp = file;
1324
1325 - debug(D_REGISTRY, "Registry: registry_person_save_url('%s')", pu->url->url);
1325 + debug(D_REGISTRY, "Registry: registry_person_save_url('%s')", pu->url->url);
1326
1327 - int ret = fprintf(fp, "U\t%08x\t%08x\t%08x\t%02x\t%s\t%s\t%s\n",
1328 - pu->first_t,
1329 - pu->last_t,
1330 - pu->usages,
1331 - pu->flags,
1332 - pu->machine->guid,
1333 - pu->name,
1334 - pu->url->url
1335 - );
1327 + int ret = fprintf(fp, "U\t%08x\t%08x\t%08x\t%02x\t%s\t%s\t%s\n",
1328 + pu->first_t,
1329 + pu->last_t,
1330 + pu->usages,
1331 + pu->flags,
1332 + pu->machine->guid,
1333 + pu->name,
1334 + pu->url->url
1335 + );
1336
1337 - // error handling is done at registry_save()
1337 + // error handling is done at registry_save()
1338
1339 - return ret;
1339 + return ret;
1340 }
1341
1342 static inline int registry_person_save(void *entry, void *file) {
1343 - PERSON *p = entry;
1344 - FILE *fp = file;
1343 + PERSON *p = entry;
1344 + FILE *fp = file;
1345
1346 - debug(D_REGISTRY, "Registry: registry_person_save('%s')", p->guid);
1346 + debug(D_REGISTRY, "Registry: registry_person_save('%s')", p->guid);
1347
1348 - int ret = fprintf(fp, "P\t%08x\t%08x\t%08x\t%s\n",
1349 - p->first_t,
1350 - p->last_t,
1351 - p->usages,
1352 - p->guid
1353 - );
1348 + int ret = fprintf(fp, "P\t%08x\t%08x\t%08x\t%s\n",
1349 + p->first_t,
1350 + p->last_t,
1351 + p->usages,
1352 + p->guid
1353 + );
1354
1355 - if(ret >= 0) {
1356 - int ret2 = dictionary_get_all(p->urls, registry_person_save_url, fp);
1357 - if (ret2 < 0) return ret2;
1358 - ret += ret2;
1359 - }
1355 + if(ret >= 0) {
1356 + int ret2 = dictionary_get_all(p->urls, registry_person_save_url, fp);
1357 + if (ret2 < 0) return ret2;
1358 + ret += ret2;
1359 + }
1360
1361 - // error handling is done at registry_save()
1361 + // error handling is done at registry_save()
1362
1363 - return ret;
1363 + return ret;
1364 }
1365
1366 int registry_save(void) {
1367 - if(!registry.enabled) return -1;
1368 -
1369 - // make sure the log is not updated
1370 - registry_log_lock();
1371 -
1372 - if(unlikely(!registry_should_save_db())) {
1373 - registry_log_unlock();
1374 - return -2;
1375 - }
1376 -
1377 - char tmp_filename[FILENAME_MAX + 1];
1378 - char old_filename[FILENAME_MAX + 1];
1379 -
1380 - snprintfz(old_filename, FILENAME_MAX, "%s.old", registry.db_filename);
1381 - snprintfz(tmp_filename, FILENAME_MAX, "%s.tmp", registry.db_filename);
1382 -
1383 - debug(D_REGISTRY, "Registry: Creating file '%s'", tmp_filename);
1384 - FILE *fp = fopen(tmp_filename, "w");
1385 - if(!fp) {
1386 - error("Registry: Cannot create file: %s", tmp_filename);
1387 - registry_log_unlock();
1388 - return -1;
1389 - }
1390 -
1391 - // dictionary_get_all() has its own locking, so this is safe to do
1392 -
1393 - debug(D_REGISTRY, "Saving all machines");
1394 - int bytes1 = dictionary_get_all(registry.machines, registry_machine_save, fp);
1395 - if(bytes1 < 0) {
1396 - error("Registry: Cannot save registry machines - return value %d", bytes1);
1397 - fclose(fp);
1398 - registry_log_unlock();
1399 - return bytes1;
1400 - }
1401 - debug(D_REGISTRY, "Registry: saving machines took %d bytes", bytes1);
1402 -
1403 - debug(D_REGISTRY, "Saving all persons");
1404 - int bytes2 = dictionary_get_all(registry.persons, registry_person_save, fp);
1405 - if(bytes2 < 0) {
1406 - error("Registry: Cannot save registry persons - return value %d", bytes2);
1407 - fclose(fp);
1408 - registry_log_unlock();
1409 - return bytes2;
1410 - }
1411 - debug(D_REGISTRY, "Registry: saving persons took %d bytes", bytes2);
1412 -
1413 - // save the totals
1414 - fprintf(fp, "T\t%016llx\t%016llx\t%016llx\t%016llx\t%016llx\t%016llx\n",
1415 - registry.persons_count,
1416 - registry.machines_count,
1417 - registry.usages_count + 1, // this is required - it is lost on db rotation
1418 - registry.urls_count,
1419 - registry.persons_urls_count,
1420 - registry.machines_urls_count
1421 - );
1422 -
1423 - fclose(fp);
1424 -
1425 - errno = 0;
1426 -
1427 - // remove the .old db
1428 - debug(D_REGISTRY, "Registry: Removing old db '%s'", old_filename);
1429 - if(unlink(old_filename) == -1 && errno != ENOENT)
1430 - error("Registry: cannot remove old registry file '%s'", old_filename);
1431 -
1432 - // rename the db to .old
1433 - debug(D_REGISTRY, "Registry: Link current db '%s' to .old: '%s'", registry.db_filename, old_filename);
1434 - if(link(registry.db_filename, old_filename) == -1 && errno != ENOENT)
1435 - error("Registry: cannot move file '%s' to '%s'. Saving registry DB failed!", tmp_filename, registry.db_filename);
1436 -
1437 - else {
1438 - // remove the database (it is saved in .old)
1439 - debug(D_REGISTRY, "Registry: removing db '%s'", registry.db_filename);
1440 - if (unlink(registry.db_filename) == -1 && errno != ENOENT)
1441 - error("Registry: cannot remove old registry file '%s'", registry.db_filename);
1442 -
1443 - // move the .tmp to make it active
1444 - debug(D_REGISTRY, "Registry: linking tmp db '%s' to active db '%s'", tmp_filename, registry.db_filename);
1445 - if (link(tmp_filename, registry.db_filename) == -1) {
1446 - error("Registry: cannot move file '%s' to '%s'. Saving registry DB failed!", tmp_filename,
1447 - registry.db_filename);
1448 -
1449 - // move the .old back
1450 - debug(D_REGISTRY, "Registry: linking old db '%s' to active db '%s'", old_filename, registry.db_filename);
1451 - if(link(old_filename, registry.db_filename) == -1)
1452 - error("Registry: cannot move file '%s' to '%s'. Recovering the old registry DB failed!", old_filename, registry.db_filename);
1453 - }
1454 - else {
1455 - debug(D_REGISTRY, "Registry: removing tmp db '%s'", tmp_filename);
1456 - if(unlink(tmp_filename) == -1)
1457 - error("Registry: cannot remove tmp registry file '%s'", tmp_filename);
1458 -
1459 - // it has been moved successfully
1460 - // discard the current registry log
1461 - registry_log_recreate_nolock();
1462 -
1463 - registry.log_count = 0;
1464 - }
1465 - }
1466 -
1467 - // continue operations
1468 - registry_log_unlock();
1469 -
1470 - return -1;
1367 + if(!registry.enabled) return -1;
1368 +
1369 + // make sure the log is not updated
1370 + registry_log_lock();
1371 +
1372 + if(unlikely(!registry_should_save_db())) {
1373 + registry_log_unlock();
1374 + return -2;
1375 + }
1376 +
1377 + char tmp_filename[FILENAME_MAX + 1];
1378 + char old_filename[FILENAME_MAX + 1];
1379 +
1380 + snprintfz(old_filename, FILENAME_MAX, "%s.old", registry.db_filename);
1381 + snprintfz(tmp_filename, FILENAME_MAX, "%s.tmp", registry.db_filename);
1382 +
1383 + debug(D_REGISTRY, "Registry: Creating file '%s'", tmp_filename);
1384 + FILE *fp = fopen(tmp_filename, "w");
1385 + if(!fp) {
1386 + error("Registry: Cannot create file: %s", tmp_filename);
1387 + registry_log_unlock();
1388 + return -1;
1389 + }
1390 +
1391 + // dictionary_get_all() has its own locking, so this is safe to do
1392 +
1393 + debug(D_REGISTRY, "Saving all machines");
1394 + int bytes1 = dictionary_get_all(registry.machines, registry_machine_save, fp);
1395 + if(bytes1 < 0) {
1396 + error("Registry: Cannot save registry machines - return value %d", bytes1);
1397 + fclose(fp);
1398 + registry_log_unlock();
1399 + return bytes1;
1400 + }
1401 + debug(D_REGISTRY, "Registry: saving machines took %d bytes", bytes1);
1402 +
1403 + debug(D_REGISTRY, "Saving all persons");
1404 + int bytes2 = dictionary_get_all(registry.persons, registry_person_save, fp);
1405 + if(bytes2 < 0) {
1406 + error("Registry: Cannot save registry persons - return value %d", bytes2);
1407 + fclose(fp);
1408 + registry_log_unlock();
1409 + return bytes2;
1410 + }
1411 + debug(D_REGISTRY, "Registry: saving persons took %d bytes", bytes2);
1412 +
1413 + // save the totals
1414 + fprintf(fp, "T\t%016llx\t%016llx\t%016llx\t%016llx\t%016llx\t%016llx\n",
1415 + registry.persons_count,
1416 + registry.machines_count,
1417 + registry.usages_count + 1, // this is required - it is lost on db rotation
1418 + registry.urls_count,
1419 + registry.persons_urls_count,
1420 + registry.machines_urls_count
1421 + );
1422 +
1423 + fclose(fp);
1424 +
1425 + errno = 0;
1426 +
1427 + // remove the .old db
1428 + debug(D_REGISTRY, "Registry: Removing old db '%s'", old_filename);
1429 + if(unlink(old_filename) == -1 && errno != ENOENT)
1430 + error("Registry: cannot remove old registry file '%s'", old_filename);
1431 +
1432 + // rename the db to .old
1433 + debug(D_REGISTRY, "Registry: Link current db '%s' to .old: '%s'", registry.db_filename, old_filename);
1434 + if(link(registry.db_filename, old_filename) == -1 && errno != ENOENT)
1435 + error("Registry: cannot move file '%s' to '%s'. Saving registry DB failed!", tmp_filename, registry.db_filename);
1436 +
1437 + else {
1438 + // remove the database (it is saved in .old)
1439 + debug(D_REGISTRY, "Registry: removing db '%s'", registry.db_filename);
1440 + if (unlink(registry.db_filename) == -1 && errno != ENOENT)
1441 + error("Registry: cannot remove old registry file '%s'", registry.db_filename);
1442 +
1443 + // move the .tmp to make it active
1444 + debug(D_REGISTRY, "Registry: linking tmp db '%s' to active db '%s'", tmp_filename, registry.db_filename);
1445 + if (link(tmp_filename, registry.db_filename) == -1) {
1446 + error("Registry: cannot move file '%s' to '%s'. Saving registry DB failed!", tmp_filename,
1447 + registry.db_filename);
1448 +
1449 + // move the .old back
1450 + debug(D_REGISTRY, "Registry: linking old db '%s' to active db '%s'", old_filename, registry.db_filename);
1451 + if(link(old_filename, registry.db_filename) == -1)
1452 + error("Registry: cannot move file '%s' to '%s'. Recovering the old registry DB failed!", old_filename, registry.db_filename);
1453 + }
1454 + else {
1455 + debug(D_REGISTRY, "Registry: removing tmp db '%s'", tmp_filename);
1456 + if(unlink(tmp_filename) == -1)
1457 + error("Registry: cannot remove tmp registry file '%s'", tmp_filename);
1458 +
1459 + // it has been moved successfully
1460 + // discard the current registry log
1461 + registry_log_recreate_nolock();
1462 +
1463 + registry.log_count = 0;
1464 + }
1465 + }
1466 +
1467 + // continue operations
1468 + registry_log_unlock();
1469 +
1470 + return -1;
1471 }
1472
1473 static inline size_t registry_load(void) {
1474 - char *s, buf[4096 + 1];
1475 - PERSON *p = NULL;
1476 - MACHINE *m = NULL;
1477 - URL *u = NULL;
1478 - size_t line = 0;
1479 -
1480 - debug(D_REGISTRY, "Registry: loading active db from: '%s'", registry.db_filename);
1481 - FILE *fp = fopen(registry.db_filename, "r");
1482 - if(!fp) {
1483 - error("Registry: cannot open registry file: '%s'", registry.db_filename);
1484 - return 0;
1485 - }
1486 -
1487 - size_t len = 0;
1488 - buf[4096] = '\0';
1489 - while((s = fgets_trim_len(buf, 4096, fp, &len))) {
1490 - line++;
1491 -
1492 - debug(D_REGISTRY, "Registry: read line %zu to length %zu: %s", line, len, s);
1493 - switch(*s) {
1494 - case 'T': // totals
1495 - if(unlikely(len != 103 || s[1] != '\t' || s[18] != '\t' || s[35] != '\t' || s[52] != '\t' || s[69] != '\t' || s[86] != '\t' || s[103] != '\0')) {
1496 - error("Registry totals line %zu is wrong (len = %zu).", line, len);
1497 - continue;
1498 - }
1499 - registry.persons_count = strtoull(&s[2], NULL, 16);
1500 - registry.machines_count = strtoull(&s[19], NULL, 16);
1501 - registry.usages_count = strtoull(&s[36], NULL, 16);
1502 - registry.urls_count = strtoull(&s[53], NULL, 16);
1503 - registry.persons_urls_count = strtoull(&s[70], NULL, 16);
1504 - registry.machines_urls_count = strtoull(&s[87], NULL, 16);
1505 - break;
1506 -
1507 - case 'P': // person
1508 - m = NULL;
1509 - // verify it is valid
1510 - if(unlikely(len != 65 || s[1] != '\t' || s[10] != '\t' || s[19] != '\t' || s[28] != '\t' || s[65] != '\0')) {
1511 - error("Registry person line %zu is wrong (len = %zu).", line, len);
1512 - continue;
1513 - }
1514 -
1515 - s[1] = s[10] = s[19] = s[28] = '\0';
1516 - p = registry_person_allocate(&s[29], strtoul(&s[2], NULL, 16));
1517 - p->last_t = strtoul(&s[11], NULL, 16);
1518 - p->usages = strtoul(&s[20], NULL, 16);
1519 - debug(D_REGISTRY, "Registry loaded person '%s', first: %u, last: %u, usages: %u", p->guid, p->first_t, p->last_t, p->usages);
1520 - break;
1521 -
1522 - case 'M': // machine
1523 - p = NULL;
1524 - // verify it is valid
1525 - if(unlikely(len != 65 || s[1] != '\t' || s[10] != '\t' || s[19] != '\t' || s[28] != '\t' || s[65] != '\0')) {
1526 - error("Registry person line %zu is wrong (len = %zu).", line, len);
1527 - continue;
1528 - }
1529 -
1530 - s[1] = s[10] = s[19] = s[28] = '\0';
1531 - m = registry_machine_allocate(&s[29], strtoul(&s[2], NULL, 16));
1532 - m->last_t = strtoul(&s[11], NULL, 16);
1533 - m->usages = strtoul(&s[20], NULL, 16);
1534 - debug(D_REGISTRY, "Registry loaded machine '%s', first: %u, last: %u, usages: %u", m->guid, m->first_t, m->last_t, m->usages);
1535 - break;
1536 -
1537 - case 'U': // person URL
1538 - if(unlikely(!p)) {
1539 - error("Registry: ignoring line %zu, no person loaded: %s", line, s);
1540 - continue;
1541 - }
1542 -
1543 - // verify it is valid
1544 - if(len < 69 || s[1] != '\t' || s[10] != '\t' || s[19] != '\t' || s[28] != '\t' || s[31] != '\t' || s[68] != '\t') {
1545 - error("Registry person URL line %zu is wrong (len = %zu).", line, len);
1546 - continue;
1547 - }
1548 -
1549 - s[1] = s[10] = s[19] = s[28] = s[31] = s[68] = '\0';
1550 -
1551 - // skip the name to find the url
1552 - char *url = &s[69];
1553 - while(*url && *url != '\t') url++;
1554 - if(!*url) {
1555 - error("Registry person URL line %zu does not have a url.", line);
1556 - continue;
1557 - }
1558 - *url++ = '\0';
1559 -
1560 - u = registry_url_allocate_nolock(url, strlen(url));
1561 -
1562 - time_t first_t = strtoul(&s[2], NULL, 16);
1563 -
1564 - m = registry_machine_find(&s[32]);
1565 - if(!m) m = registry_machine_allocate(&s[32], first_t);
1566 -
1567 - PERSON_URL *pu = registry_person_url_allocate(p, m, u, &s[69], strlen(&s[69]), first_t);
1568 - pu->last_t = strtoul(&s[11], NULL, 16);
1569 - pu->usages = strtoul(&s[20], NULL, 16);
1570 - pu->flags = strtoul(&s[29], NULL, 16);
1571 - debug(D_REGISTRY, "Registry loaded person URL '%s' with name '%s' of machine '%s', first: %u, last: %u, usages: %u, flags: %02x", u->url, pu->name, m->guid, pu->first_t, pu->last_t, pu->usages, pu->flags);
1572 - break;
1573 -
1574 - case 'V': // machine URL
1575 - if(unlikely(!m)) {
1576 - error("Registry: ignoring line %zu, no machine loaded: %s", line, s);
1577 - continue;
1578 - }
1579 -
1580 - // verify it is valid
1581 - if(len < 32 || s[1] != '\t' || s[10] != '\t' || s[19] != '\t' || s[28] != '\t' || s[31] != '\t') {
1582 - error("Registry person URL line %zu is wrong (len = %zu).", line, len);
1583 - continue;
1584 - }
1585 -
1586 - s[1] = s[10] = s[19] = s[28] = s[31] = '\0';
1587 - u = registry_url_allocate_nolock(&s[32], strlen(&s[32]));
1588 -
1589 - MACHINE_URL *mu = registry_machine_url_allocate(m, u, strtoul(&s[2], NULL, 16));
1590 - mu->last_t = strtoul(&s[11], NULL, 16);
1591 - mu->usages = strtoul(&s[20], NULL, 16);
1592 - mu->flags = strtoul(&s[29], NULL, 16);
1593 - debug(D_REGISTRY, "Registry loaded machine URL '%s', machine '%s', first: %u, last: %u, usages: %u, flags: %02x", u->url, m->guid, mu->first_t, mu->last_t, mu->usages, mu->flags);
1594 - break;
1595 -
1596 - default:
1597 - error("Registry: ignoring line %zu of filename '%s': %s.", line, registry.db_filename, s);
1598 - break;
1599 - }
1600 - }
1601 - fclose(fp);
1602 -
1603 - return line;
1474 + char *s, buf[4096 + 1];
1475 + PERSON *p = NULL;
1476 + MACHINE *m = NULL;
1477 + URL *u = NULL;
1478 + size_t line = 0;
1479 +
1480 + debug(D_REGISTRY, "Registry: loading active db from: '%s'", registry.db_filename);
1481 + FILE *fp = fopen(registry.db_filename, "r");
1482 + if(!fp) {
1483 + error("Registry: cannot open registry file: '%s'", registry.db_filename);
1484 + return 0;
1485 + }
1486 +
1487 + size_t len = 0;
1488 + buf[4096] = '\0';
1489 + while((s = fgets_trim_len(buf, 4096, fp, &len))) {
1490 + line++;
1491 +
1492 + debug(D_REGISTRY, "Registry: read line %zu to length %zu: %s", line, len, s);
1493 + switch(*s) {
1494 + case 'T': // totals
1495 + if(unlikely(len != 103 || s[1] != '\t' || s[18] != '\t' || s[35] != '\t' || s[52] != '\t' || s[69] != '\t' || s[86] != '\t' || s[103] != '\0')) {
1496 + error("Registry totals line %zu is wrong (len = %zu).", line, len);
1497 + continue;
1498 + }
1499 + registry.persons_count = strtoull(&s[2], NULL, 16);
1500 + registry.machines_count = strtoull(&s[19], NULL, 16);
1501 + registry.usages_count = strtoull(&s[36], NULL, 16);
1502 + registry.urls_count = strtoull(&s[53], NULL, 16);
1503 + registry.persons_urls_count = strtoull(&s[70], NULL, 16);
1504 + registry.machines_urls_count = strtoull(&s[87], NULL, 16);
1505 + break;
1506 +
1507 + case 'P': // person
1508 + m = NULL;
1509 + // verify it is valid
1510 + if(unlikely(len != 65 || s[1] != '\t' || s[10] != '\t' || s[19] != '\t' || s[28] != '\t' || s[65] != '\0')) {
1511 + error("Registry person line %zu is wrong (len = %zu).", line, len);
1512 + continue;
1513 + }
1514 +
1515 + s[1] = s[10] = s[19] = s[28] = '\0';
1516 + p = registry_person_allocate(&s[29], strtoul(&s[2], NULL, 16));
1517 + p->last_t = strtoul(&s[11], NULL, 16);
1518 + p->usages = strtoul(&s[20], NULL, 16);
1519 + debug(D_REGISTRY, "Registry loaded person '%s', first: %u, last: %u, usages: %u", p->guid, p->first_t, p->last_t, p->usages);
1520 + break;
1521 +
1522 + case 'M': // machine
1523 + p = NULL;
1524 + // verify it is valid
1525 + if(unlikely(len != 65 || s[1] != '\t' || s[10] != '\t' || s[19] != '\t' || s[28] != '\t' || s[65] != '\0')) {
1526 + error("Registry person line %zu is wrong (len = %zu).", line, len);
1527 + continue;
1528 + }
1529 +
1530 + s[1] = s[10] = s[19] = s[28] = '\0';
1531 + m = registry_machine_allocate(&s[29], strtoul(&s[2], NULL, 16));
1532 + m->last_t = strtoul(&s[11], NULL, 16);
1533 + m->usages = strtoul(&s[20], NULL, 16);
1534 + debug(D_REGISTRY, "Registry loaded machine '%s', first: %u, last: %u, usages: %u", m->guid, m->first_t, m->last_t, m->usages);
1535 + break;
1536 +
1537 + case 'U': // person URL
1538 + if(unlikely(!p)) {
1539 + error("Registry: ignoring line %zu, no person loaded: %s", line, s);
1540 + continue;
1541 + }
1542 +
1543 + // verify it is valid
1544 + if(len < 69 || s[1] != '\t' || s[10] != '\t' || s[19] != '\t' || s[28] != '\t' || s[31] != '\t' || s[68] != '\t') {
1545 + error("Registry person URL line %zu is wrong (len = %zu).", line, len);
1546 + continue;
1547 + }
1548 +
1549 + s[1] = s[10] = s[19] = s[28] = s[31] = s[68] = '\0';
1550 +
1551 + // skip the name to find the url
1552 + char *url = &s[69];
1553 + while(*url && *url != '\t') url++;
1554 + if(!*url) {
1555 + error("Registry person URL line %zu does not have a url.", line);
1556 + continue;
1557 + }
1558 + *url++ = '\0';
1559 +
1560 + u = registry_url_allocate_nolock(url, strlen(url));
1561 +
1562 + time_t first_t = strtoul(&s[2], NULL, 16);
1563 +
1564 + m = registry_machine_find(&s[32]);
1565 + if(!m) m = registry_machine_allocate(&s[32], first_t);
1566 +
1567 + PERSON_URL *pu = registry_person_url_allocate(p, m, u, &s[69], strlen(&s[69]), first_t);
1568 + pu->last_t = strtoul(&s[11], NULL, 16);
1569 + pu->usages = strtoul(&s[20], NULL, 16);
1570 + pu->flags = strtoul(&s[29], NULL, 16);
1571 + debug(D_REGISTRY, "Registry loaded person URL '%s' with name '%s' of machine '%s', first: %u, last: %u, usages: %u, flags: %02x", u->url, pu->name, m->guid, pu->first_t, pu->last_t, pu->usages, pu->flags);
1572 + break;
1573 +
1574 + case 'V': // machine URL
1575 + if(unlikely(!m)) {
1576 + error("Registry: ignoring line %zu, no machine loaded: %s", line, s);
1577 + continue;
1578 + }
1579 +
1580 + // verify it is valid
1581 + if(len < 32 || s[1] != '\t' || s[10] != '\t' || s[19] != '\t' || s[28] != '\t' || s[31] != '\t') {
1582 + error("Registry person URL line %zu is wrong (len = %zu).", line, len);
1583 + continue;
1584 + }
1585 +
1586 + s[1] = s[10] = s[19] = s[28] = s[31] = '\0';
1587 + u = registry_url_allocate_nolock(&s[32], strlen(&s[32]));
1588 +
1589 + MACHINE_URL *mu = registry_machine_url_allocate(m, u, strtoul(&s[2], NULL, 16));
1590 + mu->last_t = strtoul(&s[11], NULL, 16);
1591 + mu->usages = strtoul(&s[20], NULL, 16);
1592 + mu->flags = strtoul(&s[29], NULL, 16);
1593 + debug(D_REGISTRY, "Registry loaded machine URL '%s', machine '%s', first: %u, last: %u, usages: %u, flags: %02x", u->url, m->guid, mu->first_t, mu->last_t, mu->usages, mu->flags);
1594 + break;
1595 +
1596 + default:
1597 + error("Registry: ignoring line %zu of filename '%s': %s.", line, registry.db_filename, s);
1598 + break;
1599 + }
1600 + }
1601 + fclose(fp);
1602 +
1603 + return line;
1604 }
1605
1606 // ----------------------------------------------------------------------------
1607 // REGISTRY
1608
1609 int registry_init(void) {
1610 - char filename[FILENAME_MAX + 1];
1611 -
1612 - // registry enabled?
1613 - registry.enabled = config_get_boolean("registry", "enabled", 0);
1614 -
1615 - if(mkdir(VARLIB_DIR, 0755) == -1 && errno != EEXIST)
1616 - error("Cannot create directory '" VARLIB_DIR "'");
1617 -
1618 - // pathnames
1619 - registry.pathname = config_get("registry", "registry db directory", VARLIB_DIR "/registry");
1620 - if(mkdir(registry.pathname, 0755) == -1 && errno != EEXIST) {
1621 - error("Cannot create directory '%s'. Registry disabled.", registry.pathname);
1622 - registry.enabled = 0;
1623 - return -1;
1624 - }
1625 -
1626 - // filenames
1627 - snprintfz(filename, FILENAME_MAX, "%s/netdata.public.unique.id", registry.pathname);
1628 - registry.machine_guid_filename = config_get("registry", "netdata unique id file", filename);
1629 - registry_get_this_machine_guid();
1630 -
1631 - snprintfz(filename, FILENAME_MAX, "%s/registry.db", registry.pathname);
1632 - registry.db_filename = config_get("registry", "registry db file", filename);
1633 -
1634 - snprintfz(filename, FILENAME_MAX, "%s/registry-log.db", registry.pathname);
1635 - registry.log_filename = config_get("registry", "registry log file", filename);
1636 -
1637 - // configuration options
1638 - registry.save_registry_every_entries = config_get_number("registry", "registry save db every new entries", 1000000);
1639 - registry.persons_expiration = config_get_number("registry", "registry expire idle persons days", 365) * 86400;
1640 - registry.registry_domain = config_get("registry", "registry domain", "");
1641 - registry.registry_to_announce = config_get("registry", "registry to announce", "https://registry.my-netdata.io");
1642 - registry.hostname = config_get("registry", "registry hostname", config_get("global", "hostname", hostname));
1643 - registry.verify_cookies_redirects = config_get_boolean("registry", "verify browser cookies support", 1);
1644 -
1645 - registry.max_url_length = config_get_number("registry", "max URL length", 1024);
1646 - if(registry.max_url_length < 10) {
1647 - registry.max_url_length = 10;
1648 - config_set_number("registry", "max URL length", registry.max_url_length);
1649 - }
1650 -
1651 - registry.max_name_length = config_get_number("registry", "max URL name length", 50);
1652 - if(registry.max_name_length < 10) {
1653 - registry.max_name_length = 10;
1654 - config_set_number("registry", "max URL name length", registry.max_name_length);
1655 - }
1656 -
1657 - // initialize entries counters
1658 - registry.persons_count = 0;
1659 - registry.machines_count = 0;
1660 - registry.usages_count = 0;
1661 - registry.urls_count = 0;
1662 - registry.persons_urls_count = 0;
1663 - registry.machines_urls_count = 0;
1664 -
1665 - // initialize memory counters
1666 - registry.persons_memory = 0;
1667 - registry.machines_memory = 0;
1668 - registry.urls_memory = 0;
1669 - registry.persons_urls_memory = 0;
1670 - registry.machines_urls_memory = 0;
1671 -
1672 - // initialize locks
1673 - pthread_mutex_init(&registry.persons_lock, NULL);
1674 - pthread_mutex_init(&registry.machines_lock, NULL);
1675 - pthread_mutex_init(&registry.urls_lock, NULL);
1676 - pthread_mutex_init(&registry.person_urls_lock, NULL);
1677 - pthread_mutex_init(&registry.machine_urls_lock, NULL);
1678 -
1679 - // create dictionaries
1680 - registry.persons = dictionary_create(DICTIONARY_FLAGS);
1681 - registry.machines = dictionary_create(DICTIONARY_FLAGS);
1682 - registry.urls = dictionary_create(DICTIONARY_FLAGS);
1683 -
1684 - // load the registry database
1685 - if(registry.enabled) {
1686 - registry_log_open_nolock();
1687 - registry_load();
1688 - registry_log_load();
1689 - }
1690 -
1691 - return 0;
1610 + char filename[FILENAME_MAX + 1];
1611 +
1612 + // registry enabled?
1613 + registry.enabled = config_get_boolean("registry", "enabled", 0);
1614 +
1615 + if(mkdir(VARLIB_DIR, 0755) == -1 && errno != EEXIST)
1616 + error("Cannot create directory '" VARLIB_DIR "'");
1617 +
1618 + // pathnames
1619 + registry.pathname = config_get("registry", "registry db directory", VARLIB_DIR "/registry");
1620 + if(mkdir(registry.pathname, 0755) == -1 && errno != EEXIST) {
1621 + error("Cannot create directory '%s'. Registry disabled.", registry.pathname);
1622 + registry.enabled = 0;
1623 + return -1;
1624 + }
1625 +
1626 + // filenames
1627 + snprintfz(filename, FILENAME_MAX, "%s/netdata.public.unique.id", registry.pathname);
1628 + registry.machine_guid_filename = config_get("registry", "netdata unique id file", filename);
1629 + registry_get_this_machine_guid();
1630 +
1631 + snprintfz(filename, FILENAME_MAX, "%s/registry.db", registry.pathname);
1632 + registry.db_filename = config_get("registry", "registry db file", filename);
1633 +
1634 + snprintfz(filename, FILENAME_MAX, "%s/registry-log.db", registry.pathname);
1635 + registry.log_filename = config_get("registry", "registry log file", filename);
1636 +
1637 + // configuration options
1638 + registry.save_registry_every_entries = config_get_number("registry", "registry save db every new entries", 1000000);
1639 + registry.persons_expiration = config_get_number("registry", "registry expire idle persons days", 365) * 86400;
1640 + registry.registry_domain = config_get("registry", "registry domain", "");
1641 + registry.registry_to_announce = config_get("registry", "registry to announce", "https://registry.my-netdata.io");
1642 + registry.hostname = config_get("registry", "registry hostname", config_get("global", "hostname", hostname));
1643 + registry.verify_cookies_redirects = config_get_boolean("registry", "verify browser cookies support", 1);
1644 +
1645 + registry.max_url_length = config_get_number("registry", "max URL length", 1024);
1646 + if(registry.max_url_length < 10) {
1647 + registry.max_url_length = 10;
1648 + config_set_number("registry", "max URL length", registry.max_url_length);
1649 + }
1650 +
1651 + registry.max_name_length = config_get_number("registry", "max URL name length", 50);
1652 + if(registry.max_name_length < 10) {
1653 + registry.max_name_length = 10;
1654 + config_set_number("registry", "max URL name length", registry.max_name_length);
1655 + }
1656 +
1657 + // initialize entries counters
1658 + registry.persons_count = 0;
1659 + registry.machines_count = 0;
1660 + registry.usages_count = 0;
1661 + registry.urls_count = 0;
1662 + registry.persons_urls_count = 0;
1663 + registry.machines_urls_count = 0;
1664 +
1665 + // initialize memory counters
1666 + registry.persons_memory = 0;
1667 + registry.machines_memory = 0;
1668 + registry.urls_memory = 0;
1669 + registry.persons_urls_memory = 0;
1670 + registry.machines_urls_memory = 0;
1671 +
1672 + // initialize locks
1673 + pthread_mutex_init(&registry.persons_lock, NULL);
1674 + pthread_mutex_init(&registry.machines_lock, NULL);
1675 + pthread_mutex_init(&registry.urls_lock, NULL);
1676 + pthread_mutex_init(&registry.person_urls_lock, NULL);
1677 + pthread_mutex_init(&registry.machine_urls_lock, NULL);
1678 +
1679 + // create dictionaries
1680 + registry.persons = dictionary_create(DICTIONARY_FLAGS);
1681 + registry.machines = dictionary_create(DICTIONARY_FLAGS);
1682 + registry.urls = dictionary_create(DICTIONARY_FLAGS);
1683 +
1684 + // load the registry database
1685 + if(registry.enabled) {
1686 + registry_log_open_nolock();
1687 + registry_load();
1688 + registry_log_load();
1689 + }
1690 +
1691 + return 0;
1692 }
1693
1694 void registry_free(void) {
1695 - if(!registry.enabled) return;
1695 + if(!registry.enabled) return;
1696
1697 - // we need to destroy the dictionaries ourselves
1698 - // since the dictionaries use memory we allocated
1697 + // we need to destroy the dictionaries ourselves
1698 + // since the dictionaries use memory we allocated
1699
1700 - while(registry.persons->values_index.root) {
1701 - PERSON *p = ((NAME_VALUE *)registry.persons->values_index.root)->value;
1700 + while(registry.persons->values_index.root) {
1701 + PERSON *p = ((NAME_VALUE *)registry.persons->values_index.root)->value;
1702
1703 - // fprintf(stderr, "\nPERSON: '%s', first: %u, last: %u, usages: %u\n", p->guid, p->first_t, p->last_t, p->usages);
1703 + // fprintf(stderr, "\nPERSON: '%s', first: %u, last: %u, usages: %u\n", p->guid, p->first_t, p->last_t, p->usages);
1704
1705 - while(p->urls->values_index.root) {
1706 - PERSON_URL *pu = ((NAME_VALUE *)p->urls->values_index.root)->value;
1705 + while(p->urls->values_index.root) {
1706 + PERSON_URL *pu = ((NAME_VALUE *)p->urls->values_index.root)->value;
1707
1708 - // fprintf(stderr, "\tURL: '%s', first: %u, last: %u, usages: %u, flags: 0x%02x\n", pu->url->url, pu->first_t, pu->last_t, pu->usages, pu->flags);
1708 + // fprintf(stderr, "\tURL: '%s', first: %u, last: %u, usages: %u, flags: 0x%02x\n", pu->url->url, pu->first_t, pu->last_t, pu->usages, pu->flags);
1709
1710 - debug(D_REGISTRY, "Registry: deleting url '%s' from person '%s'", pu->url->url, p->guid);
1711 - dictionary_del(p->urls, pu->url->url);
1710 + debug(D_REGISTRY, "Registry: deleting url '%s' from person '%s'", pu->url->url, p->guid);
1711 + dictionary_del(p->urls, pu->url->url);
1712
1713 - debug(D_REGISTRY, "Registry: unlinking url '%s' from person", pu->url->url);
1714 - registry_url_unlink_nolock(pu->url);
1713 + debug(D_REGISTRY, "Registry: unlinking url '%s' from person", pu->url->url);
1714 + registry_url_unlink_nolock(pu->url);
1715
1716 - debug(D_REGISTRY, "Registry: freeing person url");
1717 - freez(pu);
1718 - }
1716 + debug(D_REGISTRY, "Registry: freeing person url");
1717 + freez(pu);
1718 + }
1719
1720 - debug(D_REGISTRY, "Registry: deleting person '%s' from persons registry", p->guid);
1721 - dictionary_del(registry.persons, p->guid);
1720 + debug(D_REGISTRY, "Registry: deleting person '%s' from persons registry", p->guid);
1721 + dictionary_del(registry.persons, p->guid);
1722
1723 - debug(D_REGISTRY, "Registry: destroying URL dictionary of person '%s'", p->guid);
1724 - dictionary_destroy(p->urls);
1723 + debug(D_REGISTRY, "Registry: destroying URL dictionary of person '%s'", p->guid);
1724 + dictionary_destroy(p->urls);
1725
1726 - debug(D_REGISTRY, "Registry: freeing person '%s'", p->guid);
1727 - freez(p);
1728 - }
1726 + debug(D_REGISTRY, "Registry: freeing person '%s'", p->guid);
1727 + freez(p);
1728 + }
1729
1730 - while(registry.machines->values_index.root) {
1731 - MACHINE *m = ((NAME_VALUE *)registry.machines->values_index.root)->value;
1730 + while(registry.machines->values_index.root) {
1731 + MACHINE *m = ((NAME_VALUE *)registry.machines->values_index.root)->value;
1732
1733 - // fprintf(stderr, "\nMACHINE: '%s', first: %u, last: %u, usages: %u\n", m->guid, m->first_t, m->last_t, m->usages);
1733 + // fprintf(stderr, "\nMACHINE: '%s', first: %u, last: %u, usages: %u\n", m->guid, m->first_t, m->last_t, m->usages);
1734
1735 - while(m->urls->values_index.root) {
1736 - MACHINE_URL *mu = ((NAME_VALUE *)m->urls->values_index.root)->value;
1735 + while(m->urls->values_index.root) {
1736 + MACHINE_URL *mu = ((NAME_VALUE *)m->urls->values_index.root)->value;
1737
1738 - // fprintf(stderr, "\tURL: '%s', first: %u, last: %u, usages: %u, flags: 0x%02x\n", mu->url->url, mu->first_t, mu->last_t, mu->usages, mu->flags);
1738 + // fprintf(stderr, "\tURL: '%s', first: %u, last: %u, usages: %u, flags: 0x%02x\n", mu->url->url, mu->first_t, mu->last_t, mu->usages, mu->flags);
1739
1740 - //debug(D_REGISTRY, "Registry: destroying persons dictionary from url '%s'", mu->url->url);
1741 - //dictionary_destroy(mu->persons);
1740 + //debug(D_REGISTRY, "Registry: destroying persons dictionary from url '%s'", mu->url->url);
1741 + //dictionary_destroy(mu->persons);
1742
1743 - debug(D_REGISTRY, "Registry: deleting url '%s' from person '%s'", mu->url->url, m->guid);
1744 - dictionary_del(m->urls, mu->url->url);
1743 + debug(D_REGISTRY, "Registry: deleting url '%s' from person '%s'", mu->url->url, m->guid);
1744 + dictionary_del(m->urls, mu->url->url);
1745
1746 - debug(D_REGISTRY, "Registry: unlinking url '%s' from machine", mu->url->url);
1747 - registry_url_unlink_nolock(mu->url);
1746 + debug(D_REGISTRY, "Registry: unlinking url '%s' from machine", mu->url->url);
1747 + registry_url_unlink_nolock(mu->url);
1748
1749 - debug(D_REGISTRY, "Registry: freeing machine url");
1750 - freez(mu);
1751 - }
1749 + debug(D_REGISTRY, "Registry: freeing machine url");
1750 + freez(mu);
1751 + }
1752
1753 - debug(D_REGISTRY, "Registry: deleting machine '%s' from machines registry", m->guid);
1754 - dictionary_del(registry.machines, m->guid);
1753 + debug(D_REGISTRY, "Registry: deleting machine '%s' from machines registry", m->guid);
1754 + dictionary_del(registry.machines, m->guid);
1755
1756 - debug(D_REGISTRY, "Registry: destroying URL dictionary of machine '%s'", m->guid);
1757 - dictionary_destroy(m->urls);
1756 + debug(D_REGISTRY, "Registry: destroying URL dictionary of machine '%s'", m->guid);
1757 + dictionary_destroy(m->urls);
1758
1759 - debug(D_REGISTRY, "Registry: freeing machine '%s'", m->guid);
1760 - freez(m);
1761 - }
1759 + debug(D_REGISTRY, "Registry: freeing machine '%s'", m->guid);
1760 + freez(m);
1761 + }
1762
1763 - // and free the memory of remaining dictionary structures
1763 + // and free the memory of remaining dictionary structures
1764
1765 - debug(D_REGISTRY, "Registry: destroying persons dictionary");
1766 - dictionary_destroy(registry.persons);
1765 + debug(D_REGISTRY, "Registry: destroying persons dictionary");
1766 + dictionary_destroy(registry.persons);
1767
1768 - debug(D_REGISTRY, "Registry: destroying machines dictionary");
1769 - dictionary_destroy(registry.machines);
1768 + debug(D_REGISTRY, "Registry: destroying machines dictionary");
1769 + dictionary_destroy(registry.machines);
1770
1771 - debug(D_REGISTRY, "Registry: destroying urls dictionary");
1772 - dictionary_destroy(registry.urls);
1771 + debug(D_REGISTRY, "Registry: destroying urls dictionary");
1772 + dictionary_destroy(registry.urls);
1773 }
1774
1775 // ----------------------------------------------------------------------------
1776 // STATISTICS
1777
1778 void registry_statistics(void) {
1779 - if(!registry.enabled) return;
1780 -
1781 - static RRDSET *sts = NULL, *stc = NULL, *stm = NULL;
1782 -
1783 - if(!sts) sts = rrdset_find("netdata.registry_sessions");
1784 - if(!sts) {
1785 - sts = rrdset_create("netdata", "registry_sessions", NULL, "registry", NULL, "NetData Registry Sessions", "session", 131000, rrd_update_every, RRDSET_TYPE_LINE);
1786 -
1787 - rrddim_add(sts, "sessions", NULL, 1, 1, RRDDIM_ABSOLUTE);
1788 - }
1789 - else rrdset_next(sts);
1790 -
1791 - rrddim_set(sts, "sessions", registry.usages_count);
1792 - rrdset_done(sts);
1793 -
1794 - // ------------------------------------------------------------------------
1795 -
1796 - if(!stc) stc = rrdset_find("netdata.registry_entries");
1797 - if(!stc) {
1798 - stc = rrdset_create("netdata", "registry_entries", NULL, "registry", NULL, "NetData Registry Entries", "entries", 131100, rrd_update_every, RRDSET_TYPE_LINE);
1799 -
1800 - rrddim_add(stc, "persons", NULL, 1, 1, RRDDIM_ABSOLUTE);
1801 - rrddim_add(stc, "machines", NULL, 1, 1, RRDDIM_ABSOLUTE);
1802 - rrddim_add(stc, "urls", NULL, 1, 1, RRDDIM_ABSOLUTE);
1803 - rrddim_add(stc, "persons_urls", NULL, 1, 1, RRDDIM_ABSOLUTE);
1804 - rrddim_add(stc, "machines_urls", NULL, 1, 1, RRDDIM_ABSOLUTE);
1805 - }
1806 - else rrdset_next(stc);
1807 -
1808 - rrddim_set(stc, "persons", registry.persons_count);
1809 - rrddim_set(stc, "machines", registry.machines_count);
1810 - rrddim_set(stc, "urls", registry.urls_count);
1811 - rrddim_set(stc, "persons_urls", registry.persons_urls_count);
1812 - rrddim_set(stc, "machines_urls", registry.machines_urls_count);
1813 - rrdset_done(stc);
1814 -
1815 - // ------------------------------------------------------------------------
1816 -
1817 - if(!stm) stm = rrdset_find("netdata.registry_mem");
1818 - if(!stm) {
1819 - stm = rrdset_create("netdata", "registry_mem", NULL, "registry", NULL, "NetData Registry Memory", "KB", 131300, rrd_update_every, RRDSET_TYPE_STACKED);
1820 -
1821 - rrddim_add(stm, "persons", NULL, 1, 1024, RRDDIM_ABSOLUTE);
1822 - rrddim_add(stm, "machines", NULL, 1, 1024, RRDDIM_ABSOLUTE);
1823 - rrddim_add(stm, "urls", NULL, 1, 1024, RRDDIM_ABSOLUTE);
1824 - rrddim_add(stm, "persons_urls", NULL, 1, 1024, RRDDIM_ABSOLUTE);
1825 - rrddim_add(stm, "machines_urls", NULL, 1, 1024, RRDDIM_ABSOLUTE);
1826 - }
1827 - else rrdset_next(stm);
1828 -
1829 - rrddim_set(stm, "persons", registry.persons_memory + registry.persons_count * sizeof(NAME_VALUE) + sizeof(DICTIONARY));
1830 - rrddim_set(stm, "machines", registry.machines_memory + registry.machines_count * sizeof(NAME_VALUE) + sizeof(DICTIONARY));
1831 - rrddim_set(stm, "urls", registry.urls_memory + registry.urls_count * sizeof(NAME_VALUE) + sizeof(DICTIONARY));
1832 - rrddim_set(stm, "persons_urls", registry.persons_urls_memory + registry.persons_count * sizeof(DICTIONARY) + registry.persons_urls_count * sizeof(NAME_VALUE));
1833 - rrddim_set(stm, "machines_urls", registry.machines_urls_memory + registry.machines_count * sizeof(DICTIONARY) + registry.machines_urls_count * sizeof(NAME_VALUE));
1834 - rrdset_done(stm);
1779 + if(!registry.enabled) return;
1780 +
1781 + static RRDSET *sts = NULL, *stc = NULL, *stm = NULL;
1782 +
1783 + if(!sts) sts = rrdset_find("netdata.registry_sessions");
1784 + if(!sts) {
1785 + sts = rrdset_create("netdata", "registry_sessions", NULL, "registry", NULL, "NetData Registry Sessions", "session", 131000, rrd_update_every, RRDSET_TYPE_LINE);
1786 +
1787 + rrddim_add(sts, "sessions", NULL, 1, 1, RRDDIM_ABSOLUTE);
1788 + }
1789 + else rrdset_next(sts);
1790 +
1791 + rrddim_set(sts, "sessions", registry.usages_count);
1792 + rrdset_done(sts);
1793 +
1794 + // ------------------------------------------------------------------------
1795 +
1796 + if(!stc) stc = rrdset_find("netdata.registry_entries");
1797 + if(!stc) {
1798 + stc = rrdset_create("netdata", "registry_entries", NULL, "registry", NULL, "NetData Registry Entries", "entries", 131100, rrd_update_every, RRDSET_TYPE_LINE);
1799 +
1800 + rrddim_add(stc, "persons", NULL, 1, 1, RRDDIM_ABSOLUTE);
1801 + rrddim_add(stc, "machines", NULL, 1, 1, RRDDIM_ABSOLUTE);
1802 + rrddim_add(stc, "urls", NULL, 1, 1, RRDDIM_ABSOLUTE);
1803 + rrddim_add(stc, "persons_urls", NULL, 1, 1, RRDDIM_ABSOLUTE);
1804 + rrddim_add(stc, "machines_urls", NULL, 1, 1, RRDDIM_ABSOLUTE);
1805 + }
1806 + else rrdset_next(stc);
1807 +
1808 + rrddim_set(stc, "persons", registry.persons_count);
1809 + rrddim_set(stc, "machines", registry.machines_count);
1810 + rrddim_set(stc, "urls", registry.urls_count);
1811 + rrddim_set(stc, "persons_urls", registry.persons_urls_count);
1812 + rrddim_set(stc, "machines_urls", registry.machines_urls_count);
1813 + rrdset_done(stc);
1814 +
1815 + // ------------------------------------------------------------------------
1816 +
1817 + if(!stm) stm = rrdset_find("netdata.registry_mem");
1818 + if(!stm) {
1819 + stm = rrdset_create("netdata", "registry_mem", NULL, "registry", NULL, "NetData Registry Memory", "KB", 131300, rrd_update_every, RRDSET_TYPE_STACKED);
1820 +
1821 + rrddim_add(stm, "persons", NULL, 1, 1024, RRDDIM_ABSOLUTE);
1822 + rrddim_add(stm, "machines", NULL, 1, 1024, RRDDIM_ABSOLUTE);
1823 + rrddim_add(stm, "urls", NULL, 1, 1024, RRDDIM_ABSOLUTE);
1824 + rrddim_add(stm, "persons_urls", NULL, 1, 1024, RRDDIM_ABSOLUTE);
1825 + rrddim_add(stm, "machines_urls", NULL, 1, 1024, RRDDIM_ABSOLUTE);
1826 + }
1827 + else rrdset_next(stm);
1828 +
1829 + rrddim_set(stm, "persons", registry.persons_memory + registry.persons_count * sizeof(NAME_VALUE) + sizeof(DICTIONARY));
1830 + rrddim_set(stm, "machines", registry.machines_memory + registry.machines_count * sizeof(NAME_VALUE) + sizeof(DICTIONARY));
1831 + rrddim_set(stm, "urls", registry.urls_memory + registry.urls_count * sizeof(NAME_VALUE) + sizeof(DICTIONARY));
1832 + rrddim_set(stm, "persons_urls", registry.persons_urls_memory + registry.persons_count * sizeof(DICTIONARY) + registry.persons_urls_count * sizeof(NAME_VALUE));
1833 + rrddim_set(stm, "machines_urls", registry.machines_urls_memory + registry.machines_count * sizeof(DICTIONARY) + registry.machines_urls_count * sizeof(NAME_VALUE));
1834 + rrdset_done(stm);
1835 }
src/rrd.c
+1048 -1048
@@ -22,9 +22,9 @@ static int rrdcontext_compare(void* a, void* b);
22 // RRDHOST
23
24 RRDHOST localhost = {
25 - .hostname = "localhost",
26 - .rrdset_root = NULL,
27 - .rrdset_root_rwlock = PTHREAD_RWLOCK_INITIALIZER,
25 + .hostname = "localhost",
26 + .rrdset_root = NULL,
27 + .rrdset_root_rwlock = PTHREAD_RWLOCK_INITIALIZER,
28 .rrdset_root_index = {
29 { NULL, rrdset_compare },
30 AVL_LOCK_INITIALIZER
@@ -44,21 +44,21 @@ RRDHOST localhost = {
44 };
45
46 void rrdhost_rwlock(RRDHOST *host) {
47 - pthread_rwlock_wrlock(&host->rrdset_root_rwlock);
47 + pthread_rwlock_wrlock(&host->rrdset_root_rwlock);
48 }
49
50 void rrdhost_rdlock(RRDHOST *host) {
51 - pthread_rwlock_rdlock(&host->rrdset_root_rwlock);
51 + pthread_rwlock_rdlock(&host->rrdset_root_rwlock);
52 }
53
54 void rrdhost_unlock(RRDHOST *host) {
55 - pthread_rwlock_unlock(&host->rrdset_root_rwlock);
55 + pthread_rwlock_unlock(&host->rrdset_root_rwlock);
56 }
57
58 void rrdhost_check_wrlock_int(RRDHOST *host, const char *file, const char *function, const unsigned long line) {
59 - if(pthread_rwlock_tryrdlock(&host->rrdset_root_rwlock) == 0) {
60 - fatal("RRDHOST '%s' should be write-locked, but it is not, at function %s() at line %lu of file '%s'", host->hostname, function, line, file);
61 - }
59 + if(pthread_rwlock_tryrdlock(&host->rrdset_root_rwlock) == 0) {
60 + fatal("RRDHOST '%s' should be write-locked, but it is not, at function %s() at line %lu of file '%s'", host->hostname, function, line, file);
61 + }
62 }
63
64 // ----------------------------------------------------------------------------
@@ -142,20 +142,20 @@ static RRDSET *rrdset_index_find(RRDHOST *host, const char *id, uint32_t hash) {
142 #define rrdset_from_avlname(avlname_ptr) ((RRDSET *)((avlname_ptr) - offsetof(RRDSET, avlname)))
143
144 static int rrdset_compare_name(void* a, void* b) {
145 - RRDSET *A = rrdset_from_avlname(a);
146 - RRDSET *B = rrdset_from_avlname(b);
145 + RRDSET *A = rrdset_from_avlname(a);
146 + RRDSET *B = rrdset_from_avlname(b);
147
148 - // fprintf(stderr, "COMPARING: %s with %s\n", A->name, B->name);
148 + // fprintf(stderr, "COMPARING: %s with %s\n", A->name, B->name);
149
150 - if(A->hash_name < B->hash_name) return -1;
151 - else if(A->hash_name > B->hash_name) return 1;
152 - else return strcmp(A->name, B->name);
150 + if(A->hash_name < B->hash_name) return -1;
151 + else if(A->hash_name > B->hash_name) return 1;
152 + else return strcmp(A->name, B->name);
153 }
154
155 RRDSET *rrdset_index_add_name(RRDHOST *host, RRDSET *st) {
156 void *result;
157 - // fprintf(stderr, "ADDING: %s (name: %s)\n", st->id, st->name);
158 - result = avl_insert_lock(&host->rrdset_root_index_name, (avl *) (&st->avlname));
157 + // fprintf(stderr, "ADDING: %s (name: %s)\n", st->id, st->name);
158 + result = avl_insert_lock(&host->rrdset_root_index_name, (avl *) (&st->avlname));
159 if(result) return rrdset_from_avlname(result);
160 return NULL;
161 }
@@ -169,23 +169,23 @@ RRDSET *rrdset_index_del_name(RRDHOST *host, RRDSET *st) {
169 }
170
171 static RRDSET *rrdset_index_find_name(RRDHOST *host, const char *name, uint32_t hash) {
172 - void *result = NULL;
173 - RRDSET tmp;
174 - tmp.name = name;
175 - tmp.hash_name = (hash)?hash:simple_hash(tmp.name);
176 -
177 - // fprintf(stderr, "SEARCHING: %s\n", name);
178 - result = avl_search_lock(&host->rrdset_root_index_name, (avl *) (&(tmp.avlname)));
179 - if(result) {
180 - RRDSET *st = rrdset_from_avlname(result);
181 - if(strcmp(st->magic, RRDSET_MAGIC))
182 - error("Search for RRDSET %s returned an invalid RRDSET %s (name %s)", name, st->id, st->name);
183 -
184 - // fprintf(stderr, "FOUND: %s\n", name);
185 - return rrdset_from_avlname(result);
186 - }
187 - // fprintf(stderr, "NOT FOUND: %s\n", name);
188 - return NULL;
172 + void *result = NULL;
173 + RRDSET tmp;
174 + tmp.name = name;
175 + tmp.hash_name = (hash)?hash:simple_hash(tmp.name);
176 +
177 + // fprintf(stderr, "SEARCHING: %s\n", name);
178 + result = avl_search_lock(&host->rrdset_root_index_name, (avl *) (&(tmp.avlname)));
179 + if(result) {
180 + RRDSET *st = rrdset_from_avlname(result);
181 + if(strcmp(st->magic, RRDSET_MAGIC))
182 + error("Search for RRDSET %s returned an invalid RRDSET %s (name %s)", name, st->id, st->name);
183 +
184 + // fprintf(stderr, "FOUND: %s\n", name);
185 + return rrdset_from_avlname(result);
186 + }
187 + // fprintf(stderr, "NOT FOUND: %s\n", name);
188 + return NULL;
189 }
190
191
@@ -193,20 +193,20 @@ static RRDSET *rrdset_index_find_name(RRDHOST *host, const char *name, uint32_t
193 // RRDDIM index
194
195 static int rrddim_compare(void* a, void* b) {
196 - if(((RRDDIM *)a)->hash < ((RRDDIM *)b)->hash) return -1;
197 - else if(((RRDDIM *)a)->hash > ((RRDDIM *)b)->hash) return 1;
198 - else return strcmp(((RRDDIM *)a)->id, ((RRDDIM *)b)->id);
196 + if(((RRDDIM *)a)->hash < ((RRDDIM *)b)->hash) return -1;
197 + else if(((RRDDIM *)a)->hash > ((RRDDIM *)b)->hash) return 1;
198 + else return strcmp(((RRDDIM *)a)->id, ((RRDDIM *)b)->id);
199 }
200
201 #define rrddim_index_add(st, rd) avl_insert_lock(&((st)->dimensions_index), (avl *)(rd))
202 #define rrddim_index_del(st,rd ) avl_remove_lock(&((st)->dimensions_index), (avl *)(rd))
203
204 static RRDDIM *rrddim_index_find(RRDSET *st, const char *id, uint32_t hash) {
205 - RRDDIM tmp;
206 - strncpyz(tmp.id, id, RRD_ID_LENGTH_MAX);
207 - tmp.hash = (hash)?hash:simple_hash(tmp.id);
205 + RRDDIM tmp;
206 + strncpyz(tmp.id, id, RRD_ID_LENGTH_MAX);
207 + tmp.hash = (hash)?hash:simple_hash(tmp.id);
208
209 - return (RRDDIM *)avl_search_lock(&(st->dimensions_index), (avl *) &tmp);
209 + return (RRDDIM *)avl_search_lock(&(st->dimensions_index), (avl *) &tmp);
210 }
211
212 // ----------------------------------------------------------------------------
@@ -214,29 +214,29 @@ static RRDDIM *rrddim_index_find(RRDSET *st, const char *id, uint32_t hash) {
214
215 int rrdset_type_id(const char *name)
216 {
217 - if(unlikely(strcmp(name, RRDSET_TYPE_AREA_NAME) == 0)) return RRDSET_TYPE_AREA;
218 - else if(unlikely(strcmp(name, RRDSET_TYPE_STACKED_NAME) == 0)) return RRDSET_TYPE_STACKED;
219 - else if(unlikely(strcmp(name, RRDSET_TYPE_LINE_NAME) == 0)) return RRDSET_TYPE_LINE;
220 - return RRDSET_TYPE_LINE;
217 + if(unlikely(strcmp(name, RRDSET_TYPE_AREA_NAME) == 0)) return RRDSET_TYPE_AREA;
218 + else if(unlikely(strcmp(name, RRDSET_TYPE_STACKED_NAME) == 0)) return RRDSET_TYPE_STACKED;
219 + else if(unlikely(strcmp(name, RRDSET_TYPE_LINE_NAME) == 0)) return RRDSET_TYPE_LINE;
220 + return RRDSET_TYPE_LINE;
221 }
222
223 const char *rrdset_type_name(int chart_type)
224 {
225 - static char line[] = RRDSET_TYPE_LINE_NAME;
226 - static char area[] = RRDSET_TYPE_AREA_NAME;
227 - static char stacked[] = RRDSET_TYPE_STACKED_NAME;
225 + static char line[] = RRDSET_TYPE_LINE_NAME;
226 + static char area[] = RRDSET_TYPE_AREA_NAME;
227 + static char stacked[] = RRDSET_TYPE_STACKED_NAME;
228
229 - switch(chart_type) {
230 - case RRDSET_TYPE_LINE:
231 - return line;
229 + switch(chart_type) {
230 + case RRDSET_TYPE_LINE:
231 + return line;
232
233 - case RRDSET_TYPE_AREA:
234 - return area;
233 + case RRDSET_TYPE_AREA:
234 + return area;
235
236 - case RRDSET_TYPE_STACKED:
237 - return stacked;
238 - }
239 - return line;
236 + case RRDSET_TYPE_STACKED:
237 + return stacked;
238 + }
239 + return line;
240 }
241
242 // ----------------------------------------------------------------------------
@@ -244,33 +244,33 @@ const char *rrdset_type_name(int chart_type)
244
245 const char *rrd_memory_mode_name(int id)
246 {
247 - static const char ram[] = RRD_MEMORY_MODE_RAM_NAME;
248 - static const char map[] = RRD_MEMORY_MODE_MAP_NAME;
249 - static const char save[] = RRD_MEMORY_MODE_SAVE_NAME;
247 + static const char ram[] = RRD_MEMORY_MODE_RAM_NAME;
248 + static const char map[] = RRD_MEMORY_MODE_MAP_NAME;
249 + static const char save[] = RRD_MEMORY_MODE_SAVE_NAME;
250
251 - switch(id) {
252 - case RRD_MEMORY_MODE_RAM:
253 - return ram;
251 + switch(id) {
252 + case RRD_MEMORY_MODE_RAM:
253 + return ram;
254
255 - case RRD_MEMORY_MODE_MAP:
256 - return map;
255 + case RRD_MEMORY_MODE_MAP:
256 + return map;
257
258 - case RRD_MEMORY_MODE_SAVE:
259 - default:
260 - return save;
261 - }
258 + case RRD_MEMORY_MODE_SAVE:
259 + default:
260 + return save;
261 + }
262
263 - return save;
263 + return save;
264 }
265
266 int rrd_memory_mode_id(const char *name)
267 {
268 - if(unlikely(!strcmp(name, RRD_MEMORY_MODE_RAM_NAME)))
269 - return RRD_MEMORY_MODE_RAM;
270 - else if(unlikely(!strcmp(name, RRD_MEMORY_MODE_MAP_NAME)))
271 - return RRD_MEMORY_MODE_MAP;
268 + if(unlikely(!strcmp(name, RRD_MEMORY_MODE_RAM_NAME)))
269 + return RRD_MEMORY_MODE_RAM;
270 + else if(unlikely(!strcmp(name, RRD_MEMORY_MODE_MAP_NAME)))
271 + return RRD_MEMORY_MODE_MAP;
272
273 - return RRD_MEMORY_MODE_SAVE;
273 + return RRD_MEMORY_MODE_SAVE;
274 }
275
276 // ----------------------------------------------------------------------------
@@ -278,34 +278,34 @@ int rrd_memory_mode_id(const char *name)
278
279 int rrddim_algorithm_id(const char *name)
280 {
281 - if(strcmp(name, RRDDIM_INCREMENTAL_NAME) == 0) return RRDDIM_INCREMENTAL;
282 - if(strcmp(name, RRDDIM_ABSOLUTE_NAME) == 0) return RRDDIM_ABSOLUTE;
283 - if(strcmp(name, RRDDIM_PCENT_OVER_ROW_TOTAL_NAME) == 0) return RRDDIM_PCENT_OVER_ROW_TOTAL;
284 - if(strcmp(name, RRDDIM_PCENT_OVER_DIFF_TOTAL_NAME) == 0) return RRDDIM_PCENT_OVER_DIFF_TOTAL;
285 - return RRDDIM_ABSOLUTE;
281 + if(strcmp(name, RRDDIM_INCREMENTAL_NAME) == 0) return RRDDIM_INCREMENTAL;
282 + if(strcmp(name, RRDDIM_ABSOLUTE_NAME) == 0) return RRDDIM_ABSOLUTE;
283 + if(strcmp(name, RRDDIM_PCENT_OVER_ROW_TOTAL_NAME) == 0) return RRDDIM_PCENT_OVER_ROW_TOTAL;
284 + if(strcmp(name, RRDDIM_PCENT_OVER_DIFF_TOTAL_NAME) == 0) return RRDDIM_PCENT_OVER_DIFF_TOTAL;
285 + return RRDDIM_ABSOLUTE;
286 }
287
288 const char *rrddim_algorithm_name(int chart_type)
289 {
290 - static char absolute[] = RRDDIM_ABSOLUTE_NAME;
291 - static char incremental[] = RRDDIM_INCREMENTAL_NAME;
292 - static char percentage_of_absolute_row[] = RRDDIM_PCENT_OVER_ROW_TOTAL_NAME;
293 - static char percentage_of_incremental_row[] = RRDDIM_PCENT_OVER_DIFF_TOTAL_NAME;
290 + static char absolute[] = RRDDIM_ABSOLUTE_NAME;
291 + static char incremental[] = RRDDIM_INCREMENTAL_NAME;
292 + static char percentage_of_absolute_row[] = RRDDIM_PCENT_OVER_ROW_TOTAL_NAME;
293 + static char percentage_of_incremental_row[] = RRDDIM_PCENT_OVER_DIFF_TOTAL_NAME;
294
295 - switch(chart_type) {
296 - case RRDDIM_ABSOLUTE:
297 - return absolute;
295 + switch(chart_type) {
296 + case RRDDIM_ABSOLUTE:
297 + return absolute;
298
299 - case RRDDIM_INCREMENTAL:
300 - return incremental;
299 + case RRDDIM_INCREMENTAL:
300 + return incremental;
301
302 - case RRDDIM_PCENT_OVER_ROW_TOTAL:
303 - return percentage_of_absolute_row;
302 + case RRDDIM_PCENT_OVER_ROW_TOTAL:
303 + return percentage_of_absolute_row;
304
305 - case RRDDIM_PCENT_OVER_DIFF_TOTAL:
306 - return percentage_of_incremental_row;
307 - }
308 - return absolute;
305 + case RRDDIM_PCENT_OVER_DIFF_TOTAL:
306 + return percentage_of_incremental_row;
307 + }
308 + return absolute;
309 }
310
311 // ----------------------------------------------------------------------------
@@ -313,38 +313,38 @@ const char *rrddim_algorithm_name(int chart_type)
313
314 char *rrdset_strncpyz_name(char *to, const char *from, size_t length)
315 {
316 - char c, *p = to;
316 + char c, *p = to;
317
318 - while (length-- && (c = *from++)) {
319 - if(c != '.' && !isalnum(c))
320 - c = '_';
318 + while (length-- && (c = *from++)) {
319 + if(c != '.' && !isalnum(c))
320 + c = '_';
321
322 - *p++ = c;
323 - }
322 + *p++ = c;
323 + }
324
325 - *p = '\0';
325 + *p = '\0';
326
327 - return to;
327 + return to;
328 }
329
330 void rrdset_set_name(RRDSET *st, const char *name)
331 {
332 - debug(D_RRD_CALLS, "rrdset_set_name() old: %s, new: %s", st->name, name);
332 + debug(D_RRD_CALLS, "rrdset_set_name() old: %s, new: %s", st->name, name);
333
334 - if(st->name) {
334 + if(st->name) {
335 rrdset_index_del_name(&localhost, st);
336 rrdsetvar_rename_all(st);
337 }
338
339 - char b[CONFIG_MAX_VALUE + 1];
340 - char n[RRD_ID_LENGTH_MAX + 1];
339 + char b[CONFIG_MAX_VALUE + 1];
340 + char n[RRD_ID_LENGTH_MAX + 1];
341
342 - snprintfz(n, RRD_ID_LENGTH_MAX, "%s.%s", st->type, name);
343 - rrdset_strncpyz_name(b, n, CONFIG_MAX_VALUE);
344 - st->name = config_get(st->id, "name", b);
345 - st->hash_name = simple_hash(st->name);
342 + snprintfz(n, RRD_ID_LENGTH_MAX, "%s.%s", st->type, name);
343 + rrdset_strncpyz_name(b, n, CONFIG_MAX_VALUE);
344 + st->name = config_get(st->id, "name", b);
345 + st->hash_name = simple_hash(st->name);
346
347 - rrdset_index_add_name(&localhost, st);
347 + rrdset_index_add_name(&localhost, st);
348 }
349
350 // ----------------------------------------------------------------------------
@@ -352,30 +352,30 @@ void rrdset_set_name(RRDSET *st, const char *name)
352
353 char *rrdset_cache_dir(const char *id)
354 {
355 - char *ret = NULL;
356 -
357 - static char *cache_dir = NULL;
358 - if(!cache_dir) {
359 - cache_dir = config_get("global", "cache directory", CACHE_DIR);
360 - int r = mkdir(cache_dir, 0755);
361 - if(r != 0 && errno != EEXIST)
362 - error("Cannot create directory '%s'", cache_dir);
363 - }
364 -
365 - char b[FILENAME_MAX + 1];
366 - char n[FILENAME_MAX + 1];
367 - rrdset_strncpyz_name(b, id, FILENAME_MAX);
368 -
369 - snprintfz(n, FILENAME_MAX, "%s/%s", cache_dir, b);
370 - ret = config_get(id, "cache directory", n);
371 -
372 - if(rrd_memory_mode == RRD_MEMORY_MODE_MAP || rrd_memory_mode == RRD_MEMORY_MODE_SAVE) {
373 - int r = mkdir(ret, 0775);
374 - if(r != 0 && errno != EEXIST)
375 - error("Cannot create directory '%s'", ret);
376 - }
377 -
378 - return ret;
355 + char *ret = NULL;
356 +
357 + static char *cache_dir = NULL;
358 + if(!cache_dir) {
359 + cache_dir = config_get("global", "cache directory", CACHE_DIR);
360 + int r = mkdir(cache_dir, 0755);
361 + if(r != 0 && errno != EEXIST)
362 + error("Cannot create directory '%s'", cache_dir);
363 + }
364 +
365 + char b[FILENAME_MAX + 1];
366 + char n[FILENAME_MAX + 1];
367 + rrdset_strncpyz_name(b, id, FILENAME_MAX);
368 +
369 + snprintfz(n, FILENAME_MAX, "%s/%s", cache_dir, b);
370 + ret = config_get(id, "cache directory", n);
371 +
372 + if(rrd_memory_mode == RRD_MEMORY_MODE_MAP || rrd_memory_mode == RRD_MEMORY_MODE_SAVE) {
373 + int r = mkdir(ret, 0775);
374 + if(r != 0 && errno != EEXIST)
375 + error("Cannot create directory '%s'", ret);
376 + }
377 +
378 + return ret;
379 }
380
381 // ----------------------------------------------------------------------------
@@ -383,156 +383,156 @@ char *rrdset_cache_dir(const char *id)
383
384 void rrdset_reset(RRDSET *st)
385 {
386 - debug(D_RRD_CALLS, "rrdset_reset() %s", st->name);
387 -
388 - st->last_collected_time.tv_sec = 0;
389 - st->last_collected_time.tv_usec = 0;
390 - st->last_updated.tv_sec = 0;
391 - st->last_updated.tv_usec = 0;
392 - st->current_entry = 0;
393 - st->counter = 0;
394 - st->counter_done = 0;
395 -
396 - RRDDIM *rd;
397 - for(rd = st->dimensions; rd ; rd = rd->next) {
398 - rd->last_collected_time.tv_sec = 0;
399 - rd->last_collected_time.tv_usec = 0;
400 - rd->counter = 0;
401 - bzero(rd->values, rd->entries * sizeof(storage_number));
402 - }
386 + debug(D_RRD_CALLS, "rrdset_reset() %s", st->name);
387 +
388 + st->last_collected_time.tv_sec = 0;
389 + st->last_collected_time.tv_usec = 0;
390 + st->last_updated.tv_sec = 0;
391 + st->last_updated.tv_usec = 0;
392 + st->current_entry = 0;
393 + st->counter = 0;
394 + st->counter_done = 0;
395 +
396 + RRDDIM *rd;
397 + for(rd = st->dimensions; rd ; rd = rd->next) {
398 + rd->last_collected_time.tv_sec = 0;
399 + rd->last_collected_time.tv_usec = 0;
400 + rd->counter = 0;
401 + bzero(rd->values, rd->entries * sizeof(storage_number));
402 + }
403 }
404
405 RRDSET *rrdset_create(const char *type, const char *id, const char *name, const char *family, const char *context, const char *title, const char *units, long priority, int update_every, int chart_type)
406 {
407 - if(!type || !type[0]) {
408 - fatal("Cannot create rrd stats without a type.");
409 - return NULL;
410 - }
411 -
412 - if(!id || !id[0]) {
413 - fatal("Cannot create rrd stats without an id.");
414 - return NULL;
415 - }
416 -
417 - char fullid[RRD_ID_LENGTH_MAX + 1];
418 - char fullfilename[FILENAME_MAX + 1];
419 - RRDSET *st = NULL;
420 -
421 - snprintfz(fullid, RRD_ID_LENGTH_MAX, "%s.%s", type, id);
422 -
423 - st = rrdset_find(fullid);
424 - if(st) {
425 - error("Cannot create rrd stats for '%s', it already exists.", fullid);
426 - return st;
427 - }
428 -
429 - long entries = config_get_number(fullid, "history", rrd_default_history_entries);
430 - if(entries < 5) entries = config_set_number(fullid, "history", 5);
431 - if(entries > RRD_HISTORY_ENTRIES_MAX) entries = config_set_number(fullid, "history", RRD_HISTORY_ENTRIES_MAX);
432 -
433 - int enabled = config_get_boolean(fullid, "enabled", 1);
434 - if(!enabled) entries = 5;
435 -
436 - unsigned long size = sizeof(RRDSET);
437 - char *cache_dir = rrdset_cache_dir(fullid);
438 -
439 - debug(D_RRD_CALLS, "Creating RRD_STATS for '%s.%s'.", type, id);
440 -
441 - snprintfz(fullfilename, FILENAME_MAX, "%s/main.db", cache_dir);
442 - if(rrd_memory_mode != RRD_MEMORY_MODE_RAM) st = (RRDSET *)mymmap(fullfilename, size, ((rrd_memory_mode == RRD_MEMORY_MODE_MAP)?MAP_SHARED:MAP_PRIVATE), 0);
443 - if(st) {
444 - if(strcmp(st->magic, RRDSET_MAGIC) != 0) {
445 - errno = 0;
446 - info("Initializing file %s.", fullfilename);
447 - bzero(st, size);
448 - }
449 - else if(strcmp(st->id, fullid) != 0) {
450 - errno = 0;
451 - error("File %s contents are not for chart %s. Clearing it.", fullfilename, fullid);
452 - // munmap(st, size);
453 - // st = NULL;
454 - bzero(st, size);
455 - }
456 - else if(st->memsize != size || st->entries != entries) {
457 - errno = 0;
458 - error("File %s does not have the desired size. Clearing it.", fullfilename);
459 - bzero(st, size);
460 - }
461 - else if(st->update_every != update_every) {
462 - errno = 0;
463 - error("File %s does not have the desired update frequency. Clearing it.", fullfilename);
464 - bzero(st, size);
465 - }
466 - else if((time(NULL) - st->last_updated.tv_sec) > update_every * entries) {
467 - errno = 0;
468 - error("File %s is too old. Clearing it.", fullfilename);
469 - bzero(st, size);
470 - }
471 - }
472 -
473 - if(st) {
474 - st->name = NULL;
475 - st->type = NULL;
476 - st->family = NULL;
477 - st->context = NULL;
478 - st->title = NULL;
479 - st->units = NULL;
480 - st->dimensions = NULL;
481 - st->next = NULL;
482 - st->mapped = rrd_memory_mode;
407 + if(!type || !type[0]) {
408 + fatal("Cannot create rrd stats without a type.");
409 + return NULL;
410 + }
411 +
412 + if(!id || !id[0]) {
413 + fatal("Cannot create rrd stats without an id.");
414 + return NULL;
415 + }
416 +
417 + char fullid[RRD_ID_LENGTH_MAX + 1];
418 + char fullfilename[FILENAME_MAX + 1];
419 + RRDSET *st = NULL;
420 +
421 + snprintfz(fullid, RRD_ID_LENGTH_MAX, "%s.%s", type, id);
422 +
423 + st = rrdset_find(fullid);
424 + if(st) {
425 + error("Cannot create rrd stats for '%s', it already exists.", fullid);
426 + return st;
427 + }
428 +
429 + long entries = config_get_number(fullid, "history", rrd_default_history_entries);
430 + if(entries < 5) entries = config_set_number(fullid, "history", 5);
431 + if(entries > RRD_HISTORY_ENTRIES_MAX) entries = config_set_number(fullid, "history", RRD_HISTORY_ENTRIES_MAX);
432 +
433 + int enabled = config_get_boolean(fullid, "enabled", 1);
434 + if(!enabled) entries = 5;
435 +
436 + unsigned long size = sizeof(RRDSET);
437 + char *cache_dir = rrdset_cache_dir(fullid);
438 +
439 + debug(D_RRD_CALLS, "Creating RRD_STATS for '%s.%s'.", type, id);
440 +
441 + snprintfz(fullfilename, FILENAME_MAX, "%s/main.db", cache_dir);
442 + if(rrd_memory_mode != RRD_MEMORY_MODE_RAM) st = (RRDSET *)mymmap(fullfilename, size, ((rrd_memory_mode == RRD_MEMORY_MODE_MAP)?MAP_SHARED:MAP_PRIVATE), 0);
443 + if(st) {
444 + if(strcmp(st->magic, RRDSET_MAGIC) != 0) {
445 + errno = 0;
446 + info("Initializing file %s.", fullfilename);
447 + bzero(st, size);
448 + }
449 + else if(strcmp(st->id, fullid) != 0) {
450 + errno = 0;
451 + error("File %s contents are not for chart %s. Clearing it.", fullfilename, fullid);
452 + // munmap(st, size);
453 + // st = NULL;
454 + bzero(st, size);
455 + }
456 + else if(st->memsize != size || st->entries != entries) {
457 + errno = 0;
458 + error("File %s does not have the desired size. Clearing it.", fullfilename);
459 + bzero(st, size);
460 + }
461 + else if(st->update_every != update_every) {
462 + errno = 0;
463 + error("File %s does not have the desired update frequency. Clearing it.", fullfilename);
464 + bzero(st, size);
465 + }
466 + else if((time(NULL) - st->last_updated.tv_sec) > update_every * entries) {
467 + errno = 0;
468 + error("File %s is too old. Clearing it.", fullfilename);
469 + bzero(st, size);
470 + }
471 + }
472 +
473 + if(st) {
474 + st->name = NULL;
475 + st->type = NULL;
476 + st->family = NULL;
477 + st->context = NULL;
478 + st->title = NULL;
479 + st->units = NULL;
480 + st->dimensions = NULL;
481 + st->next = NULL;
482 + st->mapped = rrd_memory_mode;
483 st->variables = NULL;
484 - }
485 - else {
486 - st = callocz(1, size);
487 - st->mapped = RRD_MEMORY_MODE_RAM;
488 - }
489 - st->memsize = size;
490 - st->entries = entries;
491 - st->update_every = update_every;
484 + }
485 + else {
486 + st = callocz(1, size);
487 + st->mapped = RRD_MEMORY_MODE_RAM;
488 + }
489 + st->memsize = size;
490 + st->entries = entries;
491 + st->update_every = update_every;
492
493 - if(st->current_entry >= st->entries) st->current_entry = 0;
493 + if(st->current_entry >= st->entries) st->current_entry = 0;
494
495 - strcpy(st->cache_filename, fullfilename);
496 - strcpy(st->magic, RRDSET_MAGIC);
495 + strcpy(st->cache_filename, fullfilename);
496 + strcpy(st->magic, RRDSET_MAGIC);
497
498 - strcpy(st->id, fullid);
499 - st->hash = simple_hash(st->id);
498 + strcpy(st->id, fullid);
499 + st->hash = simple_hash(st->id);
500
501 - st->cache_dir = cache_dir;
501 + st->cache_dir = cache_dir;
502
503 - st->chart_type = rrdset_type_id(config_get(st->id, "chart type", rrdset_type_name(chart_type)));
504 - st->type = config_get(st->id, "type", type);
505 - st->family = config_get(st->id, "family", family?family:st->type);
506 - st->context = config_get(st->id, "context", context?context:st->id);
507 - st->units = config_get(st->id, "units", units?units:"");
503 + st->chart_type = rrdset_type_id(config_get(st->id, "chart type", rrdset_type_name(chart_type)));
504 + st->type = config_get(st->id, "type", type);
505 + st->family = config_get(st->id, "family", family?family:st->type);
506 + st->context = config_get(st->id, "context", context?context:st->id);
507 + st->units = config_get(st->id, "units", units?units:"");
508
509 - st->priority = config_get_number(st->id, "priority", priority);
510 - st->enabled = enabled;
509 + st->priority = config_get_number(st->id, "priority", priority);
510 + st->enabled = enabled;
511
512 - st->isdetail = 0;
513 - st->debug = 0;
512 + st->isdetail = 0;
513 + st->debug = 0;
514
515 - st->last_collected_time.tv_sec = 0;
516 - st->last_collected_time.tv_usec = 0;
517 - st->counter_done = 0;
515 + st->last_collected_time.tv_sec = 0;
516 + st->last_collected_time.tv_usec = 0;
517 + st->counter_done = 0;
518
519 - st->gap_when_lost_iterations_above = (int) (
520 - config_get_number(st->id, "gap when lost iterations above", RRD_DEFAULT_GAP_INTERPOLATIONS) + 2);
519 + st->gap_when_lost_iterations_above = (int) (
520 + config_get_number(st->id, "gap when lost iterations above", RRD_DEFAULT_GAP_INTERPOLATIONS) + 2);
521
522 - avl_init_lock(&st->dimensions_index, rrddim_compare);
522 + avl_init_lock(&st->dimensions_index, rrddim_compare);
523 avl_init_lock(&st->variables_root_index, rrdvar_compare);
524
525 - pthread_rwlock_init(&st->rwlock, NULL);
526 - pthread_rwlock_wrlock(&localhost.rrdset_root_rwlock);
525 + pthread_rwlock_init(&st->rwlock, NULL);
526 + pthread_rwlock_wrlock(&localhost.rrdset_root_rwlock);
527
528 - if(name && *name) rrdset_set_name(st, name);
529 - else rrdset_set_name(st, id);
528 + if(name && *name) rrdset_set_name(st, name);
529 + else rrdset_set_name(st, id);
530
531 - {
532 - char varvalue[CONFIG_MAX_VALUE + 1];
533 - snprintfz(varvalue, CONFIG_MAX_VALUE, "%s (%s)", title?title:"", st->name);
534 - st->title = config_get(st->id, "title", varvalue);
535 - }
531 + {
532 + char varvalue[CONFIG_MAX_VALUE + 1];
533 + snprintfz(varvalue, CONFIG_MAX_VALUE, "%s (%s)", title?title:"", st->name);
534 + st->title = config_get(st->id, "title", varvalue);
535 + }
536
537 st->rrdcontext = rrdcontext_create(st->context);
538 st->rrdhost = &localhost;
@@ -547,204 +547,204 @@ RRDSET *rrdset_create(const char *type, const char *id, const char *name, const
547
548 rrdsetcalc_link_matching(st);
549
550 - pthread_rwlock_unlock(&localhost.rrdset_root_rwlock);
550 + pthread_rwlock_unlock(&localhost.rrdset_root_rwlock);
551
552 - return(st);
552 + return(st);
553 }
554
555 RRDDIM *rrddim_add(RRDSET *st, const char *id, const char *name, long multiplier, long divisor, int algorithm)
556 {
557 - char filename[FILENAME_MAX + 1];
558 - char fullfilename[FILENAME_MAX + 1];
559 -
560 - char varname[CONFIG_MAX_NAME + 1];
561 - RRDDIM *rd = NULL;
562 - unsigned long size = sizeof(RRDDIM) + (st->entries * sizeof(storage_number));
563 -
564 - debug(D_RRD_CALLS, "Adding dimension '%s/%s'.", st->id, id);
565 -
566 - rrdset_strncpyz_name(filename, id, FILENAME_MAX);
567 - snprintfz(fullfilename, FILENAME_MAX, "%s/%s.db", st->cache_dir, filename);
568 - if(rrd_memory_mode != RRD_MEMORY_MODE_RAM) rd = (RRDDIM *)mymmap(fullfilename, size, ((rrd_memory_mode == RRD_MEMORY_MODE_MAP)?MAP_SHARED:MAP_PRIVATE), 1);
569 - if(rd) {
570 - struct timeval now;
571 - gettimeofday(&now, NULL);
572 -
573 - if(strcmp(rd->magic, RRDDIMENSION_MAGIC) != 0) {
574 - errno = 0;
575 - info("Initializing file %s.", fullfilename);
576 - bzero(rd, size);
577 - }
578 - else if(rd->memsize != size) {
579 - errno = 0;
580 - error("File %s does not have the desired size. Clearing it.", fullfilename);
581 - bzero(rd, size);
582 - }
583 - else if(rd->multiplier != multiplier) {
584 - errno = 0;
585 - error("File %s does not have the same multiplier. Clearing it.", fullfilename);
586 - bzero(rd, size);
587 - }
588 - else if(rd->divisor != divisor) {
589 - errno = 0;
590 - error("File %s does not have the same divisor. Clearing it.", fullfilename);
591 - bzero(rd, size);
592 - }
593 - else if(rd->algorithm != algorithm) {
594 - errno = 0;
595 - error("File %s does not have the same algorithm. Clearing it.", fullfilename);
596 - bzero(rd, size);
597 - }
598 - else if(rd->update_every != st->update_every) {
599 - errno = 0;
600 - error("File %s does not have the same refresh frequency. Clearing it.", fullfilename);
601 - bzero(rd, size);
602 - }
603 - else if(usec_dt(&now, &rd->last_collected_time) > (rd->entries * rd->update_every * 1000000ULL)) {
604 - errno = 0;
605 - error("File %s is too old. Clearing it.", fullfilename);
606 - bzero(rd, size);
607 - }
608 - else if(strcmp(rd->id, id) != 0) {
609 - errno = 0;
610 - error("File %s contents are not for dimension %s. Clearing it.", fullfilename, id);
611 - // munmap(rd, size);
612 - // rd = NULL;
613 - bzero(rd, size);
614 - }
615 - }
616 -
617 - if(rd) {
618 - // we have a file mapped for rd
619 - rd->mapped = rrd_memory_mode;
620 - rd->flags = 0x00000000;
557 + char filename[FILENAME_MAX + 1];
558 + char fullfilename[FILENAME_MAX + 1];
559 +
560 + char varname[CONFIG_MAX_NAME + 1];
561 + RRDDIM *rd = NULL;
562 + unsigned long size = sizeof(RRDDIM) + (st->entries * sizeof(storage_number));
563 +
564 + debug(D_RRD_CALLS, "Adding dimension '%s/%s'.", st->id, id);
565 +
566 + rrdset_strncpyz_name(filename, id, FILENAME_MAX);
567 + snprintfz(fullfilename, FILENAME_MAX, "%s/%s.db", st->cache_dir, filename);
568 + if(rrd_memory_mode != RRD_MEMORY_MODE_RAM) rd = (RRDDIM *)mymmap(fullfilename, size, ((rrd_memory_mode == RRD_MEMORY_MODE_MAP)?MAP_SHARED:MAP_PRIVATE), 1);
569 + if(rd) {
570 + struct timeval now;
571 + gettimeofday(&now, NULL);
572 +
573 + if(strcmp(rd->magic, RRDDIMENSION_MAGIC) != 0) {
574 + errno = 0;
575 + info("Initializing file %s.", fullfilename);
576 + bzero(rd, size);
577 + }
578 + else if(rd->memsize != size) {
579 + errno = 0;
580 + error("File %s does not have the desired size. Clearing it.", fullfilename);
581 + bzero(rd, size);
582 + }
583 + else if(rd->multiplier != multiplier) {
584 + errno = 0;
585 + error("File %s does not have the same multiplier. Clearing it.", fullfilename);
586 + bzero(rd, size);
587 + }
588 + else if(rd->divisor != divisor) {
589 + errno = 0;
590 + error("File %s does not have the same divisor. Clearing it.", fullfilename);
591 + bzero(rd, size);
592 + }
593 + else if(rd->algorithm != algorithm) {
594 + errno = 0;
595 + error("File %s does not have the same algorithm. Clearing it.", fullfilename);
596 + bzero(rd, size);
597 + }
598 + else if(rd->update_every != st->update_every) {
599 + errno = 0;
600 + error("File %s does not have the same refresh frequency. Clearing it.", fullfilename);
601 + bzero(rd, size);
602 + }
603 + else if(usec_dt(&now, &rd->last_collected_time) > (rd->entries * rd->update_every * 1000000ULL)) {
604 + errno = 0;
605 + error("File %s is too old. Clearing it.", fullfilename);
606 + bzero(rd, size);
607 + }
608 + else if(strcmp(rd->id, id) != 0) {
609 + errno = 0;
610 + error("File %s contents are not for dimension %s. Clearing it.", fullfilename, id);
611 + // munmap(rd, size);
612 + // rd = NULL;
613 + bzero(rd, size);
614 + }
615 + }
616 +
617 + if(rd) {
618 + // we have a file mapped for rd
619 + rd->mapped = rrd_memory_mode;
620 + rd->flags = 0x00000000;
621 rd->variables = NULL;
622 - rd->next = NULL;
623 - rd->name = NULL;
624 - }
625 - else {
626 - // if we didn't manage to get a mmap'd dimension, just create one
627 -
628 - rd = callocz(1, size);
629 - rd->mapped = RRD_MEMORY_MODE_RAM;
630 - }
631 - rd->memsize = size;
632 -
633 - strcpy(rd->magic, RRDDIMENSION_MAGIC);
634 - strcpy(rd->cache_filename, fullfilename);
635 - strncpyz(rd->id, id, RRD_ID_LENGTH_MAX);
636 - rd->hash = simple_hash(rd->id);
637 -
638 - snprintfz(varname, CONFIG_MAX_NAME, "dim %s name", rd->id);
639 - rd->name = config_get(st->id, varname, (name && *name)?name:rd->id);
640 -
641 - snprintfz(varname, CONFIG_MAX_NAME, "dim %s algorithm", rd->id);
642 - rd->algorithm = rrddim_algorithm_id(config_get(st->id, varname, rrddim_algorithm_name(algorithm)));
643 -
644 - snprintfz(varname, CONFIG_MAX_NAME, "dim %s multiplier", rd->id);
645 - rd->multiplier = config_get_number(st->id, varname, multiplier);
646 -
647 - snprintfz(varname, CONFIG_MAX_NAME, "dim %s divisor", rd->id);
648 - rd->divisor = config_get_number(st->id, varname, divisor);
649 - if(!rd->divisor) rd->divisor = 1;
650 -
651 - rd->entries = st->entries;
652 - rd->update_every = st->update_every;
653 -
654 - // prevent incremental calculation spikes
655 - rd->counter = 0;
656 - rd->updated = 0;
657 - rd->calculated_value = 0;
658 - rd->last_calculated_value = 0;
659 - rd->collected_value = 0;
660 - rd->last_collected_value = 0;
661 - rd->collected_volume = 0;
662 - rd->stored_volume = 0;
663 - rd->values[st->current_entry] = pack_storage_number(0, SN_NOT_EXISTS);
664 - rd->last_collected_time.tv_sec = 0;
665 - rd->last_collected_time.tv_usec = 0;
622 + rd->next = NULL;
623 + rd->name = NULL;
624 + }
625 + else {
626 + // if we didn't manage to get a mmap'd dimension, just create one
627 +
628 + rd = callocz(1, size);
629 + rd->mapped = RRD_MEMORY_MODE_RAM;
630 + }
631 + rd->memsize = size;
632 +
633 + strcpy(rd->magic, RRDDIMENSION_MAGIC);
634 + strcpy(rd->cache_filename, fullfilename);
635 + strncpyz(rd->id, id, RRD_ID_LENGTH_MAX);
636 + rd->hash = simple_hash(rd->id);
637 +
638 + snprintfz(varname, CONFIG_MAX_NAME, "dim %s name", rd->id);
639 + rd->name = config_get(st->id, varname, (name && *name)?name:rd->id);
640 +
641 + snprintfz(varname, CONFIG_MAX_NAME, "dim %s algorithm", rd->id);
642 + rd->algorithm = rrddim_algorithm_id(config_get(st->id, varname, rrddim_algorithm_name(algorithm)));
643 +
644 + snprintfz(varname, CONFIG_MAX_NAME, "dim %s multiplier", rd->id);
645 + rd->multiplier = config_get_number(st->id, varname, multiplier);
646 +
647 + snprintfz(varname, CONFIG_MAX_NAME, "dim %s divisor", rd->id);
648 + rd->divisor = config_get_number(st->id, varname, divisor);
649 + if(!rd->divisor) rd->divisor = 1;
650 +
651 + rd->entries = st->entries;
652 + rd->update_every = st->update_every;
653 +
654 + // prevent incremental calculation spikes
655 + rd->counter = 0;
656 + rd->updated = 0;
657 + rd->calculated_value = 0;
658 + rd->last_calculated_value = 0;
659 + rd->collected_value = 0;
660 + rd->last_collected_value = 0;
661 + rd->collected_volume = 0;
662 + rd->stored_volume = 0;
663 + rd->values[st->current_entry] = pack_storage_number(0, SN_NOT_EXISTS);
664 + rd->last_collected_time.tv_sec = 0;
665 + rd->last_collected_time.tv_usec = 0;
666 rd->rrdset = st;
667
668 // append this dimension
669 - pthread_rwlock_wrlock(&st->rwlock);
670 - if(!st->dimensions)
671 - st->dimensions = rd;
672 - else {
673 - RRDDIM *td = st->dimensions;
674 - for(; td->next; td = td->next) ;
675 - td->next = rd;
676 - }
669 + pthread_rwlock_wrlock(&st->rwlock);
670 + if(!st->dimensions)
671 + st->dimensions = rd;
672 + else {
673 + RRDDIM *td = st->dimensions;
674 + for(; td->next; td = td->next) ;
675 + td->next = rd;
676 + }
677
678 rrddimvar_create(rd, RRDVAR_TYPE_CALCULATED, NULL, NULL, &rd->calculated_value, 0);
679 rrddimvar_create(rd, RRDVAR_TYPE_COLLECTED, NULL, "_raw", &rd->collected_value, 0);
680 rrddimvar_create(rd, RRDVAR_TYPE_TIME_T, NULL, "_last_collected", &rd->last_collected_time.tv_sec, 0);
681
682 - pthread_rwlock_unlock(&st->rwlock);
682 + pthread_rwlock_unlock(&st->rwlock);
683
684 - rrddim_index_add(st, rd);
684 + rrddim_index_add(st, rd);
685
686 - return(rd);
686 + return(rd);
687 }
688
689 void rrddim_set_name(RRDSET *st, RRDDIM *rd, const char *name)
690 {
691 - debug(D_RRD_CALLS, "rrddim_set_name() %s.%s", st->name, rd->name);
691 + debug(D_RRD_CALLS, "rrddim_set_name() %s.%s", st->name, rd->name);
692
693 - char varname[CONFIG_MAX_NAME + 1];
694 - snprintfz(varname, CONFIG_MAX_NAME, "dim %s name", rd->id);
695 - config_set_default(st->id, varname, name);
693 + char varname[CONFIG_MAX_NAME + 1];
694 + snprintfz(varname, CONFIG_MAX_NAME, "dim %s name", rd->id);
695 + config_set_default(st->id, varname, name);
696
697 rrddimvar_rename_all(rd);
698 }
699
700 void rrddim_free(RRDSET *st, RRDDIM *rd)
701 {
702 - debug(D_RRD_CALLS, "rrddim_free() %s.%s", st->name, rd->name);
702 + debug(D_RRD_CALLS, "rrddim_free() %s.%s", st->name, rd->name);
703
704 - RRDDIM *i, *last = NULL;
705 - for(i = st->dimensions; i && i != rd ; i = i->next) last = i;
704 + RRDDIM *i, *last = NULL;
705 + for(i = st->dimensions; i && i != rd ; i = i->next) last = i;
706
707 - if(!i) {
708 - error("Request to free dimension %s.%s but it is not linked.", st->id, rd->name);
709 - return;
710 - }
707 + if(!i) {
708 + error("Request to free dimension %s.%s but it is not linked.", st->id, rd->name);
709 + return;
710 + }
711
712 - if(last) last->next = rd->next;
713 - else st->dimensions = rd->next;
714 - rd->next = NULL;
712 + if(last) last->next = rd->next;
713 + else st->dimensions = rd->next;
714 + rd->next = NULL;
715
716 while(rd->variables)
717 rrddimvar_free(rd->variables);
718
719 rrddim_index_del(st, rd);
720
721 - // free(rd->annotations);
722 - if(rd->mapped == RRD_MEMORY_MODE_SAVE) {
723 - debug(D_RRD_CALLS, "Saving dimension '%s' to '%s'.", rd->name, rd->cache_filename);
724 - savememory(rd->cache_filename, rd, rd->memsize);
725 -
726 - debug(D_RRD_CALLS, "Unmapping dimension '%s'.", rd->name);
727 - munmap(rd, rd->memsize);
728 - }
729 - else if(rd->mapped == RRD_MEMORY_MODE_MAP) {
730 - debug(D_RRD_CALLS, "Unmapping dimension '%s'.", rd->name);
731 - munmap(rd, rd->memsize);
732 - }
733 - else {
734 - debug(D_RRD_CALLS, "Removing dimension '%s'.", rd->name);
735 - freez(rd);
736 - }
721 + // free(rd->annotations);
722 + if(rd->mapped == RRD_MEMORY_MODE_SAVE) {
723 + debug(D_RRD_CALLS, "Saving dimension '%s' to '%s'.", rd->name, rd->cache_filename);
724 + savememory(rd->cache_filename, rd, rd->memsize);
725 +
726 + debug(D_RRD_CALLS, "Unmapping dimension '%s'.", rd->name);
727 + munmap(rd, rd->memsize);
728 + }
729 + else if(rd->mapped == RRD_MEMORY_MODE_MAP) {
730 + debug(D_RRD_CALLS, "Unmapping dimension '%s'.", rd->name);
731 + munmap(rd, rd->memsize);
732 + }
733 + else {
734 + debug(D_RRD_CALLS, "Removing dimension '%s'.", rd->name);
735 + freez(rd);
736 + }
737 }
738
739 void rrdset_free_all(void)
740 {
741 - info("Freeing all memory...");
741 + info("Freeing all memory...");
742
743 pthread_rwlock_wrlock(&localhost.rrdset_root_rwlock);
744
745 - RRDSET *st;
746 - for(st = localhost.rrdset_root; st ;) {
747 - RRDSET *next = st->next;
745 + RRDSET *st;
746 + for(st = localhost.rrdset_root; st ;) {
747 + RRDSET *next = st->next;
748
749 pthread_rwlock_wrlock(&st->rwlock);
750
@@ -755,7 +755,7 @@ void rrdset_free_all(void)
755 rrdsetcalc_unlink(st->calculations);
756
757 while(st->dimensions)
758 - rrddim_free(st, st->dimensions);
758 + rrddim_free(st, st->dimensions);
759
760 rrdset_index_del(&localhost, st);
761
@@ -765,704 +765,704 @@ void rrdset_free_all(void)
765
766 pthread_rwlock_unlock(&st->rwlock);
767
768 - if(st->mapped == RRD_MEMORY_MODE_SAVE) {
769 - debug(D_RRD_CALLS, "Saving stats '%s' to '%s'.", st->name, st->cache_filename);
770 - savememory(st->cache_filename, st, st->memsize);
771 -
772 - debug(D_RRD_CALLS, "Unmapping stats '%s'.", st->name);
773 - munmap(st, st->memsize);
774 - }
775 - else if(st->mapped == RRD_MEMORY_MODE_MAP) {
776 - debug(D_RRD_CALLS, "Unmapping stats '%s'.", st->name);
777 - munmap(st, st->memsize);
778 - }
779 - else
780 - freez(st);
781 -
782 - st = next;
783 - }
768 + if(st->mapped == RRD_MEMORY_MODE_SAVE) {
769 + debug(D_RRD_CALLS, "Saving stats '%s' to '%s'.", st->name, st->cache_filename);
770 + savememory(st->cache_filename, st, st->memsize);
771 +
772 + debug(D_RRD_CALLS, "Unmapping stats '%s'.", st->name);
773 + munmap(st, st->memsize);
774 + }
775 + else if(st->mapped == RRD_MEMORY_MODE_MAP) {
776 + debug(D_RRD_CALLS, "Unmapping stats '%s'.", st->name);
777 + munmap(st, st->memsize);
778 + }
779 + else
780 + freez(st);
781 +
782 + st = next;
783 + }
784 localhost.rrdset_root = NULL;
785
786 pthread_rwlock_unlock(&localhost.rrdset_root_rwlock);
787
788 - info("Memory cleanup completed...");
788 + info("Memory cleanup completed...");
789 }
790
791 void rrdset_save_all(void) {
792 - info("Saving database...");
793 -
794 - RRDSET *st;
795 - RRDDIM *rd;
796 -
797 - pthread_rwlock_wrlock(&localhost.rrdset_root_rwlock);
798 - for(st = localhost.rrdset_root; st ; st = st->next) {
799 - pthread_rwlock_wrlock(&st->rwlock);
800 -
801 - if(st->mapped == RRD_MEMORY_MODE_SAVE) {
802 - debug(D_RRD_CALLS, "Saving stats '%s' to '%s'.", st->name, st->cache_filename);
803 - savememory(st->cache_filename, st, st->memsize);
804 - }
805 -
806 - for(rd = st->dimensions; rd ; rd = rd->next) {
807 - if(likely(rd->mapped == RRD_MEMORY_MODE_SAVE)) {
808 - debug(D_RRD_CALLS, "Saving dimension '%s' to '%s'.", rd->name, rd->cache_filename);
809 - savememory(rd->cache_filename, rd, rd->memsize);
810 - }
811 - }
812 -
813 - pthread_rwlock_unlock(&st->rwlock);
814 - }
815 - pthread_rwlock_unlock(&localhost.rrdset_root_rwlock);
792 + info("Saving database...");
793 +
794 + RRDSET *st;
795 + RRDDIM *rd;
796 +
797 + pthread_rwlock_wrlock(&localhost.rrdset_root_rwlock);
798 + for(st = localhost.rrdset_root; st ; st = st->next) {
799 + pthread_rwlock_wrlock(&st->rwlock);
800 +
801 + if(st->mapped == RRD_MEMORY_MODE_SAVE) {
802 + debug(D_RRD_CALLS, "Saving stats '%s' to '%s'.", st->name, st->cache_filename);
803 + savememory(st->cache_filename, st, st->memsize);
804 + }
805 +
806 + for(rd = st->dimensions; rd ; rd = rd->next) {
807 + if(likely(rd->mapped == RRD_MEMORY_MODE_SAVE)) {
808 + debug(D_RRD_CALLS, "Saving dimension '%s' to '%s'.", rd->name, rd->cache_filename);
809 + savememory(rd->cache_filename, rd, rd->memsize);
810 + }
811 + }
812 +
813 + pthread_rwlock_unlock(&st->rwlock);
814 + }
815 + pthread_rwlock_unlock(&localhost.rrdset_root_rwlock);
816 }
817
818
819 RRDSET *rrdset_find(const char *id)
820 {
821 - debug(D_RRD_CALLS, "rrdset_find() for chart %s", id);
821 + debug(D_RRD_CALLS, "rrdset_find() for chart %s", id);
822
823 - RRDSET *st = rrdset_index_find(&localhost, id, 0);
824 - return(st);
823 + RRDSET *st = rrdset_index_find(&localhost, id, 0);
824 + return(st);
825 }
826
827 RRDSET *rrdset_find_bytype(const char *type, const char *id)
828 {
829 - debug(D_RRD_CALLS, "rrdset_find_bytype() for chart %s.%s", type, id);
829 + debug(D_RRD_CALLS, "rrdset_find_bytype() for chart %s.%s", type, id);
830
831 - char buf[RRD_ID_LENGTH_MAX + 1];
831 + char buf[RRD_ID_LENGTH_MAX + 1];
832
833 - strncpyz(buf, type, RRD_ID_LENGTH_MAX - 1);
834 - strcat(buf, ".");
835 - int len = (int) strlen(buf);
836 - strncpyz(&buf[len], id, (size_t) (RRD_ID_LENGTH_MAX - len));
833 + strncpyz(buf, type, RRD_ID_LENGTH_MAX - 1);
834 + strcat(buf, ".");
835 + int len = (int) strlen(buf);
836 + strncpyz(&buf[len], id, (size_t) (RRD_ID_LENGTH_MAX - len));
837
838 - return(rrdset_find(buf));
838 + return(rrdset_find(buf));
839 }
840
841 RRDSET *rrdset_find_byname(const char *name)
842 {
843 - debug(D_RRD_CALLS, "rrdset_find_byname() for chart %s", name);
843 + debug(D_RRD_CALLS, "rrdset_find_byname() for chart %s", name);
844
845 - RRDSET *st = rrdset_index_find_name(&localhost, name, 0);
846 - return(st);
845 + RRDSET *st = rrdset_index_find_name(&localhost, name, 0);
846 + return(st);
847 }
848
849 RRDDIM *rrddim_find(RRDSET *st, const char *id)
850 {
851 - debug(D_RRD_CALLS, "rrddim_find() for chart %s, dimension %s", st->name, id);
851 + debug(D_RRD_CALLS, "rrddim_find() for chart %s, dimension %s", st->name, id);
852
853 - return rrddim_index_find(st, id, 0);
853 + return rrddim_index_find(st, id, 0);
854 }
855
856 int rrddim_hide(RRDSET *st, const char *id)
857 {
858 - debug(D_RRD_CALLS, "rrddim_hide() for chart %s, dimension %s", st->name, id);
858 + debug(D_RRD_CALLS, "rrddim_hide() for chart %s, dimension %s", st->name, id);
859
860 - RRDDIM *rd = rrddim_find(st, id);
861 - if(unlikely(!rd)) {
862 - error("Cannot find dimension with id '%s' on stats '%s' (%s).", id, st->name, st->id);
863 - return 1;
864 - }
860 + RRDDIM *rd = rrddim_find(st, id);
861 + if(unlikely(!rd)) {
862 + error("Cannot find dimension with id '%s' on stats '%s' (%s).", id, st->name, st->id);
863 + return 1;
864 + }
865
866 - rd->flags |= RRDDIM_FLAG_HIDDEN;
867 - return 0;
866 + rd->flags |= RRDDIM_FLAG_HIDDEN;
867 + return 0;
868 }
869
870 int rrddim_unhide(RRDSET *st, const char *id)
871 {
872 - debug(D_RRD_CALLS, "rrddim_unhide() for chart %s, dimension %s", st->name, id);
872 + debug(D_RRD_CALLS, "rrddim_unhide() for chart %s, dimension %s", st->name, id);
873
874 - RRDDIM *rd = rrddim_find(st, id);
875 - if(unlikely(!rd)) {
876 - error("Cannot find dimension with id '%s' on stats '%s' (%s).", id, st->name, st->id);
877 - return 1;
878 - }
874 + RRDDIM *rd = rrddim_find(st, id);
875 + if(unlikely(!rd)) {
876 + error("Cannot find dimension with id '%s' on stats '%s' (%s).", id, st->name, st->id);
877 + return 1;
878 + }
879
880 - if(rd->flags & RRDDIM_FLAG_HIDDEN) rd->flags ^= RRDDIM_FLAG_HIDDEN;
881 - return 0;
880 + if(rd->flags & RRDDIM_FLAG_HIDDEN) rd->flags ^= RRDDIM_FLAG_HIDDEN;
881 + return 0;
882 }
883
884 collected_number rrddim_set_by_pointer(RRDSET *st, RRDDIM *rd, collected_number value)
885 {
886 - debug(D_RRD_CALLS, "rrddim_set_by_pointer() for chart %s, dimension %s, value " COLLECTED_NUMBER_FORMAT, st->name, rd->name, value);
886 + debug(D_RRD_CALLS, "rrddim_set_by_pointer() for chart %s, dimension %s, value " COLLECTED_NUMBER_FORMAT, st->name, rd->name, value);
887
888 - gettimeofday(&rd->last_collected_time, NULL);
889 - rd->collected_value = value;
890 - rd->updated = 1;
891 - rd->counter++;
888 + gettimeofday(&rd->last_collected_time, NULL);
889 + rd->collected_value = value;
890 + rd->updated = 1;
891 + rd->counter++;
892
893 - return rd->last_collected_value;
893 + return rd->last_collected_value;
894 }
895
896 collected_number rrddim_set(RRDSET *st, const char *id, collected_number value)
897 {
898 - RRDDIM *rd = rrddim_find(st, id);
899 - if(unlikely(!rd)) {
900 - error("Cannot find dimension with id '%s' on stats '%s' (%s).", id, st->name, st->id);
901 - return 0;
902 - }
898 + RRDDIM *rd = rrddim_find(st, id);
899 + if(unlikely(!rd)) {
900 + error("Cannot find dimension with id '%s' on stats '%s' (%s).", id, st->name, st->id);
901 + return 0;
902 + }
903
904 - return rrddim_set_by_pointer(st, rd, value);
904 + return rrddim_set_by_pointer(st, rd, value);
905 }
906
907 void rrdset_next_usec(RRDSET *st, unsigned long long microseconds)
908 {
909 - if(!microseconds) rrdset_next(st);
910 - else {
911 - debug(D_RRD_CALLS, "rrdset_next_usec() for chart %s with microseconds %llu", st->name, microseconds);
909 + if(!microseconds) rrdset_next(st);
910 + else {
911 + debug(D_RRD_CALLS, "rrdset_next_usec() for chart %s with microseconds %llu", st->name, microseconds);
912
913 - if(unlikely(st->debug)) debug(D_RRD_STATS, "%s: NEXT: %llu microseconds", st->name, microseconds);
914 - st->usec_since_last_update = microseconds;
915 - }
913 + if(unlikely(st->debug)) debug(D_RRD_STATS, "%s: NEXT: %llu microseconds", st->name, microseconds);
914 + st->usec_since_last_update = microseconds;
915 + }
916 }
917
918 void rrdset_next(RRDSET *st)
919 {
920 - unsigned long long microseconds = 0;
920 + unsigned long long microseconds = 0;
921
922 - if(likely(st->last_collected_time.tv_sec)) {
923 - struct timeval now;
924 - gettimeofday(&now, NULL);
925 - microseconds = usec_dt(&now, &st->last_collected_time);
926 - }
927 - // prevent infinite loop
928 - else microseconds = st->update_every * 1000000ULL;
922 + if(likely(st->last_collected_time.tv_sec)) {
923 + struct timeval now;
924 + gettimeofday(&now, NULL);
925 + microseconds = usec_dt(&now, &st->last_collected_time);
926 + }
927 + // prevent infinite loop
928 + else microseconds = st->update_every * 1000000ULL;
929
930 - rrdset_next_usec(st, microseconds);
930 + rrdset_next_usec(st, microseconds);
931 }
932
933 void rrdset_next_plugins(RRDSET *st)
934 {
935 - rrdset_next(st);
935 + rrdset_next(st);
936 }
937
938 unsigned long long rrdset_done(RRDSET *st)
939 {
940 - if(unlikely(netdata_exit)) return 0;
941 -
942 - debug(D_RRD_CALLS, "rrdset_done() for chart %s", st->name);
943 -
944 - RRDDIM *rd, *last;
945 - int oldstate, store_this_entry = 1, first_entry = 0;
946 - unsigned long long last_ut, now_ut, next_ut, stored_entries = 0;
947 -
948 - if(unlikely(pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate) != 0))
949 - error("Cannot set pthread cancel state to DISABLE.");
950 -
951 - // a read lock is OK here
952 - pthread_rwlock_rdlock(&st->rwlock);
953 -
954 - // enable the chart, if it was disabled
955 - if(unlikely(rrd_delete_unupdated_dimensions) && !st->enabled)
956 - st->enabled = 1;
957 -
958 - // check if the chart has a long time to be updated
959 - if(unlikely(st->usec_since_last_update > st->entries * st->update_every * 1000000ULL)) {
960 - info("%s: took too long to be updated (%0.3Lf secs). Reseting it.", st->name, (long double)(st->usec_since_last_update / 1000000.0));
961 - rrdset_reset(st);
962 - st->usec_since_last_update = st->update_every * 1000000ULL;
963 - first_entry = 1;
964 - }
965 - if(unlikely(st->debug)) debug(D_RRD_STATS, "%s: microseconds since last update: %llu", st->name, st->usec_since_last_update);
966 -
967 - // set last_collected_time
968 - if(unlikely(!st->last_collected_time.tv_sec)) {
969 - // it is the first entry
970 - // set the last_collected_time to now
971 - gettimeofday(&st->last_collected_time, NULL);
972 -
973 - // the first entry should not be stored
974 - store_this_entry = 0;
975 - first_entry = 1;
976 -
977 - if(unlikely(st->debug)) debug(D_RRD_STATS, "%s: has not set last_collected_time. Setting it now. Will not store the next entry.", st->name);
978 - }
979 - else {
980 - // it is not the first entry
981 - // calculate the proper last_collected_time, using usec_since_last_update
982 - unsigned long long ut = st->last_collected_time.tv_sec * 1000000ULL + st->last_collected_time.tv_usec + st->usec_since_last_update;
983 - st->last_collected_time.tv_sec = (time_t) (ut / 1000000ULL);
984 - st->last_collected_time.tv_usec = (suseconds_t) (ut % 1000000ULL);
985 - }
986 -
987 - // if this set has not been updated in the past
988 - // we fake the last_update time to be = now - usec_since_last_update
989 - if(unlikely(!st->last_updated.tv_sec)) {
990 - // it has never been updated before
991 - // set a fake last_updated, in the past using usec_since_last_update
992 - unsigned long long ut = st->last_collected_time.tv_sec * 1000000ULL + st->last_collected_time.tv_usec - st->usec_since_last_update;
993 - st->last_updated.tv_sec = (time_t) (ut / 1000000ULL);
994 - st->last_updated.tv_usec = (suseconds_t) (ut % 1000000ULL);
995 -
996 - // the first entry should not be stored
997 - store_this_entry = 0;
998 - first_entry = 1;
999 -
1000 - if(unlikely(st->debug)) debug(D_RRD_STATS, "%s: initializing last_updated to now - %llu microseconds (%0.3Lf). Will not store the next entry.", st->name, st->usec_since_last_update, (long double)ut/1000000.0);
1001 - }
1002 -
1003 - // check if we will re-write the entire data set
1004 - if(unlikely(usec_dt(&st->last_collected_time, &st->last_updated) > st->update_every * st->entries * 1000000ULL)) {
1005 - info("%s: too old data (last updated at %ld.%ld, last collected at %ld.%ld). Reseting it. Will not store the next entry.", st->name, st->last_updated.tv_sec, st->last_updated.tv_usec, st->last_collected_time.tv_sec, st->last_collected_time.tv_usec);
1006 - rrdset_reset(st);
1007 -
1008 - st->usec_since_last_update = st->update_every * 1000000ULL;
1009 -
1010 - gettimeofday(&st->last_collected_time, NULL);
1011 -
1012 - unsigned long long ut = st->last_collected_time.tv_sec * 1000000ULL + st->last_collected_time.tv_usec - st->usec_since_last_update;
1013 - st->last_updated.tv_sec = (time_t) (ut / 1000000ULL);
1014 - st->last_updated.tv_usec = (suseconds_t) (ut % 1000000ULL);
1015 -
1016 - // the first entry should not be stored
1017 - store_this_entry = 0;
1018 - first_entry = 1;
1019 - }
1020 -
1021 - // these are the 3 variables that will help us in interpolation
1022 - // last_ut = the last time we added a value to the storage
1023 - // now_ut = the time the current value is taken at
1024 - // next_ut = the time of the next interpolation point
1025 - last_ut = st->last_updated.tv_sec * 1000000ULL + st->last_updated.tv_usec;
1026 - now_ut = st->last_collected_time.tv_sec * 1000000ULL + st->last_collected_time.tv_usec;
1027 - next_ut = (st->last_updated.tv_sec + st->update_every) * 1000000ULL;
1028 -
1029 - if(unlikely(!first_entry && now_ut < next_ut)) {
1030 - if(unlikely(st->debug)) debug(D_RRD_STATS, "%s: THIS IS IN THE SAME INTERPOLATION POINT", st->name);
1031 - }
1032 -
1033 - if(unlikely(st->debug)) {
1034 - debug(D_RRD_STATS, "%s: last ut = %0.3Lf (last updated time)", st->name, (long double)last_ut/1000000.0);
1035 - debug(D_RRD_STATS, "%s: now ut = %0.3Lf (current update time)", st->name, (long double)now_ut/1000000.0);
1036 - debug(D_RRD_STATS, "%s: next ut = %0.3Lf (next interpolation point)", st->name, (long double)next_ut/1000000.0);
1037 - }
1038 -
1039 - if(unlikely(!st->counter_done)) {
1040 - store_this_entry = 0;
1041 - if(unlikely(st->debug)) debug(D_RRD_STATS, "%s: Will not store the next entry.", st->name);
1042 - }
1043 - st->counter_done++;
1044 -
1045 - // calculate totals and count the dimensions
1046 - int dimensions;
1047 - st->collected_total = 0;
1048 - for( rd = st->dimensions, dimensions = 0 ; likely(rd) ; rd = rd->next, dimensions++ )
1049 - if(likely(rd->updated)) st->collected_total += rd->collected_value;
1050 -
1051 - uint32_t storage_flags = SN_EXISTS;
1052 -
1053 - // process all dimensions to calculate their values
1054 - // based on the collected figures only
1055 - // at this stage we do not interpolate anything
1056 - for( rd = st->dimensions ; likely(rd) ; rd = rd->next ) {
1057 -
1058 - if(unlikely(!rd->updated)) {
1059 - rd->calculated_value = 0;
1060 - continue;
1061 - }
1062 -
1063 - if(unlikely(st->debug)) debug(D_RRD_STATS, "%s/%s: START "
1064 - " last_collected_value = " COLLECTED_NUMBER_FORMAT
1065 - " collected_value = " COLLECTED_NUMBER_FORMAT
1066 - " last_calculated_value = " CALCULATED_NUMBER_FORMAT
1067 - " calculated_value = " CALCULATED_NUMBER_FORMAT
1068 - , st->id, rd->name
1069 - , rd->last_collected_value
1070 - , rd->collected_value
1071 - , rd->last_calculated_value
1072 - , rd->calculated_value
1073 - );
1074 -
1075 - switch(rd->algorithm) {
1076 - case RRDDIM_ABSOLUTE:
1077 - rd->calculated_value = (calculated_number)rd->collected_value
1078 - * (calculated_number)rd->multiplier
1079 - / (calculated_number)rd->divisor;
1080 -
1081 - if(unlikely(st->debug))
1082 - debug(D_RRD_STATS, "%s/%s: CALC ABS/ABS-NO-IN "
1083 - CALCULATED_NUMBER_FORMAT " = "
1084 - COLLECTED_NUMBER_FORMAT
1085 - " * " CALCULATED_NUMBER_FORMAT
1086 - " / " CALCULATED_NUMBER_FORMAT
1087 - , st->id, rd->name
1088 - , rd->calculated_value
1089 - , rd->collected_value
1090 - , (calculated_number)rd->multiplier
1091 - , (calculated_number)rd->divisor
1092 - );
1093 - break;
1094 -
1095 - case RRDDIM_PCENT_OVER_ROW_TOTAL:
1096 - if(unlikely(!st->collected_total))
1097 - rd->calculated_value = 0;
1098 - else
1099 - // the percentage of the current value
1100 - // over the total of all dimensions
1101 - rd->calculated_value =
1102 - (calculated_number)100
1103 - * (calculated_number)rd->collected_value
1104 - / (calculated_number)st->collected_total;
1105 -
1106 - if(unlikely(st->debug))
1107 - debug(D_RRD_STATS, "%s/%s: CALC PCENT-ROW "
1108 - CALCULATED_NUMBER_FORMAT " = 100"
1109 - " * " COLLECTED_NUMBER_FORMAT
1110 - " / " COLLECTED_NUMBER_FORMAT
1111 - , st->id, rd->name
1112 - , rd->calculated_value
1113 - , rd->collected_value
1114 - , st->collected_total
1115 - );
1116 - break;
1117 -
1118 - case RRDDIM_INCREMENTAL:
1119 - if(unlikely(rd->counter <= 1)) {
1120 - rd->calculated_value = 0;
1121 - continue;
1122 - }
1123 -
1124 - // if the new is smaller than the old (an overflow, or reset), set the old equal to the new
1125 - // to reset the calculation (it will give zero as the calculation for this second)
1126 - if(unlikely(rd->last_collected_value > rd->collected_value)) {
1127 - debug(D_RRD_STATS, "%s.%s: RESET or OVERFLOW. Last collected value = " COLLECTED_NUMBER_FORMAT ", current = " COLLECTED_NUMBER_FORMAT
1128 - , st->name, rd->name
1129 - , rd->last_collected_value
1130 - , rd->collected_value);
1131 - if(!(rd->flags & RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS)) storage_flags = SN_EXISTS_RESET;
1132 - rd->last_collected_value = rd->collected_value;
1133 - }
1134 -
1135 - rd->calculated_value =
1136 - (calculated_number)(rd->collected_value - rd->last_collected_value)
1137 - * (calculated_number)rd->multiplier
1138 - / (calculated_number)rd->divisor;
1139 -
1140 - if(unlikely(st->debug))
1141 - debug(D_RRD_STATS, "%s/%s: CALC INC PRE "
1142 - CALCULATED_NUMBER_FORMAT " = ("
1143 - COLLECTED_NUMBER_FORMAT " - " COLLECTED_NUMBER_FORMAT
1144 - ")"
1145 - " * " CALCULATED_NUMBER_FORMAT
1146 - " / " CALCULATED_NUMBER_FORMAT
1147 - , st->id, rd->name
1148 - , rd->calculated_value
1149 - , rd->collected_value, rd->last_collected_value
1150 - , (calculated_number)rd->multiplier
1151 - , (calculated_number)rd->divisor
1152 - );
1153 - break;
1154 -
1155 - case RRDDIM_PCENT_OVER_DIFF_TOTAL:
1156 - if(unlikely(rd->counter <= 1)) {
1157 - rd->calculated_value = 0;
1158 - continue;
1159 - }
1160 -
1161 - // if the new is smaller than the old (an overflow, or reset), set the old equal to the new
1162 - // to reset the calculation (it will give zero as the calculation for this second)
1163 - if(unlikely(rd->last_collected_value > rd->collected_value)) {
1164 - debug(D_RRD_STATS, "%s.%s: RESET or OVERFLOW. Last collected value = " COLLECTED_NUMBER_FORMAT ", current = " COLLECTED_NUMBER_FORMAT
1165 - , st->name, rd->name
1166 - , rd->last_collected_value
1167 - , rd->collected_value);
1168 - if(!(rd->flags & RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS)) storage_flags = SN_EXISTS_RESET;
1169 - rd->last_collected_value = rd->collected_value;
1170 - }
1171 -
1172 - // the percentage of the current increment
1173 - // over the increment of all dimensions together
1174 - if(unlikely(st->collected_total == st->last_collected_total))
1175 - rd->calculated_value = 0;
1176 - else
1177 - rd->calculated_value =
1178 - (calculated_number)100
1179 - * (calculated_number)(rd->collected_value - rd->last_collected_value)
1180 - / (calculated_number)(st->collected_total - st->last_collected_total);
1181 -
1182 - if(unlikely(st->debug))
1183 - debug(D_RRD_STATS, "%s/%s: CALC PCENT-DIFF "
1184 - CALCULATED_NUMBER_FORMAT " = 100"
1185 - " * (" COLLECTED_NUMBER_FORMAT " - " COLLECTED_NUMBER_FORMAT ")"
1186 - " / (" COLLECTED_NUMBER_FORMAT " - " COLLECTED_NUMBER_FORMAT ")"
1187 - , st->id, rd->name
1188 - , rd->calculated_value
1189 - , rd->collected_value, rd->last_collected_value
1190 - , st->collected_total, st->last_collected_total
1191 - );
1192 - break;
1193 -
1194 - default:
1195 - // make the default zero, to make sure
1196 - // it gets noticed when we add new types
1197 - rd->calculated_value = 0;
1198 -
1199 - if(unlikely(st->debug))
1200 - debug(D_RRD_STATS, "%s/%s: CALC "
1201 - CALCULATED_NUMBER_FORMAT " = 0"
1202 - , st->id, rd->name
1203 - , rd->calculated_value
1204 - );
1205 - break;
1206 - }
1207 -
1208 - if(unlikely(st->debug)) debug(D_RRD_STATS, "%s/%s: PHASE2 "
1209 - " last_collected_value = " COLLECTED_NUMBER_FORMAT
1210 - " collected_value = " COLLECTED_NUMBER_FORMAT
1211 - " last_calculated_value = " CALCULATED_NUMBER_FORMAT
1212 - " calculated_value = " CALCULATED_NUMBER_FORMAT
1213 - , st->id, rd->name
1214 - , rd->last_collected_value
1215 - , rd->collected_value
1216 - , rd->last_calculated_value
1217 - , rd->calculated_value
1218 - );
1219 -
1220 - }
1221 -
1222 - // at this point we have all the calculated values ready
1223 - // it is now time to interpolate values on a second boundary
1224 -
1225 - unsigned long long first_ut = last_ut;
1226 - long long iterations = (now_ut - last_ut) / (st->update_every * 1000000ULL);
1227 - if((now_ut % (st->update_every * 1000000ULL)) == 0) iterations++;
1228 -
1229 - for( ; likely(next_ut <= now_ut) ; next_ut += st->update_every * 1000000ULL, iterations-- ) {
940 + if(unlikely(netdata_exit)) return 0;
941 +
942 + debug(D_RRD_CALLS, "rrdset_done() for chart %s", st->name);
943 +
944 + RRDDIM *rd, *last;
945 + int oldstate, store_this_entry = 1, first_entry = 0;
946 + unsigned long long last_ut, now_ut, next_ut, stored_entries = 0;
947 +
948 + if(unlikely(pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate) != 0))
949 + error("Cannot set pthread cancel state to DISABLE.");
950 +
951 + // a read lock is OK here
952 + pthread_rwlock_rdlock(&st->rwlock);
953 +
954 + // enable the chart, if it was disabled
955 + if(unlikely(rrd_delete_unupdated_dimensions) && !st->enabled)
956 + st->enabled = 1;
957 +
958 + // check if the chart has a long time to be updated
959 + if(unlikely(st->usec_since_last_update > st->entries * st->update_every * 1000000ULL)) {
960 + info("%s: took too long to be updated (%0.3Lf secs). Reseting it.", st->name, (long double)(st->usec_since_last_update / 1000000.0));
961 + rrdset_reset(st);
962 + st->usec_since_last_update = st->update_every * 1000000ULL;
963 + first_entry = 1;
964 + }
965 + if(unlikely(st->debug)) debug(D_RRD_STATS, "%s: microseconds since last update: %llu", st->name, st->usec_since_last_update);
966 +
967 + // set last_collected_time
968 + if(unlikely(!st->last_collected_time.tv_sec)) {
969 + // it is the first entry
970 + // set the last_collected_time to now
971 + gettimeofday(&st->last_collected_time, NULL);
972 +
973 + // the first entry should not be stored
974 + store_this_entry = 0;
975 + first_entry = 1;
976 +
977 + if(unlikely(st->debug)) debug(D_RRD_STATS, "%s: has not set last_collected_time. Setting it now. Will not store the next entry.", st->name);
978 + }
979 + else {
980 + // it is not the first entry
981 + // calculate the proper last_collected_time, using usec_since_last_update
982 + unsigned long long ut = st->last_collected_time.tv_sec * 1000000ULL + st->last_collected_time.tv_usec + st->usec_since_last_update;
983 + st->last_collected_time.tv_sec = (time_t) (ut / 1000000ULL);
984 + st->last_collected_time.tv_usec = (suseconds_t) (ut % 1000000ULL);
985 + }
986 +
987 + // if this set has not been updated in the past
988 + // we fake the last_update time to be = now - usec_since_last_update
989 + if(unlikely(!st->last_updated.tv_sec)) {
990 + // it has never been updated before
991 + // set a fake last_updated, in the past using usec_since_last_update
992 + unsigned long long ut = st->last_collected_time.tv_sec * 1000000ULL + st->last_collected_time.tv_usec - st->usec_since_last_update;
993 + st->last_updated.tv_sec = (time_t) (ut / 1000000ULL);
994 + st->last_updated.tv_usec = (suseconds_t) (ut % 1000000ULL);
995 +
996 + // the first entry should not be stored
997 + store_this_entry = 0;
998 + first_entry = 1;
999 +
1000 + if(unlikely(st->debug)) debug(D_RRD_STATS, "%s: initializing last_updated to now - %llu microseconds (%0.3Lf). Will not store the next entry.", st->name, st->usec_since_last_update, (long double)ut/1000000.0);
1001 + }
1002 +
1003 + // check if we will re-write the entire data set
1004 + if(unlikely(usec_dt(&st->last_collected_time, &st->last_updated) > st->update_every * st->entries * 1000000ULL)) {
1005 + info("%s: too old data (last updated at %ld.%ld, last collected at %ld.%ld). Reseting it. Will not store the next entry.", st->name, st->last_updated.tv_sec, st->last_updated.tv_usec, st->last_collected_time.tv_sec, st->last_collected_time.tv_usec);
1006 + rrdset_reset(st);
1007 +
1008 + st->usec_since_last_update = st->update_every * 1000000ULL;
1009 +
1010 + gettimeofday(&st->last_collected_time, NULL);
1011 +
1012 + unsigned long long ut = st->last_collected_time.tv_sec * 1000000ULL + st->last_collected_time.tv_usec - st->usec_since_last_update;
1013 + st->last_updated.tv_sec = (time_t) (ut / 1000000ULL);
1014 + st->last_updated.tv_usec = (suseconds_t) (ut % 1000000ULL);
1015 +
1016 + // the first entry should not be stored
1017 + store_this_entry = 0;
1018 + first_entry = 1;
1019 + }
1020 +
1021 + // these are the 3 variables that will help us in interpolation
1022 + // last_ut = the last time we added a value to the storage
1023 + // now_ut = the time the current value is taken at
1024 + // next_ut = the time of the next interpolation point
1025 + last_ut = st->last_updated.tv_sec * 1000000ULL + st->last_updated.tv_usec;
1026 + now_ut = st->last_collected_time.tv_sec * 1000000ULL + st->last_collected_time.tv_usec;
1027 + next_ut = (st->last_updated.tv_sec + st->update_every) * 1000000ULL;
1028 +
1029 + if(unlikely(!first_entry && now_ut < next_ut)) {
1030 + if(unlikely(st->debug)) debug(D_RRD_STATS, "%s: THIS IS IN THE SAME INTERPOLATION POINT", st->name);
1031 + }
1032 +
1033 + if(unlikely(st->debug)) {
1034 + debug(D_RRD_STATS, "%s: last ut = %0.3Lf (last updated time)", st->name, (long double)last_ut/1000000.0);
1035 + debug(D_RRD_STATS, "%s: now ut = %0.3Lf (current update time)", st->name, (long double)now_ut/1000000.0);
1036 + debug(D_RRD_STATS, "%s: next ut = %0.3Lf (next interpolation point)", st->name, (long double)next_ut/1000000.0);
1037 + }
1038 +
1039 + if(unlikely(!st->counter_done)) {
1040 + store_this_entry = 0;
1041 + if(unlikely(st->debug)) debug(D_RRD_STATS, "%s: Will not store the next entry.", st->name);
1042 + }
1043 + st->counter_done++;
1044 +
1045 + // calculate totals and count the dimensions
1046 + int dimensions;
1047 + st->collected_total = 0;
1048 + for( rd = st->dimensions, dimensions = 0 ; likely(rd) ; rd = rd->next, dimensions++ )
1049 + if(likely(rd->updated)) st->collected_total += rd->collected_value;
1050 +
1051 + uint32_t storage_flags = SN_EXISTS;
1052 +
1053 + // process all dimensions to calculate their values
1054 + // based on the collected figures only
1055 + // at this stage we do not interpolate anything
1056 + for( rd = st->dimensions ; likely(rd) ; rd = rd->next ) {
1057 +
1058 + if(unlikely(!rd->updated)) {
1059 + rd->calculated_value = 0;
1060 + continue;
1061 + }
1062 +
1063 + if(unlikely(st->debug)) debug(D_RRD_STATS, "%s/%s: START "
1064 + " last_collected_value = " COLLECTED_NUMBER_FORMAT
1065 + " collected_value = " COLLECTED_NUMBER_FORMAT
1066 + " last_calculated_value = " CALCULATED_NUMBER_FORMAT
1067 + " calculated_value = " CALCULATED_NUMBER_FORMAT
1068 + , st->id, rd->name
1069 + , rd->last_collected_value
1070 + , rd->collected_value
1071 + , rd->last_calculated_value
1072 + , rd->calculated_value
1073 + );
1074 +
1075 + switch(rd->algorithm) {
1076 + case RRDDIM_ABSOLUTE:
1077 + rd->calculated_value = (calculated_number)rd->collected_value
1078 + * (calculated_number)rd->multiplier
1079 + / (calculated_number)rd->divisor;
1080 +
1081 + if(unlikely(st->debug))
1082 + debug(D_RRD_STATS, "%s/%s: CALC ABS/ABS-NO-IN "
1083 + CALCULATED_NUMBER_FORMAT " = "
1084 + COLLECTED_NUMBER_FORMAT
1085 + " * " CALCULATED_NUMBER_FORMAT
1086 + " / " CALCULATED_NUMBER_FORMAT
1087 + , st->id, rd->name
1088 + , rd->calculated_value
1089 + , rd->collected_value
1090 + , (calculated_number)rd->multiplier
1091 + , (calculated_number)rd->divisor
1092 + );
1093 + break;
1094 +
1095 + case RRDDIM_PCENT_OVER_ROW_TOTAL:
1096 + if(unlikely(!st->collected_total))
1097 + rd->calculated_value = 0;
1098 + else
1099 + // the percentage of the current value
1100 + // over the total of all dimensions
1101 + rd->calculated_value =
1102 + (calculated_number)100
1103 + * (calculated_number)rd->collected_value
1104 + / (calculated_number)st->collected_total;
1105 +
1106 + if(unlikely(st->debug))
1107 + debug(D_RRD_STATS, "%s/%s: CALC PCENT-ROW "
1108 + CALCULATED_NUMBER_FORMAT " = 100"
1109 + " * " COLLECTED_NUMBER_FORMAT
1110 + " / " COLLECTED_NUMBER_FORMAT
1111 + , st->id, rd->name
1112 + , rd->calculated_value
1113 + , rd->collected_value
1114 + , st->collected_total
1115 + );
1116 + break;
1117 +
1118 + case RRDDIM_INCREMENTAL:
1119 + if(unlikely(rd->counter <= 1)) {
1120 + rd->calculated_value = 0;
1121 + continue;
1122 + }
1123 +
1124 + // if the new is smaller than the old (an overflow, or reset), set the old equal to the new
1125 + // to reset the calculation (it will give zero as the calculation for this second)
1126 + if(unlikely(rd->last_collected_value > rd->collected_value)) {
1127 + debug(D_RRD_STATS, "%s.%s: RESET or OVERFLOW. Last collected value = " COLLECTED_NUMBER_FORMAT ", current = " COLLECTED_NUMBER_FORMAT
1128 + , st->name, rd->name
1129 + , rd->last_collected_value
1130 + , rd->collected_value);
1131 + if(!(rd->flags & RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS)) storage_flags = SN_EXISTS_RESET;
1132 + rd->last_collected_value = rd->collected_value;
1133 + }
1134 +
1135 + rd->calculated_value =
1136 + (calculated_number)(rd->collected_value - rd->last_collected_value)
1137 + * (calculated_number)rd->multiplier
1138 + / (calculated_number)rd->divisor;
1139 +
1140 + if(unlikely(st->debug))
1141 + debug(D_RRD_STATS, "%s/%s: CALC INC PRE "
1142 + CALCULATED_NUMBER_FORMAT " = ("
1143 + COLLECTED_NUMBER_FORMAT " - " COLLECTED_NUMBER_FORMAT
1144 + ")"
1145 + " * " CALCULATED_NUMBER_FORMAT
1146 + " / " CALCULATED_NUMBER_FORMAT
1147 + , st->id, rd->name
1148 + , rd->calculated_value
1149 + , rd->collected_value, rd->last_collected_value
1150 + , (calculated_number)rd->multiplier
1151 + , (calculated_number)rd->divisor
1152 + );
1153 + break;
1154 +
1155 + case RRDDIM_PCENT_OVER_DIFF_TOTAL:
1156 + if(unlikely(rd->counter <= 1)) {
1157 + rd->calculated_value = 0;
1158 + continue;
1159 + }
1160 +
1161 + // if the new is smaller than the old (an overflow, or reset), set the old equal to the new
1162 + // to reset the calculation (it will give zero as the calculation for this second)
1163 + if(unlikely(rd->last_collected_value > rd->collected_value)) {
1164 + debug(D_RRD_STATS, "%s.%s: RESET or OVERFLOW. Last collected value = " COLLECTED_NUMBER_FORMAT ", current = " COLLECTED_NUMBER_FORMAT
1165 + , st->name, rd->name
1166 + , rd->last_collected_value
1167 + , rd->collected_value);
1168 + if(!(rd->flags & RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS)) storage_flags = SN_EXISTS_RESET;
1169 + rd->last_collected_value = rd->collected_value;
1170 + }
1171 +
1172 + // the percentage of the current increment
1173 + // over the increment of all dimensions together
1174 + if(unlikely(st->collected_total == st->last_collected_total))
1175 + rd->calculated_value = 0;
1176 + else
1177 + rd->calculated_value =
1178 + (calculated_number)100
1179 + * (calculated_number)(rd->collected_value - rd->last_collected_value)
1180 + / (calculated_number)(st->collected_total - st->last_collected_total);
1181 +
1182 + if(unlikely(st->debug))
1183 + debug(D_RRD_STATS, "%s/%s: CALC PCENT-DIFF "
1184 + CALCULATED_NUMBER_FORMAT " = 100"
1185 + " * (" COLLECTED_NUMBER_FORMAT " - " COLLECTED_NUMBER_FORMAT ")"
1186 + " / (" COLLECTED_NUMBER_FORMAT " - " COLLECTED_NUMBER_FORMAT ")"
1187 + , st->id, rd->name
1188 + , rd->calculated_value
1189 + , rd->collected_value, rd->last_collected_value
1190 + , st->collected_total, st->last_collected_total
1191 + );
1192 + break;
1193 +
1194 + default:
1195 + // make the default zero, to make sure
1196 + // it gets noticed when we add new types
1197 + rd->calculated_value = 0;
1198 +
1199 + if(unlikely(st->debug))
1200 + debug(D_RRD_STATS, "%s/%s: CALC "
1201 + CALCULATED_NUMBER_FORMAT " = 0"
1202 + , st->id, rd->name
1203 + , rd->calculated_value
1204 + );
1205 + break;
1206 + }
1207 +
1208 + if(unlikely(st->debug)) debug(D_RRD_STATS, "%s/%s: PHASE2 "
1209 + " last_collected_value = " COLLECTED_NUMBER_FORMAT
1210 + " collected_value = " COLLECTED_NUMBER_FORMAT
1211 + " last_calculated_value = " CALCULATED_NUMBER_FORMAT
1212 + " calculated_value = " CALCULATED_NUMBER_FORMAT
1213 + , st->id, rd->name
1214 + , rd->last_collected_value
1215 + , rd->collected_value
1216 + , rd->last_calculated_value
1217 + , rd->calculated_value
1218 + );
1219 +
1220 + }
1221 +
1222 + // at this point we have all the calculated values ready
1223 + // it is now time to interpolate values on a second boundary
1224 +
1225 + unsigned long long first_ut = last_ut;
1226 + long long iterations = (now_ut - last_ut) / (st->update_every * 1000000ULL);
1227 + if((now_ut % (st->update_every * 1000000ULL)) == 0) iterations++;
1228 +
1229 + for( ; likely(next_ut <= now_ut) ; next_ut += st->update_every * 1000000ULL, iterations-- ) {
1230 #ifdef NETDATA_INTERNAL_CHECKS
1231 - if(iterations < 0) { error("%s: iterations calculation wrapped! first_ut = %llu, last_ut = %llu, next_ut = %llu, now_ut = %llu", st->name, first_ut, last_ut, next_ut, now_ut); }
1231 + if(iterations < 0) { error("%s: iterations calculation wrapped! first_ut = %llu, last_ut = %llu, next_ut = %llu, now_ut = %llu", st->name, first_ut, last_ut, next_ut, now_ut); }
1232 #endif
1233
1234 - if(unlikely(st->debug)) {
1235 - debug(D_RRD_STATS, "%s: last ut = %0.3Lf (last updated time)", st->name, (long double)last_ut/1000000.0);
1236 - debug(D_RRD_STATS, "%s: next ut = %0.3Lf (next interpolation point)", st->name, (long double)next_ut/1000000.0);
1237 - }
1238 -
1239 - st->last_updated.tv_sec = (time_t) (next_ut / 1000000ULL);
1240 - st->last_updated.tv_usec = 0;
1241 -
1242 - for( rd = st->dimensions ; likely(rd) ; rd = rd->next ) {
1243 - calculated_number new_value;
1244 -
1245 - switch(rd->algorithm) {
1246 - case RRDDIM_INCREMENTAL:
1247 - new_value = (calculated_number)
1248 - ( rd->calculated_value
1249 - * (calculated_number)(next_ut - last_ut)
1250 - / (calculated_number)(now_ut - last_ut)
1251 - );
1252 -
1253 - if(unlikely(st->debug))
1254 - debug(D_RRD_STATS, "%s/%s: CALC2 INC "
1255 - CALCULATED_NUMBER_FORMAT " = "
1256 - CALCULATED_NUMBER_FORMAT
1257 - " * %llu"
1258 - " / %llu"
1259 - , st->id, rd->name
1260 - , new_value
1261 - , rd->calculated_value
1262 - , (next_ut - last_ut)
1263 - , (now_ut - last_ut)
1264 - );
1265 -
1266 - rd->calculated_value -= new_value;
1267 - new_value += rd->last_calculated_value;
1268 - rd->last_calculated_value = 0;
1269 - new_value /= (calculated_number)st->update_every;
1270 - break;
1271 -
1272 - case RRDDIM_ABSOLUTE:
1273 - case RRDDIM_PCENT_OVER_ROW_TOTAL:
1274 - case RRDDIM_PCENT_OVER_DIFF_TOTAL:
1275 - default:
1276 - if(iterations == 1) {
1277 - // this is the last iteration
1278 - // do not interpolate
1279 - // just show the calculated value
1280 -
1281 - new_value = rd->calculated_value;
1282 - }
1283 - else {
1284 - // we have missed an update
1285 - // interpolate in the middle values
1286 -
1287 - new_value = (calculated_number)
1288 - ( ( (rd->calculated_value - rd->last_calculated_value)
1289 - * (calculated_number)(next_ut - first_ut)
1290 - / (calculated_number)(now_ut - first_ut)
1291 - )
1292 - + rd->last_calculated_value
1293 - );
1294 -
1295 - if(unlikely(st->debug))
1296 - debug(D_RRD_STATS, "%s/%s: CALC2 DEF "
1297 - CALCULATED_NUMBER_FORMAT " = ((("
1298 - "(" CALCULATED_NUMBER_FORMAT " - " CALCULATED_NUMBER_FORMAT ")"
1299 - " * %llu"
1300 - " / %llu) + " CALCULATED_NUMBER_FORMAT
1301 - , st->id, rd->name
1302 - , new_value
1303 - , rd->calculated_value, rd->last_calculated_value
1304 - , (next_ut - first_ut)
1305 - , (now_ut - first_ut), rd->last_calculated_value
1306 - );
1307 -
1308 - // this is wrong
1309 - // it fades the value towards the target
1310 - // while we know the calculated value is different
1311 - // if(likely(next_ut + st->update_every * 1000000ULL > now_ut)) rd->calculated_value = new_value;
1312 - }
1313 - break;
1314 - }
1315 -
1316 - if(unlikely(!store_this_entry)) {
1317 - store_this_entry = 1;
1318 - continue;
1319 - }
1320 -
1321 - if(likely(rd->updated && rd->counter > 1 && iterations < st->gap_when_lost_iterations_above)) {
1322 - rd->values[st->current_entry] = pack_storage_number(new_value, storage_flags );
1323 -
1324 - if(unlikely(st->debug))
1325 - debug(D_RRD_STATS, "%s/%s: STORE[%ld] "
1326 - CALCULATED_NUMBER_FORMAT " = " CALCULATED_NUMBER_FORMAT
1327 - , st->id, rd->name
1328 - , st->current_entry
1329 - , unpack_storage_number(rd->values[st->current_entry]), new_value
1330 - );
1331 - }
1332 - else {
1333 - if(unlikely(st->debug)) debug(D_RRD_STATS, "%s/%s: STORE[%ld] = NON EXISTING "
1334 - , st->id, rd->name
1335 - , st->current_entry
1336 - );
1337 - rd->values[st->current_entry] = pack_storage_number(0, SN_NOT_EXISTS);
1338 - }
1339 -
1340 - stored_entries++;
1341 -
1342 - if(unlikely(st->debug)) {
1343 - calculated_number t1 = new_value * (calculated_number)rd->multiplier / (calculated_number)rd->divisor;
1344 - calculated_number t2 = unpack_storage_number(rd->values[st->current_entry]);
1345 - calculated_number accuracy = accuracy_loss(t1, t2);
1346 - debug(D_RRD_STATS, "%s/%s: UNPACK[%ld] = " CALCULATED_NUMBER_FORMAT " FLAGS=0x%08x (original = " CALCULATED_NUMBER_FORMAT ", accuracy loss = " CALCULATED_NUMBER_FORMAT "%%%s)"
1347 - , st->id, rd->name
1348 - , st->current_entry
1349 - , t2
1350 - , get_storage_number_flags(rd->values[st->current_entry])
1351 - , t1
1352 - , accuracy
1353 - , (accuracy > ACCURACY_LOSS) ? " **TOO BIG** " : ""
1354 - );
1355 -
1356 - rd->collected_volume += t1;
1357 - rd->stored_volume += t2;
1358 - accuracy = accuracy_loss(rd->collected_volume, rd->stored_volume);
1359 - debug(D_RRD_STATS, "%s/%s: VOLUME[%ld] = " CALCULATED_NUMBER_FORMAT ", calculated = " CALCULATED_NUMBER_FORMAT ", accuracy loss = " CALCULATED_NUMBER_FORMAT "%%%s"
1360 - , st->id, rd->name
1361 - , st->current_entry
1362 - , rd->stored_volume
1363 - , rd->collected_volume
1364 - , accuracy
1365 - , (accuracy > ACCURACY_LOSS) ? " **TOO BIG** " : ""
1366 - );
1367 -
1368 - }
1369 - }
1370 - // reset the storage flags for the next point, if any;
1371 - storage_flags = SN_EXISTS;
1372 -
1373 - st->counter++;
1374 - st->current_entry = ((st->current_entry + 1) >= st->entries) ? 0 : st->current_entry + 1;
1375 - last_ut = next_ut;
1376 - }
1377 -
1378 - // align next interpolation to last collection point
1379 - if(likely(stored_entries || !store_this_entry)) {
1380 - st->last_updated.tv_sec = st->last_collected_time.tv_sec;
1381 - st->last_updated.tv_usec = st->last_collected_time.tv_usec;
1382 - st->last_collected_total = st->collected_total;
1383 - }
1384 -
1385 - for( rd = st->dimensions; likely(rd) ; rd = rd->next ) {
1386 - if(unlikely(!rd->updated)) continue;
1387 -
1388 - if(likely(stored_entries || !store_this_entry)) {
1389 - if(unlikely(st->debug)) debug(D_RRD_STATS, "%s/%s: setting last_collected_value (old: " COLLECTED_NUMBER_FORMAT ") to last_collected_value (new: " COLLECTED_NUMBER_FORMAT ")", st->id, rd->name, rd->last_collected_value, rd->collected_value);
1390 - rd->last_collected_value = rd->collected_value;
1391 -
1392 - if(unlikely(st->debug)) debug(D_RRD_STATS, "%s/%s: setting last_calculated_value (old: " CALCULATED_NUMBER_FORMAT ") to last_calculated_value (new: " CALCULATED_NUMBER_FORMAT ")", st->id, rd->name, rd->last_calculated_value, rd->calculated_value);
1393 - rd->last_calculated_value = rd->calculated_value;
1394 - }
1395 -
1396 - rd->calculated_value = 0;
1397 - rd->collected_value = 0;
1398 - rd->updated = 0;
1399 -
1400 - if(unlikely(st->debug)) debug(D_RRD_STATS, "%s/%s: END "
1401 - " last_collected_value = " COLLECTED_NUMBER_FORMAT
1402 - " collected_value = " COLLECTED_NUMBER_FORMAT
1403 - " last_calculated_value = " CALCULATED_NUMBER_FORMAT
1404 - " calculated_value = " CALCULATED_NUMBER_FORMAT
1405 - , st->id, rd->name
1406 - , rd->last_collected_value
1407 - , rd->collected_value
1408 - , rd->last_calculated_value
1409 - , rd->calculated_value
1410 - );
1411 - }
1412 -
1413 - // ALL DONE ABOUT THE DATA UPDATE
1414 - // --------------------------------------------------------------------
1415 -
1416 - // find if there are any obsolete dimensions (not updated recently)
1417 - if(unlikely(rrd_delete_unupdated_dimensions)) {
1418 -
1419 - for( rd = st->dimensions; likely(rd) ; rd = rd->next )
1420 - if((rd->last_collected_time.tv_sec + (rrd_delete_unupdated_dimensions * st->update_every)) < st->last_collected_time.tv_sec)
1421 - break;
1422 -
1423 - if(unlikely(rd)) {
1424 - // there is dimension to free
1425 - // upgrade our read lock to a write lock
1426 - pthread_rwlock_unlock(&st->rwlock);
1427 - pthread_rwlock_wrlock(&st->rwlock);
1428 -
1429 - for( rd = st->dimensions, last = NULL ; likely(rd) ; ) {
1430 - // remove it only it is not updated in rrd_delete_unupdated_dimensions seconds
1431 -
1432 - if(unlikely((rd->last_collected_time.tv_sec + (rrd_delete_unupdated_dimensions * st->update_every)) < st->last_collected_time.tv_sec)) {
1433 - info("Removing obsolete dimension '%s' (%s) of '%s' (%s).", rd->name, rd->id, st->name, st->id);
1434 -
1435 - if(unlikely(!last)) {
1436 - st->dimensions = rd->next;
1437 - rd->next = NULL;
1438 - rrddim_free(st, rd);
1439 - rd = st->dimensions;
1440 - continue;
1441 - }
1442 - else {
1443 - last->next = rd->next;
1444 - rd->next = NULL;
1445 - rrddim_free(st, rd);
1446 - rd = last->next;
1447 - continue;
1448 - }
1449 - }
1450 -
1451 - last = rd;
1452 - rd = rd->next;
1453 - }
1454 -
1455 - if(unlikely(!st->dimensions)) {
1456 - info("Disabling chart %s (%s) since it does not have any dimensions", st->name, st->id);
1457 - st->enabled = 0;
1458 - }
1459 - }
1460 - }
1461 -
1462 - pthread_rwlock_unlock(&st->rwlock);
1463 -
1464 - if(unlikely(pthread_setcancelstate(oldstate, NULL) != 0))
1465 - error("Cannot set pthread cancel state to RESTORE (%d).", oldstate);
1466 -
1467 - return(st->usec_since_last_update);
1234 + if(unlikely(st->debug)) {
1235 + debug(D_RRD_STATS, "%s: last ut = %0.3Lf (last updated time)", st->name, (long double)last_ut/1000000.0);
1236 + debug(D_RRD_STATS, "%s: next ut = %0.3Lf (next interpolation point)", st->name, (long double)next_ut/1000000.0);
1237 + }
1238 +
1239 + st->last_updated.tv_sec = (time_t) (next_ut / 1000000ULL);
1240 + st->last_updated.tv_usec = 0;
1241 +
1242 + for( rd = st->dimensions ; likely(rd) ; rd = rd->next ) {
1243 + calculated_number new_value;
1244 +
1245 + switch(rd->algorithm) {
1246 + case RRDDIM_INCREMENTAL:
1247 + new_value = (calculated_number)
1248 + ( rd->calculated_value
1249 + * (calculated_number)(next_ut - last_ut)
1250 + / (calculated_number)(now_ut - last_ut)
1251 + );
1252 +
1253 + if(unlikely(st->debug))
1254 + debug(D_RRD_STATS, "%s/%s: CALC2 INC "
1255 + CALCULATED_NUMBER_FORMAT " = "
1256 + CALCULATED_NUMBER_FORMAT
1257 + " * %llu"
1258 + " / %llu"
1259 + , st->id, rd->name
1260 + , new_value
1261 + , rd->calculated_value
1262 + , (next_ut - last_ut)
1263 + , (now_ut - last_ut)
1264 + );
1265 +
1266 + rd->calculated_value -= new_value;
1267 + new_value += rd->last_calculated_value;
1268 + rd->last_calculated_value = 0;
1269 + new_value /= (calculated_number)st->update_every;
1270 + break;
1271 +
1272 + case RRDDIM_ABSOLUTE:
1273 + case RRDDIM_PCENT_OVER_ROW_TOTAL:
1274 + case RRDDIM_PCENT_OVER_DIFF_TOTAL:
1275 + default:
1276 + if(iterations == 1) {
1277 + // this is the last iteration
1278 + // do not interpolate
1279 + // just show the calculated value
1280 +
1281 + new_value = rd->calculated_value;
1282 + }
1283 + else {
1284 + // we have missed an update
1285 + // interpolate in the middle values
1286 +
1287 + new_value = (calculated_number)
1288 + ( ( (rd->calculated_value - rd->last_calculated_value)
1289 + * (calculated_number)(next_ut - first_ut)
1290 + / (calculated_number)(now_ut - first_ut)
1291 + )
1292 + + rd->last_calculated_value
1293 + );
1294 +
1295 + if(unlikely(st->debug))
1296 + debug(D_RRD_STATS, "%s/%s: CALC2 DEF "
1297 + CALCULATED_NUMBER_FORMAT " = ((("
1298 + "(" CALCULATED_NUMBER_FORMAT " - " CALCULATED_NUMBER_FORMAT ")"
1299 + " * %llu"
1300 + " / %llu) + " CALCULATED_NUMBER_FORMAT
1301 + , st->id, rd->name
1302 + , new_value
1303 + , rd->calculated_value, rd->last_calculated_value
1304 + , (next_ut - first_ut)
1305 + , (now_ut - first_ut), rd->last_calculated_value
1306 + );
1307 +
1308 + // this is wrong
1309 + // it fades the value towards the target
1310 + // while we know the calculated value is different
1311 + // if(likely(next_ut + st->update_every * 1000000ULL > now_ut)) rd->calculated_value = new_value;
1312 + }
1313 + break;
1314 + }
1315 +
1316 + if(unlikely(!store_this_entry)) {
1317 + store_this_entry = 1;
1318 + continue;
1319 + }
1320 +
1321 + if(likely(rd->updated && rd->counter > 1 && iterations < st->gap_when_lost_iterations_above)) {
1322 + rd->values[st->current_entry] = pack_storage_number(new_value, storage_flags );
1323 +
1324 + if(unlikely(st->debug))
1325 + debug(D_RRD_STATS, "%s/%s: STORE[%ld] "
1326 + CALCULATED_NUMBER_FORMAT " = " CALCULATED_NUMBER_FORMAT
1327 + , st->id, rd->name
1328 + , st->current_entry
1329 + , unpack_storage_number(rd->values[st->current_entry]), new_value
1330 + );
1331 + }
1332 + else {
1333 + if(unlikely(st->debug)) debug(D_RRD_STATS, "%s/%s: STORE[%ld] = NON EXISTING "
1334 + , st->id, rd->name
1335 + , st->current_entry
1336 + );
1337 + rd->values[st->current_entry] = pack_storage_number(0, SN_NOT_EXISTS);
1338 + }
1339 +
1340 + stored_entries++;
1341 +
1342 + if(unlikely(st->debug)) {
1343 + calculated_number t1 = new_value * (calculated_number)rd->multiplier / (calculated_number)rd->divisor;
1344 + calculated_number t2 = unpack_storage_number(rd->values[st->current_entry]);
1345 + calculated_number accuracy = accuracy_loss(t1, t2);
1346 + debug(D_RRD_STATS, "%s/%s: UNPACK[%ld] = " CALCULATED_NUMBER_FORMAT " FLAGS=0x%08x (original = " CALCULATED_NUMBER_FORMAT ", accuracy loss = " CALCULATED_NUMBER_FORMAT "%%%s)"
1347 + , st->id, rd->name
1348 + , st->current_entry
1349 + , t2
1350 + , get_storage_number_flags(rd->values[st->current_entry])
1351 + , t1
1352 + , accuracy
1353 + , (accuracy > ACCURACY_LOSS) ? " **TOO BIG** " : ""
1354 + );
1355 +
1356 + rd->collected_volume += t1;
1357 + rd->stored_volume += t2;
1358 + accuracy = accuracy_loss(rd->collected_volume, rd->stored_volume);
1359 + debug(D_RRD_STATS, "%s/%s: VOLUME[%ld] = " CALCULATED_NUMBER_FORMAT ", calculated = " CALCULATED_NUMBER_FORMAT ", accuracy loss = " CALCULATED_NUMBER_FORMAT "%%%s"
1360 + , st->id, rd->name
1361 + , st->current_entry
1362 + , rd->stored_volume
1363 + , rd->collected_volume
1364 + , accuracy
1365 + , (accuracy > ACCURACY_LOSS) ? " **TOO BIG** " : ""
1366 + );
1367 +
1368 + }
1369 + }
1370 + // reset the storage flags for the next point, if any;
1371 + storage_flags = SN_EXISTS;
1372 +
1373 + st->counter++;
1374 + st->current_entry = ((st->current_entry + 1) >= st->entries) ? 0 : st->current_entry + 1;
1375 + last_ut = next_ut;
1376 + }
1377 +
1378 + // align next interpolation to last collection point
1379 + if(likely(stored_entries || !store_this_entry)) {
1380 + st->last_updated.tv_sec = st->last_collected_time.tv_sec;
1381 + st->last_updated.tv_usec = st->last_collected_time.tv_usec;
1382 + st->last_collected_total = st->collected_total;
1383 + }
1384 +
1385 + for( rd = st->dimensions; likely(rd) ; rd = rd->next ) {
1386 + if(unlikely(!rd->updated)) continue;
1387 +
1388 + if(likely(stored_entries || !store_this_entry)) {
1389 + if(unlikely(st->debug)) debug(D_RRD_STATS, "%s/%s: setting last_collected_value (old: " COLLECTED_NUMBER_FORMAT ") to last_collected_value (new: " COLLECTED_NUMBER_FORMAT ")", st->id, rd->name, rd->last_collected_value, rd->collected_value);
1390 + rd->last_collected_value = rd->collected_value;
1391 +
1392 + if(unlikely(st->debug)) debug(D_RRD_STATS, "%s/%s: setting last_calculated_value (old: " CALCULATED_NUMBER_FORMAT ") to last_calculated_value (new: " CALCULATED_NUMBER_FORMAT ")", st->id, rd->name, rd->last_calculated_value, rd->calculated_value);
1393 + rd->last_calculated_value = rd->calculated_value;
1394 + }
1395 +
1396 + rd->calculated_value = 0;
1397 + rd->collected_value = 0;
1398 + rd->updated = 0;
1399 +
1400 + if(unlikely(st->debug)) debug(D_RRD_STATS, "%s/%s: END "
1401 + " last_collected_value = " COLLECTED_NUMBER_FORMAT
1402 + " collected_value = " COLLECTED_NUMBER_FORMAT
1403 + " last_calculated_value = " CALCULATED_NUMBER_FORMAT
1404 + " calculated_value = " CALCULATED_NUMBER_FORMAT
1405 + , st->id, rd->name
1406 + , rd->last_collected_value
1407 + , rd->collected_value
1408 + , rd->last_calculated_value
1409 + , rd->calculated_value
1410 + );
1411 + }
1412 +
1413 + // ALL DONE ABOUT THE DATA UPDATE
1414 + // --------------------------------------------------------------------
1415 +
1416 + // find if there are any obsolete dimensions (not updated recently)
1417 + if(unlikely(rrd_delete_unupdated_dimensions)) {
1418 +
1419 + for( rd = st->dimensions; likely(rd) ; rd = rd->next )
1420 + if((rd->last_collected_time.tv_sec + (rrd_delete_unupdated_dimensions * st->update_every)) < st->last_collected_time.tv_sec)
1421 + break;
1422 +
1423 + if(unlikely(rd)) {
1424 + // there is dimension to free
1425 + // upgrade our read lock to a write lock
1426 + pthread_rwlock_unlock(&st->rwlock);
1427 + pthread_rwlock_wrlock(&st->rwlock);
1428 +
1429 + for( rd = st->dimensions, last = NULL ; likely(rd) ; ) {
1430 + // remove it only it is not updated in rrd_delete_unupdated_dimensions seconds
1431 +
1432 + if(unlikely((rd->last_collected_time.tv_sec + (rrd_delete_unupdated_dimensions * st->update_every)) < st->last_collected_time.tv_sec)) {
1433 + info("Removing obsolete dimension '%s' (%s) of '%s' (%s).", rd->name, rd->id, st->name, st->id);
1434 +
1435 + if(unlikely(!last)) {
1436 + st->dimensions = rd->next;
1437 + rd->next = NULL;
1438 + rrddim_free(st, rd);
1439 + rd = st->dimensions;
1440 + continue;
1441 + }
1442 + else {
1443 + last->next = rd->next;
1444 + rd->next = NULL;
1445 + rrddim_free(st, rd);
1446 + rd = last->next;
1447 + continue;
1448 + }
1449 + }
1450 +
1451 + last = rd;
1452 + rd = rd->next;
1453 + }
1454 +
1455 + if(unlikely(!st->dimensions)) {
1456 + info("Disabling chart %s (%s) since it does not have any dimensions", st->name, st->id);
1457 + st->enabled = 0;
1458 + }
1459 + }
1460 + }
1461 +
1462 + pthread_rwlock_unlock(&st->rwlock);
1463 +
1464 + if(unlikely(pthread_setcancelstate(oldstate, NULL) != 0))
1465 + error("Cannot set pthread cancel state to RESTORE (%d).", oldstate);
1466 +
1467 + return(st->usec_since_last_update);
1468 }
src/rrd.h
+143 -143
@@ -15,8 +15,8 @@ extern int rrd_delete_unupdated_dimensions;
15
16 #define RRD_ID_LENGTH_MAX 1024
17
18 -#define RRDSET_MAGIC "NETDATA RRD SET FILE V018"
19 -#define RRDDIMENSION_MAGIC "NETDATA RRD DIMENSION FILE V018"
18 +#define RRDSET_MAGIC "NETDATA RRD SET FILE V018"
19 +#define RRDDIMENSION_MAGIC "NETDATA RRD DIMENSION FILE V018"
20
21 typedef long long total_number;
22 #define TOTAL_NUMBER_FORMAT "%lld"
@@ -28,8 +28,8 @@ typedef long long total_number;
28 #define RRDSET_TYPE_AREA_NAME "area"
29 #define RRDSET_TYPE_STACKED_NAME "stacked"
30
31 -#define RRDSET_TYPE_LINE 0
32 -#define RRDSET_TYPE_AREA 1
31 +#define RRDSET_TYPE_LINE 0
32 +#define RRDSET_TYPE_AREA 1
33 #define RRDSET_TYPE_STACKED 2
34
35 int rrdset_type_id(const char *name);
@@ -56,15 +56,15 @@ extern int rrd_memory_mode_id(const char *name);
56 // ----------------------------------------------------------------------------
57 // algorithms types
58
59 -#define RRDDIM_ABSOLUTE_NAME "absolute"
60 -#define RRDDIM_INCREMENTAL_NAME "incremental"
61 -#define RRDDIM_PCENT_OVER_DIFF_TOTAL_NAME "percentage-of-incremental-row"
62 -#define RRDDIM_PCENT_OVER_ROW_TOTAL_NAME "percentage-of-absolute-row"
59 +#define RRDDIM_ABSOLUTE_NAME "absolute"
60 +#define RRDDIM_INCREMENTAL_NAME "incremental"
61 +#define RRDDIM_PCENT_OVER_DIFF_TOTAL_NAME "percentage-of-incremental-row"
62 +#define RRDDIM_PCENT_OVER_ROW_TOTAL_NAME "percentage-of-absolute-row"
63
64 -#define RRDDIM_ABSOLUTE 0
65 -#define RRDDIM_INCREMENTAL 1
66 -#define RRDDIM_PCENT_OVER_DIFF_TOTAL 2
67 -#define RRDDIM_PCENT_OVER_ROW_TOTAL 3
64 +#define RRDDIM_ABSOLUTE 0
65 +#define RRDDIM_INCREMENTAL 1
66 +#define RRDDIM_PCENT_OVER_DIFF_TOTAL 2
67 +#define RRDDIM_PCENT_OVER_ROW_TOTAL 3
68
69 extern int rrddim_algorithm_id(const char *name);
70 extern const char *rrddim_algorithm_name(int chart_type);
@@ -94,83 +94,83 @@ typedef struct rrdcontext RRDCONTEXT;
94 // RRD DIMENSION
95
96 struct rrddim {
97 - // ------------------------------------------------------------------------
98 - // binary indexing structures
97 + // ------------------------------------------------------------------------
98 + // binary indexing structures
99
100 - avl avl; // the binary index - this has to be first member!
100 + avl avl; // the binary index - this has to be first member!
101
102 - // ------------------------------------------------------------------------
103 - // the dimension definition
102 + // ------------------------------------------------------------------------
103 + // the dimension definition
104
105 - char id[RRD_ID_LENGTH_MAX + 1]; // the id of this dimension (for internal identification)
105 + char id[RRD_ID_LENGTH_MAX + 1]; // the id of this dimension (for internal identification)
106
107 - const char *name; // the name of this dimension (as presented to user)
108 - // this is a pointer to the config structure
109 - // since the config always has a higher priority
110 - // (the user overwrites the name of the charts)
107 + const char *name; // the name of this dimension (as presented to user)
108 + // this is a pointer to the config structure
109 + // since the config always has a higher priority
110 + // (the user overwrites the name of the charts)
111
112 - int algorithm; // the algorithm that is applied to add new collected values
113 - long multiplier; // the multiplier of the collected values
114 - long divisor; // the divider of the collected values
112 + int algorithm; // the algorithm that is applied to add new collected values
113 + long multiplier; // the multiplier of the collected values
114 + long divisor; // the divider of the collected values
115
116 - int mapped; // if set to non zero, this dimension is mapped to a file
116 + int mapped; // if set to non zero, this dimension is mapped to a file
117
118 - // ------------------------------------------------------------------------
119 - // members for temporary data we need for calculations
118 + // ------------------------------------------------------------------------
119 + // members for temporary data we need for calculations
120
121 - uint32_t hash; // a simple hash of the id, to speed up searching / indexing
122 - // instead of strcmp() every item in the binary index
123 - // we first compare the hashes
121 + uint32_t hash; // a simple hash of the id, to speed up searching / indexing
122 + // instead of strcmp() every item in the binary index
123 + // we first compare the hashes
124
125 - // FIXME
126 - // we need the hash_name too!
125 + // FIXME
126 + // we need the hash_name too!
127
128 - uint32_t flags;
128 + uint32_t flags;
129
130 - char cache_filename[FILENAME_MAX+1]; // the filename we load/save from/to this set
130 + char cache_filename[FILENAME_MAX+1]; // the filename we load/save from/to this set
131
132 - unsigned long counter; // the number of times we added values to this rrdim
132 + unsigned long counter; // the number of times we added values to this rrdim
133
134 - int updated; // set to 0 after each calculation, to 1 after each collected value
135 - // we use this to detect that a dimension is not updated
134 + int updated; // set to 0 after each calculation, to 1 after each collected value
135 + // we use this to detect that a dimension is not updated
136
137 - struct timeval last_collected_time; // when was this dimension last updated
138 - // this is actual date time we updated the last_collected_value
139 - // THIS IS DIFFERENT FROM THE SAME MEMBER OF RRDSET
137 + struct timeval last_collected_time; // when was this dimension last updated
138 + // this is actual date time we updated the last_collected_value
139 + // THIS IS DIFFERENT FROM THE SAME MEMBER OF RRDSET
140
141 - calculated_number calculated_value; // the current calculated value, after applying the algorithm
142 - calculated_number last_calculated_value; // the last calculated value
141 + calculated_number calculated_value; // the current calculated value, after applying the algorithm
142 + calculated_number last_calculated_value; // the last calculated value
143
144 - collected_number collected_value; // the current value, as collected
145 - collected_number last_collected_value; // the last value that was collected
144 + collected_number collected_value; // the current value, as collected
145 + collected_number last_collected_value; // the last value that was collected
146
147 - // the *_volume members are used to calculate the accuracy of the rounding done by the
148 - // storage number - they are printed to debug.log when debug is enabled for a set.
149 - calculated_number collected_volume; // the sum of all collected values so far
150 - calculated_number stored_volume; // the sum of all stored values so far
147 + // the *_volume members are used to calculate the accuracy of the rounding done by the
148 + // storage number - they are printed to debug.log when debug is enabled for a set.
149 + calculated_number collected_volume; // the sum of all collected values so far
150 + calculated_number stored_volume; // the sum of all stored values so far
151
152 - struct rrddim *next; // linking of dimensions within the same data set
152 + struct rrddim *next; // linking of dimensions within the same data set
153 struct rrdset *rrdset;
154
155 - // ------------------------------------------------------------------------
156 - // members for checking the data when loading from disk
155 + // ------------------------------------------------------------------------
156 + // members for checking the data when loading from disk
157
158 - long entries; // how many entries this dimension has in ram
159 - // this is the same to the entries of the data set
160 - // we set it here, to check the data when we load it from disk.
158 + long entries; // how many entries this dimension has in ram
159 + // this is the same to the entries of the data set
160 + // we set it here, to check the data when we load it from disk.
161
162 - int update_every; // every how many seconds is this updated
162 + int update_every; // every how many seconds is this updated
163
164 - unsigned long memsize; // the memory allocated for this dimension
164 + unsigned long memsize; // the memory allocated for this dimension
165
166 - char magic[sizeof(RRDDIMENSION_MAGIC) + 1]; // a string to be saved, used to identify our data file
166 + char magic[sizeof(RRDDIMENSION_MAGIC) + 1]; // a string to be saved, used to identify our data file
167
168 struct rrddimvar *variables;
169
170 - // ------------------------------------------------------------------------
171 - // the values stored in this dimension, using our floating point numbers
170 + // ------------------------------------------------------------------------
171 + // the values stored in this dimension, using our floating point numbers
172
173 - storage_number values[]; // the array of values - THIS HAS TO BE THE LAST MEMBER
173 + storage_number values[]; // the array of values - THIS HAS TO BE THE LAST MEMBER
174 };
175 typedef struct rrddim RRDDIM;
176
@@ -179,99 +179,99 @@ typedef struct rrddim RRDDIM;
179 // RRDSET
180
181 struct rrdset {
182 - // ------------------------------------------------------------------------
183 - // binary indexing structures
182 + // ------------------------------------------------------------------------
183 + // binary indexing structures
184
185 - avl avl; // the index, with key the id - this has to be first!
186 - avl avlname; // the index, with key the name
185 + avl avl; // the index, with key the id - this has to be first!
186 + avl avlname; // the index, with key the name
187
188 - // ------------------------------------------------------------------------
189 - // the set configuration
188 + // ------------------------------------------------------------------------
189 + // the set configuration
190
191 - char id[RRD_ID_LENGTH_MAX + 1]; // id of the data set
191 + char id[RRD_ID_LENGTH_MAX + 1]; // id of the data set
192
193 - const char *name; // the name of this dimension (as presented to user)
194 - // this is a pointer to the config structure
195 - // since the config always has a higher priority
196 - // (the user overwrites the name of the charts)
193 + const char *name; // the name of this dimension (as presented to user)
194 + // this is a pointer to the config structure
195 + // since the config always has a higher priority
196 + // (the user overwrites the name of the charts)
197
198 - char *type; // the type of graph RRD_TYPE_* (a category, for determining graphing options)
199 - char *family; // grouping sets under the same family
200 - char *context; // the template of this data set
201 - char *title; // title shown to user
202 - char *units; // units of measurement
198 + char *type; // the type of graph RRD_TYPE_* (a category, for determining graphing options)
199 + char *family; // grouping sets under the same family
200 + char *context; // the template of this data set
201 + char *title; // title shown to user
202 + char *units; // units of measurement
203
204 - int chart_type;
204 + int chart_type;
205
206 - int update_every; // every how many seconds is this updated?
206 + int update_every; // every how many seconds is this updated?
207
208 - long entries; // total number of entries in the data set
208 + long entries; // total number of entries in the data set
209
210 - long current_entry; // the entry that is currently being updated
211 - // it goes around in a round-robin fashion
210 + long current_entry; // the entry that is currently being updated
211 + // it goes around in a round-robin fashion
212
213 - int enabled;
213 + int enabled;
214
215 - int gap_when_lost_iterations_above; // after how many lost iterations a gap should be stored
216 - // netdata will interpolate values for gaps lower than this
215 + int gap_when_lost_iterations_above; // after how many lost iterations a gap should be stored
216 + // netdata will interpolate values for gaps lower than this
217
218 - long priority;
218 + long priority;
219
220 - int isdetail; // if set, the data set should be considered as a detail of another
221 - // (the master data set should be the one that has the same family and is not detail)
220 + int isdetail; // if set, the data set should be considered as a detail of another
221 + // (the master data set should be the one that has the same family and is not detail)
222
223 - // ------------------------------------------------------------------------
224 - // members for temporary data we need for calculations
223 + // ------------------------------------------------------------------------
224 + // members for temporary data we need for calculations
225
226 - int mapped; // if set to 1, this is memory mapped
226 + int mapped; // if set to 1, this is memory mapped
227
228 - int debug;
228 + int debug;
229
230 - char *cache_dir; // the directory to store dimensions
231 - char cache_filename[FILENAME_MAX+1]; // the filename to store this set
230 + char *cache_dir; // the directory to store dimensions
231 + char cache_filename[FILENAME_MAX+1]; // the filename to store this set
232
233 - pthread_rwlock_t rwlock;
233 + pthread_rwlock_t rwlock;
234
235 - unsigned long counter; // the number of times we added values to this rrd
236 - unsigned long counter_done; // the number of times we added values to this rrd
235 + unsigned long counter; // the number of times we added values to this rrd
236 + unsigned long counter_done; // the number of times we added values to this rrd
237
238 - uint32_t hash; // a simple hash on the id, to speed up searching
239 - // we first compare hashes, and only if the hashes are equal we do string comparisons
238 + uint32_t hash; // a simple hash on the id, to speed up searching
239 + // we first compare hashes, and only if the hashes are equal we do string comparisons
240
241 - uint32_t hash_name; // a simple hash on the name
241 + uint32_t hash_name; // a simple hash on the name
242
243 - unsigned long long usec_since_last_update; // the time in microseconds since the last collection of data
243 + unsigned long long usec_since_last_update; // the time in microseconds since the last collection of data
244
245 - struct timeval last_updated; // when this data set was last updated (updated every time the rrd_stats_done() function)
246 - struct timeval last_collected_time; // when did this data set last collected values
245 + struct timeval last_updated; // when this data set was last updated (updated every time the rrd_stats_done() function)
246 + struct timeval last_collected_time; // when did this data set last collected values
247
248 - total_number collected_total; // used internally to calculate percentages
249 - total_number last_collected_total; // used internally to calculate percentages
248 + total_number collected_total; // used internally to calculate percentages
249 + total_number last_collected_total; // used internally to calculate percentages
250
251 RRDCONTEXT *rrdcontext;
252 struct rrdhost *rrdhost;
253
254 - struct rrdset *next; // linking of rrdsets
254 + struct rrdset *next; // linking of rrdsets
255
256 - // ------------------------------------------------------------------------
257 - // local variables
256 + // ------------------------------------------------------------------------
257 + // local variables
258
259 - avl_tree_lock variables_root_index;
260 - RRDSETVAR *variables;
261 - RRDCALC *calculations;
259 + avl_tree_lock variables_root_index;
260 + RRDSETVAR *variables;
261 + RRDCALC *calculations;
262
263 - // ------------------------------------------------------------------------
264 - // members for checking the data when loading from disk
263 + // ------------------------------------------------------------------------
264 + // members for checking the data when loading from disk
265
266 - unsigned long memsize; // how much mem we have allocated for this (without dimensions)
266 + unsigned long memsize; // how much mem we have allocated for this (without dimensions)
267
268 - char magic[sizeof(RRDSET_MAGIC) + 1]; // our magic
268 + char magic[sizeof(RRDSET_MAGIC) + 1]; // our magic
269
270 - // ------------------------------------------------------------------------
271 - // the dimensions
270 + // ------------------------------------------------------------------------
271 + // the dimensions
272
273 - avl_tree_lock dimensions_index; // the root of the dimensions index
274 - RRDDIM *dimensions; // the actual data for every dimension
273 + avl_tree_lock dimensions_index; // the root of the dimensions index
274 + RRDDIM *dimensions; // the actual data for every dimension
275
276 };
277 typedef struct rrdset RRDSET;
@@ -293,10 +293,10 @@ struct rrdhost {
293 avl_tree_lock rrdcontext_root_index;
294 avl_tree_lock variables_root_index;
295
296 - // all RRDCALCs are primarily allocated and linked here
297 - // RRDCALCs may be linked to charts at any point
298 - // (charts may or may not exist when these are loaded)
299 - RRDCALC *calculations;
296 + // all RRDCALCs are primarily allocated and linked here
297 + // RRDCALCs may be linked to charts at any point
298 + // (charts may or may not exist when these are loaded)
299 + RRDCALC *calculations;
300
301 // all variable references are linked here
302 // RRDVARs may be free'd, so every time this happens
@@ -324,15 +324,15 @@ extern char *rrdset_cache_dir(const char *id);
324 extern void rrdset_reset(RRDSET *st);
325
326 extern RRDSET *rrdset_create(const char *type
327 - , const char *id
328 - , const char *name
329 - , const char *family
330 - , const char *context
331 - , const char *title
332 - , const char *units
333 - , long priority
334 - , int update_every
335 - , int chart_type);
327 + , const char *id
328 + , const char *name
329 + , const char *family
330 + , const char *context
331 + , const char *title
332 + , const char *units
333 + , long priority
334 + , int update_every
335 + , int chart_type);
336
337 extern void rrdset_free_all(void);
338 extern void rrdset_save_all(void);
@@ -365,20 +365,20 @@ extern unsigned long long rrdset_done(RRDSET *st);
365 // get the slot of the round robin database, for the given timestamp (t)
366 // it always returns a valid slot, although may not be for the time requested if the time is outside the round robin database
367 #define rrdset_time2slot(st, t) ( \
368 - ( (time_t)(t) >= rrdset_last_entry_t(st)) ? ( rrdset_last_slot(st) ) : \
369 - ( ((time_t)(t) <= rrdset_first_entry_t(st)) ? rrdset_first_slot(st) : \
370 - ( (rrdset_last_slot(st) >= (unsigned long)((rrdset_last_entry_t(st) - (time_t)(t)) / (unsigned long)((st)->update_every)) ) ? \
371 - (rrdset_last_slot(st) - (unsigned long)((rrdset_last_entry_t(st) - (time_t)(t)) / (unsigned long)((st)->update_every)) ) : \
372 - (rrdset_last_slot(st) - (unsigned long)((rrdset_last_entry_t(st) - (time_t)(t)) / (unsigned long)((st)->update_every)) + (unsigned long)(st)->entries ) \
373 - )))
368 + ( (time_t)(t) >= rrdset_last_entry_t(st)) ? ( rrdset_last_slot(st) ) : \
369 + ( ((time_t)(t) <= rrdset_first_entry_t(st)) ? rrdset_first_slot(st) : \
370 + ( (rrdset_last_slot(st) >= (unsigned long)((rrdset_last_entry_t(st) - (time_t)(t)) / (unsigned long)((st)->update_every)) ) ? \
371 + (rrdset_last_slot(st) - (unsigned long)((rrdset_last_entry_t(st) - (time_t)(t)) / (unsigned long)((st)->update_every)) ) : \
372 + (rrdset_last_slot(st) - (unsigned long)((rrdset_last_entry_t(st) - (time_t)(t)) / (unsigned long)((st)->update_every)) + (unsigned long)(st)->entries ) \
373 + )))
374
375 // get the timestamp of a specific slot in the round robin database
376 #define rrdset_slot2time(st, slot) ( rrdset_last_entry_t(st) - \
377 - ((unsigned long)(st)->update_every * ( \
378 - ( (unsigned long)(slot) > rrdset_last_slot(st)) ? \
379 - ( (rrdset_last_slot(st) - (unsigned long)(slot) + (unsigned long)(st)->entries) ) : \
380 - ( (rrdset_last_slot(st) - (unsigned long)(slot)) )) \
381 - ))
377 + ((unsigned long)(st)->update_every * ( \
378 + ( (unsigned long)(slot) > rrdset_last_slot(st)) ? \
379 + ( (rrdset_last_slot(st) - (unsigned long)(slot) + (unsigned long)(st)->entries) ) : \
380 + ( (rrdset_last_slot(st) - (unsigned long)(slot)) )) \
381 + ))
382
383 // ----------------------------------------------------------------------------
384 // RRD DIMENSION functions
src/rrd2json.c
+1851 -1851
@@ -5,207 +5,207 @@ char *hostname = "unknown";
5
6 void rrd_stats_api_v1_chart(RRDSET *st, BUFFER *wb)
7 {
8 - pthread_rwlock_rdlock(&st->rwlock);
9 -
10 - buffer_sprintf(wb,
11 - "\t\t{\n"
12 - "\t\t\t\"id\": \"%s\",\n"
13 - "\t\t\t\"name\": \"%s\",\n"
14 - "\t\t\t\"type\": \"%s\",\n"
15 - "\t\t\t\"family\": \"%s\",\n"
16 - "\t\t\t\"context\": \"%s\",\n"
17 - "\t\t\t\"title\": \"%s\",\n"
18 - "\t\t\t\"priority\": %ld,\n"
19 - "\t\t\t\"enabled\": %s,\n"
20 - "\t\t\t\"units\": \"%s\",\n"
21 - "\t\t\t\"data_url\": \"/api/v1/data?chart=%s\",\n"
22 - "\t\t\t\"chart_type\": \"%s\",\n"
23 - "\t\t\t\"duration\": %ld,\n"
24 - "\t\t\t\"first_entry\": %ld,\n"
25 - "\t\t\t\"last_entry\": %ld,\n"
26 - "\t\t\t\"update_every\": %d,\n"
27 - "\t\t\t\"dimensions\": {\n"
28 - , st->id
29 - , st->name
30 - , st->type
31 - , st->family
32 - , st->context
33 - , st->title
34 - , st->priority
35 - , st->enabled?"true":"false"
36 - , st->units
37 - , st->name
38 - , rrdset_type_name(st->chart_type)
39 - , st->entries * st->update_every
40 - , rrdset_first_entry_t(st)
41 - , rrdset_last_entry_t(st)
42 - , st->update_every
43 - );
44 -
45 - unsigned long memory = st->memsize;
46 -
47 - int c = 0;
48 - RRDDIM *rd;
49 - for(rd = st->dimensions; rd ; rd = rd->next) {
50 - if(rd->flags & RRDDIM_FLAG_HIDDEN) continue;
51 -
52 - memory += rd->memsize;
53 -
54 - buffer_sprintf(wb,
55 - "%s"
56 - "\t\t\t\t\"%s\": { \"name\": \"%s\" }"
57 - , c?",\n":""
58 - , rd->id
59 - , rd->name
60 - );
61 -
62 - c++;
63 - }
64 -
65 - buffer_sprintf(wb,
66 - "\n\t\t\t}\n"
67 - "\t\t}"
68 - );
69 -
70 - pthread_rwlock_unlock(&st->rwlock);
8 + pthread_rwlock_rdlock(&st->rwlock);
9 +
10 + buffer_sprintf(wb,
11 + "\t\t{\n"
12 + "\t\t\t\"id\": \"%s\",\n"
13 + "\t\t\t\"name\": \"%s\",\n"
14 + "\t\t\t\"type\": \"%s\",\n"
15 + "\t\t\t\"family\": \"%s\",\n"
16 + "\t\t\t\"context\": \"%s\",\n"
17 + "\t\t\t\"title\": \"%s\",\n"
18 + "\t\t\t\"priority\": %ld,\n"
19 + "\t\t\t\"enabled\": %s,\n"
20 + "\t\t\t\"units\": \"%s\",\n"
21 + "\t\t\t\"data_url\": \"/api/v1/data?chart=%s\",\n"
22 + "\t\t\t\"chart_type\": \"%s\",\n"
23 + "\t\t\t\"duration\": %ld,\n"
24 + "\t\t\t\"first_entry\": %ld,\n"
25 + "\t\t\t\"last_entry\": %ld,\n"
26 + "\t\t\t\"update_every\": %d,\n"
27 + "\t\t\t\"dimensions\": {\n"
28 + , st->id
29 + , st->name
30 + , st->type
31 + , st->family
32 + , st->context
33 + , st->title
34 + , st->priority
35 + , st->enabled?"true":"false"
36 + , st->units
37 + , st->name
38 + , rrdset_type_name(st->chart_type)
39 + , st->entries * st->update_every
40 + , rrdset_first_entry_t(st)
41 + , rrdset_last_entry_t(st)
42 + , st->update_every
43 + );
44 +
45 + unsigned long memory = st->memsize;
46 +
47 + int c = 0;
48 + RRDDIM *rd;
49 + for(rd = st->dimensions; rd ; rd = rd->next) {
50 + if(rd->flags & RRDDIM_FLAG_HIDDEN) continue;
51 +
52 + memory += rd->memsize;
53 +
54 + buffer_sprintf(wb,
55 + "%s"
56 + "\t\t\t\t\"%s\": { \"name\": \"%s\" }"
57 + , c?",\n":""
58 + , rd->id
59 + , rd->name
60 + );
61 +
62 + c++;
63 + }
64 +
65 + buffer_sprintf(wb,
66 + "\n\t\t\t}\n"
67 + "\t\t}"
68 + );
69 +
70 + pthread_rwlock_unlock(&st->rwlock);
71 }
72
73 void rrd_stats_api_v1_charts(BUFFER *wb)
74 {
75 - long c;
76 - RRDSET *st;
77 -
78 - buffer_sprintf(wb, "{\n"
79 - "\t\"hostname\": \"%s\""
80 - ",\n\t\"update_every\": %d"
81 - ",\n\t\"history\": %d"
82 - ",\n\t\"charts\": {"
83 - , hostname
84 - , rrd_update_every
85 - , rrd_default_history_entries
86 - );
87 -
88 - pthread_rwlock_rdlock(&localhost.rrdset_root_rwlock);
89 - for(st = localhost.rrdset_root, c = 0; st ; st = st->next) {
90 - if(st->enabled && st->dimensions) {
91 - if(c) buffer_strcat(wb, ",");
92 - buffer_strcat(wb, "\n\t\t\"");
93 - buffer_strcat(wb, st->id);
94 - buffer_strcat(wb, "\": ");
95 - rrd_stats_api_v1_chart(st, wb);
96 - c++;
97 - }
98 - }
99 - pthread_rwlock_unlock(&localhost.rrdset_root_rwlock);
100 -
101 - buffer_strcat(wb, "\n\t}\n}\n");
75 + long c;
76 + RRDSET *st;
77 +
78 + buffer_sprintf(wb, "{\n"
79 + "\t\"hostname\": \"%s\""
80 + ",\n\t\"update_every\": %d"
81 + ",\n\t\"history\": %d"
82 + ",\n\t\"charts\": {"
83 + , hostname
84 + , rrd_update_every
85 + , rrd_default_history_entries
86 + );
87 +
88 + pthread_rwlock_rdlock(&localhost.rrdset_root_rwlock);
89 + for(st = localhost.rrdset_root, c = 0; st ; st = st->next) {
90 + if(st->enabled && st->dimensions) {
91 + if(c) buffer_strcat(wb, ",");
92 + buffer_strcat(wb, "\n\t\t\"");
93 + buffer_strcat(wb, st->id);
94 + buffer_strcat(wb, "\": ");
95 + rrd_stats_api_v1_chart(st, wb);
96 + c++;
97 + }
98 + }
99 + pthread_rwlock_unlock(&localhost.rrdset_root_rwlock);
100 +
101 + buffer_strcat(wb, "\n\t}\n}\n");
102 }
103
104
105 unsigned long rrd_stats_one_json(RRDSET *st, char *options, BUFFER *wb)
106 {
107 - time_t now = time(NULL);
108 -
109 - pthread_rwlock_rdlock(&st->rwlock);
110 -
111 - buffer_sprintf(wb,
112 - "\t\t{\n"
113 - "\t\t\t\"id\": \"%s\",\n"
114 - "\t\t\t\"name\": \"%s\",\n"
115 - "\t\t\t\"type\": \"%s\",\n"
116 - "\t\t\t\"family\": \"%s\",\n"
117 - "\t\t\t\"context\": \"%s\",\n"
118 - "\t\t\t\"title\": \"%s\",\n"
119 - "\t\t\t\"priority\": %ld,\n"
120 - "\t\t\t\"enabled\": %d,\n"
121 - "\t\t\t\"units\": \"%s\",\n"
122 - "\t\t\t\"url\": \"/data/%s/%s\",\n"
123 - "\t\t\t\"chart_type\": \"%s\",\n"
124 - "\t\t\t\"counter\": %lu,\n"
125 - "\t\t\t\"entries\": %ld,\n"
126 - "\t\t\t\"first_entry_t\": %ld,\n"
127 - "\t\t\t\"last_entry\": %lu,\n"
128 - "\t\t\t\"last_entry_t\": %ld,\n"
129 - "\t\t\t\"last_entry_secs_ago\": %ld,\n"
130 - "\t\t\t\"update_every\": %d,\n"
131 - "\t\t\t\"isdetail\": %d,\n"
132 - "\t\t\t\"usec_since_last_update\": %llu,\n"
133 - "\t\t\t\"collected_total\": " TOTAL_NUMBER_FORMAT ",\n"
134 - "\t\t\t\"last_collected_total\": " TOTAL_NUMBER_FORMAT ",\n"
135 - "\t\t\t\"dimensions\": [\n"
136 - , st->id
137 - , st->name
138 - , st->type
139 - , st->family
140 - , st->context
141 - , st->title
142 - , st->priority
143 - , st->enabled
144 - , st->units
145 - , st->name, options?options:""
146 - , rrdset_type_name(st->chart_type)
147 - , st->counter
148 - , st->entries
149 - , rrdset_first_entry_t(st)
150 - , rrdset_last_slot(st)
151 - , rrdset_last_entry_t(st)
152 - , (now < rrdset_last_entry_t(st)) ? (time_t)0 : now - rrdset_last_entry_t(st)
153 - , st->update_every
154 - , st->isdetail
155 - , st->usec_since_last_update
156 - , st->collected_total
157 - , st->last_collected_total
158 - );
159 -
160 - unsigned long memory = st->memsize;
161 -
162 - RRDDIM *rd;
163 - for(rd = st->dimensions; rd ; rd = rd->next) {
164 -
165 - memory += rd->memsize;
166 -
167 - buffer_sprintf(wb,
168 - "\t\t\t\t{\n"
169 - "\t\t\t\t\t\"id\": \"%s\",\n"
170 - "\t\t\t\t\t\"name\": \"%s\",\n"
171 - "\t\t\t\t\t\"entries\": %ld,\n"
172 - "\t\t\t\t\t\"isHidden\": %d,\n"
173 - "\t\t\t\t\t\"algorithm\": \"%s\",\n"
174 - "\t\t\t\t\t\"multiplier\": %ld,\n"
175 - "\t\t\t\t\t\"divisor\": %ld,\n"
176 - "\t\t\t\t\t\"last_entry_t\": %ld,\n"
177 - "\t\t\t\t\t\"collected_value\": " COLLECTED_NUMBER_FORMAT ",\n"
178 - "\t\t\t\t\t\"calculated_value\": " CALCULATED_NUMBER_FORMAT ",\n"
179 - "\t\t\t\t\t\"last_collected_value\": " COLLECTED_NUMBER_FORMAT ",\n"
180 - "\t\t\t\t\t\"last_calculated_value\": " CALCULATED_NUMBER_FORMAT ",\n"
181 - "\t\t\t\t\t\"memory\": %lu\n"
182 - "\t\t\t\t}%s\n"
183 - , rd->id
184 - , rd->name
185 - , rd->entries
186 - , (rd->flags & RRDDIM_FLAG_HIDDEN)?1:0
187 - , rrddim_algorithm_name(rd->algorithm)
188 - , rd->multiplier
189 - , rd->divisor
190 - , rd->last_collected_time.tv_sec
191 - , rd->collected_value
192 - , rd->calculated_value
193 - , rd->last_collected_value
194 - , rd->last_calculated_value
195 - , rd->memsize
196 - , rd->next?",":""
197 - );
198 - }
199 -
200 - buffer_sprintf(wb,
201 - "\t\t\t],\n"
202 - "\t\t\t\"memory\" : %lu\n"
203 - "\t\t}"
204 - , memory
205 - );
206 -
207 - pthread_rwlock_unlock(&st->rwlock);
208 - return memory;
107 + time_t now = time(NULL);
108 +
109 + pthread_rwlock_rdlock(&st->rwlock);
110 +
111 + buffer_sprintf(wb,
112 + "\t\t{\n"
113 + "\t\t\t\"id\": \"%s\",\n"
114 + "\t\t\t\"name\": \"%s\",\n"
115 + "\t\t\t\"type\": \"%s\",\n"
116 + "\t\t\t\"family\": \"%s\",\n"
117 + "\t\t\t\"context\": \"%s\",\n"
118 + "\t\t\t\"title\": \"%s\",\n"
119 + "\t\t\t\"priority\": %ld,\n"
120 + "\t\t\t\"enabled\": %d,\n"
121 + "\t\t\t\"units\": \"%s\",\n"
122 + "\t\t\t\"url\": \"/data/%s/%s\",\n"
123 + "\t\t\t\"chart_type\": \"%s\",\n"
124 + "\t\t\t\"counter\": %lu,\n"
125 + "\t\t\t\"entries\": %ld,\n"
126 + "\t\t\t\"first_entry_t\": %ld,\n"
127 + "\t\t\t\"last_entry\": %lu,\n"
128 + "\t\t\t\"last_entry_t\": %ld,\n"
129 + "\t\t\t\"last_entry_secs_ago\": %ld,\n"
130 + "\t\t\t\"update_every\": %d,\n"
131 + "\t\t\t\"isdetail\": %d,\n"
132 + "\t\t\t\"usec_since_last_update\": %llu,\n"
133 + "\t\t\t\"collected_total\": " TOTAL_NUMBER_FORMAT ",\n"
134 + "\t\t\t\"last_collected_total\": " TOTAL_NUMBER_FORMAT ",\n"
135 + "\t\t\t\"dimensions\": [\n"
136 + , st->id
137 + , st->name
138 + , st->type
139 + , st->family
140 + , st->context
141 + , st->title
142 + , st->priority
143 + , st->enabled
144 + , st->units
145 + , st->name, options?options:""
146 + , rrdset_type_name(st->chart_type)
147 + , st->counter
148 + , st->entries
149 + , rrdset_first_entry_t(st)
150 + , rrdset_last_slot(st)
151 + , rrdset_last_entry_t(st)
152 + , (now < rrdset_last_entry_t(st)) ? (time_t)0 : now - rrdset_last_entry_t(st)
153 + , st->update_every
154 + , st->isdetail
155 + , st->usec_since_last_update
156 + , st->collected_total
157 + , st->last_collected_total
158 + );
159 +
160 + unsigned long memory = st->memsize;
161 +
162 + RRDDIM *rd;
163 + for(rd = st->dimensions; rd ; rd = rd->next) {
164 +
165 + memory += rd->memsize;
166 +
167 + buffer_sprintf(wb,
168 + "\t\t\t\t{\n"
169 + "\t\t\t\t\t\"id\": \"%s\",\n"
170 + "\t\t\t\t\t\"name\": \"%s\",\n"
171 + "\t\t\t\t\t\"entries\": %ld,\n"
172 + "\t\t\t\t\t\"isHidden\": %d,\n"
173 + "\t\t\t\t\t\"algorithm\": \"%s\",\n"
174 + "\t\t\t\t\t\"multiplier\": %ld,\n"
175 + "\t\t\t\t\t\"divisor\": %ld,\n"
176 + "\t\t\t\t\t\"last_entry_t\": %ld,\n"
177 + "\t\t\t\t\t\"collected_value\": " COLLECTED_NUMBER_FORMAT ",\n"
178 + "\t\t\t\t\t\"calculated_value\": " CALCULATED_NUMBER_FORMAT ",\n"
179 + "\t\t\t\t\t\"last_collected_value\": " COLLECTED_NUMBER_FORMAT ",\n"
180 + "\t\t\t\t\t\"last_calculated_value\": " CALCULATED_NUMBER_FORMAT ",\n"
181 + "\t\t\t\t\t\"memory\": %lu\n"
182 + "\t\t\t\t}%s\n"
183 + , rd->id
184 + , rd->name
185 + , rd->entries
186 + , (rd->flags & RRDDIM_FLAG_HIDDEN)?1:0
187 + , rrddim_algorithm_name(rd->algorithm)
188 + , rd->multiplier
189 + , rd->divisor
190 + , rd->last_collected_time.tv_sec
191 + , rd->collected_value
192 + , rd->calculated_value
193 + , rd->last_collected_value
194 + , rd->last_calculated_value
195 + , rd->memsize
196 + , rd->next?",":""
197 + );
198 + }
199 +
200 + buffer_sprintf(wb,
201 + "\t\t\t],\n"
202 + "\t\t\t\"memory\" : %lu\n"
203 + "\t\t}"
204 + , memory
205 + );
206 +
207 + pthread_rwlock_unlock(&st->rwlock);
208 + return memory;
209 }
210
211 #define RRD_GRAPH_JSON_HEADER "{\n\t\"charts\": [\n"
@@ -213,40 +213,40 @@ unsigned long rrd_stats_one_json(RRDSET *st, char *options, BUFFER *wb)
213
214 void rrd_stats_graph_json(RRDSET *st, char *options, BUFFER *wb)
215 {
216 - buffer_strcat(wb, RRD_GRAPH_JSON_HEADER);
217 - rrd_stats_one_json(st, options, wb);
218 - buffer_strcat(wb, RRD_GRAPH_JSON_FOOTER);
216 + buffer_strcat(wb, RRD_GRAPH_JSON_HEADER);
217 + rrd_stats_one_json(st, options, wb);
218 + buffer_strcat(wb, RRD_GRAPH_JSON_FOOTER);
219 }
220
221 void rrd_stats_all_json(BUFFER *wb)
222 {
223 - unsigned long memory = 0;
224 - long c;
225 - RRDSET *st;
226 -
227 - buffer_strcat(wb, RRD_GRAPH_JSON_HEADER);
228 -
229 - pthread_rwlock_rdlock(&localhost.rrdset_root_rwlock);
230 - for(st = localhost.rrdset_root, c = 0; st ; st = st->next) {
231 - if(st->enabled && st->dimensions) {
232 - if(c) buffer_strcat(wb, ",\n");
233 - memory += rrd_stats_one_json(st, NULL, wb);
234 - c++;
235 - }
236 - }
237 - pthread_rwlock_unlock(&localhost.rrdset_root_rwlock);
238 -
239 - buffer_sprintf(wb, "\n\t],\n"
240 - "\t\"hostname\": \"%s\",\n"
241 - "\t\"update_every\": %d,\n"
242 - "\t\"history\": %d,\n"
243 - "\t\"memory\": %lu\n"
244 - "}\n"
245 - , hostname
246 - , rrd_update_every
247 - , rrd_default_history_entries
248 - , memory
249 - );
223 + unsigned long memory = 0;
224 + long c;
225 + RRDSET *st;
226 +
227 + buffer_strcat(wb, RRD_GRAPH_JSON_HEADER);
228 +
229 + pthread_rwlock_rdlock(&localhost.rrdset_root_rwlock);
230 + for(st = localhost.rrdset_root, c = 0; st ; st = st->next) {
231 + if(st->enabled && st->dimensions) {
232 + if(c) buffer_strcat(wb, ",\n");
233 + memory += rrd_stats_one_json(st, NULL, wb);
234 + c++;
235 + }
236 + }
237 + pthread_rwlock_unlock(&localhost.rrdset_root_rwlock);
238 +
239 + buffer_sprintf(wb, "\n\t],\n"
240 + "\t\"hostname\": \"%s\",\n"
241 + "\t\"update_every\": %d,\n"
242 + "\t\"history\": %d,\n"
243 + "\t\"memory\": %lu\n"
244 + "}\n"
245 + , hostname
246 + , rrd_update_every
247 + , rrd_default_history_entries
248 + , memory
249 + );
250 }
251
252
@@ -254,42 +254,42 @@ void rrd_stats_all_json(BUFFER *wb)
254 // ----------------------------------------------------------------------------
255
256 // RRDR dimension options
257 -#define RRDR_EMPTY 0x01 // the dimension contains / the value is empty (null)
258 -#define RRDR_RESET 0x02 // the dimension contains / the value is reset
259 -#define RRDR_HIDDEN 0x04 // the dimension contains / the value is hidden
260 -#define RRDR_NONZERO 0x08 // the dimension contains / the value is non-zero
257 +#define RRDR_EMPTY 0x01 // the dimension contains / the value is empty (null)
258 +#define RRDR_RESET 0x02 // the dimension contains / the value is reset
259 +#define RRDR_HIDDEN 0x04 // the dimension contains / the value is hidden
260 +#define RRDR_NONZERO 0x08 // the dimension contains / the value is non-zero
261
262 // RRDR result options
263 #define RRDR_RESULT_OPTION_ABSOLUTE 0x00000001
264 #define RRDR_RESULT_OPTION_RELATIVE 0x00000002
265
266 typedef struct rrdresult {
267 - RRDSET *st; // the chart this result refers to
267 + RRDSET *st; // the chart this result refers to
268
269 - uint32_t result_options; // RRDR_RESULT_OPTION_*
269 + uint32_t result_options; // RRDR_RESULT_OPTION_*
270
271 - int d; // the number of dimensions
272 - long n; // the number of values in the arrays
273 - long rows; // the number of rows used
271 + int d; // the number of dimensions
272 + long n; // the number of values in the arrays
273 + long rows; // the number of rows used
274
275 - uint8_t *od; // the options for the dimensions
275 + uint8_t *od; // the options for the dimensions
276
277 - time_t *t; // array of n timestamps
278 - calculated_number *v; // array n x d values
279 - uint8_t *o; // array n x d options
277 + time_t *t; // array of n timestamps
278 + calculated_number *v; // array n x d values
279 + uint8_t *o; // array n x d options
280
281 - long c; // current line ( -1 ~ n ), ( -1 = none, use rrdr_rows() to get number of rows )
281 + long c; // current line ( -1 ~ n ), ( -1 = none, use rrdr_rows() to get number of rows )
282
283 - long group; // how many collected values were grouped for each row
284 - int update_every; // what is the suggested update frequency in seconds
283 + long group; // how many collected values were grouped for each row
284 + int update_every; // what is the suggested update frequency in seconds
285
286 - calculated_number min;
287 - calculated_number max;
286 + calculated_number min;
287 + calculated_number max;
288
289 - time_t before;
290 - time_t after;
289 + time_t before;
290 + time_t after;
291
292 - int has_st_lock; // if st is read locked by us
292 + int has_st_lock; // if st is read locked by us
293 } RRDR;
294
295 #define rrdr_rows(r) ((r)->rows)
@@ -297,347 +297,347 @@ typedef struct rrdresult {
297 /*
298 static void rrdr_dump(RRDR *r)
299 {
300 - long c, i;
301 - RRDDIM *d;
302 -
303 - fprintf(stderr, "\nCHART %s (%s)\n", r->st->id, r->st->name);
304 -
305 - for(c = 0, d = r->st->dimensions; d ;c++, d = d->next) {
306 - fprintf(stderr, "DIMENSION %s (%s), %s%s%s%s\n"
307 - , d->id
308 - , d->name
309 - , (r->od[c] & RRDR_EMPTY)?"EMPTY ":""
310 - , (r->od[c] & RRDR_RESET)?"RESET ":""
311 - , (r->od[c] & RRDR_HIDDEN)?"HIDDEN ":""
312 - , (r->od[c] & RRDR_NONZERO)?"NONZERO ":""
313 - );
314 - }
315 -
316 - if(r->rows <= 0) {
317 - fprintf(stderr, "RRDR does not have any values in it.\n");
318 - return;
319 - }
320 -
321 - fprintf(stderr, "RRDR includes %d values in it:\n", r->rows);
322 -
323 - // for each line in the array
324 - for(i = 0; i < r->rows ;i++) {
325 - calculated_number *cn = &r->v[ i * r->d ];
326 - uint8_t *co = &r->o[ i * r->d ];
327 -
328 - // print the id and the timestamp of the line
329 - fprintf(stderr, "%ld %ld ", i + 1, r->t[i]);
330 -
331 - // for each dimension
332 - for(c = 0, d = r->st->dimensions; d ;c++, d = d->next) {
333 - if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
334 - if(unlikely(!(r->od[c] & RRDR_NONZERO))) continue;
335 -
336 - if(co[c] & RRDR_EMPTY)
337 - fprintf(stderr, "null ");
338 - else
339 - fprintf(stderr, CALCULATED_NUMBER_FORMAT " %s%s%s%s "
340 - , cn[c]
341 - , (co[c] & RRDR_EMPTY)?"E":" "
342 - , (co[c] & RRDR_RESET)?"R":" "
343 - , (co[c] & RRDR_HIDDEN)?"H":" "
344 - , (co[c] & RRDR_NONZERO)?"N":" "
345 - );
346 - }
347 -
348 - fprintf(stderr, "\n");
349 - }
300 + long c, i;
301 + RRDDIM *d;
302 +
303 + fprintf(stderr, "\nCHART %s (%s)\n", r->st->id, r->st->name);
304 +
305 + for(c = 0, d = r->st->dimensions; d ;c++, d = d->next) {
306 + fprintf(stderr, "DIMENSION %s (%s), %s%s%s%s\n"
307 + , d->id
308 + , d->name
309 + , (r->od[c] & RRDR_EMPTY)?"EMPTY ":""
310 + , (r->od[c] & RRDR_RESET)?"RESET ":""
311 + , (r->od[c] & RRDR_HIDDEN)?"HIDDEN ":""
312 + , (r->od[c] & RRDR_NONZERO)?"NONZERO ":""
313 + );
314 + }
315 +
316 + if(r->rows <= 0) {
317 + fprintf(stderr, "RRDR does not have any values in it.\n");
318 + return;
319 + }
320 +
321 + fprintf(stderr, "RRDR includes %d values in it:\n", r->rows);
322 +
323 + // for each line in the array
324 + for(i = 0; i < r->rows ;i++) {
325 + calculated_number *cn = &r->v[ i * r->d ];
326 + uint8_t *co = &r->o[ i * r->d ];
327 +
328 + // print the id and the timestamp of the line
329 + fprintf(stderr, "%ld %ld ", i + 1, r->t[i]);
330 +
331 + // for each dimension
332 + for(c = 0, d = r->st->dimensions; d ;c++, d = d->next) {
333 + if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
334 + if(unlikely(!(r->od[c] & RRDR_NONZERO))) continue;
335 +
336 + if(co[c] & RRDR_EMPTY)
337 + fprintf(stderr, "null ");
338 + else
339 + fprintf(stderr, CALCULATED_NUMBER_FORMAT " %s%s%s%s "
340 + , cn[c]
341 + , (co[c] & RRDR_EMPTY)?"E":" "
342 + , (co[c] & RRDR_RESET)?"R":" "
343 + , (co[c] & RRDR_HIDDEN)?"H":" "
344 + , (co[c] & RRDR_NONZERO)?"N":" "
345 + );
346 + }
347 +
348 + fprintf(stderr, "\n");
349 + }
350 }
351 */
352
353 void rrdr_disable_not_selected_dimensions(RRDR *r, const char *dims)
354 {
355 - char b[strlen(dims) + 1];
356 - char *o = b, *tok;
357 - strcpy(o, dims);
358 -
359 - long c;
360 - RRDDIM *d;
361 -
362 - // disable all of them
363 - for(c = 0, d = r->st->dimensions; d ;c++, d = d->next)
364 - r->od[c] |= RRDR_HIDDEN;
365 -
366 - while(o && *o && (tok = mystrsep(&o, ",|"))) {
367 - if(!*tok) continue;
368 -
369 - uint32_t hash = simple_hash(tok);
370 -
371 - // find it and enable it
372 - for(c = 0, d = r->st->dimensions; d ;c++, d = d->next) {
373 - if(unlikely((hash == d->hash && !strcmp(d->id, tok)) || !strcmp(d->name, tok))) {
374 - r->od[c] &= ~RRDR_HIDDEN;
375 -
376 - // since the user needs this dimension
377 - // make it appear as NONZERO, to return it
378 - // even if the dimension has only zeros
379 - r->od[c] |= RRDR_NONZERO;
380 - }
381 - }
382 - }
355 + char b[strlen(dims) + 1];
356 + char *o = b, *tok;
357 + strcpy(o, dims);
358 +
359 + long c;
360 + RRDDIM *d;
361 +
362 + // disable all of them
363 + for(c = 0, d = r->st->dimensions; d ;c++, d = d->next)
364 + r->od[c] |= RRDR_HIDDEN;
365 +
366 + while(o && *o && (tok = mystrsep(&o, ",|"))) {
367 + if(!*tok) continue;
368 +
369 + uint32_t hash = simple_hash(tok);
370 +
371 + // find it and enable it
372 + for(c = 0, d = r->st->dimensions; d ;c++, d = d->next) {
373 + if(unlikely((hash == d->hash && !strcmp(d->id, tok)) || !strcmp(d->name, tok))) {
374 + r->od[c] &= ~RRDR_HIDDEN;
375 +
376 + // since the user needs this dimension
377 + // make it appear as NONZERO, to return it
378 + // even if the dimension has only zeros
379 + r->od[c] |= RRDR_NONZERO;
380 + }
381 + }
382 + }
383 }
384
385 void rrdr_buffer_print_format(BUFFER *wb, uint32_t format)
386 {
387 - switch(format) {
388 - case DATASOURCE_JSON:
389 - buffer_strcat(wb, DATASOURCE_FORMAT_JSON);
390 - break;
391 -
392 - case DATASOURCE_DATATABLE_JSON:
393 - buffer_strcat(wb, DATASOURCE_FORMAT_DATATABLE_JSON);
394 - break;
395 -
396 - case DATASOURCE_DATATABLE_JSONP:
397 - buffer_strcat(wb, DATASOURCE_FORMAT_DATATABLE_JSONP);
398 - break;
399 -
400 - case DATASOURCE_JSONP:
401 - buffer_strcat(wb, DATASOURCE_FORMAT_JSONP);
402 - break;
403 -
404 - case DATASOURCE_SSV:
405 - buffer_strcat(wb, DATASOURCE_FORMAT_SSV);
406 - break;
407 -
408 - case DATASOURCE_CSV:
409 - buffer_strcat(wb, DATASOURCE_FORMAT_CSV);
410 - break;
411 -
412 - case DATASOURCE_TSV:
413 - buffer_strcat(wb, DATASOURCE_FORMAT_TSV);
414 - break;
415 -
416 - case DATASOURCE_HTML:
417 - buffer_strcat(wb, DATASOURCE_FORMAT_HTML);
418 - break;
419 -
420 - case DATASOURCE_JS_ARRAY:
421 - buffer_strcat(wb, DATASOURCE_FORMAT_JS_ARRAY);
422 - break;
423 -
424 - case DATASOURCE_SSV_COMMA:
425 - buffer_strcat(wb, DATASOURCE_FORMAT_SSV_COMMA);
426 - break;
427 -
428 - default:
429 - buffer_strcat(wb, "unknown");
430 - break;
431 - }
387 + switch(format) {
388 + case DATASOURCE_JSON:
389 + buffer_strcat(wb, DATASOURCE_FORMAT_JSON);
390 + break;
391 +
392 + case DATASOURCE_DATATABLE_JSON:
393 + buffer_strcat(wb, DATASOURCE_FORMAT_DATATABLE_JSON);
394 + break;
395 +
396 + case DATASOURCE_DATATABLE_JSONP:
397 + buffer_strcat(wb, DATASOURCE_FORMAT_DATATABLE_JSONP);
398 + break;
399 +
400 + case DATASOURCE_JSONP:
401 + buffer_strcat(wb, DATASOURCE_FORMAT_JSONP);
402 + break;
403 +
404 + case DATASOURCE_SSV:
405 + buffer_strcat(wb, DATASOURCE_FORMAT_SSV);
406 + break;
407 +
408 + case DATASOURCE_CSV:
409 + buffer_strcat(wb, DATASOURCE_FORMAT_CSV);
410 + break;
411 +
412 + case DATASOURCE_TSV:
413 + buffer_strcat(wb, DATASOURCE_FORMAT_TSV);
414 + break;
415 +
416 + case DATASOURCE_HTML:
417 + buffer_strcat(wb, DATASOURCE_FORMAT_HTML);
418 + break;
419 +
420 + case DATASOURCE_JS_ARRAY:
421 + buffer_strcat(wb, DATASOURCE_FORMAT_JS_ARRAY);
422 + break;
423 +
424 + case DATASOURCE_SSV_COMMA:
425 + buffer_strcat(wb, DATASOURCE_FORMAT_SSV_COMMA);
426 + break;
427 +
428 + default:
429 + buffer_strcat(wb, "unknown");
430 + break;
431 + }
432 }
433
434 uint32_t rrdr_check_options(RRDR *r, uint32_t options, const char *dims)
435 {
436 - if(options & RRDR_OPTION_NONZERO) {
437 - long i;
438 -
439 - if(dims && *dims) {
440 - // the caller wants specific dimensions
441 - // disable NONZERO option
442 - // to make sure we don't accidentally prevent
443 - // the specific dimensions from being returned
444 - i = 0;
445 - }
446 - else {
447 - // find how many dimensions are not zero
448 - long c;
449 - RRDDIM *rd;
450 - for(c = 0, i = 0, rd = r->st->dimensions; rd && c < r->d ; c++, rd = rd->next) {
451 - if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
452 - if(unlikely(!(r->od[c] & RRDR_NONZERO))) continue;
453 - i++;
454 - }
455 - }
456 -
457 - // if with nonzero we get i = 0 (no dimensions will be returned)
458 - // disable nonzero to show all dimensions
459 - if(!i) options &= ~RRDR_OPTION_NONZERO;
460 - }
461 -
462 - return options;
436 + if(options & RRDR_OPTION_NONZERO) {
437 + long i;
438 +
439 + if(dims && *dims) {
440 + // the caller wants specific dimensions
441 + // disable NONZERO option
442 + // to make sure we don't accidentally prevent
443 + // the specific dimensions from being returned
444 + i = 0;
445 + }
446 + else {
447 + // find how many dimensions are not zero
448 + long c;
449 + RRDDIM *rd;
450 + for(c = 0, i = 0, rd = r->st->dimensions; rd && c < r->d ; c++, rd = rd->next) {
451 + if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
452 + if(unlikely(!(r->od[c] & RRDR_NONZERO))) continue;
453 + i++;
454 + }
455 + }
456 +
457 + // if with nonzero we get i = 0 (no dimensions will be returned)
458 + // disable nonzero to show all dimensions
459 + if(!i) options &= ~RRDR_OPTION_NONZERO;
460 + }
461 +
462 + return options;
463 }
464
465 void rrdr_json_wrapper_begin(RRDR *r, BUFFER *wb, uint32_t format, uint32_t options, int string_value)
466 {
467 - long rows = rrdr_rows(r);
468 - long c, i;
469 - RRDDIM *rd;
470 -
471 - //info("JSONWRAPPER(): %s: BEGIN", r->st->id);
472 - char kq[2] = "", // key quote
473 - sq[2] = ""; // string quote
474 -
475 - if( options & RRDR_OPTION_GOOGLE_JSON ) {
476 - kq[0] = '\0';
477 - sq[0] = '\'';
478 - }
479 - else {
480 - kq[0] = '"';
481 - sq[0] = '"';
482 - }
483 -
484 - buffer_sprintf(wb, "{\n"
485 - " %sapi%s: 1,\n"
486 - " %sid%s: %s%s%s,\n"
487 - " %sname%s: %s%s%s,\n"
488 - " %sview_update_every%s: %d,\n"
489 - " %supdate_every%s: %d,\n"
490 - " %sfirst_entry%s: %u,\n"
491 - " %slast_entry%s: %u,\n"
492 - " %sbefore%s: %u,\n"
493 - " %safter%s: %u,\n"
494 - " %sdimension_names%s: ["
495 - , kq, kq
496 - , kq, kq, sq, r->st->id, sq
497 - , kq, kq, sq, r->st->name, sq
498 - , kq, kq, r->update_every
499 - , kq, kq, r->st->update_every
500 - , kq, kq, (uint32_t)rrdset_first_entry_t(r->st)
501 - , kq, kq, (uint32_t)rrdset_last_entry_t(r->st)
502 - , kq, kq, (uint32_t)r->before
503 - , kq, kq, (uint32_t)r->after
504 - , kq, kq);
505 -
506 - for(c = 0, i = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
507 - if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
508 - if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
509 -
510 - if(i) buffer_strcat(wb, ", ");
511 - buffer_strcat(wb, sq);
512 - buffer_strcat(wb, rd->name);
513 - buffer_strcat(wb, sq);
514 - i++;
515 - }
516 - if(!i) {
467 + long rows = rrdr_rows(r);
468 + long c, i;
469 + RRDDIM *rd;
470 +
471 + //info("JSONWRAPPER(): %s: BEGIN", r->st->id);
472 + char kq[2] = "", // key quote
473 + sq[2] = ""; // string quote
474 +
475 + if( options & RRDR_OPTION_GOOGLE_JSON ) {
476 + kq[0] = '\0';
477 + sq[0] = '\'';
478 + }
479 + else {
480 + kq[0] = '"';
481 + sq[0] = '"';
482 + }
483 +
484 + buffer_sprintf(wb, "{\n"
485 + " %sapi%s: 1,\n"
486 + " %sid%s: %s%s%s,\n"
487 + " %sname%s: %s%s%s,\n"
488 + " %sview_update_every%s: %d,\n"
489 + " %supdate_every%s: %d,\n"
490 + " %sfirst_entry%s: %u,\n"
491 + " %slast_entry%s: %u,\n"
492 + " %sbefore%s: %u,\n"
493 + " %safter%s: %u,\n"
494 + " %sdimension_names%s: ["
495 + , kq, kq
496 + , kq, kq, sq, r->st->id, sq
497 + , kq, kq, sq, r->st->name, sq
498 + , kq, kq, r->update_every
499 + , kq, kq, r->st->update_every
500 + , kq, kq, (uint32_t)rrdset_first_entry_t(r->st)
501 + , kq, kq, (uint32_t)rrdset_last_entry_t(r->st)
502 + , kq, kq, (uint32_t)r->before
503 + , kq, kq, (uint32_t)r->after
504 + , kq, kq);
505 +
506 + for(c = 0, i = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
507 + if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
508 + if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
509 +
510 + if(i) buffer_strcat(wb, ", ");
511 + buffer_strcat(wb, sq);
512 + buffer_strcat(wb, rd->name);
513 + buffer_strcat(wb, sq);
514 + i++;
515 + }
516 + if(!i) {
517 #ifdef NETDATA_INTERNAL_CHECKS
518 - error("RRDR is empty for %s (RRDR has %d dimensions, options is 0x%08x)", r->st->id, r->d, options);
518 + error("RRDR is empty for %s (RRDR has %d dimensions, options is 0x%08x)", r->st->id, r->d, options);
519 #endif
520 - rows = 0;
521 - buffer_strcat(wb, sq);
522 - buffer_strcat(wb, "no data");
523 - buffer_strcat(wb, sq);
524 - }
525 -
526 - buffer_sprintf(wb, "],\n"
527 - " %sdimension_ids%s: ["
528 - , kq, kq);
529 -
530 - for(c = 0, i = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
531 - if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
532 - if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
533 -
534 - if(i) buffer_strcat(wb, ", ");
535 - buffer_strcat(wb, sq);
536 - buffer_strcat(wb, rd->id);
537 - buffer_strcat(wb, sq);
538 - i++;
539 - }
540 - if(!i) {
541 - rows = 0;
542 - buffer_strcat(wb, sq);
543 - buffer_strcat(wb, "no data");
544 - buffer_strcat(wb, sq);
545 - }
546 -
547 - buffer_sprintf(wb, "],\n"
548 - " %slatest_values%s: ["
549 - , kq, kq);
550 -
551 - for(c = 0, i = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
552 - if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
553 - if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
554 -
555 - if(i) buffer_strcat(wb, ", ");
556 - i++;
557 -
558 - storage_number n = rd->values[rrdset_last_slot(r->st)];
559 -
560 - if(!does_storage_number_exist(n))
561 - buffer_strcat(wb, "null");
562 - else
563 - buffer_rrd_value(wb, unpack_storage_number(n));
564 - }
565 - if(!i) {
566 - rows = 0;
567 - buffer_strcat(wb, "null");
568 - }
569 -
570 - buffer_sprintf(wb, "],\n"
571 - " %sview_latest_values%s: ["
572 - , kq, kq);
573 -
574 - i = 0;
575 - if(rows) {
576 - for(c = 0, i = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
577 - if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
578 - if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
579 -
580 - if(i) buffer_strcat(wb, ", ");
581 - i++;
582 -
583 - calculated_number *cn = &r->v[ (0) * r->d ];
584 - uint8_t *co = &r->o[ (0) * r->d ];
585 -
586 - if(co[c] & RRDR_EMPTY)
587 - buffer_strcat(wb, "null");
588 - else
589 - buffer_rrd_value(wb, cn[c]);
590 - }
591 - }
592 - if(!i) {
593 - rows = 0;
594 - buffer_strcat(wb, "null");
595 - }
596 -
597 - buffer_sprintf(wb, "],\n"
598 - " %sdimensions%s: %ld,\n"
599 - " %spoints%s: %ld,\n"
600 - " %sformat%s: %s"
601 - , kq, kq, i
602 - , kq, kq, rows
603 - , kq, kq, sq
604 - );
605 -
606 - rrdr_buffer_print_format(wb, format);
607 -
608 - buffer_sprintf(wb, "%s,\n"
609 - " %sresult%s: "
610 - , sq
611 - , kq, kq
612 - );
613 -
614 - if(string_value) buffer_strcat(wb, sq);
615 - //info("JSONWRAPPER(): %s: END", r->st->id);
520 + rows = 0;
521 + buffer_strcat(wb, sq);
522 + buffer_strcat(wb, "no data");
523 + buffer_strcat(wb, sq);
524 + }
525 +
526 + buffer_sprintf(wb, "],\n"
527 + " %sdimension_ids%s: ["
528 + , kq, kq);
529 +
530 + for(c = 0, i = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
531 + if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
532 + if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
533 +
534 + if(i) buffer_strcat(wb, ", ");
535 + buffer_strcat(wb, sq);
536 + buffer_strcat(wb, rd->id);
537 + buffer_strcat(wb, sq);
538 + i++;
539 + }
540 + if(!i) {
541 + rows = 0;
542 + buffer_strcat(wb, sq);
543 + buffer_strcat(wb, "no data");
544 + buffer_strcat(wb, sq);
545 + }
546 +
547 + buffer_sprintf(wb, "],\n"
548 + " %slatest_values%s: ["
549 + , kq, kq);
550 +
551 + for(c = 0, i = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
552 + if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
553 + if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
554 +
555 + if(i) buffer_strcat(wb, ", ");
556 + i++;
557 +
558 + storage_number n = rd->values[rrdset_last_slot(r->st)];
559 +
560 + if(!does_storage_number_exist(n))
561 + buffer_strcat(wb, "null");
562 + else
563 + buffer_rrd_value(wb, unpack_storage_number(n));
564 + }
565 + if(!i) {
566 + rows = 0;
567 + buffer_strcat(wb, "null");
568 + }
569 +
570 + buffer_sprintf(wb, "],\n"
571 + " %sview_latest_values%s: ["
572 + , kq, kq);
573 +
574 + i = 0;
575 + if(rows) {
576 + for(c = 0, i = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
577 + if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
578 + if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
579 +
580 + if(i) buffer_strcat(wb, ", ");
581 + i++;
582 +
583 + calculated_number *cn = &r->v[ (0) * r->d ];
584 + uint8_t *co = &r->o[ (0) * r->d ];
585 +
586 + if(co[c] & RRDR_EMPTY)
587 + buffer_strcat(wb, "null");
588 + else
589 + buffer_rrd_value(wb, cn[c]);
590 + }
591 + }
592 + if(!i) {
593 + rows = 0;
594 + buffer_strcat(wb, "null");
595 + }
596 +
597 + buffer_sprintf(wb, "],\n"
598 + " %sdimensions%s: %ld,\n"
599 + " %spoints%s: %ld,\n"
600 + " %sformat%s: %s"
601 + , kq, kq, i
602 + , kq, kq, rows
603 + , kq, kq, sq
604 + );
605 +
606 + rrdr_buffer_print_format(wb, format);
607 +
608 + buffer_sprintf(wb, "%s,\n"
609 + " %sresult%s: "
610 + , sq
611 + , kq, kq
612 + );
613 +
614 + if(string_value) buffer_strcat(wb, sq);
615 + //info("JSONWRAPPER(): %s: END", r->st->id);
616 }
617
618 void rrdr_json_wrapper_end(RRDR *r, BUFFER *wb, uint32_t format, uint32_t options, int string_value)
619 {
620 - (void)format;
621 -
622 - char kq[2] = "", // key quote
623 - sq[2] = ""; // string quote
624 -
625 - if( options & RRDR_OPTION_GOOGLE_JSON ) {
626 - kq[0] = '\0';
627 - sq[0] = '\'';
628 - }
629 - else {
630 - kq[0] = '"';
631 - sq[0] = '"';
632 - }
633 -
634 - if(string_value) buffer_strcat(wb, sq);
635 -
636 - buffer_sprintf(wb, ",\n %smin%s: ", kq, kq);
637 - buffer_rrd_value(wb, r->min);
638 - buffer_sprintf(wb, ",\n %smax%s: ", kq, kq);
639 - buffer_rrd_value(wb, r->max);
640 - buffer_strcat(wb, "\n}\n");
620 + (void)format;
621 +
622 + char kq[2] = "", // key quote
623 + sq[2] = ""; // string quote
624 +
625 + if( options & RRDR_OPTION_GOOGLE_JSON ) {
626 + kq[0] = '\0';
627 + sq[0] = '\'';
628 + }
629 + else {
630 + kq[0] = '"';
631 + sq[0] = '"';
632 + }
633 +
634 + if(string_value) buffer_strcat(wb, sq);
635 +
636 + buffer_sprintf(wb, ",\n %smin%s: ", kq, kq);
637 + buffer_rrd_value(wb, r->min);
638 + buffer_sprintf(wb, ",\n %smax%s: ", kq, kq);
639 + buffer_rrd_value(wb, r->max);
640 + buffer_strcat(wb, "\n}\n");
641 }
642
643 #define JSON_DATES_JS 1
@@ -645,1407 +645,1407 @@ void rrdr_json_wrapper_end(RRDR *r, BUFFER *wb, uint32_t format, uint32_t option
645
646 static void rrdr2json(RRDR *r, BUFFER *wb, uint32_t options, int datatable)
647 {
648 - //info("RRD2JSON(): %s: BEGIN", r->st->id);
649 - int row_annotations = 0, dates, dates_with_new = 0;
650 - char kq[2] = "", // key quote
651 - sq[2] = "", // string quote
652 - pre_label[101] = "", // before each label
653 - post_label[101] = "", // after each label
654 - pre_date[101] = "", // the beginning of line, to the date
655 - post_date[101] = "", // closing the date
656 - pre_value[101] = "", // before each value
657 - post_value[101] = "", // after each value
658 - post_line[101] = "", // at the end of each row
659 - normal_annotation[201] = "", // default row annotation
660 - overflow_annotation[201] = "", // overflow row annotation
661 - data_begin[101] = "", // between labels and values
662 - finish[101] = ""; // at the end of everything
663 -
664 - if(datatable) {
665 - dates = JSON_DATES_JS;
666 - if( options & RRDR_OPTION_GOOGLE_JSON ) {
667 - kq[0] = '\0';
668 - sq[0] = '\'';
669 - }
670 - else {
671 - kq[0] = '"';
672 - sq[0] = '"';
673 - }
674 - row_annotations = 1;
675 - snprintfz(pre_date, 100, " {%sc%s:[{%sv%s:%s", kq, kq, kq, kq, sq);
676 - snprintfz(post_date, 100, "%s}", sq);
677 - snprintfz(pre_label, 100, ",\n {%sid%s:%s%s,%slabel%s:%s", kq, kq, sq, sq, kq, kq, sq);
678 - snprintfz(post_label, 100, "%s,%spattern%s:%s%s,%stype%s:%snumber%s}", sq, kq, kq, sq, sq, kq, kq, sq, sq);
679 - snprintfz(pre_value, 100, ",{%sv%s:", kq, kq);
680 - strcpy(post_value, "}");
681 - strcpy(post_line, "]}");
682 - snprintfz(data_begin, 100, "\n ],\n %srows%s:\n [\n", kq, kq);
683 - strcpy(finish, "\n ]\n}");
684 -
685 - snprintfz(overflow_annotation, 200, ",{%sv%s:%sRESET OR OVERFLOW%s},{%sv%s:%sThe counters have been wrapped.%s}", kq, kq, sq, sq, kq, kq, sq, sq);
686 - snprintfz(normal_annotation, 200, ",{%sv%s:null},{%sv%s:null}", kq, kq, kq, kq);
687 -
688 - buffer_sprintf(wb, "{\n %scols%s:\n [\n", kq, kq);
689 - buffer_sprintf(wb, " {%sid%s:%s%s,%slabel%s:%stime%s,%spattern%s:%s%s,%stype%s:%sdatetime%s},\n", kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq);
690 - buffer_sprintf(wb, " {%sid%s:%s%s,%slabel%s:%s%s,%spattern%s:%s%s,%stype%s:%sstring%s,%sp%s:{%srole%s:%sannotation%s}},\n", kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, kq, kq, sq, sq);
691 - buffer_sprintf(wb, " {%sid%s:%s%s,%slabel%s:%s%s,%spattern%s:%s%s,%stype%s:%sstring%s,%sp%s:{%srole%s:%sannotationText%s}}", kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, kq, kq, sq, sq);
692 -
693 - // remove the valueobjects flag
694 - // google wants its own keys
695 - if(options & RRDR_OPTION_OBJECTSROWS)
696 - options &= ~RRDR_OPTION_OBJECTSROWS;
697 - }
698 - else {
699 - kq[0] = '"';
700 - sq[0] = '"';
701 - if((options & RRDR_OPTION_SECONDS) || (options & RRDR_OPTION_MILLISECONDS)) {
702 - dates = JSON_DATES_TIMESTAMP;
703 - dates_with_new = 0;
704 - }
705 - else {
706 - dates = JSON_DATES_JS;
707 - dates_with_new = 1;
708 - }
709 - if( options & RRDR_OPTION_OBJECTSROWS )
710 - strcpy(pre_date, " { ");
711 - else
712 - strcpy(pre_date, " [ ");
713 - strcpy(pre_label, ", \"");
714 - strcpy(post_label, "\"");
715 - strcpy(pre_value, ", ");
716 - if( options & RRDR_OPTION_OBJECTSROWS )
717 - strcpy(post_line, "}");
718 - else
719 - strcpy(post_line, "]");
720 - snprintfz(data_begin, 100, "],\n %sdata%s:\n [\n", kq, kq);
721 - strcpy(finish, "\n ]\n}");
722 -
723 - buffer_sprintf(wb, "{\n %slabels%s: [", kq, kq);
724 - buffer_sprintf(wb, "%stime%s", sq, sq);
725 - }
726 -
727 - // -------------------------------------------------------------------------
728 - // print the JSON header
729 -
730 - long c, i;
731 - RRDDIM *rd;
732 -
733 - // print the header lines
734 - for(c = 0, i = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
735 - if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
736 - if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
737 -
738 - buffer_strcat(wb, pre_label);
739 - buffer_strcat(wb, rd->name);
740 - buffer_strcat(wb, post_label);
741 - i++;
742 - }
743 - if(!i) {
744 - buffer_strcat(wb, pre_label);
745 - buffer_strcat(wb, "no data");
746 - buffer_strcat(wb, post_label);
747 - }
748 -
749 - // print the begin of row data
750 - buffer_strcat(wb, data_begin);
751 -
752 - // if all dimensions are hidden, print a null
753 - if(!i) {
754 - buffer_strcat(wb, finish);
755 - return;
756 - }
757 -
758 - long start = 0, end = rrdr_rows(r), step = 1;
759 - if((options & RRDR_OPTION_REVERSED)) {
760 - start = rrdr_rows(r) - 1;
761 - end = -1;
762 - step = -1;
763 - }
764 -
765 - // for each line in the array
766 - calculated_number total = 1;
767 - for(i = start; i != end ;i += step) {
768 - calculated_number *cn = &r->v[ i * r->d ];
769 - uint8_t *co = &r->o[ i * r->d ];
770 -
771 - time_t now = r->t[i];
772 -
773 - if(dates == JSON_DATES_JS) {
774 - // generate the local date time
775 - struct tm tmbuf, *tm = localtime_r(&now, &tmbuf);
776 - if(!tm) { error("localtime_r() failed."); continue; }
777 -
778 - if(likely(i != start)) buffer_strcat(wb, ",\n");
779 - buffer_strcat(wb, pre_date);
780 -
781 - if( options & RRDR_OPTION_OBJECTSROWS )
782 - buffer_sprintf(wb, "%stime%s: ", kq, kq);
783 -
784 - if(dates_with_new)
785 - buffer_strcat(wb, "new ");
786 -
787 - buffer_jsdate(wb, tm->tm_year + 1900, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
788 -
789 - buffer_strcat(wb, post_date);
790 -
791 - if(row_annotations) {
792 - // google supports one annotation per row
793 - int annotation_found = 0;
794 - for(c = 0, rd = r->st->dimensions; rd ;c++, rd = rd->next) {
795 - if(co[c] & RRDR_RESET) {
796 - buffer_strcat(wb, overflow_annotation);
797 - annotation_found = 1;
798 - break;
799 - }
800 - }
801 - if(!annotation_found)
802 - buffer_strcat(wb, normal_annotation);
803 - }
804 - }
805 - else {
806 - // print the timestamp of the line
807 - if(likely(i != start)) buffer_strcat(wb, ",\n");
808 - buffer_strcat(wb, pre_date);
809 -
810 - if( options & RRDR_OPTION_OBJECTSROWS )
811 - buffer_sprintf(wb, "%stime%s: ", kq, kq);
812 -
813 - buffer_rrd_value(wb, (calculated_number)r->t[i]);
814 - // in ms
815 - if(options & RRDR_OPTION_MILLISECONDS) buffer_strcat(wb, "000");
816 -
817 - buffer_strcat(wb, post_date);
818 - }
819 -
820 - if(unlikely(options & RRDR_OPTION_PERCENTAGE)) {
821 - total = 0;
822 - for(c = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
823 - calculated_number n = cn[c];
824 -
825 - if(likely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
826 - n = -n;
827 -
828 - total += n;
829 - }
830 - // prevent a division by zero
831 - if(total == 0) total = 1;
832 - }
833 -
834 - // for each dimension
835 - for(c = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
836 - if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
837 - if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
838 -
839 - calculated_number n = cn[c];
840 -
841 - buffer_strcat(wb, pre_value);
842 -
843 - if( options & RRDR_OPTION_OBJECTSROWS )
844 - buffer_sprintf(wb, "%s%s%s: ", kq, rd->name, kq);
845 -
846 - if(co[c] & RRDR_EMPTY) {
847 - if(options & RRDR_OPTION_NULL2ZERO)
848 - buffer_strcat(wb, "0");
849 - else
850 - buffer_strcat(wb, "null");
851 - }
852 - else {
853 - if(unlikely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
854 - n = -n;
855 -
856 - if(unlikely(options & RRDR_OPTION_PERCENTAGE))
857 - n = n * 100 / total;
858 -
859 - buffer_rrd_value(wb, n);
860 - }
861 -
862 - buffer_strcat(wb, post_value);
863 - }
864 -
865 - buffer_strcat(wb, post_line);
866 - }
867 -
868 - buffer_strcat(wb, finish);
869 - //info("RRD2JSON(): %s: END", r->st->id);
648 + //info("RRD2JSON(): %s: BEGIN", r->st->id);
649 + int row_annotations = 0, dates, dates_with_new = 0;
650 + char kq[2] = "", // key quote
651 + sq[2] = "", // string quote
652 + pre_label[101] = "", // before each label
653 + post_label[101] = "", // after each label
654 + pre_date[101] = "", // the beginning of line, to the date
655 + post_date[101] = "", // closing the date
656 + pre_value[101] = "", // before each value
657 + post_value[101] = "", // after each value
658 + post_line[101] = "", // at the end of each row
659 + normal_annotation[201] = "", // default row annotation
660 + overflow_annotation[201] = "", // overflow row annotation
661 + data_begin[101] = "", // between labels and values
662 + finish[101] = ""; // at the end of everything
663 +
664 + if(datatable) {
665 + dates = JSON_DATES_JS;
666 + if( options & RRDR_OPTION_GOOGLE_JSON ) {
667 + kq[0] = '\0';
668 + sq[0] = '\'';
669 + }
670 + else {
671 + kq[0] = '"';
672 + sq[0] = '"';
673 + }
674 + row_annotations = 1;
675 + snprintfz(pre_date, 100, " {%sc%s:[{%sv%s:%s", kq, kq, kq, kq, sq);
676 + snprintfz(post_date, 100, "%s}", sq);
677 + snprintfz(pre_label, 100, ",\n {%sid%s:%s%s,%slabel%s:%s", kq, kq, sq, sq, kq, kq, sq);
678 + snprintfz(post_label, 100, "%s,%spattern%s:%s%s,%stype%s:%snumber%s}", sq, kq, kq, sq, sq, kq, kq, sq, sq);
679 + snprintfz(pre_value, 100, ",{%sv%s:", kq, kq);
680 + strcpy(post_value, "}");
681 + strcpy(post_line, "]}");
682 + snprintfz(data_begin, 100, "\n ],\n %srows%s:\n [\n", kq, kq);
683 + strcpy(finish, "\n ]\n}");
684 +
685 + snprintfz(overflow_annotation, 200, ",{%sv%s:%sRESET OR OVERFLOW%s},{%sv%s:%sThe counters have been wrapped.%s}", kq, kq, sq, sq, kq, kq, sq, sq);
686 + snprintfz(normal_annotation, 200, ",{%sv%s:null},{%sv%s:null}", kq, kq, kq, kq);
687 +
688 + buffer_sprintf(wb, "{\n %scols%s:\n [\n", kq, kq);
689 + buffer_sprintf(wb, " {%sid%s:%s%s,%slabel%s:%stime%s,%spattern%s:%s%s,%stype%s:%sdatetime%s},\n", kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq);
690 + buffer_sprintf(wb, " {%sid%s:%s%s,%slabel%s:%s%s,%spattern%s:%s%s,%stype%s:%sstring%s,%sp%s:{%srole%s:%sannotation%s}},\n", kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, kq, kq, sq, sq);
691 + buffer_sprintf(wb, " {%sid%s:%s%s,%slabel%s:%s%s,%spattern%s:%s%s,%stype%s:%sstring%s,%sp%s:{%srole%s:%sannotationText%s}}", kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, kq, kq, sq, sq);
692 +
693 + // remove the valueobjects flag
694 + // google wants its own keys
695 + if(options & RRDR_OPTION_OBJECTSROWS)
696 + options &= ~RRDR_OPTION_OBJECTSROWS;
697 + }
698 + else {
699 + kq[0] = '"';
700 + sq[0] = '"';
701 + if((options & RRDR_OPTION_SECONDS) || (options & RRDR_OPTION_MILLISECONDS)) {
702 + dates = JSON_DATES_TIMESTAMP;
703 + dates_with_new = 0;
704 + }
705 + else {
706 + dates = JSON_DATES_JS;
707 + dates_with_new = 1;
708 + }
709 + if( options & RRDR_OPTION_OBJECTSROWS )
710 + strcpy(pre_date, " { ");
711 + else
712 + strcpy(pre_date, " [ ");
713 + strcpy(pre_label, ", \"");
714 + strcpy(post_label, "\"");
715 + strcpy(pre_value, ", ");
716 + if( options & RRDR_OPTION_OBJECTSROWS )
717 + strcpy(post_line, "}");
718 + else
719 + strcpy(post_line, "]");
720 + snprintfz(data_begin, 100, "],\n %sdata%s:\n [\n", kq, kq);
721 + strcpy(finish, "\n ]\n}");
722 +
723 + buffer_sprintf(wb, "{\n %slabels%s: [", kq, kq);
724 + buffer_sprintf(wb, "%stime%s", sq, sq);
725 + }
726 +
727 + // -------------------------------------------------------------------------
728 + // print the JSON header
729 +
730 + long c, i;
731 + RRDDIM *rd;
732 +
733 + // print the header lines
734 + for(c = 0, i = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
735 + if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
736 + if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
737 +
738 + buffer_strcat(wb, pre_label);
739 + buffer_strcat(wb, rd->name);
740 + buffer_strcat(wb, post_label);
741 + i++;
742 + }
743 + if(!i) {
744 + buffer_strcat(wb, pre_label);
745 + buffer_strcat(wb, "no data");
746 + buffer_strcat(wb, post_label);
747 + }
748 +
749 + // print the begin of row data
750 + buffer_strcat(wb, data_begin);
751 +
752 + // if all dimensions are hidden, print a null
753 + if(!i) {
754 + buffer_strcat(wb, finish);
755 + return;
756 + }
757 +
758 + long start = 0, end = rrdr_rows(r), step = 1;
759 + if((options & RRDR_OPTION_REVERSED)) {
760 + start = rrdr_rows(r) - 1;
761 + end = -1;
762 + step = -1;
763 + }
764 +
765 + // for each line in the array
766 + calculated_number total = 1;
767 + for(i = start; i != end ;i += step) {
768 + calculated_number *cn = &r->v[ i * r->d ];
769 + uint8_t *co = &r->o[ i * r->d ];
770 +
771 + time_t now = r->t[i];
772 +
773 + if(dates == JSON_DATES_JS) {
774 + // generate the local date time
775 + struct tm tmbuf, *tm = localtime_r(&now, &tmbuf);
776 + if(!tm) { error("localtime_r() failed."); continue; }
777 +
778 + if(likely(i != start)) buffer_strcat(wb, ",\n");
779 + buffer_strcat(wb, pre_date);
780 +
781 + if( options & RRDR_OPTION_OBJECTSROWS )
782 + buffer_sprintf(wb, "%stime%s: ", kq, kq);
783 +
784 + if(dates_with_new)
785 + buffer_strcat(wb, "new ");
786 +
787 + buffer_jsdate(wb, tm->tm_year + 1900, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
788 +
789 + buffer_strcat(wb, post_date);
790 +
791 + if(row_annotations) {
792 + // google supports one annotation per row
793 + int annotation_found = 0;
794 + for(c = 0, rd = r->st->dimensions; rd ;c++, rd = rd->next) {
795 + if(co[c] & RRDR_RESET) {
796 + buffer_strcat(wb, overflow_annotation);
797 + annotation_found = 1;
798 + break;
799 + }
800 + }
801 + if(!annotation_found)
802 + buffer_strcat(wb, normal_annotation);
803 + }
804 + }
805 + else {
806 + // print the timestamp of the line
807 + if(likely(i != start)) buffer_strcat(wb, ",\n");
808 + buffer_strcat(wb, pre_date);
809 +
810 + if( options & RRDR_OPTION_OBJECTSROWS )
811 + buffer_sprintf(wb, "%stime%s: ", kq, kq);
812 +
813 + buffer_rrd_value(wb, (calculated_number)r->t[i]);
814 + // in ms
815 + if(options & RRDR_OPTION_MILLISECONDS) buffer_strcat(wb, "000");
816 +
817 + buffer_strcat(wb, post_date);
818 + }
819 +
820 + if(unlikely(options & RRDR_OPTION_PERCENTAGE)) {
821 + total = 0;
822 + for(c = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
823 + calculated_number n = cn[c];
824 +
825 + if(likely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
826 + n = -n;
827 +
828 + total += n;
829 + }
830 + // prevent a division by zero
831 + if(total == 0) total = 1;
832 + }
833 +
834 + // for each dimension
835 + for(c = 0, rd = r->st->dimensions; rd && c < r->d ;c++, rd = rd->next) {
836 + if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
837 + if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
838 +
839 + calculated_number n = cn[c];
840 +
841 + buffer_strcat(wb, pre_value);
842 +
843 + if( options & RRDR_OPTION_OBJECTSROWS )
844 + buffer_sprintf(wb, "%s%s%s: ", kq, rd->name, kq);
845 +
846 + if(co[c] & RRDR_EMPTY) {
847 + if(options & RRDR_OPTION_NULL2ZERO)
848 + buffer_strcat(wb, "0");
849 + else
850 + buffer_strcat(wb, "null");
851 + }
852 + else {
853 + if(unlikely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
854 + n = -n;
855 +
856 + if(unlikely(options & RRDR_OPTION_PERCENTAGE))
857 + n = n * 100 / total;
858 +
859 + buffer_rrd_value(wb, n);
860 + }
861 +
862 + buffer_strcat(wb, post_value);
863 + }
864 +
865 + buffer_strcat(wb, post_line);
866 + }
867 +
868 + buffer_strcat(wb, finish);
869 + //info("RRD2JSON(): %s: END", r->st->id);
870 }
871
872 static void rrdr2csv(RRDR *r, BUFFER *wb, uint32_t options, const char *startline, const char *separator, const char *endline, const char *betweenlines)
873 {
874 - //info("RRD2CSV(): %s: BEGIN", r->st->id);
875 - long c, i;
876 - RRDDIM *d;
877 -
878 - // print the csv header
879 - for(c = 0, i = 0, d = r->st->dimensions; d && c < r->d ;c++, d = d->next) {
880 - if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
881 - if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
882 -
883 - if(!i) {
884 - buffer_strcat(wb, startline);
885 - if(options & RRDR_OPTION_LABEL_QUOTES) buffer_strcat(wb, "\"");
886 - buffer_strcat(wb, "time");
887 - if(options & RRDR_OPTION_LABEL_QUOTES) buffer_strcat(wb, "\"");
888 - }
889 - buffer_strcat(wb, separator);
890 - if(options & RRDR_OPTION_LABEL_QUOTES) buffer_strcat(wb, "\"");
891 - buffer_strcat(wb, d->name);
892 - if(options & RRDR_OPTION_LABEL_QUOTES) buffer_strcat(wb, "\"");
893 - i++;
894 - }
895 - buffer_strcat(wb, endline);
896 -
897 - if(!i) {
898 - // no dimensions present
899 - return;
900 - }
901 -
902 - long start = 0, end = rrdr_rows(r), step = 1;
903 - if((options & RRDR_OPTION_REVERSED)) {
904 - start = rrdr_rows(r) - 1;
905 - end = -1;
906 - step = -1;
907 - }
908 -
909 - // for each line in the array
910 - calculated_number total = 1;
911 - for(i = start; i != end ;i += step) {
912 - calculated_number *cn = &r->v[ i * r->d ];
913 - uint8_t *co = &r->o[ i * r->d ];
914 -
915 - buffer_strcat(wb, betweenlines);
916 - buffer_strcat(wb, startline);
917 -
918 - time_t now = r->t[i];
919 -
920 - if((options & RRDR_OPTION_SECONDS) || (options & RRDR_OPTION_MILLISECONDS)) {
921 - // print the timestamp of the line
922 - buffer_rrd_value(wb, (calculated_number)now);
923 - // in ms
924 - if(options & RRDR_OPTION_MILLISECONDS) buffer_strcat(wb, "000");
925 - }
926 - else {
927 - // generate the local date time
928 - struct tm tmbuf, *tm = localtime_r(&now, &tmbuf);
929 - if(!tm) { error("localtime() failed."); continue; }
930 - buffer_date(wb, tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
931 - }
932 -
933 - if(unlikely(options & RRDR_OPTION_PERCENTAGE)) {
934 - total = 0;
935 - for(c = 0, d = r->st->dimensions; d && c < r->d ;c++, d = d->next) {
936 - calculated_number n = cn[c];
937 -
938 - if(likely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
939 - n = -n;
940 -
941 - total += n;
942 - }
943 - // prevent a division by zero
944 - if(total == 0) total = 1;
945 - }
946 -
947 - // for each dimension
948 - for(c = 0, d = r->st->dimensions; d && c < r->d ;c++, d = d->next) {
949 - if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
950 - if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
951 -
952 - buffer_strcat(wb, separator);
953 -
954 - calculated_number n = cn[c];
955 -
956 - if(co[c] & RRDR_EMPTY) {
957 - if(options & RRDR_OPTION_NULL2ZERO)
958 - buffer_strcat(wb, "0");
959 - else
960 - buffer_strcat(wb, "null");
961 - }
962 - else {
963 - if(unlikely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
964 - n = -n;
965 -
966 - if(unlikely(options & RRDR_OPTION_PERCENTAGE))
967 - n = n * 100 / total;
968 -
969 - buffer_rrd_value(wb, n);
970 - }
971 - }
972 -
973 - buffer_strcat(wb, endline);
974 - }
975 - //info("RRD2CSV(): %s: END", r->st->id);
874 + //info("RRD2CSV(): %s: BEGIN", r->st->id);
875 + long c, i;
876 + RRDDIM *d;
877 +
878 + // print the csv header
879 + for(c = 0, i = 0, d = r->st->dimensions; d && c < r->d ;c++, d = d->next) {
880 + if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
881 + if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
882 +
883 + if(!i) {
884 + buffer_strcat(wb, startline);
885 + if(options & RRDR_OPTION_LABEL_QUOTES) buffer_strcat(wb, "\"");
886 + buffer_strcat(wb, "time");
887 + if(options & RRDR_OPTION_LABEL_QUOTES) buffer_strcat(wb, "\"");
888 + }
889 + buffer_strcat(wb, separator);
890 + if(options & RRDR_OPTION_LABEL_QUOTES) buffer_strcat(wb, "\"");
891 + buffer_strcat(wb, d->name);
892 + if(options & RRDR_OPTION_LABEL_QUOTES) buffer_strcat(wb, "\"");
893 + i++;
894 + }
895 + buffer_strcat(wb, endline);
896 +
897 + if(!i) {
898 + // no dimensions present
899 + return;
900 + }
901 +
902 + long start = 0, end = rrdr_rows(r), step = 1;
903 + if((options & RRDR_OPTION_REVERSED)) {
904 + start = rrdr_rows(r) - 1;
905 + end = -1;
906 + step = -1;
907 + }
908 +
909 + // for each line in the array
910 + calculated_number total = 1;
911 + for(i = start; i != end ;i += step) {
912 + calculated_number *cn = &r->v[ i * r->d ];
913 + uint8_t *co = &r->o[ i * r->d ];
914 +
915 + buffer_strcat(wb, betweenlines);
916 + buffer_strcat(wb, startline);
917 +
918 + time_t now = r->t[i];
919 +
920 + if((options & RRDR_OPTION_SECONDS) || (options & RRDR_OPTION_MILLISECONDS)) {
921 + // print the timestamp of the line
922 + buffer_rrd_value(wb, (calculated_number)now);
923 + // in ms
924 + if(options & RRDR_OPTION_MILLISECONDS) buffer_strcat(wb, "000");
925 + }
926 + else {
927 + // generate the local date time
928 + struct tm tmbuf, *tm = localtime_r(&now, &tmbuf);
929 + if(!tm) { error("localtime() failed."); continue; }
930 + buffer_date(wb, tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
931 + }
932 +
933 + if(unlikely(options & RRDR_OPTION_PERCENTAGE)) {
934 + total = 0;
935 + for(c = 0, d = r->st->dimensions; d && c < r->d ;c++, d = d->next) {
936 + calculated_number n = cn[c];
937 +
938 + if(likely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
939 + n = -n;
940 +
941 + total += n;
942 + }
943 + // prevent a division by zero
944 + if(total == 0) total = 1;
945 + }
946 +
947 + // for each dimension
948 + for(c = 0, d = r->st->dimensions; d && c < r->d ;c++, d = d->next) {
949 + if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
950 + if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
951 +
952 + buffer_strcat(wb, separator);
953 +
954 + calculated_number n = cn[c];
955 +
956 + if(co[c] & RRDR_EMPTY) {
957 + if(options & RRDR_OPTION_NULL2ZERO)
958 + buffer_strcat(wb, "0");
959 + else
960 + buffer_strcat(wb, "null");
961 + }
962 + else {
963 + if(unlikely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
964 + n = -n;
965 +
966 + if(unlikely(options & RRDR_OPTION_PERCENTAGE))
967 + n = n * 100 / total;
968 +
969 + buffer_rrd_value(wb, n);
970 + }
971 + }
972 +
973 + buffer_strcat(wb, endline);
974 + }
975 + //info("RRD2CSV(): %s: END", r->st->id);
976 }
977
978 inline static calculated_number rrdr2value(RRDR *r, long i, uint32_t options, int *all_values_are_null) {
979 - long c;
980 - RRDDIM *d;
981 -
982 - calculated_number *cn = &r->v[ i * r->d ];
983 - uint8_t *co = &r->o[ i * r->d ];
984 -
985 - calculated_number sum = 0, min = 0, max = 0, v;
986 - int all_null = 1, init = 1;
987 -
988 - calculated_number total = 1;
989 - if(unlikely(options & RRDR_OPTION_PERCENTAGE)) {
990 - total = 0;
991 - for(c = 0, d = r->st->dimensions; d && c < r->d ;c++, d = d->next) {
992 - calculated_number n = cn[c];
993 -
994 - if(likely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
995 - n = -n;
996 -
997 - total += n;
998 - }
999 - // prevent a division by zero
1000 - if(total == 0) total = 1;
1001 - }
1002 -
1003 - // for each dimension
1004 - for(c = 0, d = r->st->dimensions; d && c < r->d ;c++, d = d->next) {
1005 - if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
1006 - if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
1007 -
1008 - calculated_number n = cn[c];
1009 -
1010 - if(likely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
1011 - n = -n;
1012 -
1013 - if(unlikely(options & RRDR_OPTION_PERCENTAGE))
1014 - n = n * 100 / total;
1015 -
1016 - if(unlikely(init)) {
1017 - if(n > 0) {
1018 - min = 0;
1019 - max = n;
1020 - }
1021 - else {
1022 - min = n;
1023 - max = 0;
1024 - }
1025 - init = 0;
1026 - }
1027 -
1028 - if(likely(!(co[c] & RRDR_EMPTY))) {
1029 - all_null = 0;
1030 - sum += n;
1031 - }
1032 -
1033 - if(n < min) min = n;
1034 - if(n > max) max = n;
1035 - }
1036 -
1037 - if(unlikely(all_null)) {
1038 - if(likely(*all_values_are_null))
1039 - *all_values_are_null = 1;
1040 - return 0;
1041 - }
1042 - else {
1043 - if(likely(*all_values_are_null))
1044 - *all_values_are_null = 0;
1045 - }
1046 -
1047 - if(options & RRDR_OPTION_MIN2MAX)
1048 - v = max - min;
1049 - else
1050 - v = sum;
1051 -
1052 - return v;
979 + long c;
980 + RRDDIM *d;
981 +
982 + calculated_number *cn = &r->v[ i * r->d ];
983 + uint8_t *co = &r->o[ i * r->d ];
984 +
985 + calculated_number sum = 0, min = 0, max = 0, v;
986 + int all_null = 1, init = 1;
987 +
988 + calculated_number total = 1;
989 + if(unlikely(options & RRDR_OPTION_PERCENTAGE)) {
990 + total = 0;
991 + for(c = 0, d = r->st->dimensions; d && c < r->d ;c++, d = d->next) {
992 + calculated_number n = cn[c];
993 +
994 + if(likely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
995 + n = -n;
996 +
997 + total += n;
998 + }
999 + // prevent a division by zero
1000 + if(total == 0) total = 1;
1001 + }
1002 +
1003 + // for each dimension
1004 + for(c = 0, d = r->st->dimensions; d && c < r->d ;c++, d = d->next) {
1005 + if(unlikely(r->od[c] & RRDR_HIDDEN)) continue;
1006 + if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_NONZERO))) continue;
1007 +
1008 + calculated_number n = cn[c];
1009 +
1010 + if(likely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
1011 + n = -n;
1012 +
1013 + if(unlikely(options & RRDR_OPTION_PERCENTAGE))
1014 + n = n * 100 / total;
1015 +
1016 + if(unlikely(init)) {
1017 + if(n > 0) {
1018 + min = 0;
1019 + max = n;
1020 + }
1021 + else {
1022 + min = n;
1023 + max = 0;
1024 + }
1025 + init = 0;
1026 + }
1027 +
1028 + if(likely(!(co[c] & RRDR_EMPTY))) {
1029 + all_null = 0;
1030 + sum += n;
1031 + }
1032 +
1033 + if(n < min) min = n;
1034 + if(n > max) max = n;
1035 + }
1036 +
1037 + if(unlikely(all_null)) {
1038 + if(likely(*all_values_are_null))
1039 + *all_values_are_null = 1;
1040 + return 0;
1041 + }
1042 + else {
1043 + if(likely(*all_values_are_null))
1044 + *all_values_are_null = 0;
1045 + }
1046 +
1047 + if(options & RRDR_OPTION_MIN2MAX)
1048 + v = max - min;
1049 + else
1050 + v = sum;
1051 +
1052 + return v;
1053 }
1054
1055 static void rrdr2ssv(RRDR *r, BUFFER *wb, uint32_t options, const char *prefix, const char *separator, const char *suffix)
1056 {
1057 - //info("RRD2SSV(): %s: BEGIN", r->st->id);
1058 - long i;
1059 -
1060 - buffer_strcat(wb, prefix);
1061 - long start = 0, end = rrdr_rows(r), step = 1;
1062 - if((options & RRDR_OPTION_REVERSED)) {
1063 - start = rrdr_rows(r) - 1;
1064 - end = -1;
1065 - step = -1;
1066 - }
1067 -
1068 - // for each line in the array
1069 - for(i = start; i != end ;i += step) {
1070 - int all_values_are_null = 0;
1071 - calculated_number v = rrdr2value(r, i, options, &all_values_are_null);
1072 -
1073 - if(likely(i != start)) {
1074 - if(r->min > v) r->min = v;
1075 - if(r->max < v) r->max = v;
1076 - }
1077 - else {
1078 - r->min = v;
1079 - r->max = v;
1080 - }
1081 -
1082 - if(likely(i != start))
1083 - buffer_strcat(wb, separator);
1084 -
1085 - if(all_values_are_null) {
1086 - if(options & RRDR_OPTION_NULL2ZERO)
1087 - buffer_strcat(wb, "0");
1088 - else
1089 - buffer_strcat(wb, "null");
1090 - }
1091 - else
1092 - buffer_rrd_value(wb, v);
1093 - }
1094 - buffer_strcat(wb, suffix);
1095 - //info("RRD2SSV(): %s: END", r->st->id);
1057 + //info("RRD2SSV(): %s: BEGIN", r->st->id);
1058 + long i;
1059 +
1060 + buffer_strcat(wb, prefix);
1061 + long start = 0, end = rrdr_rows(r), step = 1;
1062 + if((options & RRDR_OPTION_REVERSED)) {
1063 + start = rrdr_rows(r) - 1;
1064 + end = -1;
1065 + step = -1;
1066 + }
1067 +
1068 + // for each line in the array
1069 + for(i = start; i != end ;i += step) {
1070 + int all_values_are_null = 0;
1071 + calculated_number v = rrdr2value(r, i, options, &all_values_are_null);
1072 +
1073 + if(likely(i != start)) {
1074 + if(r->min > v) r->min = v;
1075 + if(r->max < v) r->max = v;
1076 + }
1077 + else {
1078 + r->min = v;
1079 + r->max = v;
1080 + }
1081 +
1082 + if(likely(i != start))
1083 + buffer_strcat(wb, separator);
1084 +
1085 + if(all_values_are_null) {
1086 + if(options & RRDR_OPTION_NULL2ZERO)
1087 + buffer_strcat(wb, "0");
1088 + else
1089 + buffer_strcat(wb, "null");
1090 + }
1091 + else
1092 + buffer_rrd_value(wb, v);
1093 + }
1094 + buffer_strcat(wb, suffix);
1095 + //info("RRD2SSV(): %s: END", r->st->id);
1096 }
1097
1098 inline static calculated_number *rrdr_line_values(RRDR *r)
1099 {
1100 - return &r->v[ r->c * r->d ];
1100 + return &r->v[ r->c * r->d ];
1101 }
1102
1103 inline static uint8_t *rrdr_line_options(RRDR *r)
1104 {
1105 - return &r->o[ r->c * r->d ];
1105 + return &r->o[ r->c * r->d ];
1106 }
1107
1108 inline static int rrdr_line_init(RRDR *r, time_t t)
1109 {
1110 - r->c++;
1110 + r->c++;
1111
1112 - if(unlikely(r->c >= r->n)) {
1113 - error("requested to step above RRDR size for chart %s", r->st->name);
1114 - r->c = r->n - 1;
1115 - }
1112 + if(unlikely(r->c >= r->n)) {
1113 + error("requested to step above RRDR size for chart %s", r->st->name);
1114 + r->c = r->n - 1;
1115 + }
1116
1117 - // save the time
1118 - r->t[r->c] = t;
1117 + // save the time
1118 + r->t[r->c] = t;
1119
1120 - return 1;
1120 + return 1;
1121 }
1122
1123 inline static void rrdr_lock_rrdset(RRDR *r) {
1124 - if(unlikely(!r)) {
1125 - error("NULL value given!");
1126 - return;
1127 - }
1124 + if(unlikely(!r)) {
1125 + error("NULL value given!");
1126 + return;
1127 + }
1128
1129 - pthread_rwlock_rdlock(&r->st->rwlock);
1130 - r->has_st_lock = 1;
1129 + pthread_rwlock_rdlock(&r->st->rwlock);
1130 + r->has_st_lock = 1;
1131 }
1132
1133 inline static void rrdr_unlock_rrdset(RRDR *r) {
1134 - if(unlikely(!r)) {
1135 - error("NULL value given!");
1136 - return;
1137 - }
1138 -
1139 - if(likely(r->has_st_lock)) {
1140 - pthread_rwlock_unlock(&r->st->rwlock);
1141 - r->has_st_lock = 0;
1142 - }
1134 + if(unlikely(!r)) {
1135 + error("NULL value given!");
1136 + return;
1137 + }
1138 +
1139 + if(likely(r->has_st_lock)) {
1140 + pthread_rwlock_unlock(&r->st->rwlock);
1141 + r->has_st_lock = 0;
1142 + }
1143 }
1144
1145 inline static void rrdr_free(RRDR *r)
1146 {
1147 - if(unlikely(!r)) {
1148 - error("NULL value given!");
1149 - return;
1150 - }
1151 -
1152 - rrdr_unlock_rrdset(r);
1153 - freez(r->t);
1154 - freez(r->v);
1155 - freez(r->o);
1156 - freez(r->od);
1157 - freez(r);
1147 + if(unlikely(!r)) {
1148 + error("NULL value given!");
1149 + return;
1150 + }
1151 +
1152 + rrdr_unlock_rrdset(r);
1153 + freez(r->t);
1154 + freez(r->v);
1155 + freez(r->o);
1156 + freez(r->od);
1157 + freez(r);
1158 }
1159
1160 inline void rrdr_done(RRDR *r)
1161 {
1162 - r->rows = r->c + 1;
1163 - r->c = 0;
1162 + r->rows = r->c + 1;
1163 + r->c = 0;
1164 }
1165
1166 static RRDR *rrdr_create(RRDSET *st, long n)
1167 {
1168 - if(unlikely(!st)) {
1169 - error("NULL value given!");
1170 - return NULL;
1171 - }
1168 + if(unlikely(!st)) {
1169 + error("NULL value given!");
1170 + return NULL;
1171 + }
1172
1173 - RRDR *r = callocz(1, sizeof(RRDR));
1174 - r->st = st;
1173 + RRDR *r = callocz(1, sizeof(RRDR));
1174 + r->st = st;
1175
1176 - rrdr_lock_rrdset(r);
1176 + rrdr_lock_rrdset(r);
1177
1178 - RRDDIM *rd;
1179 - for(rd = st->dimensions ; rd ; rd = rd->next) r->d++;
1178 + RRDDIM *rd;
1179 + for(rd = st->dimensions ; rd ; rd = rd->next) r->d++;
1180
1181 - r->n = n;
1181 + r->n = n;
1182
1183 - r->t = mallocz(n * sizeof(time_t));
1184 - r->v = mallocz(n * r->d * sizeof(calculated_number));
1185 - r->o = mallocz(n * r->d * sizeof(uint8_t));
1186 - r->od = mallocz(r->d * sizeof(uint8_t));
1183 + r->t = mallocz(n * sizeof(time_t));
1184 + r->v = mallocz(n * r->d * sizeof(calculated_number));
1185 + r->o = mallocz(n * r->d * sizeof(uint8_t));
1186 + r->od = mallocz(r->d * sizeof(uint8_t));
1187
1188 - // set the hidden flag on hidden dimensions
1189 - int c;
1190 - for(c = 0, rd = st->dimensions ; rd ; c++, rd = rd->next) {
1191 - if(unlikely(rd->flags & RRDDIM_FLAG_HIDDEN)) r->od[c] = RRDR_HIDDEN;
1192 - else r->od[c] = 0;
1193 - }
1188 + // set the hidden flag on hidden dimensions
1189 + int c;
1190 + for(c = 0, rd = st->dimensions ; rd ; c++, rd = rd->next) {
1191 + if(unlikely(rd->flags & RRDDIM_FLAG_HIDDEN)) r->od[c] = RRDR_HIDDEN;
1192 + else r->od[c] = 0;
1193 + }
1194
1195 - r->c = -1;
1196 - r->group = 1;
1197 - r->update_every = 1;
1195 + r->c = -1;
1196 + r->group = 1;
1197 + r->update_every = 1;
1198
1199 - return r;
1199 + return r;
1200 }
1201
1202 RRDR *rrd2rrdr(RRDSET *st, long points, long long after, long long before, int group_method, int aligned)
1203 {
1204 - int debug = st->debug;
1205 - int absolute_period_requested = -1;
1206 -
1207 - time_t first_entry_t = rrdset_first_entry_t(st);
1208 - time_t last_entry_t = rrdset_last_entry_t(st);
1209 -
1210 - if(before == 0 && after == 0) {
1211 - before = last_entry_t;
1212 - after = first_entry_t;
1213 - absolute_period_requested = 0;
1214 - }
1215 -
1216 - // allow relative for before and after
1217 - if(((before < 0)?-before:before) <= (st->update_every * st->entries)) {
1218 - before = last_entry_t + before;
1219 - absolute_period_requested = 0;
1220 - }
1221 -
1222 - if(((after < 0)?-after:after) <= (st->update_every * st->entries)) {
1223 - if(after == 0) after = -st->update_every;
1224 - after = before + after;
1225 - absolute_period_requested = 0;
1226 - }
1227 -
1228 - if(absolute_period_requested == -1)
1229 - absolute_period_requested = 1;
1230 -
1231 - // make sure they are within our timeframe
1232 - if(before > last_entry_t) before = last_entry_t;
1233 - if(before < first_entry_t) before = first_entry_t;
1234 -
1235 - if(after > last_entry_t) after = last_entry_t;
1236 - if(after < first_entry_t) after = first_entry_t;
1237 -
1238 - // check if they are upside down
1239 - if(after > before) {
1240 - time_t tmp = before;
1241 - before = after;
1242 - after = tmp;
1243 - }
1244 -
1245 - // the duration of the chart
1246 - time_t duration = before - after;
1247 - long available_points = duration / st->update_every;
1248 -
1249 - if(duration <= 0 || available_points <= 0)
1250 - return rrdr_create(st, 1);
1251 -
1252 - // check the wanted points
1253 - if(points < 0) points = -points;
1254 - if(points > available_points) points = available_points;
1255 - if(points == 0) points = available_points;
1256 -
1257 - // calculate proper grouping of source data
1258 - long group = available_points / points;
1259 - if(group <= 0) group = 1;
1260 -
1261 - // round group to the closest integer
1262 - if(available_points % points > points / 2) group++;
1263 -
1264 - time_t after_new = (aligned) ? (after - (after % (group * st->update_every))) : after;
1265 - time_t before_new = (aligned) ? (before - (before % (group * st->update_every))) : before;
1266 - long points_new = (before_new - after_new) / st->update_every / group;
1267 -
1268 - // find the starting and ending slots in our round robin db
1269 - long start_at_slot = rrdset_time2slot(st, before_new),
1270 - stop_at_slot = rrdset_time2slot(st, after_new);
1204 + int debug = st->debug;
1205 + int absolute_period_requested = -1;
1206 +
1207 + time_t first_entry_t = rrdset_first_entry_t(st);
1208 + time_t last_entry_t = rrdset_last_entry_t(st);
1209 +
1210 + if(before == 0 && after == 0) {
1211 + before = last_entry_t;
1212 + after = first_entry_t;
1213 + absolute_period_requested = 0;
1214 + }
1215 +
1216 + // allow relative for before and after
1217 + if(((before < 0)?-before:before) <= (st->update_every * st->entries)) {
1218 + before = last_entry_t + before;
1219 + absolute_period_requested = 0;
1220 + }
1221 +
1222 + if(((after < 0)?-after:after) <= (st->update_every * st->entries)) {
1223 + if(after == 0) after = -st->update_every;
1224 + after = before + after;
1225 + absolute_period_requested = 0;
1226 + }
1227 +
1228 + if(absolute_period_requested == -1)
1229 + absolute_period_requested = 1;
1230 +
1231 + // make sure they are within our timeframe
1232 + if(before > last_entry_t) before = last_entry_t;
1233 + if(before < first_entry_t) before = first_entry_t;
1234 +
1235 + if(after > last_entry_t) after = last_entry_t;
1236 + if(after < first_entry_t) after = first_entry_t;
1237 +
1238 + // check if they are upside down
1239 + if(after > before) {
1240 + time_t tmp = before;
1241 + before = after;
1242 + after = tmp;
1243 + }
1244 +
1245 + // the duration of the chart
1246 + time_t duration = before - after;
1247 + long available_points = duration / st->update_every;
1248 +
1249 + if(duration <= 0 || available_points <= 0)
1250 + return rrdr_create(st, 1);
1251 +
1252 + // check the wanted points
1253 + if(points < 0) points = -points;
1254 + if(points > available_points) points = available_points;
1255 + if(points == 0) points = available_points;
1256 +
1257 + // calculate proper grouping of source data
1258 + long group = available_points / points;
1259 + if(group <= 0) group = 1;
1260 +
1261 + // round group to the closest integer
1262 + if(available_points % points > points / 2) group++;
1263 +
1264 + time_t after_new = (aligned) ? (after - (after % (group * st->update_every))) : after;
1265 + time_t before_new = (aligned) ? (before - (before % (group * st->update_every))) : before;
1266 + long points_new = (before_new - after_new) / st->update_every / group;
1267 +
1268 + // find the starting and ending slots in our round robin db
1269 + long start_at_slot = rrdset_time2slot(st, before_new),
1270 + stop_at_slot = rrdset_time2slot(st, after_new);
1271
1272 #ifdef NETDATA_INTERNAL_CHECKS
1273 - if(after_new < first_entry_t) {
1274 - error("after_new %u is too small, minimum %u", (uint32_t)after_new, (uint32_t)first_entry_t);
1275 - }
1276 - if(after_new > last_entry_t) {
1277 - error("after_new %u is too big, maximum %u", (uint32_t)after_new, (uint32_t)last_entry_t);
1278 - }
1279 - if(before_new < first_entry_t) {
1280 - error("before_new %u is too small, minimum %u", (uint32_t)before_new, (uint32_t)first_entry_t);
1281 - }
1282 - if(before_new > last_entry_t) {
1283 - error("before_new %u is too big, maximum %u", (uint32_t)before_new, (uint32_t)last_entry_t);
1284 - }
1285 - if(start_at_slot < 0 || start_at_slot >= st->entries) {
1286 - error("start_at_slot is invalid %ld, expected 0 to %ld", start_at_slot, st->entries - 1);
1287 - }
1288 - if(stop_at_slot < 0 || stop_at_slot >= st->entries) {
1289 - error("stop_at_slot is invalid %ld, expected 0 to %ld", stop_at_slot, st->entries - 1);
1290 - }
1291 - if(points_new > (before_new - after_new) / group / st->update_every + 1) {
1292 - error("points_new %ld is more than points %ld", points_new, (before_new - after_new) / group / st->update_every + 1);
1293 - }
1273 + if(after_new < first_entry_t) {
1274 + error("after_new %u is too small, minimum %u", (uint32_t)after_new, (uint32_t)first_entry_t);
1275 + }
1276 + if(after_new > last_entry_t) {
1277 + error("after_new %u is too big, maximum %u", (uint32_t)after_new, (uint32_t)last_entry_t);
1278 + }
1279 + if(before_new < first_entry_t) {
1280 + error("before_new %u is too small, minimum %u", (uint32_t)before_new, (uint32_t)first_entry_t);
1281 + }
1282 + if(before_new > last_entry_t) {
1283 + error("before_new %u is too big, maximum %u", (uint32_t)before_new, (uint32_t)last_entry_t);
1284 + }
1285 + if(start_at_slot < 0 || start_at_slot >= st->entries) {
1286 + error("start_at_slot is invalid %ld, expected 0 to %ld", start_at_slot, st->entries - 1);
1287 + }
1288 + if(stop_at_slot < 0 || stop_at_slot >= st->entries) {
1289 + error("stop_at_slot is invalid %ld, expected 0 to %ld", stop_at_slot, st->entries - 1);
1290 + }
1291 + if(points_new > (before_new - after_new) / group / st->update_every + 1) {
1292 + error("points_new %ld is more than points %ld", points_new, (before_new - after_new) / group / st->update_every + 1);
1293 + }
1294 #endif
1295
1296 - //info("RRD2RRDR(): %s: wanted %ld points, got %ld - group=%ld, wanted duration=%u, got %u - wanted %ld - %ld, got %ld - %ld", st->id, points, points_new, group, before - after, before_new - after_new, after, before, after_new, before_new);
1296 + //info("RRD2RRDR(): %s: wanted %ld points, got %ld - group=%ld, wanted duration=%u, got %u - wanted %ld - %ld, got %ld - %ld", st->id, points, points_new, group, before - after, before_new - after_new, after, before, after_new, before_new);
1297
1298 - after = after_new;
1299 - before = before_new;
1300 - duration = before - after;
1301 - points = points_new;
1298 + after = after_new;
1299 + before = before_new;
1300 + duration = before - after;
1301 + points = points_new;
1302
1303 - // Now we have:
1304 - // before = the end time of the calculation
1305 - // after = the start time of the calculation
1306 - // duration = the duration of the calculation
1307 - // group = the number of source points to aggregate / group together
1308 - // method = the method of grouping source points
1309 - // points = the number of points to generate
1303 + // Now we have:
1304 + // before = the end time of the calculation
1305 + // after = the start time of the calculation
1306 + // duration = the duration of the calculation
1307 + // group = the number of source points to aggregate / group together
1308 + // method = the method of grouping source points
1309 + // points = the number of points to generate
1310
1311
1312 - // -------------------------------------------------------------------------
1313 - // initialize our result set
1312 + // -------------------------------------------------------------------------
1313 + // initialize our result set
1314
1315 - RRDR *r = rrdr_create(st, points);
1316 - if(!r) {
1315 + RRDR *r = rrdr_create(st, points);
1316 + if(!r) {
1317 #ifdef NETDATA_INTERNAL_CHECKS
1318 - error("Cannot create RRDR for %s, after=%u, before=%u, duration=%u, points=%ld", st->id, (uint32_t)after, (uint32_t)before, (uint32_t)duration, points);
1318 + error("Cannot create RRDR for %s, after=%u, before=%u, duration=%u, points=%ld", st->id, (uint32_t)after, (uint32_t)before, (uint32_t)duration, points);
1319 #endif
1320 - return NULL;
1321 - }
1322 - if(!r->d) {
1320 + return NULL;
1321 + }
1322 + if(!r->d) {
1323 #ifdef NETDATA_INTERNAL_CHECKS
1324 - error("Returning empty RRDR (no dimensions in RRDSET) for %s, after=%u, before=%u, duration=%u, points=%ld", st->id, (uint32_t)after, (uint32_t)before, (uint32_t)duration, points);
1324 + error("Returning empty RRDR (no dimensions in RRDSET) for %s, after=%u, before=%u, duration=%u, points=%ld", st->id, (uint32_t)after, (uint32_t)before, (uint32_t)duration, points);
1325 #endif
1326 - return r;
1327 - }
1328 -
1329 - if(absolute_period_requested == 1)
1330 - r->result_options |= RRDR_RESULT_OPTION_ABSOLUTE;
1331 - else
1332 - r->result_options |= RRDR_RESULT_OPTION_RELATIVE;
1333 -
1334 - // find how many dimensions we have
1335 - long dimensions = r->d;
1336 -
1337 -
1338 - // -------------------------------------------------------------------------
1339 - // checks for debugging
1340 -
1341 - if(debug) debug(D_RRD_STATS, "INFO %s first_t: %u, last_t: %u, all_duration: %u, after: %u, before: %u, duration: %u, points: %ld, group: %ld"
1342 - , st->id
1343 - , (uint32_t)first_entry_t
1344 - , (uint32_t)last_entry_t
1345 - , (uint32_t)(last_entry_t - first_entry_t)
1346 - , (uint32_t)after
1347 - , (uint32_t)before
1348 - , (uint32_t)duration
1349 - , points
1350 - , group
1351 - );
1352 -
1353 -
1354 - // -------------------------------------------------------------------------
1355 - // temp arrays for keeping values per dimension
1356 -
1357 - calculated_number last_values[dimensions]; // keep the last value of each dimension
1358 - calculated_number group_values[dimensions]; // keep sums when grouping
1359 - long group_counts[dimensions]; // keep the number of values added to group_values
1360 - uint8_t group_options[dimensions];
1361 - uint8_t found_non_zero[dimensions];
1362 -
1363 -
1364 - // initialize them
1365 - RRDDIM *rd;
1366 - long c;
1367 - for( rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) {
1368 - last_values[c] = 0;
1369 - group_values[c] = 0;
1370 - group_counts[c] = 0;
1371 - group_options[c] = 0;
1372 - found_non_zero[c] = 0;
1373 - }
1374 -
1375 -
1376 - // -------------------------------------------------------------------------
1377 - // the main loop
1378 -
1379 - time_t now = rrdset_slot2time(st, start_at_slot),
1380 - dt = st->update_every,
1381 - group_start_t = 0;
1382 -
1383 - if(unlikely(debug)) debug(D_RRD_STATS, "BEGIN %s after_t: %u (stop_at_t: %ld), before_t: %u (start_at_t: %ld), start_t(now): %u, current_entry: %ld, entries: %ld"
1384 - , st->id
1385 - , (uint32_t)after
1386 - , stop_at_slot
1387 - , (uint32_t)before
1388 - , start_at_slot
1389 - , (uint32_t)now
1390 - , st->current_entry
1391 - , st->entries
1392 - );
1393 -
1394 - r->group = group;
1395 - r->update_every = group * st->update_every;
1396 - r->before = now;
1397 - r->after = now;
1398 -
1399 - //info("RRD2RRDR(): %s: STARTING", st->id);
1400 -
1401 - long slot = start_at_slot, counter = 0, stop_now = 0, added = 0, group_count = 0, add_this = 0;
1402 - for(; !stop_now ; now -= dt, slot--, counter++) {
1403 - if(unlikely(slot < 0)) slot = st->entries - 1;
1404 - if(unlikely(slot == stop_at_slot)) stop_now = counter;
1405 -
1406 - if(unlikely(debug)) debug(D_RRD_STATS, "ROW %s slot: %ld, entries_counter: %ld, group_count: %ld, added: %ld, now: %ld, %s %s"
1407 - , st->id
1408 - , slot
1409 - , counter
1410 - , group_count + 1
1411 - , added
1412 - , now
1413 - , (group_count + 1 == group)?"PRINT":" - "
1414 - , (now >= after && now <= before)?"RANGE":" - "
1415 - );
1416 -
1417 - // make sure we return data in the proper time range
1418 - if(unlikely(now > before)) continue;
1419 - if(unlikely(now < after)) break;
1420 -
1421 - if(unlikely(group_count == 0)) {
1422 - group_start_t = now;
1423 - }
1424 - group_count++;
1425 -
1426 - if(unlikely(group_count == group)) {
1427 - if(unlikely(added >= points)) break;
1428 - add_this = 1;
1429 - }
1430 -
1431 - // do the calculations
1432 - for(rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) {
1433 - storage_number n = rd->values[slot];
1434 - if(unlikely(!does_storage_number_exist(n))) continue;
1435 -
1436 - group_counts[c]++;
1437 -
1438 - calculated_number value = unpack_storage_number(n);
1439 - if(likely(value != 0.0)) {
1440 - group_options[c] |= RRDR_NONZERO;
1441 - found_non_zero[c] = 1;
1442 - }
1443 -
1444 - if(unlikely(did_storage_number_reset(n)))
1445 - group_options[c] |= RRDR_RESET;
1446 -
1447 - switch(group_method) {
1448 - case GROUP_MAX:
1449 - if(unlikely(fabsl(value) > fabsl(group_values[c])))
1450 - group_values[c] = value;
1451 - break;
1452 -
1453 - default:
1454 - case GROUP_SUM:
1455 - case GROUP_AVERAGE:
1456 - group_values[c] += value;
1457 - break;
1458 -
1459 - case GROUP_INCREMENTAL_SUM:
1460 - if(unlikely(slot == start_at_slot))
1461 - last_values[c] = value;
1462 -
1463 - group_values[c] += last_values[c] - value;
1464 - last_values[c] = value;
1465 - break;
1466 - }
1467 - }
1468 -
1469 - // added it
1470 - if(unlikely(add_this)) {
1471 - if(unlikely(!rrdr_line_init(r, group_start_t))) break;
1472 -
1473 - r->after = now;
1474 -
1475 - calculated_number *cn = rrdr_line_values(r);
1476 - uint8_t *co = rrdr_line_options(r);
1477 -
1478 - for(rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) {
1479 -
1480 - // update the dimension options
1481 - if(likely(found_non_zero[c])) r->od[c] |= RRDR_NONZERO;
1482 -
1483 - // store the specific point options
1484 - co[c] = group_options[c];
1485 -
1486 - // store the value
1487 - if(unlikely(group_counts[c] == 0)) {
1488 - cn[c] = 0.0;
1489 - co[c] |= RRDR_EMPTY;
1490 - }
1491 - else if(unlikely(group_method == GROUP_AVERAGE)) {
1492 - // GROUP_AVERAGE
1493 - cn[c] = group_values[c] / group_counts[c];
1494 - }
1495 - else {
1496 - // GROUP_SUM
1497 - // GROUP_MAX
1498 - // GROUP_INCREMENTAL_SUM
1499 - cn[c] = group_values[c];
1500 - }
1501 -
1502 - if(cn[c] < r->min) r->min = cn[c];
1503 - if(cn[c] > r->max) r->max = cn[c];
1504 -
1505 - // reset them for the next loop
1506 - group_values[c] = 0;
1507 - group_counts[c] = 0;
1508 - group_options[c] = 0;
1509 - }
1510 -
1511 - added++;
1512 - group_count = 0;
1513 - add_this = 0;
1514 - }
1515 - }
1516 -
1517 - rrdr_done(r);
1518 - //info("RRD2RRDR(): %s: END %ld loops made, %ld points generated", st->id, counter, rrdr_rows(r));
1519 - //error("SHIFT: %s: wanted %ld points, got %ld", st->id, points, rrdr_rows(r));
1520 - return r;
1326 + return r;
1327 + }
1328 +
1329 + if(absolute_period_requested == 1)
1330 + r->result_options |= RRDR_RESULT_OPTION_ABSOLUTE;
1331 + else
1332 + r->result_options |= RRDR_RESULT_OPTION_RELATIVE;
1333 +
1334 + // find how many dimensions we have
1335 + long dimensions = r->d;
1336 +
1337 +
1338 + // -------------------------------------------------------------------------
1339 + // checks for debugging
1340 +
1341 + if(debug) debug(D_RRD_STATS, "INFO %s first_t: %u, last_t: %u, all_duration: %u, after: %u, before: %u, duration: %u, points: %ld, group: %ld"
1342 + , st->id
1343 + , (uint32_t)first_entry_t
1344 + , (uint32_t)last_entry_t
1345 + , (uint32_t)(last_entry_t - first_entry_t)
1346 + , (uint32_t)after
1347 + , (uint32_t)before
1348 + , (uint32_t)duration
1349 + , points
1350 + , group
1351 + );
1352 +
1353 +
1354 + // -------------------------------------------------------------------------
1355 + // temp arrays for keeping values per dimension
1356 +
1357 + calculated_number last_values[dimensions]; // keep the last value of each dimension
1358 + calculated_number group_values[dimensions]; // keep sums when grouping
1359 + long group_counts[dimensions]; // keep the number of values added to group_values
1360 + uint8_t group_options[dimensions];
1361 + uint8_t found_non_zero[dimensions];
1362 +
1363 +
1364 + // initialize them
1365 + RRDDIM *rd;
1366 + long c;
1367 + for( rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) {
1368 + last_values[c] = 0;
1369 + group_values[c] = 0;
1370 + group_counts[c] = 0;
1371 + group_options[c] = 0;
1372 + found_non_zero[c] = 0;
1373 + }
1374 +
1375 +
1376 + // -------------------------------------------------------------------------
1377 + // the main loop
1378 +
1379 + time_t now = rrdset_slot2time(st, start_at_slot),
1380 + dt = st->update_every,
1381 + group_start_t = 0;
1382 +
1383 + if(unlikely(debug)) debug(D_RRD_STATS, "BEGIN %s after_t: %u (stop_at_t: %ld), before_t: %u (start_at_t: %ld), start_t(now): %u, current_entry: %ld, entries: %ld"
1384 + , st->id
1385 + , (uint32_t)after
1386 + , stop_at_slot
1387 + , (uint32_t)before
1388 + , start_at_slot
1389 + , (uint32_t)now
1390 + , st->current_entry
1391 + , st->entries
1392 + );
1393 +
1394 + r->group = group;
1395 + r->update_every = group * st->update_every;
1396 + r->before = now;
1397 + r->after = now;
1398 +
1399 + //info("RRD2RRDR(): %s: STARTING", st->id);
1400 +
1401 + long slot = start_at_slot, counter = 0, stop_now = 0, added = 0, group_count = 0, add_this = 0;
1402 + for(; !stop_now ; now -= dt, slot--, counter++) {
1403 + if(unlikely(slot < 0)) slot = st->entries - 1;
1404 + if(unlikely(slot == stop_at_slot)) stop_now = counter;
1405 +
1406 + if(unlikely(debug)) debug(D_RRD_STATS, "ROW %s slot: %ld, entries_counter: %ld, group_count: %ld, added: %ld, now: %ld, %s %s"
1407 + , st->id
1408 + , slot
1409 + , counter
1410 + , group_count + 1
1411 + , added
1412 + , now
1413 + , (group_count + 1 == group)?"PRINT":" - "
1414 + , (now >= after && now <= before)?"RANGE":" - "
1415 + );
1416 +
1417 + // make sure we return data in the proper time range
1418 + if(unlikely(now > before)) continue;
1419 + if(unlikely(now < after)) break;
1420 +
1421 + if(unlikely(group_count == 0)) {
1422 + group_start_t = now;
1423 + }
1424 + group_count++;
1425 +
1426 + if(unlikely(group_count == group)) {
1427 + if(unlikely(added >= points)) break;
1428 + add_this = 1;
1429 + }
1430 +
1431 + // do the calculations
1432 + for(rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) {
1433 + storage_number n = rd->values[slot];
1434 + if(unlikely(!does_storage_number_exist(n))) continue;
1435 +
1436 + group_counts[c]++;
1437 +
1438 + calculated_number value = unpack_storage_number(n);
1439 + if(likely(value != 0.0)) {
1440 + group_options[c] |= RRDR_NONZERO;
1441 + found_non_zero[c] = 1;
1442 + }
1443 +
1444 + if(unlikely(did_storage_number_reset(n)))
1445 + group_options[c] |= RRDR_RESET;
1446 +
1447 + switch(group_method) {
1448 + case GROUP_MAX:
1449 + if(unlikely(fabsl(value) > fabsl(group_values[c])))
1450 + group_values[c] = value;
1451 + break;
1452 +
1453 + default:
1454 + case GROUP_SUM:
1455 + case GROUP_AVERAGE:
1456 + group_values[c] += value;
1457 + break;
1458 +
1459 + case GROUP_INCREMENTAL_SUM:
1460 + if(unlikely(slot == start_at_slot))
1461 + last_values[c] = value;
1462 +
1463 + group_values[c] += last_values[c] - value;
1464 + last_values[c] = value;
1465 + break;
1466 + }
1467 + }
1468 +
1469 + // added it
1470 + if(unlikely(add_this)) {
1471 + if(unlikely(!rrdr_line_init(r, group_start_t))) break;
1472 +
1473 + r->after = now;
1474 +
1475 + calculated_number *cn = rrdr_line_values(r);
1476 + uint8_t *co = rrdr_line_options(r);
1477 +
1478 + for(rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) {
1479 +
1480 + // update the dimension options
1481 + if(likely(found_non_zero[c])) r->od[c] |= RRDR_NONZERO;
1482 +
1483 + // store the specific point options
1484 + co[c] = group_options[c];
1485 +
1486 + // store the value
1487 + if(unlikely(group_counts[c] == 0)) {
1488 + cn[c] = 0.0;
1489 + co[c] |= RRDR_EMPTY;
1490 + }
1491 + else if(unlikely(group_method == GROUP_AVERAGE)) {
1492 + // GROUP_AVERAGE
1493 + cn[c] = group_values[c] / group_counts[c];
1494 + }
1495 + else {
1496 + // GROUP_SUM
1497 + // GROUP_MAX
1498 + // GROUP_INCREMENTAL_SUM
1499 + cn[c] = group_values[c];
1500 + }
1501 +
1502 + if(cn[c] < r->min) r->min = cn[c];
1503 + if(cn[c] > r->max) r->max = cn[c];
1504 +
1505 + // reset them for the next loop
1506 + group_values[c] = 0;
1507 + group_counts[c] = 0;
1508 + group_options[c] = 0;
1509 + }
1510 +
1511 + added++;
1512 + group_count = 0;
1513 + add_this = 0;
1514 + }
1515 + }
1516 +
1517 + rrdr_done(r);
1518 + //info("RRD2RRDR(): %s: END %ld loops made, %ld points generated", st->id, counter, rrdr_rows(r));
1519 + //error("SHIFT: %s: wanted %ld points, got %ld", st->id, points, rrdr_rows(r));
1520 + return r;
1521 }
1522
1523 int rrd2value(RRDSET *st, BUFFER *wb, calculated_number *n, BUFFER *dimensions, long points, long long after, long long before, int group_method, uint32_t options, time_t *latest_timestamp, int *value_is_null)
1524 {
1525 - RRDR *r = rrd2rrdr(st, points, after, before, group_method, !(options & RRDR_OPTION_NOT_ALIGNED));
1526 - if(!r) {
1527 - if(value_is_null) *value_is_null = 1;
1528 - return 500;
1529 - }
1525 + RRDR *r = rrd2rrdr(st, points, after, before, group_method, !(options & RRDR_OPTION_NOT_ALIGNED));
1526 + if(!r) {
1527 + if(value_is_null) *value_is_null = 1;
1528 + return 500;
1529 + }
1530
1531 - if(rrdr_rows(r) == 0) {
1532 - rrdr_free(r);
1533 - if(value_is_null) *value_is_null = 1;
1534 - return 400;
1535 - }
1531 + if(rrdr_rows(r) == 0) {
1532 + rrdr_free(r);
1533 + if(value_is_null) *value_is_null = 1;
1534 + return 400;
1535 + }
1536
1537 - if(r->result_options & RRDR_RESULT_OPTION_RELATIVE)
1538 - wb->options |= WB_CONTENT_NO_CACHEABLE;
1539 - else if(r->result_options & RRDR_RESULT_OPTION_ABSOLUTE)
1540 - wb->options |= WB_CONTENT_CACHEABLE;
1537 + if(r->result_options & RRDR_RESULT_OPTION_RELATIVE)
1538 + wb->options |= WB_CONTENT_NO_CACHEABLE;
1539 + else if(r->result_options & RRDR_RESULT_OPTION_ABSOLUTE)
1540 + wb->options |= WB_CONTENT_CACHEABLE;
1541
1542 - options = rrdr_check_options(r, options, (dimensions)?buffer_tostring(dimensions):NULL);
1542 + options = rrdr_check_options(r, options, (dimensions)?buffer_tostring(dimensions):NULL);
1543
1544 - if(dimensions)
1545 - rrdr_disable_not_selected_dimensions(r, buffer_tostring(dimensions));
1544 + if(dimensions)
1545 + rrdr_disable_not_selected_dimensions(r, buffer_tostring(dimensions));
1546
1547 - if(latest_timestamp)
1548 - *latest_timestamp = r->before;
1547 + if(latest_timestamp)
1548 + *latest_timestamp = r->before;
1549
1550 - long i = (options & RRDR_OPTION_REVERSED)?rrdr_rows(r) - 1:0;
1551 - *n = rrdr2value(r, i, options, value_is_null);
1550 + long i = (options & RRDR_OPTION_REVERSED)?rrdr_rows(r) - 1:0;
1551 + *n = rrdr2value(r, i, options, value_is_null);
1552
1553 - rrdr_free(r);
1554 - return 200;
1553 + rrdr_free(r);
1554 + return 200;
1555 }
1556
1557 int rrd2format(RRDSET *st, BUFFER *wb, BUFFER *dimensions, uint32_t format, long points, long long after, long long before, int group_method, uint32_t options, time_t *latest_timestamp)
1558 {
1559 - RRDR *r = rrd2rrdr(st, points, after, before, group_method, !(options & RRDR_OPTION_NOT_ALIGNED));
1560 - if(!r) {
1561 - buffer_strcat(wb, "Cannot generate output with these parameters on this chart.");
1562 - return 500;
1563 - }
1564 -
1565 - if(r->result_options & RRDR_RESULT_OPTION_RELATIVE)
1566 - wb->options |= WB_CONTENT_NO_CACHEABLE;
1567 - else if(r->result_options & RRDR_RESULT_OPTION_ABSOLUTE)
1568 - wb->options |= WB_CONTENT_CACHEABLE;
1569 -
1570 - options = rrdr_check_options(r, options, (dimensions)?buffer_tostring(dimensions):NULL);
1571 -
1572 - if(dimensions)
1573 - rrdr_disable_not_selected_dimensions(r, buffer_tostring(dimensions));
1574 -
1575 - if(latest_timestamp && rrdr_rows(r) > 0)
1576 - *latest_timestamp = r->before;
1577 -
1578 - switch(format) {
1579 - case DATASOURCE_SSV:
1580 - if(options & RRDR_OPTION_JSON_WRAP) {
1581 - wb->contenttype = CT_APPLICATION_JSON;
1582 - rrdr_json_wrapper_begin(r, wb, format, options, 1);
1583 - rrdr2ssv(r, wb, options, "", " ", "");
1584 - rrdr_json_wrapper_end(r, wb, format, options, 1);
1585 - }
1586 - else {
1587 - wb->contenttype = CT_TEXT_PLAIN;
1588 - rrdr2ssv(r, wb, options, "", " ", "");
1589 - }
1590 - break;
1591 -
1592 - case DATASOURCE_SSV_COMMA:
1593 - if(options & RRDR_OPTION_JSON_WRAP) {
1594 - wb->contenttype = CT_APPLICATION_JSON;
1595 - rrdr_json_wrapper_begin(r, wb, format, options, 1);
1596 - rrdr2ssv(r, wb, options, "", ",", "");
1597 - rrdr_json_wrapper_end(r, wb, format, options, 1);
1598 - }
1599 - else {
1600 - wb->contenttype = CT_TEXT_PLAIN;
1601 - rrdr2ssv(r, wb, options, "", ",", "");
1602 - }
1603 - break;
1604 -
1605 - case DATASOURCE_JS_ARRAY:
1606 - if(options & RRDR_OPTION_JSON_WRAP) {
1607 - wb->contenttype = CT_APPLICATION_JSON;
1608 - rrdr_json_wrapper_begin(r, wb, format, options, 0);
1609 - rrdr2ssv(r, wb, options, "[", ",", "]");
1610 - rrdr_json_wrapper_end(r, wb, format, options, 0);
1611 - }
1612 - else {
1613 - wb->contenttype = CT_APPLICATION_JSON;
1614 - rrdr2ssv(r, wb, options, "[", ",", "]");
1615 - }
1616 - break;
1617 -
1618 - case DATASOURCE_CSV:
1619 - if(options & RRDR_OPTION_JSON_WRAP) {
1620 - wb->contenttype = CT_APPLICATION_JSON;
1621 - rrdr_json_wrapper_begin(r, wb, format, options, 1);
1622 - rrdr2csv(r, wb, options, "", ",", "\\n", "");
1623 - rrdr_json_wrapper_end(r, wb, format, options, 1);
1624 - }
1625 - else {
1626 - wb->contenttype = CT_TEXT_PLAIN;
1627 - rrdr2csv(r, wb, options, "", ",", "\r\n", "");
1628 - }
1629 - break;
1630 -
1631 - case DATASOURCE_CSV_JSON_ARRAY:
1632 - wb->contenttype = CT_APPLICATION_JSON;
1633 - if(options & RRDR_OPTION_JSON_WRAP) {
1634 - rrdr_json_wrapper_begin(r, wb, format, options, 0);
1635 - buffer_strcat(wb, "[\n");
1636 - rrdr2csv(r, wb, options + RRDR_OPTION_LABEL_QUOTES, "[", ",", "]", ",\n");
1637 - buffer_strcat(wb, "\n]");
1638 - rrdr_json_wrapper_end(r, wb, format, options, 0);
1639 - }
1640 - else {
1641 - wb->contenttype = CT_TEXT_PLAIN;
1642 - buffer_strcat(wb, "[\n");
1643 - rrdr2csv(r, wb, options + RRDR_OPTION_LABEL_QUOTES, "[", ",", "]", ",\n");
1644 - buffer_strcat(wb, "\n]");
1645 - }
1646 - break;
1647 -
1648 - case DATASOURCE_TSV:
1649 - if(options & RRDR_OPTION_JSON_WRAP) {
1650 - wb->contenttype = CT_APPLICATION_JSON;
1651 - rrdr_json_wrapper_begin(r, wb, format, options, 1);
1652 - rrdr2csv(r, wb, options, "", "\t", "\\n", "");
1653 - rrdr_json_wrapper_end(r, wb, format, options, 1);
1654 - }
1655 - else {
1656 - wb->contenttype = CT_TEXT_PLAIN;
1657 - rrdr2csv(r, wb, options, "", "\t", "\r\n", "");
1658 - }
1659 - break;
1660 -
1661 - case DATASOURCE_HTML:
1662 - if(options & RRDR_OPTION_JSON_WRAP) {
1663 - wb->contenttype = CT_APPLICATION_JSON;
1664 - rrdr_json_wrapper_begin(r, wb, format, options, 1);
1665 - buffer_strcat(wb, "<html>\\n<center>\\n<table border=\\\"0\\\" cellpadding=\\\"5\\\" cellspacing=\\\"5\\\">\\n");
1666 - rrdr2csv(r, wb, options, "<tr><td>", "</td><td>", "</td></tr>\\n", "");
1667 - buffer_strcat(wb, "</table>\\n</center>\\n</html>\\n");
1668 - rrdr_json_wrapper_end(r, wb, format, options, 1);
1669 - }
1670 - else {
1671 - wb->contenttype = CT_TEXT_HTML;
1672 - buffer_strcat(wb, "<html>\n<center>\n<table border=\"0\" cellpadding=\"5\" cellspacing=\"5\">\n");
1673 - rrdr2csv(r, wb, options, "<tr><td>", "</td><td>", "</td></tr>\n", "");
1674 - buffer_strcat(wb, "</table>\n</center>\n</html>\n");
1675 - }
1676 - break;
1677 -
1678 - case DATASOURCE_DATATABLE_JSONP:
1679 - wb->contenttype = CT_APPLICATION_X_JAVASCRIPT;
1680 -
1681 - if(options & RRDR_OPTION_JSON_WRAP)
1682 - rrdr_json_wrapper_begin(r, wb, format, options, 0);
1683 -
1684 - rrdr2json(r, wb, options, 1);
1685 -
1686 - if(options & RRDR_OPTION_JSON_WRAP)
1687 - rrdr_json_wrapper_end(r, wb, format, options, 0);
1688 - break;
1689 -
1690 - case DATASOURCE_DATATABLE_JSON:
1691 - wb->contenttype = CT_APPLICATION_JSON;
1692 -
1693 - if(options & RRDR_OPTION_JSON_WRAP)
1694 - rrdr_json_wrapper_begin(r, wb, format, options, 0);
1695 -
1696 - rrdr2json(r, wb, options, 1);
1697 -
1698 - if(options & RRDR_OPTION_JSON_WRAP)
1699 - rrdr_json_wrapper_end(r, wb, format, options, 0);
1700 - break;
1701 -
1702 - case DATASOURCE_JSONP:
1703 - wb->contenttype = CT_APPLICATION_X_JAVASCRIPT;
1704 - if(options & RRDR_OPTION_JSON_WRAP)
1705 - rrdr_json_wrapper_begin(r, wb, format, options, 0);
1706 -
1707 - rrdr2json(r, wb, options, 0);
1708 -
1709 - if(options & RRDR_OPTION_JSON_WRAP)
1710 - rrdr_json_wrapper_end(r, wb, format, options, 0);
1711 - break;
1712 -
1713 - case DATASOURCE_JSON:
1714 - default:
1715 - wb->contenttype = CT_APPLICATION_JSON;
1716 -
1717 - if(options & RRDR_OPTION_JSON_WRAP)
1718 - rrdr_json_wrapper_begin(r, wb, format, options, 0);
1719 -
1720 - rrdr2json(r, wb, options, 0);
1721 -
1722 - if(options & RRDR_OPTION_JSON_WRAP)
1723 - rrdr_json_wrapper_end(r, wb, format, options, 0);
1724 - break;
1725 - }
1726 -
1727 - rrdr_free(r);
1728 - return 200;
1559 + RRDR *r = rrd2rrdr(st, points, after, before, group_method, !(options & RRDR_OPTION_NOT_ALIGNED));
1560 + if(!r) {
1561 + buffer_strcat(wb, "Cannot generate output with these parameters on this chart.");
1562 + return 500;
1563 + }
1564 +
1565 + if(r->result_options & RRDR_RESULT_OPTION_RELATIVE)
1566 + wb->options |= WB_CONTENT_NO_CACHEABLE;
1567 + else if(r->result_options & RRDR_RESULT_OPTION_ABSOLUTE)
1568 + wb->options |= WB_CONTENT_CACHEABLE;
1569 +
1570 + options = rrdr_check_options(r, options, (dimensions)?buffer_tostring(dimensions):NULL);
1571 +
1572 + if(dimensions)
1573 + rrdr_disable_not_selected_dimensions(r, buffer_tostring(dimensions));
1574 +
1575 + if(latest_timestamp && rrdr_rows(r) > 0)
1576 + *latest_timestamp = r->before;
1577 +
1578 + switch(format) {
1579 + case DATASOURCE_SSV:
1580 + if(options & RRDR_OPTION_JSON_WRAP) {
1581 + wb->contenttype = CT_APPLICATION_JSON;
1582 + rrdr_json_wrapper_begin(r, wb, format, options, 1);
1583 + rrdr2ssv(r, wb, options, "", " ", "");
1584 + rrdr_json_wrapper_end(r, wb, format, options, 1);
1585 + }
1586 + else {
1587 + wb->contenttype = CT_TEXT_PLAIN;
1588 + rrdr2ssv(r, wb, options, "", " ", "");
1589 + }
1590 + break;
1591 +
1592 + case DATASOURCE_SSV_COMMA:
1593 + if(options & RRDR_OPTION_JSON_WRAP) {
1594 + wb->contenttype = CT_APPLICATION_JSON;
1595 + rrdr_json_wrapper_begin(r, wb, format, options, 1);
1596 + rrdr2ssv(r, wb, options, "", ",", "");
1597 + rrdr_json_wrapper_end(r, wb, format, options, 1);
1598 + }
1599 + else {
1600 + wb->contenttype = CT_TEXT_PLAIN;
1601 + rrdr2ssv(r, wb, options, "", ",", "");
1602 + }
1603 + break;
1604 +
1605 + case DATASOURCE_JS_ARRAY:
1606 + if(options & RRDR_OPTION_JSON_WRAP) {
1607 + wb->contenttype = CT_APPLICATION_JSON;
1608 + rrdr_json_wrapper_begin(r, wb, format, options, 0);
1609 + rrdr2ssv(r, wb, options, "[", ",", "]");
1610 + rrdr_json_wrapper_end(r, wb, format, options, 0);
1611 + }
1612 + else {
1613 + wb->contenttype = CT_APPLICATION_JSON;
1614 + rrdr2ssv(r, wb, options, "[", ",", "]");
1615 + }
1616 + break;
1617 +
1618 + case DATASOURCE_CSV:
1619 + if(options & RRDR_OPTION_JSON_WRAP) {
1620 + wb->contenttype = CT_APPLICATION_JSON;
1621 + rrdr_json_wrapper_begin(r, wb, format, options, 1);
1622 + rrdr2csv(r, wb, options, "", ",", "\\n", "");
1623 + rrdr_json_wrapper_end(r, wb, format, options, 1);
1624 + }
1625 + else {
1626 + wb->contenttype = CT_TEXT_PLAIN;
1627 + rrdr2csv(r, wb, options, "", ",", "\r\n", "");
1628 + }
1629 + break;
1630 +
1631 + case DATASOURCE_CSV_JSON_ARRAY:
1632 + wb->contenttype = CT_APPLICATION_JSON;
1633 + if(options & RRDR_OPTION_JSON_WRAP) {
1634 + rrdr_json_wrapper_begin(r, wb, format, options, 0);
1635 + buffer_strcat(wb, "[\n");
1636 + rrdr2csv(r, wb, options + RRDR_OPTION_LABEL_QUOTES, "[", ",", "]", ",\n");
1637 + buffer_strcat(wb, "\n]");
1638 + rrdr_json_wrapper_end(r, wb, format, options, 0);
1639 + }
1640 + else {
1641 + wb->contenttype = CT_TEXT_PLAIN;
1642 + buffer_strcat(wb, "[\n");
1643 + rrdr2csv(r, wb, options + RRDR_OPTION_LABEL_QUOTES, "[", ",", "]", ",\n");
1644 + buffer_strcat(wb, "\n]");
1645 + }
1646 + break;
1647 +
1648 + case DATASOURCE_TSV:
1649 + if(options & RRDR_OPTION_JSON_WRAP) {
1650 + wb->contenttype = CT_APPLICATION_JSON;
1651 + rrdr_json_wrapper_begin(r, wb, format, options, 1);
1652 + rrdr2csv(r, wb, options, "", "\t", "\\n", "");
1653 + rrdr_json_wrapper_end(r, wb, format, options, 1);
1654 + }
1655 + else {
1656 + wb->contenttype = CT_TEXT_PLAIN;
1657 + rrdr2csv(r, wb, options, "", "\t", "\r\n", "");
1658 + }
1659 + break;
1660 +
1661 + case DATASOURCE_HTML:
1662 + if(options & RRDR_OPTION_JSON_WRAP) {
1663 + wb->contenttype = CT_APPLICATION_JSON;
1664 + rrdr_json_wrapper_begin(r, wb, format, options, 1);
1665 + buffer_strcat(wb, "<html>\\n<center>\\n<table border=\\\"0\\\" cellpadding=\\\"5\\\" cellspacing=\\\"5\\\">\\n");
1666 + rrdr2csv(r, wb, options, "<tr><td>", "</td><td>", "</td></tr>\\n", "");
1667 + buffer_strcat(wb, "</table>\\n</center>\\n</html>\\n");
1668 + rrdr_json_wrapper_end(r, wb, format, options, 1);
1669 + }
1670 + else {
1671 + wb->contenttype = CT_TEXT_HTML;
1672 + buffer_strcat(wb, "<html>\n<center>\n<table border=\"0\" cellpadding=\"5\" cellspacing=\"5\">\n");
1673 + rrdr2csv(r, wb, options, "<tr><td>", "</td><td>", "</td></tr>\n", "");
1674 + buffer_strcat(wb, "</table>\n</center>\n</html>\n");
1675 + }
1676 + break;
1677 +
1678 + case DATASOURCE_DATATABLE_JSONP:
1679 + wb->contenttype = CT_APPLICATION_X_JAVASCRIPT;
1680 +
1681 + if(options & RRDR_OPTION_JSON_WRAP)
1682 + rrdr_json_wrapper_begin(r, wb, format, options, 0);
1683 +
1684 + rrdr2json(r, wb, options, 1);
1685 +
1686 + if(options & RRDR_OPTION_JSON_WRAP)
1687 + rrdr_json_wrapper_end(r, wb, format, options, 0);
1688 + break;
1689 +
1690 + case DATASOURCE_DATATABLE_JSON:
1691 + wb->contenttype = CT_APPLICATION_JSON;
1692 +
1693 + if(options & RRDR_OPTION_JSON_WRAP)
1694 + rrdr_json_wrapper_begin(r, wb, format, options, 0);
1695 +
1696 + rrdr2json(r, wb, options, 1);
1697 +
1698 + if(options & RRDR_OPTION_JSON_WRAP)
1699 + rrdr_json_wrapper_end(r, wb, format, options, 0);
1700 + break;
1701 +
1702 + case DATASOURCE_JSONP:
1703 + wb->contenttype = CT_APPLICATION_X_JAVASCRIPT;
1704 + if(options & RRDR_OPTION_JSON_WRAP)
1705 + rrdr_json_wrapper_begin(r, wb, format, options, 0);
1706 +
1707 + rrdr2json(r, wb, options, 0);
1708 +
1709 + if(options & RRDR_OPTION_JSON_WRAP)
1710 + rrdr_json_wrapper_end(r, wb, format, options, 0);
1711 + break;
1712 +
1713 + case DATASOURCE_JSON:
1714 + default:
1715 + wb->contenttype = CT_APPLICATION_JSON;
1716 +
1717 + if(options & RRDR_OPTION_JSON_WRAP)
1718 + rrdr_json_wrapper_begin(r, wb, format, options, 0);
1719 +
1720 + rrdr2json(r, wb, options, 0);
1721 +
1722 + if(options & RRDR_OPTION_JSON_WRAP)
1723 + rrdr_json_wrapper_end(r, wb, format, options, 0);
1724 + break;
1725 + }
1726 +
1727 + rrdr_free(r);
1728 + return 200;
1729 }
1730
1731 time_t rrd_stats_json(int type, RRDSET *st, BUFFER *wb, long points, long group, int group_method, time_t after, time_t before, int only_non_zero)
1732 {
1733 - int c;
1734 - pthread_rwlock_rdlock(&st->rwlock);
1733 + int c;
1734 + pthread_rwlock_rdlock(&st->rwlock);
1735
1736
1737 - // -------------------------------------------------------------------------
1738 - // switch from JSON to google JSON
1737 + // -------------------------------------------------------------------------
1738 + // switch from JSON to google JSON
1739
1740 - char kq[2] = "\"";
1741 - char sq[2] = "\"";
1742 - switch(type) {
1743 - case DATASOURCE_DATATABLE_JSON:
1744 - case DATASOURCE_DATATABLE_JSONP:
1745 - kq[0] = '\0';
1746 - sq[0] = '\'';
1747 - break;
1740 + char kq[2] = "\"";
1741 + char sq[2] = "\"";
1742 + switch(type) {
1743 + case DATASOURCE_DATATABLE_JSON:
1744 + case DATASOURCE_DATATABLE_JSONP:
1745 + kq[0] = '\0';
1746 + sq[0] = '\'';
1747 + break;
1748
1749 - case DATASOURCE_JSON:
1750 - default:
1751 - break;
1752 - }
1749 + case DATASOURCE_JSON:
1750 + default:
1751 + break;
1752 + }
1753
1754
1755 - // -------------------------------------------------------------------------
1756 - // validate the parameters
1755 + // -------------------------------------------------------------------------
1756 + // validate the parameters
1757
1758 - if(points < 1) points = 1;
1759 - if(group < 1) group = 1;
1758 + if(points < 1) points = 1;
1759 + if(group < 1) group = 1;
1760
1761 - if(before == 0 || before > rrdset_last_entry_t(st)) before = rrdset_last_entry_t(st);
1762 - if(after == 0 || after < rrdset_first_entry_t(st)) after = rrdset_first_entry_t(st);
1761 + if(before == 0 || before > rrdset_last_entry_t(st)) before = rrdset_last_entry_t(st);
1762 + if(after == 0 || after < rrdset_first_entry_t(st)) after = rrdset_first_entry_t(st);
1763
1764 - // ---
1764 + // ---
1765
1766 - // our return value (the last timestamp printed)
1767 - // this is required to detect re-transmit in google JSONP
1768 - time_t last_timestamp = 0;
1766 + // our return value (the last timestamp printed)
1767 + // this is required to detect re-transmit in google JSONP
1768 + time_t last_timestamp = 0;
1769
1770
1771 - // -------------------------------------------------------------------------
1772 - // find how many dimensions we have
1771 + // -------------------------------------------------------------------------
1772 + // find how many dimensions we have
1773
1774 - int dimensions = 0;
1775 - RRDDIM *rd;
1776 - for( rd = st->dimensions ; rd ; rd = rd->next) dimensions++;
1777 - if(!dimensions) {
1778 - pthread_rwlock_unlock(&st->rwlock);
1779 - buffer_strcat(wb, "No dimensions yet.");
1780 - return 0;
1781 - }
1774 + int dimensions = 0;
1775 + RRDDIM *rd;
1776 + for( rd = st->dimensions ; rd ; rd = rd->next) dimensions++;
1777 + if(!dimensions) {
1778 + pthread_rwlock_unlock(&st->rwlock);
1779 + buffer_strcat(wb, "No dimensions yet.");
1780 + return 0;
1781 + }
1782
1783
1784 - // -------------------------------------------------------------------------
1785 - // prepare various strings, to speed up the loop
1784 + // -------------------------------------------------------------------------
1785 + // prepare various strings, to speed up the loop
1786
1787 - char overflow_annotation[201]; snprintfz(overflow_annotation, 200, ",{%sv%s:%sRESET OR OVERFLOW%s},{%sv%s:%sThe counters have been wrapped.%s}", kq, kq, sq, sq, kq, kq, sq, sq);
1788 - char normal_annotation[201]; snprintfz(normal_annotation, 200, ",{%sv%s:null},{%sv%s:null}", kq, kq, kq, kq);
1789 - char pre_date[51]; snprintfz(pre_date, 50, " {%sc%s:[{%sv%s:%s", kq, kq, kq, kq, sq);
1790 - char post_date[21]; snprintfz(post_date, 20, "%s}", sq);
1791 - char pre_value[21]; snprintfz(pre_value, 20, ",{%sv%s:", kq, kq);
1792 - char post_value[21]; strcpy(post_value, "}");
1787 + char overflow_annotation[201]; snprintfz(overflow_annotation, 200, ",{%sv%s:%sRESET OR OVERFLOW%s},{%sv%s:%sThe counters have been wrapped.%s}", kq, kq, sq, sq, kq, kq, sq, sq);
1788 + char normal_annotation[201]; snprintfz(normal_annotation, 200, ",{%sv%s:null},{%sv%s:null}", kq, kq, kq, kq);
1789 + char pre_date[51]; snprintfz(pre_date, 50, " {%sc%s:[{%sv%s:%s", kq, kq, kq, kq, sq);
1790 + char post_date[21]; snprintfz(post_date, 20, "%s}", sq);
1791 + char pre_value[21]; snprintfz(pre_value, 20, ",{%sv%s:", kq, kq);
1792 + char post_value[21]; strcpy(post_value, "}");
1793
1794
1795 - // -------------------------------------------------------------------------
1796 - // checks for debugging
1795 + // -------------------------------------------------------------------------
1796 + // checks for debugging
1797
1798 - if(st->debug) {
1799 - debug(D_RRD_STATS, "%s first_entry_t = %ld, last_entry_t = %ld, duration = %ld, after = %ld, before = %ld, duration = %ld, entries_to_show = %ld, group = %ld"
1800 - , st->id
1801 - , rrdset_first_entry_t(st)
1802 - , rrdset_last_entry_t(st)
1803 - , rrdset_last_entry_t(st) - rrdset_first_entry_t(st)
1804 - , after
1805 - , before
1806 - , before - after
1807 - , points
1808 - , group
1809 - );
1798 + if(st->debug) {
1799 + debug(D_RRD_STATS, "%s first_entry_t = %ld, last_entry_t = %ld, duration = %ld, after = %ld, before = %ld, duration = %ld, entries_to_show = %ld, group = %ld"
1800 + , st->id
1801 + , rrdset_first_entry_t(st)
1802 + , rrdset_last_entry_t(st)
1803 + , rrdset_last_entry_t(st) - rrdset_first_entry_t(st)
1804 + , after
1805 + , before
1806 + , before - after
1807 + , points
1808 + , group
1809 + );
1810
1811 - if(before < after)
1812 - debug(D_RRD_STATS, "WARNING: %s The newest value in the database (%ld) is earlier than the oldest (%ld)", st->name, before, after);
1811 + if(before < after)
1812 + debug(D_RRD_STATS, "WARNING: %s The newest value in the database (%ld) is earlier than the oldest (%ld)", st->name, before, after);
1813
1814 - if((before - after) > st->entries * st->update_every)
1815 - debug(D_RRD_STATS, "WARNING: %s The time difference between the oldest and the newest entries (%ld) is higher than the capacity of the database (%ld)", st->name, before - after, st->entries * st->update_every);
1816 - }
1817 -
1818 -
1819 - // -------------------------------------------------------------------------
1820 - // temp arrays for keeping values per dimension
1821 -
1822 - calculated_number group_values[dimensions]; // keep sums when grouping
1823 - int print_hidden[dimensions]; // keep hidden flags
1824 - int found_non_zero[dimensions];
1825 - int found_non_existing[dimensions];
1814 + if((before - after) > st->entries * st->update_every)
1815 + debug(D_RRD_STATS, "WARNING: %s The time difference between the oldest and the newest entries (%ld) is higher than the capacity of the database (%ld)", st->name, before - after, st->entries * st->update_every);
1816 + }
1817 +
1818 +
1819 + // -------------------------------------------------------------------------
1820 + // temp arrays for keeping values per dimension
1821 +
1822 + calculated_number group_values[dimensions]; // keep sums when grouping
1823 + int print_hidden[dimensions]; // keep hidden flags
1824 + int found_non_zero[dimensions];
1825 + int found_non_existing[dimensions];
1826
1827 - // initialize them
1828 - for( rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) {
1829 - group_values[c] = 0;
1830 - print_hidden[c] = (rd->flags & RRDDIM_FLAG_HIDDEN)?1:0;
1831 - found_non_zero[c] = 0;
1832 - found_non_existing[c] = 0;
1833 - }
1827 + // initialize them
1828 + for( rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) {
1829 + group_values[c] = 0;
1830 + print_hidden[c] = (rd->flags & RRDDIM_FLAG_HIDDEN)?1:0;
1831 + found_non_zero[c] = 0;
1832 + found_non_existing[c] = 0;
1833 + }
1834
1835
1836 - // error("OLD: points=%d after=%d before=%d group=%d, duration=%d", entries_to_show, before - (st->update_every * group * entries_to_show), before, group, before - after + 1);
1837 - // rrd2array(st, entries_to_show, before - (st->update_every * group * entries_to_show), before, group_method, only_non_zero);
1838 - // rrd2rrdr(st, entries_to_show, before - (st->update_every * group * entries_to_show), before, group_method);
1839 -
1840 - // -------------------------------------------------------------------------
1841 - // remove dimensions that contain only zeros
1842 -
1843 - int max_loop = 1;
1844 - if(only_non_zero) max_loop = 2;
1845 -
1846 - for(; max_loop ; max_loop--) {
1847 -
1848 - // -------------------------------------------------------------------------
1849 - // print the JSON header
1850 -
1851 - buffer_sprintf(wb, "{\n %scols%s:\n [\n", kq, kq);
1852 - buffer_sprintf(wb, " {%sid%s:%s%s,%slabel%s:%stime%s,%spattern%s:%s%s,%stype%s:%sdatetime%s},\n", kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq);
1853 - buffer_sprintf(wb, " {%sid%s:%s%s,%slabel%s:%s%s,%spattern%s:%s%s,%stype%s:%sstring%s,%sp%s:{%srole%s:%sannotation%s}},\n", kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, kq, kq, sq, sq);
1854 - buffer_sprintf(wb, " {%sid%s:%s%s,%slabel%s:%s%s,%spattern%s:%s%s,%stype%s:%sstring%s,%sp%s:{%srole%s:%sannotationText%s}}", kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, kq, kq, sq, sq);
1855 -
1856 - // print the header for each dimension
1857 - // and update the print_hidden array for the dimensions that should be hidden
1858 - int pc = 0;
1859 - for( rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) {
1860 - if(!print_hidden[c]) {
1861 - pc++;
1862 - buffer_sprintf(wb, ",\n {%sid%s:%s%s,%slabel%s:%s%s%s,%spattern%s:%s%s,%stype%s:%snumber%s}", kq, kq, sq, sq, kq, kq, sq, rd->name, sq, kq, kq, sq, sq, kq, kq, sq, sq);
1863 - }
1864 - }
1865 - if(!pc) {
1866 - buffer_sprintf(wb, ",\n {%sid%s:%s%s,%slabel%s:%s%s%s,%spattern%s:%s%s,%stype%s:%snumber%s}", kq, kq, sq, sq, kq, kq, sq, "no data", sq, kq, kq, sq, sq, kq, kq, sq, sq);
1867 - }
1868 -
1869 - // print the begin of row data
1870 - buffer_sprintf(wb, "\n ],\n %srows%s:\n [\n", kq, kq);
1871 -
1872 -
1873 - // -------------------------------------------------------------------------
1874 - // the main loop
1875 -
1876 - int annotate_reset = 0;
1877 - int annotation_count = 0;
1878 -
1879 - long t = rrdset_time2slot(st, before),
1880 - stop_at_t = rrdset_time2slot(st, after),
1881 - stop_now = 0;
1882 -
1883 - t -= t % group;
1884 -
1885 - time_t now = rrdset_slot2time(st, t),
1886 - dt = st->update_every;
1887 -
1888 - long count = 0, printed = 0, group_count = 0;
1889 - last_timestamp = 0;
1890 -
1891 - if(st->debug) debug(D_RRD_STATS, "%s: REQUEST after:%u before:%u, points:%ld, group:%ld, CHART cur:%ld first: %u last:%u, CALC start_t:%ld, stop_t:%ld"
1892 - , st->id
1893 - , (uint32_t)after
1894 - , (uint32_t)before
1895 - , points
1896 - , group
1897 - , st->current_entry
1898 - , (uint32_t)rrdset_first_entry_t(st)
1899 - , (uint32_t)rrdset_last_entry_t(st)
1900 - , t
1901 - , stop_at_t
1902 - );
1903 -
1904 - long counter = 0;
1905 - for(; !stop_now ; now -= dt, t--, counter++) {
1906 - if(t < 0) t = st->entries - 1;
1907 - if(t == stop_at_t) stop_now = counter;
1908 -
1909 - int print_this = 0;
1910 -
1911 - if(st->debug) debug(D_RRD_STATS, "%s t = %ld, count = %ld, group_count = %ld, printed = %ld, now = %ld, %s %s"
1912 - , st->id
1913 - , t
1914 - , count + 1
1915 - , group_count + 1
1916 - , printed
1917 - , now
1918 - , (group_count + 1 == group)?"PRINT":" - "
1919 - , (now >= after && now <= before)?"RANGE":" - "
1920 - );
1921 -
1922 -
1923 - // make sure we return data in the proper time range
1924 - if(now > before) continue;
1925 - if(now < after) break;
1926 -
1927 - //if(rrdset_slot2time(st, t) != now)
1928 - // error("%s: slot=%ld, now=%ld, slot2time=%ld, diff=%ld, last_entry_t=%ld, rrdset_last_slot=%ld", st->id, t, now, rrdset_slot2time(st,t), now - rrdset_slot2time(st,t), rrdset_last_entry_t(st), rrdset_last_slot(st));
1929 -
1930 - count++;
1931 - group_count++;
1932 -
1933 - // check if we have to print this now
1934 - if(group_count == group) {
1935 - if(printed >= points) {
1936 - // debug(D_RRD_STATS, "Already printed all rows. Stopping.");
1937 - break;
1938 - }
1939 -
1940 - // generate the local date time
1941 - struct tm tmbuf, *tm = localtime_r(&now, &tmbuf);
1942 - if(!tm) { error("localtime() failed."); continue; }
1943 - if(now > last_timestamp) last_timestamp = now;
1944 -
1945 - if(printed) buffer_strcat(wb, "]},\n");
1946 - buffer_strcat(wb, pre_date);
1947 - buffer_jsdate(wb, tm->tm_year + 1900, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
1948 - buffer_strcat(wb, post_date);
1949 -
1950 - print_this = 1;
1951 - }
1952 -
1953 - // do the calculations
1954 - for(rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) {
1955 - storage_number n = rd->values[t];
1956 - calculated_number value = unpack_storage_number(n);
1957 -
1958 - if(!does_storage_number_exist(n)) {
1959 - value = 0.0;
1960 - found_non_existing[c]++;
1961 - }
1962 - if(did_storage_number_reset(n)) annotate_reset = 1;
1963 -
1964 - switch(group_method) {
1965 - case GROUP_MAX:
1966 - if(abs(value) > abs(group_values[c])) group_values[c] = value;
1967 - break;
1968 -
1969 - case GROUP_SUM:
1970 - group_values[c] += value;
1971 - break;
1972 -
1973 - default:
1974 - case GROUP_AVERAGE:
1975 - group_values[c] += value;
1976 - if(print_this) group_values[c] /= ( group_count - found_non_existing[c] );
1977 - break;
1978 - }
1979 - }
1980 -
1981 - if(print_this) {
1982 - if(annotate_reset) {
1983 - annotation_count++;
1984 - buffer_strcat(wb, overflow_annotation);
1985 - annotate_reset = 0;
1986 - }
1987 - else
1988 - buffer_strcat(wb, normal_annotation);
1989 -
1990 - pc = 0;
1991 - for(c = 0 ; c < dimensions ; c++) {
1992 - if(found_non_existing[c] == group_count) {
1993 - // all entries are non-existing
1994 - pc++;
1995 - buffer_strcat(wb, pre_value);
1996 - buffer_strcat(wb, "null");
1997 - buffer_strcat(wb, post_value);
1998 - }
1999 - else if(!print_hidden[c]) {
2000 - pc++;
2001 - buffer_strcat(wb, pre_value);
2002 - buffer_rrd_value(wb, group_values[c]);
2003 - buffer_strcat(wb, post_value);
2004 -
2005 - if(group_values[c]) found_non_zero[c]++;
2006 - }
2007 -
2008 - // reset them for the next loop
2009 - group_values[c] = 0;
2010 - found_non_existing[c] = 0;
2011 - }
2012 -
2013 - // if all dimensions are hidden, print a null
2014 - if(!pc) {
2015 - buffer_strcat(wb, pre_value);
2016 - buffer_strcat(wb, "null");
2017 - buffer_strcat(wb, post_value);
2018 - }
2019 -
2020 - printed++;
2021 - group_count = 0;
2022 - }
2023 - }
2024 -
2025 - if(printed) buffer_strcat(wb, "]}");
2026 - buffer_strcat(wb, "\n ]\n}\n");
2027 -
2028 - if(only_non_zero && max_loop > 1) {
2029 - int changed = 0;
2030 - for(rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) {
2031 - group_values[c] = 0;
2032 - found_non_existing[c] = 0;
2033 -
2034 - if(!print_hidden[c] && !found_non_zero[c]) {
2035 - changed = 1;
2036 - print_hidden[c] = 1;
2037 - }
2038 - }
2039 -
2040 - if(changed) buffer_flush(wb);
2041 - else break;
2042 - }
2043 - else break;
2044 -
2045 - } // max_loop
2046 -
2047 - debug(D_RRD_STATS, "RRD_STATS_JSON: %s total %lu bytes", st->name, wb->len);
2048 -
2049 - pthread_rwlock_unlock(&st->rwlock);
2050 - return last_timestamp;
1836 + // error("OLD: points=%d after=%d before=%d group=%d, duration=%d", entries_to_show, before - (st->update_every * group * entries_to_show), before, group, before - after + 1);
1837 + // rrd2array(st, entries_to_show, before - (st->update_every * group * entries_to_show), before, group_method, only_non_zero);
1838 + // rrd2rrdr(st, entries_to_show, before - (st->update_every * group * entries_to_show), before, group_method);
1839 +
1840 + // -------------------------------------------------------------------------
1841 + // remove dimensions that contain only zeros
1842 +
1843 + int max_loop = 1;
1844 + if(only_non_zero) max_loop = 2;
1845 +
1846 + for(; max_loop ; max_loop--) {
1847 +
1848 + // -------------------------------------------------------------------------
1849 + // print the JSON header
1850 +
1851 + buffer_sprintf(wb, "{\n %scols%s:\n [\n", kq, kq);
1852 + buffer_sprintf(wb, " {%sid%s:%s%s,%slabel%s:%stime%s,%spattern%s:%s%s,%stype%s:%sdatetime%s},\n", kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq);
1853 + buffer_sprintf(wb, " {%sid%s:%s%s,%slabel%s:%s%s,%spattern%s:%s%s,%stype%s:%sstring%s,%sp%s:{%srole%s:%sannotation%s}},\n", kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, kq, kq, sq, sq);
1854 + buffer_sprintf(wb, " {%sid%s:%s%s,%slabel%s:%s%s,%spattern%s:%s%s,%stype%s:%sstring%s,%sp%s:{%srole%s:%sannotationText%s}}", kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, sq, sq, kq, kq, kq, kq, sq, sq);
1855 +
1856 + // print the header for each dimension
1857 + // and update the print_hidden array for the dimensions that should be hidden
1858 + int pc = 0;
1859 + for( rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) {
1860 + if(!print_hidden[c]) {
1861 + pc++;
1862 + buffer_sprintf(wb, ",\n {%sid%s:%s%s,%slabel%s:%s%s%s,%spattern%s:%s%s,%stype%s:%snumber%s}", kq, kq, sq, sq, kq, kq, sq, rd->name, sq, kq, kq, sq, sq, kq, kq, sq, sq);
1863 + }
1864 + }
1865 + if(!pc) {
1866 + buffer_sprintf(wb, ",\n {%sid%s:%s%s,%slabel%s:%s%s%s,%spattern%s:%s%s,%stype%s:%snumber%s}", kq, kq, sq, sq, kq, kq, sq, "no data", sq, kq, kq, sq, sq, kq, kq, sq, sq);
1867 + }
1868 +
1869 + // print the begin of row data
1870 + buffer_sprintf(wb, "\n ],\n %srows%s:\n [\n", kq, kq);
1871 +
1872 +
1873 + // -------------------------------------------------------------------------
1874 + // the main loop
1875 +
1876 + int annotate_reset = 0;
1877 + int annotation_count = 0;
1878 +
1879 + long t = rrdset_time2slot(st, before),
1880 + stop_at_t = rrdset_time2slot(st, after),
1881 + stop_now = 0;
1882 +
1883 + t -= t % group;
1884 +
1885 + time_t now = rrdset_slot2time(st, t),
1886 + dt = st->update_every;
1887 +
1888 + long count = 0, printed = 0, group_count = 0;
1889 + last_timestamp = 0;
1890 +
1891 + if(st->debug) debug(D_RRD_STATS, "%s: REQUEST after:%u before:%u, points:%ld, group:%ld, CHART cur:%ld first: %u last:%u, CALC start_t:%ld, stop_t:%ld"
1892 + , st->id
1893 + , (uint32_t)after
1894 + , (uint32_t)before
1895 + , points
1896 + , group
1897 + , st->current_entry
1898 + , (uint32_t)rrdset_first_entry_t(st)
1899 + , (uint32_t)rrdset_last_entry_t(st)
1900 + , t
1901 + , stop_at_t
1902 + );
1903 +
1904 + long counter = 0;
1905 + for(; !stop_now ; now -= dt, t--, counter++) {
1906 + if(t < 0) t = st->entries - 1;
1907 + if(t == stop_at_t) stop_now = counter;
1908 +
1909 + int print_this = 0;
1910 +
1911 + if(st->debug) debug(D_RRD_STATS, "%s t = %ld, count = %ld, group_count = %ld, printed = %ld, now = %ld, %s %s"
1912 + , st->id
1913 + , t
1914 + , count + 1
1915 + , group_count + 1
1916 + , printed
1917 + , now
1918 + , (group_count + 1 == group)?"PRINT":" - "
1919 + , (now >= after && now <= before)?"RANGE":" - "
1920 + );
1921 +
1922 +
1923 + // make sure we return data in the proper time range
1924 + if(now > before) continue;
1925 + if(now < after) break;
1926 +
1927 + //if(rrdset_slot2time(st, t) != now)
1928 + // error("%s: slot=%ld, now=%ld, slot2time=%ld, diff=%ld, last_entry_t=%ld, rrdset_last_slot=%ld", st->id, t, now, rrdset_slot2time(st,t), now - rrdset_slot2time(st,t), rrdset_last_entry_t(st), rrdset_last_slot(st));
1929 +
1930 + count++;
1931 + group_count++;
1932 +
1933 + // check if we have to print this now
1934 + if(group_count == group) {
1935 + if(printed >= points) {
1936 + // debug(D_RRD_STATS, "Already printed all rows. Stopping.");
1937 + break;
1938 + }
1939 +
1940 + // generate the local date time
1941 + struct tm tmbuf, *tm = localtime_r(&now, &tmbuf);
1942 + if(!tm) { error("localtime() failed."); continue; }
1943 + if(now > last_timestamp) last_timestamp = now;
1944 +
1945 + if(printed) buffer_strcat(wb, "]},\n");
1946 + buffer_strcat(wb, pre_date);
1947 + buffer_jsdate(wb, tm->tm_year + 1900, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
1948 + buffer_strcat(wb, post_date);
1949 +
1950 + print_this = 1;
1951 + }
1952 +
1953 + // do the calculations
1954 + for(rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) {
1955 + storage_number n = rd->values[t];
1956 + calculated_number value = unpack_storage_number(n);
1957 +
1958 + if(!does_storage_number_exist(n)) {
1959 + value = 0.0;
1960 + found_non_existing[c]++;
1961 + }
1962 + if(did_storage_number_reset(n)) annotate_reset = 1;
1963 +
1964 + switch(group_method) {
1965 + case GROUP_MAX:
1966 + if(abs(value) > abs(group_values[c])) group_values[c] = value;
1967 + break;
1968 +
1969 + case GROUP_SUM:
1970 + group_values[c] += value;
1971 + break;
1972 +
1973 + default:
1974 + case GROUP_AVERAGE:
1975 + group_values[c] += value;
1976 + if(print_this) group_values[c] /= ( group_count - found_non_existing[c] );
1977 + break;
1978 + }
1979 + }
1980 +
1981 + if(print_this) {
1982 + if(annotate_reset) {
1983 + annotation_count++;
1984 + buffer_strcat(wb, overflow_annotation);
1985 + annotate_reset = 0;
1986 + }
1987 + else
1988 + buffer_strcat(wb, normal_annotation);
1989 +
1990 + pc = 0;
1991 + for(c = 0 ; c < dimensions ; c++) {
1992 + if(found_non_existing[c] == group_count) {
1993 + // all entries are non-existing
1994 + pc++;
1995 + buffer_strcat(wb, pre_value);
1996 + buffer_strcat(wb, "null");
1997 + buffer_strcat(wb, post_value);
1998 + }
1999 + else if(!print_hidden[c]) {
2000 + pc++;
2001 + buffer_strcat(wb, pre_value);
2002 + buffer_rrd_value(wb, group_values[c]);
2003 + buffer_strcat(wb, post_value);
2004 +
2005 + if(group_values[c]) found_non_zero[c]++;
2006 + }
2007 +
2008 + // reset them for the next loop
2009 + group_values[c] = 0;
2010 + found_non_existing[c] = 0;
2011 + }
2012 +
2013 + // if all dimensions are hidden, print a null
2014 + if(!pc) {
2015 + buffer_strcat(wb, pre_value);
2016 + buffer_strcat(wb, "null");
2017 + buffer_strcat(wb, post_value);
2018 + }
2019 +
2020 + printed++;
2021 + group_count = 0;
2022 + }
2023 + }
2024 +
2025 + if(printed) buffer_strcat(wb, "]}");
2026 + buffer_strcat(wb, "\n ]\n}\n");
2027 +
2028 + if(only_non_zero && max_loop > 1) {
2029 + int changed = 0;
2030 + for(rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) {
2031 + group_values[c] = 0;
2032 + found_non_existing[c] = 0;
2033 +
2034 + if(!print_hidden[c] && !found_non_zero[c]) {
2035 + changed = 1;
2036 + print_hidden[c] = 1;
2037 + }
2038 + }
2039 +
2040 + if(changed) buffer_flush(wb);
2041 + else break;
2042 + }
2043 + else break;
2044 +
2045 + } // max_loop
2046 +
2047 + debug(D_RRD_STATS, "RRD_STATS_JSON: %s total %lu bytes", st->name, wb->len);
2048 +
2049 + pthread_rwlock_unlock(&st->rwlock);
2050 + return last_timestamp;
2051 }
src/rrd2json.h
+17 -17
@@ -30,24 +30,24 @@ extern char *hostname;
30 #define DATASOURCE_FORMAT_SSV_COMMA "ssvcomma"
31 #define DATASOURCE_FORMAT_CSV_JSON_ARRAY "csvjsonarray"
32
33 -#define GROUP_AVERAGE 0
34 -#define GROUP_MAX 1
35 -#define GROUP_SUM 2
36 -#define GROUP_INCREMENTAL_SUM 3
33 +#define GROUP_AVERAGE 0
34 +#define GROUP_MAX 1
35 +#define GROUP_SUM 2
36 +#define GROUP_INCREMENTAL_SUM 3
37
38 -#define RRDR_OPTION_NONZERO 0x00000001 // don't output dimensions will just zero values
39 -#define RRDR_OPTION_REVERSED 0x00000002 // output the rows in reverse order (oldest to newest)
40 -#define RRDR_OPTION_ABSOLUTE 0x00000004 // values positive, for DATASOURCE_SSV before summing
41 -#define RRDR_OPTION_MIN2MAX 0x00000008 // when adding dimensions, use max - min, instead of sum
42 -#define RRDR_OPTION_SECONDS 0x00000010 // output seconds, instead of dates
43 -#define RRDR_OPTION_MILLISECONDS 0x00000020 // output milliseconds, instead of dates
44 -#define RRDR_OPTION_NULL2ZERO 0x00000040 // do not show nulls, convert them to zeros
45 -#define RRDR_OPTION_OBJECTSROWS 0x00000080 // each row of values should be an object, not an array
46 -#define RRDR_OPTION_GOOGLE_JSON 0x00000100 // comply with google JSON/JSONP specs
47 -#define RRDR_OPTION_JSON_WRAP 0x00000200 // wrap the response in a JSON header with info about the result
48 -#define RRDR_OPTION_LABEL_QUOTES 0x00000400 // in CSV output, wrap header labels in double quotes
49 -#define RRDR_OPTION_PERCENTAGE 0x00000800 // give values as percentage of total
50 -#define RRDR_OPTION_NOT_ALIGNED 0x00001000 // do not align charts for persistant timeframes
38 +#define RRDR_OPTION_NONZERO 0x00000001 // don't output dimensions will just zero values
39 +#define RRDR_OPTION_REVERSED 0x00000002 // output the rows in reverse order (oldest to newest)
40 +#define RRDR_OPTION_ABSOLUTE 0x00000004 // values positive, for DATASOURCE_SSV before summing
41 +#define RRDR_OPTION_MIN2MAX 0x00000008 // when adding dimensions, use max - min, instead of sum
42 +#define RRDR_OPTION_SECONDS 0x00000010 // output seconds, instead of dates
43 +#define RRDR_OPTION_MILLISECONDS 0x00000020 // output milliseconds, instead of dates
44 +#define RRDR_OPTION_NULL2ZERO 0x00000040 // do not show nulls, convert them to zeros
45 +#define RRDR_OPTION_OBJECTSROWS 0x00000080 // each row of values should be an object, not an array
46 +#define RRDR_OPTION_GOOGLE_JSON 0x00000100 // comply with google JSON/JSONP specs
47 +#define RRDR_OPTION_JSON_WRAP 0x00000200 // wrap the response in a JSON header with info about the result
48 +#define RRDR_OPTION_LABEL_QUOTES 0x00000400 // in CSV output, wrap header labels in double quotes
49 +#define RRDR_OPTION_PERCENTAGE 0x00000800 // give values as percentage of total
50 +#define RRDR_OPTION_NOT_ALIGNED 0x00001000 // do not align charts for persistant timeframes
51
52 extern void rrd_stats_api_v1_chart(RRDSET *st, BUFFER *wb);
53 extern void rrd_stats_api_v1_charts(BUFFER *wb);
src/storage_number.c
+124 -124
@@ -5,164 +5,164 @@ extern char *print_number_llu_r(char *str, unsigned long long uvalue);
5
6 storage_number pack_storage_number(calculated_number value, uint32_t flags)
7 {
8 - // bit 32 = sign 0:positive, 1:negative
9 - // bit 31 = 0:divide, 1:multiply
10 - // bit 30, 29, 28 = (multiplier or divider) 0-6 (7 total)
11 - // bit 27, 26, 25 flags
12 - // bit 24 to bit 1 = the value
13 -
14 - storage_number r = get_storage_number_flags(flags);
15 - if(!value) return r;
16 -
17 - int m = 0;
18 - calculated_number n = value;
19 -
20 - // if the value is negative
21 - // add the sign bit and make it positive
22 - if(n < 0) {
23 - r += (1 << 31); // the sign bit 32
24 - n = -n;
25 - }
26 -
27 - // make its integer part fit in 0x00ffffff
28 - // by dividing it by 10 up to 7 times
29 - // and increasing the multiplier
30 - while(m < 7 && n > (calculated_number)0x00ffffff) {
31 - n /= 10;
32 - m++;
33 - }
34 -
35 - if(m) {
36 - // the value was too big and we divided it
37 - // so we add a multiplier to unpack it
38 - r += (1 << 30) + (m << 27); // the multiplier m
39 -
40 - if(n > (calculated_number)0x00ffffff) {
41 - error("Number " CALCULATED_NUMBER_FORMAT " is too big.", value);
42 - r += 0x00ffffff;
43 - return r;
44 - }
45 - }
46 - else {
47 - // 0x0019999e is the number that can be multiplied
48 - // by 10 to give 0x00ffffff
49 - // while the value is below 0x0019999e we can
50 - // multiply it by 10, up to 7 times, increasing
51 - // the multiplier
52 - while(m < 7 && n < (calculated_number)0x0019999e) {
53 - n *= 10;
54 - m++;
55 - }
56 -
57 - // the value was small enough and we multiplied it
58 - // so we add a divider to unpack it
59 - r += (0 << 30) + (m << 27); // the divider m
60 - }
8 + // bit 32 = sign 0:positive, 1:negative
9 + // bit 31 = 0:divide, 1:multiply
10 + // bit 30, 29, 28 = (multiplier or divider) 0-6 (7 total)
11 + // bit 27, 26, 25 flags
12 + // bit 24 to bit 1 = the value
13 +
14 + storage_number r = get_storage_number_flags(flags);
15 + if(!value) return r;
16 +
17 + int m = 0;
18 + calculated_number n = value;
19 +
20 + // if the value is negative
21 + // add the sign bit and make it positive
22 + if(n < 0) {
23 + r += (1 << 31); // the sign bit 32
24 + n = -n;
25 + }
26 +
27 + // make its integer part fit in 0x00ffffff
28 + // by dividing it by 10 up to 7 times
29 + // and increasing the multiplier
30 + while(m < 7 && n > (calculated_number)0x00ffffff) {
31 + n /= 10;
32 + m++;
33 + }
34 +
35 + if(m) {
36 + // the value was too big and we divided it
37 + // so we add a multiplier to unpack it
38 + r += (1 << 30) + (m << 27); // the multiplier m
39 +
40 + if(n > (calculated_number)0x00ffffff) {
41 + error("Number " CALCULATED_NUMBER_FORMAT " is too big.", value);
42 + r += 0x00ffffff;
43 + return r;
44 + }
45 + }
46 + else {
47 + // 0x0019999e is the number that can be multiplied
48 + // by 10 to give 0x00ffffff
49 + // while the value is below 0x0019999e we can
50 + // multiply it by 10, up to 7 times, increasing
51 + // the multiplier
52 + while(m < 7 && n < (calculated_number)0x0019999e) {
53 + n *= 10;
54 + m++;
55 + }
56 +
57 + // the value was small enough and we multiplied it
58 + // so we add a divider to unpack it
59 + r += (0 << 30) + (m << 27); // the divider m
60 + }
61
62 #ifdef STORAGE_WITH_MATH
63 - // without this there are rounding problems
64 - // example: 0.9 becomes 0.89
65 - r += lrint((double) n);
63 + // without this there are rounding problems
64 + // example: 0.9 becomes 0.89
65 + r += lrint((double) n);
66 #else
67 - r += (storage_number)n;
67 + r += (storage_number)n;
68 #endif
69
70 - return r;
70 + return r;
71 }
72
73 calculated_number unpack_storage_number(storage_number value)
74 {
75 - if(!value) return 0;
75 + if(!value) return 0;
76
77 - int sign = 0, exp = 0;
77 + int sign = 0, exp = 0;
78
79 - value ^= get_storage_number_flags(value);
79 + value ^= get_storage_number_flags(value);
80
81 - if(value & (1 << 31)) {
82 - sign = 1;
83 - value ^= 1 << 31;
84 - }
81 + if(value & (1 << 31)) {
82 + sign = 1;
83 + value ^= 1 << 31;
84 + }
85
86 - if(value & (1 << 30)) {
87 - exp = 1;
88 - value ^= 1 << 30;
89 - }
86 + if(value & (1 << 30)) {
87 + exp = 1;
88 + value ^= 1 << 30;
89 + }
90
91 - int mul = value >> 27;
92 - value ^= mul << 27;
91 + int mul = value >> 27;
92 + value ^= mul << 27;
93
94 - calculated_number n = value;
94 + calculated_number n = value;
95
96 - // fprintf(stderr, "UNPACK: %08X, sign = %d, exp = %d, mul = %d, n = " CALCULATED_NUMBER_FORMAT "\n", value, sign, exp, mul, n);
96 + // fprintf(stderr, "UNPACK: %08X, sign = %d, exp = %d, mul = %d, n = " CALCULATED_NUMBER_FORMAT "\n", value, sign, exp, mul, n);
97
98 - while(mul > 0) {
99 - if(exp) n *= 10;
100 - else n /= 10;
101 - mul--;
102 - }
98 + while(mul > 0) {
99 + if(exp) n *= 10;
100 + else n /= 10;
101 + mul--;
102 + }
103
104 - if(sign) n = -n;
105 - return n;
104 + if(sign) n = -n;
105 + return n;
106 }
107
108 int print_calculated_number(char *str, calculated_number value)
109 {
110 - char *wstr = str;
110 + char *wstr = str;
111
112 - int sign = (value < 0) ? 1 : 0;
113 - if(sign) value = -value;
112 + int sign = (value < 0) ? 1 : 0;
113 + if(sign) value = -value;
114
115 #ifdef STORAGE_WITH_MATH
116 - // without llrint() there are rounding problems
117 - // for example 0.9 becomes 0.89
118 - unsigned long long uvalue = (unsigned long long int) llrint(value * (calculated_number)100000);
116 + // without llrint() there are rounding problems
117 + // for example 0.9 becomes 0.89
118 + unsigned long long uvalue = (unsigned long long int) llrint(value * (calculated_number)100000);
119 #else
120 - unsigned long long uvalue = value * (calculated_number)100000;
120 + unsigned long long uvalue = value * (calculated_number)100000;
121 #endif
122
123 #ifdef ENVIRONMENT32
124 - if(uvalue > (unsigned long long)0xffffffff)
125 - wstr = print_number_llu_r(str, uvalue);
126 - else
127 - wstr = print_number_lu_r(str, uvalue);
124 + if(uvalue > (unsigned long long)0xffffffff)
125 + wstr = print_number_llu_r(str, uvalue);
126 + else
127 + wstr = print_number_lu_r(str, uvalue);
128 #else
129 - do *wstr++ = (char)('0' + (uvalue % 10)); while(uvalue /= 10);
129 + do *wstr++ = (char)('0' + (uvalue % 10)); while(uvalue /= 10);
130 #endif
131
132 - // make sure we have 6 bytes at least
133 - while((wstr - str) < 6) *wstr++ = '0';
132 + // make sure we have 6 bytes at least
133 + while((wstr - str) < 6) *wstr++ = '0';
134
135 - // put the sign back
136 - if(sign) *wstr++ = '-';
135 + // put the sign back
136 + if(sign) *wstr++ = '-';
137
138 - // reverse it
138 + // reverse it
139 char *begin = str, *end = --wstr, aux;
140 while (end > begin) aux = *end, *end-- = *begin, *begin++ = aux;
141 - // wstr--;
142 - // strreverse(str, wstr);
143 -
144 - // remove trailing zeros
145 - int decimal = 5;
146 - while(decimal > 0 && *wstr == '0') {
147 - *wstr-- = '\0';
148 - decimal--;
149 - }
150 -
151 - // terminate it, one position to the right
152 - // to let space for a dot
153 - wstr[2] = '\0';
154 -
155 - // make space for the dot
156 - int i;
157 - for(i = 0; i < decimal ;i++) {
158 - wstr[1] = wstr[0];
159 - wstr--;
160 - }
161 -
162 - // put the dot
163 - if(wstr[2] == '\0') { wstr[1] = '\0'; decimal--; }
164 - else wstr[1] = '.';
165 -
166 - // return the buffer length
167 - return (int) ((wstr - str) + 2 + decimal );
141 + // wstr--;
142 + // strreverse(str, wstr);
143 +
144 + // remove trailing zeros
145 + int decimal = 5;
146 + while(decimal > 0 && *wstr == '0') {
147 + *wstr-- = '\0';
148 + decimal--;
149 + }
150 +
151 + // terminate it, one position to the right
152 + // to let space for a dot
153 + wstr[2] = '\0';
154 +
155 + // make space for the dot
156 + int i;
157 + for(i = 0; i < decimal ;i++) {
158 + wstr[1] = wstr[0];
159 + wstr--;
160 + }
161 +
162 + // put the dot
163 + if(wstr[2] == '\0') { wstr[1] = '\0'; decimal--; }
164 + else wstr[1] = '.';
165 +
166 + // return the buffer length
167 + return (int) ((wstr - str) + 2 + decimal );
168 }
src/storage_number.h
+9 -9
@@ -17,15 +17,15 @@ typedef long double collected_number;
17 typedef uint32_t storage_number;
18 #define STORAGE_NUMBER_FORMAT "%u"
19
20 -#define SN_NOT_EXISTS (0x0 << 24)
21 -#define SN_EXISTS (0x1 << 24)
22 -#define SN_EXISTS_RESET (0x2 << 24)
23 -#define SN_EXISTS_UNDEF1 (0x3 << 24)
24 -#define SN_EXISTS_UNDEF2 (0x4 << 24)
25 -#define SN_EXISTS_UNDEF3 (0x5 << 24)
26 -#define SN_EXISTS_UNDEF4 (0x6 << 24)
27 -
28 -#define SN_FLAGS_MASK (~(0x6 << 24))
20 +#define SN_NOT_EXISTS (0x0 << 24)
21 +#define SN_EXISTS (0x1 << 24)
22 +#define SN_EXISTS_RESET (0x2 << 24)
23 +#define SN_EXISTS_UNDEF1 (0x3 << 24)
24 +#define SN_EXISTS_UNDEF2 (0x4 << 24)
25 +#define SN_EXISTS_UNDEF3 (0x5 << 24)
26 +#define SN_EXISTS_UNDEF4 (0x6 << 24)
27 +
28 +#define SN_FLAGS_MASK (~(0x6 << 24))
29
30 // extract the flags
31 #define get_storage_number_flags(value) ((((storage_number)value) & (1 << 24)) | (((storage_number)value) & (2 << 24)) | (((storage_number)value) & (4 << 24)))
src/sys_fs_cgroup.c
+1067 -1067
@@ -20,171 +20,171 @@ static int cgroup_root_max = 500;
20 static int cgroup_max_depth = 0;
21
22 void read_cgroup_plugin_configuration() {
23 - cgroup_check_for_new_every = config_get_number("plugin:cgroups", "check for new cgroups every", cgroup_check_for_new_every);
24 -
25 - cgroup_enable_cpuacct_stat = config_get_boolean_ondemand("plugin:cgroups", "enable cpuacct stat", cgroup_enable_cpuacct_stat);
26 - cgroup_enable_cpuacct_usage = config_get_boolean_ondemand("plugin:cgroups", "enable cpuacct usage", cgroup_enable_cpuacct_usage);
27 - cgroup_enable_memory = config_get_boolean_ondemand("plugin:cgroups", "enable memory", cgroup_enable_memory);
28 - cgroup_enable_blkio = config_get_boolean_ondemand("plugin:cgroups", "enable blkio", cgroup_enable_blkio);
29 -
30 - char filename[FILENAME_MAX + 1], *s;
31 - struct mountinfo *mi, *root = mountinfo_read();
32 -
33 - mi = mountinfo_find_by_filesystem_super_option(root, "cgroup", "cpuacct");
34 - if(!mi) mi = mountinfo_find_by_filesystem_mount_source(root, "cgroup", "cpuacct");
35 - if(!mi) {
36 - error("Cannot find cgroup cpuacct mountinfo. Assuming default: /sys/fs/cgroup/cpuacct");
37 - s = "/sys/fs/cgroup/cpuacct";
38 - }
39 - else s = mi->mount_point;
40 - snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, s);
41 - cgroup_cpuacct_base = config_get("plugin:cgroups", "path to /sys/fs/cgroup/cpuacct", filename);
42 -
43 - mi = mountinfo_find_by_filesystem_super_option(root, "cgroup", "blkio");
44 - if(!mi) mi = mountinfo_find_by_filesystem_mount_source(root, "cgroup", "blkio");
45 - if(!mi) {
46 - error("Cannot find cgroup blkio mountinfo. Assuming default: /sys/fs/cgroup/blkio");
47 - s = "/sys/fs/cgroup/blkio";
48 - }
49 - else s = mi->mount_point;
50 - snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, s);
51 - cgroup_blkio_base = config_get("plugin:cgroups", "path to /sys/fs/cgroup/blkio", filename);
52 -
53 - mi = mountinfo_find_by_filesystem_super_option(root, "cgroup", "memory");
54 - if(!mi) mi = mountinfo_find_by_filesystem_mount_source(root, "cgroup", "memory");
55 - if(!mi) {
56 - error("Cannot find cgroup memory mountinfo. Assuming default: /sys/fs/cgroup/memory");
57 - s = "/sys/fs/cgroup/memory";
58 - }
59 - else s = mi->mount_point;
60 - snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, s);
61 - cgroup_memory_base = config_get("plugin:cgroups", "path to /sys/fs/cgroup/memory", filename);
62 -
63 - mi = mountinfo_find_by_filesystem_super_option(root, "cgroup", "devices");
64 - if(!mi) mi = mountinfo_find_by_filesystem_mount_source(root, "cgroup", "devices");
65 - if(!mi) {
66 - error("Cannot find cgroup devices mountinfo. Assuming default: /sys/fs/cgroup/devices");
67 - s = "/sys/fs/cgroup/devices";
68 - }
69 - else s = mi->mount_point;
70 - snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, s);
71 - cgroup_devices_base = config_get("plugin:cgroups", "path to /sys/fs/cgroup/devices", filename);
72 -
73 - cgroup_root_max = config_get_number("plugin:cgroups", "max cgroups to allow", cgroup_root_max);
74 - cgroup_max_depth = config_get_number("plugin:cgroups", "max cgroups depth to monitor", cgroup_max_depth);
75 -
76 - cgroup_enable_new_cgroups_detected_at_runtime = config_get_boolean("plugin:cgroups", "enable new cgroups detected at run time", cgroup_enable_new_cgroups_detected_at_runtime);
77 -
78 - mountinfo_free(root);
23 + cgroup_check_for_new_every = config_get_number("plugin:cgroups", "check for new cgroups every", cgroup_check_for_new_every);
24 +
25 + cgroup_enable_cpuacct_stat = config_get_boolean_ondemand("plugin:cgroups", "enable cpuacct stat", cgroup_enable_cpuacct_stat);
26 + cgroup_enable_cpuacct_usage = config_get_boolean_ondemand("plugin:cgroups", "enable cpuacct usage", cgroup_enable_cpuacct_usage);
27 + cgroup_enable_memory = config_get_boolean_ondemand("plugin:cgroups", "enable memory", cgroup_enable_memory);
28 + cgroup_enable_blkio = config_get_boolean_ondemand("plugin:cgroups", "enable blkio", cgroup_enable_blkio);
29 +
30 + char filename[FILENAME_MAX + 1], *s;
31 + struct mountinfo *mi, *root = mountinfo_read();
32 +
33 + mi = mountinfo_find_by_filesystem_super_option(root, "cgroup", "cpuacct");
34 + if(!mi) mi = mountinfo_find_by_filesystem_mount_source(root, "cgroup", "cpuacct");
35 + if(!mi) {
36 + error("Cannot find cgroup cpuacct mountinfo. Assuming default: /sys/fs/cgroup/cpuacct");
37 + s = "/sys/fs/cgroup/cpuacct";
38 + }
39 + else s = mi->mount_point;
40 + snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, s);
41 + cgroup_cpuacct_base = config_get("plugin:cgroups", "path to /sys/fs/cgroup/cpuacct", filename);
42 +
43 + mi = mountinfo_find_by_filesystem_super_option(root, "cgroup", "blkio");
44 + if(!mi) mi = mountinfo_find_by_filesystem_mount_source(root, "cgroup", "blkio");
45 + if(!mi) {
46 + error("Cannot find cgroup blkio mountinfo. Assuming default: /sys/fs/cgroup/blkio");
47 + s = "/sys/fs/cgroup/blkio";
48 + }
49 + else s = mi->mount_point;
50 + snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, s);
51 + cgroup_blkio_base = config_get("plugin:cgroups", "path to /sys/fs/cgroup/blkio", filename);
52 +
53 + mi = mountinfo_find_by_filesystem_super_option(root, "cgroup", "memory");
54 + if(!mi) mi = mountinfo_find_by_filesystem_mount_source(root, "cgroup", "memory");
55 + if(!mi) {
56 + error("Cannot find cgroup memory mountinfo. Assuming default: /sys/fs/cgroup/memory");
57 + s = "/sys/fs/cgroup/memory";
58 + }
59 + else s = mi->mount_point;
60 + snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, s);
61 + cgroup_memory_base = config_get("plugin:cgroups", "path to /sys/fs/cgroup/memory", filename);
62 +
63 + mi = mountinfo_find_by_filesystem_super_option(root, "cgroup", "devices");
64 + if(!mi) mi = mountinfo_find_by_filesystem_mount_source(root, "cgroup", "devices");
65 + if(!mi) {
66 + error("Cannot find cgroup devices mountinfo. Assuming default: /sys/fs/cgroup/devices");
67 + s = "/sys/fs/cgroup/devices";
68 + }
69 + else s = mi->mount_point;
70 + snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, s);
71 + cgroup_devices_base = config_get("plugin:cgroups", "path to /sys/fs/cgroup/devices", filename);
72 +
73 + cgroup_root_max = config_get_number("plugin:cgroups", "max cgroups to allow", cgroup_root_max);
74 + cgroup_max_depth = config_get_number("plugin:cgroups", "max cgroups depth to monitor", cgroup_max_depth);
75 +
76 + cgroup_enable_new_cgroups_detected_at_runtime = config_get_boolean("plugin:cgroups", "enable new cgroups detected at run time", cgroup_enable_new_cgroups_detected_at_runtime);
77 +
78 + mountinfo_free(root);
79 }
80
81 // ----------------------------------------------------------------------------
82 // cgroup objects
83
84 struct blkio {
85 - int updated;
85 + int updated;
86
87 - char *filename;
87 + char *filename;
88
89 - unsigned long long Read;
90 - unsigned long long Write;
89 + unsigned long long Read;
90 + unsigned long long Write;
91 /*
92 - unsigned long long Sync;
93 - unsigned long long Async;
94 - unsigned long long Total;
92 + unsigned long long Sync;
93 + unsigned long long Async;
94 + unsigned long long Total;
95 */
96 };
97
98 // https://www.kernel.org/doc/Documentation/cgroup-v1/memory.txt
99 struct memory {
100 - int updated;
101 -
102 - char *filename;
103 -
104 - int has_dirty_swap;
105 -
106 - unsigned long long cache;
107 - unsigned long long rss;
108 - unsigned long long rss_huge;
109 - unsigned long long mapped_file;
110 - unsigned long long writeback;
111 - unsigned long long dirty;
112 - unsigned long long swap;
113 - unsigned long long pgpgin;
114 - unsigned long long pgpgout;
115 - unsigned long long pgfault;
116 - unsigned long long pgmajfault;
100 + int updated;
101 +
102 + char *filename;
103 +
104 + int has_dirty_swap;
105 +
106 + unsigned long long cache;
107 + unsigned long long rss;
108 + unsigned long long rss_huge;
109 + unsigned long long mapped_file;
110 + unsigned long long writeback;
111 + unsigned long long dirty;
112 + unsigned long long swap;
113 + unsigned long long pgpgin;
114 + unsigned long long pgpgout;
115 + unsigned long long pgfault;
116 + unsigned long long pgmajfault;
117 /*
118 - unsigned long long inactive_anon;
119 - unsigned long long active_anon;
120 - unsigned long long inactive_file;
121 - unsigned long long active_file;
122 - unsigned long long unevictable;
123 - unsigned long long hierarchical_memory_limit;
124 - unsigned long long total_cache;
125 - unsigned long long total_rss;
126 - unsigned long long total_rss_huge;
127 - unsigned long long total_mapped_file;
128 - unsigned long long total_writeback;
129 - unsigned long long total_dirty;
130 - unsigned long long total_swap;
131 - unsigned long long total_pgpgin;
132 - unsigned long long total_pgpgout;
133 - unsigned long long total_pgfault;
134 - unsigned long long total_pgmajfault;
135 - unsigned long long total_inactive_anon;
136 - unsigned long long total_active_anon;
137 - unsigned long long total_inactive_file;
138 - unsigned long long total_active_file;
139 - unsigned long long total_unevictable;
118 + unsigned long long inactive_anon;
119 + unsigned long long active_anon;
120 + unsigned long long inactive_file;
121 + unsigned long long active_file;
122 + unsigned long long unevictable;
123 + unsigned long long hierarchical_memory_limit;
124 + unsigned long long total_cache;
125 + unsigned long long total_rss;
126 + unsigned long long total_rss_huge;
127 + unsigned long long total_mapped_file;
128 + unsigned long long total_writeback;
129 + unsigned long long total_dirty;
130 + unsigned long long total_swap;
131 + unsigned long long total_pgpgin;
132 + unsigned long long total_pgpgout;
133 + unsigned long long total_pgfault;
134 + unsigned long long total_pgmajfault;
135 + unsigned long long total_inactive_anon;
136 + unsigned long long total_active_anon;
137 + unsigned long long total_inactive_file;
138 + unsigned long long total_active_file;
139 + unsigned long long total_unevictable;
140 */
141 };
142
143 // https://www.kernel.org/doc/Documentation/cgroup-v1/cpuacct.txt
144 struct cpuacct_stat {
145 - int updated;
145 + int updated;
146
147 - char *filename;
147 + char *filename;
148
149 - unsigned long long user;
150 - unsigned long long system;
149 + unsigned long long user;
150 + unsigned long long system;
151 };
152
153 // https://www.kernel.org/doc/Documentation/cgroup-v1/cpuacct.txt
154 struct cpuacct_usage {
155 - int updated;
155 + int updated;
156
157 - char *filename;
157 + char *filename;
158
159 - unsigned int cpus;
160 - unsigned long long *cpu_percpu;
159 + unsigned int cpus;
160 + unsigned long long *cpu_percpu;
161 };
162
163 struct cgroup {
164 - int available; // found in the filesystem
165 - int enabled; // enabled in the config
164 + int available; // found in the filesystem
165 + int enabled; // enabled in the config
166
167 - char *id;
168 - uint32_t hash;
167 + char *id;
168 + uint32_t hash;
169
170 - char *chart_id;
171 - char *chart_title;
170 + char *chart_id;
171 + char *chart_title;
172
173 - struct cpuacct_stat cpuacct_stat;
174 - struct cpuacct_usage cpuacct_usage;
173 + struct cpuacct_stat cpuacct_stat;
174 + struct cpuacct_usage cpuacct_usage;
175
176 - struct memory memory;
176 + struct memory memory;
177
178 - struct blkio io_service_bytes; // bytes
179 - struct blkio io_serviced; // operations
178 + struct blkio io_service_bytes; // bytes
179 + struct blkio io_serviced; // operations
180
181 - struct blkio throttle_io_service_bytes; // bytes
182 - struct blkio throttle_io_serviced; // operations
181 + struct blkio throttle_io_service_bytes; // bytes
182 + struct blkio throttle_io_serviced; // operations
183
184 - struct blkio io_merged; // operations
185 - struct blkio io_queued; // operations
184 + struct blkio io_merged; // operations
185 + struct blkio io_queued; // operations
186
187 - struct cgroup *next;
187 + struct cgroup *next;
188
189 } *cgroup_root = NULL;
190
@@ -192,389 +192,389 @@ struct cgroup {
192 // read values from /sys
193
194 void cgroup_read_cpuacct_stat(struct cpuacct_stat *cp) {
195 - static procfile *ff = NULL;
195 + static procfile *ff = NULL;
196
197 - static uint32_t user_hash = 0;
198 - static uint32_t system_hash = 0;
197 + static uint32_t user_hash = 0;
198 + static uint32_t system_hash = 0;
199
200 - if(unlikely(user_hash == 0)) {
201 - user_hash = simple_hash("user");
202 - system_hash = simple_hash("system");
203 - }
200 + if(unlikely(user_hash == 0)) {
201 + user_hash = simple_hash("user");
202 + system_hash = simple_hash("system");
203 + }
204
205 - cp->updated = 0;
206 - if(cp->filename) {
207 - ff = procfile_reopen(ff, cp->filename, NULL, PROCFILE_FLAG_DEFAULT);
208 - if(!ff) return;
205 + cp->updated = 0;
206 + if(cp->filename) {
207 + ff = procfile_reopen(ff, cp->filename, NULL, PROCFILE_FLAG_DEFAULT);
208 + if(!ff) return;
209
210 - ff = procfile_readall(ff);
211 - if(!ff) return;
210 + ff = procfile_readall(ff);
211 + if(!ff) return;
212
213 - unsigned long i, lines = procfile_lines(ff);
213 + unsigned long i, lines = procfile_lines(ff);
214
215 - if(lines < 1) {
216 - error("File '%s' should have 1+ lines.", cp->filename);
217 - return;
218 - }
215 + if(lines < 1) {
216 + error("File '%s' should have 1+ lines.", cp->filename);
217 + return;
218 + }
219
220 - for(i = 0; i < lines ; i++) {
221 - char *s = procfile_lineword(ff, i, 0);
222 - uint32_t hash = simple_hash(s);
220 + for(i = 0; i < lines ; i++) {
221 + char *s = procfile_lineword(ff, i, 0);
222 + uint32_t hash = simple_hash(s);
223
224 - if(hash == user_hash && !strcmp(s, "user"))
225 - cp->user = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
224 + if(hash == user_hash && !strcmp(s, "user"))
225 + cp->user = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
226
227 - else if(hash == system_hash && !strcmp(s, "system"))
228 - cp->system = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
229 - }
227 + else if(hash == system_hash && !strcmp(s, "system"))
228 + cp->system = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
229 + }
230
231 - cp->updated = 1;
231 + cp->updated = 1;
232
233 - // fprintf(stderr, "READ '%s': user: %llu, system: %llu\n", cp->filename, cp->user, cp->system);
234 - }
233 + // fprintf(stderr, "READ '%s': user: %llu, system: %llu\n", cp->filename, cp->user, cp->system);
234 + }
235 }
236
237 void cgroup_read_cpuacct_usage(struct cpuacct_usage *ca) {
238 - static procfile *ff = NULL;
239 -
240 - ca->updated = 0;
241 - if(ca->filename) {
242 - ff = procfile_reopen(ff, ca->filename, NULL, PROCFILE_FLAG_DEFAULT);
243 - if(!ff) return;
244 -
245 - ff = procfile_readall(ff);
246 - if(!ff) return;
247 -
248 - if(procfile_lines(ff) < 1) {
249 - error("File '%s' should have 1+ lines but has %u.", ca->filename, procfile_lines(ff));
250 - return;
251 - }
252 -
253 - unsigned long i = procfile_linewords(ff, 0);
254 - if(i <= 0) return;
255 -
256 - // we may have 1 more CPU reported
257 - while(i > 0) {
258 - char *s = procfile_lineword(ff, 0, i - 1);
259 - if(!*s) i--;
260 - else break;
261 - }
262 -
263 - if(i != ca->cpus) {
264 - freez(ca->cpu_percpu);
265 - ca->cpu_percpu = mallocz(sizeof(unsigned long long) * i);
266 - ca->cpus = (unsigned int)i;
267 - }
268 -
269 - for(i = 0; i < ca->cpus ;i++) {
270 - ca->cpu_percpu[i] = strtoull(procfile_lineword(ff, 0, i), NULL, 10);
271 - // fprintf(stderr, "READ '%s': cpu%d/%d: %llu ('%s')\n", ca->filename, i, ca->cpus, ca->cpu_percpu[i], procfile_lineword(ff, 0, i));
272 - }
273 -
274 - ca->updated = 1;
275 - }
238 + static procfile *ff = NULL;
239 +
240 + ca->updated = 0;
241 + if(ca->filename) {
242 + ff = procfile_reopen(ff, ca->filename, NULL, PROCFILE_FLAG_DEFAULT);
243 + if(!ff) return;
244 +
245 + ff = procfile_readall(ff);
246 + if(!ff) return;
247 +
248 + if(procfile_lines(ff) < 1) {
249 + error("File '%s' should have 1+ lines but has %u.", ca->filename, procfile_lines(ff));
250 + return;
251 + }
252 +
253 + unsigned long i = procfile_linewords(ff, 0);
254 + if(i <= 0) return;
255 +
256 + // we may have 1 more CPU reported
257 + while(i > 0) {
258 + char *s = procfile_lineword(ff, 0, i - 1);
259 + if(!*s) i--;
260 + else break;
261 + }
262 +
263 + if(i != ca->cpus) {
264 + freez(ca->cpu_percpu);
265 + ca->cpu_percpu = mallocz(sizeof(unsigned long long) * i);
266 + ca->cpus = (unsigned int)i;
267 + }
268 +
269 + for(i = 0; i < ca->cpus ;i++) {
270 + ca->cpu_percpu[i] = strtoull(procfile_lineword(ff, 0, i), NULL, 10);
271 + // fprintf(stderr, "READ '%s': cpu%d/%d: %llu ('%s')\n", ca->filename, i, ca->cpus, ca->cpu_percpu[i], procfile_lineword(ff, 0, i));
272 + }
273 +
274 + ca->updated = 1;
275 + }
276 }
277
278 void cgroup_read_blkio(struct blkio *io) {
279 - static procfile *ff = NULL;
279 + static procfile *ff = NULL;
280
281 - static uint32_t Read_hash = 0;
282 - static uint32_t Write_hash = 0;
281 + static uint32_t Read_hash = 0;
282 + static uint32_t Write_hash = 0;
283 /*
284 - static uint32_t Sync_hash = 0;
285 - static uint32_t Async_hash = 0;
286 - static uint32_t Total_hash = 0;
284 + static uint32_t Sync_hash = 0;
285 + static uint32_t Async_hash = 0;
286 + static uint32_t Total_hash = 0;
287 */
288
289 - if(unlikely(Read_hash == 0)) {
290 - Read_hash = simple_hash("Read");
291 - Write_hash = simple_hash("Write");
289 + if(unlikely(Read_hash == 0)) {
290 + Read_hash = simple_hash("Read");
291 + Write_hash = simple_hash("Write");
292 /*
293 - Sync_hash = simple_hash("Sync");
294 - Async_hash = simple_hash("Async");
295 - Total_hash = simple_hash("Total");
293 + Sync_hash = simple_hash("Sync");
294 + Async_hash = simple_hash("Async");
295 + Total_hash = simple_hash("Total");
296 */
297 - }
297 + }
298
299 - io->updated = 0;
300 - if(io->filename) {
301 - ff = procfile_reopen(ff, io->filename, NULL, PROCFILE_FLAG_DEFAULT);
302 - if(!ff) return;
299 + io->updated = 0;
300 + if(io->filename) {
301 + ff = procfile_reopen(ff, io->filename, NULL, PROCFILE_FLAG_DEFAULT);
302 + if(!ff) return;
303
304 - ff = procfile_readall(ff);
305 - if(!ff) return;
304 + ff = procfile_readall(ff);
305 + if(!ff) return;
306
307 - unsigned long i, lines = procfile_lines(ff);
307 + unsigned long i, lines = procfile_lines(ff);
308
309 - if(lines < 1) {
310 - error("File '%s' should have 1+ lines.", io->filename);
311 - return;
312 - }
309 + if(lines < 1) {
310 + error("File '%s' should have 1+ lines.", io->filename);
311 + return;
312 + }
313
314 - io->Read = 0;
315 - io->Write = 0;
314 + io->Read = 0;
315 + io->Write = 0;
316 /*
317 - io->Sync = 0;
318 - io->Async = 0;
319 - io->Total = 0;
317 + io->Sync = 0;
318 + io->Async = 0;
319 + io->Total = 0;
320 */
321
322 - for(i = 0; i < lines ; i++) {
323 - char *s = procfile_lineword(ff, i, 1);
324 - uint32_t hash = simple_hash(s);
322 + for(i = 0; i < lines ; i++) {
323 + char *s = procfile_lineword(ff, i, 1);
324 + uint32_t hash = simple_hash(s);
325
326 - if(hash == Read_hash && !strcmp(s, "Read"))
327 - io->Read += strtoull(procfile_lineword(ff, i, 2), NULL, 10);
326 + if(hash == Read_hash && !strcmp(s, "Read"))
327 + io->Read += strtoull(procfile_lineword(ff, i, 2), NULL, 10);
328
329 - else if(hash == Write_hash && !strcmp(s, "Write"))
330 - io->Write += strtoull(procfile_lineword(ff, i, 2), NULL, 10);
329 + else if(hash == Write_hash && !strcmp(s, "Write"))
330 + io->Write += strtoull(procfile_lineword(ff, i, 2), NULL, 10);
331
332 /*
333 - else if(hash == Sync_hash && !strcmp(s, "Sync"))
334 - io->Sync += strtoull(procfile_lineword(ff, i, 2), NULL, 10);
333 + else if(hash == Sync_hash && !strcmp(s, "Sync"))
334 + io->Sync += strtoull(procfile_lineword(ff, i, 2), NULL, 10);
335
336 - else if(hash == Async_hash && !strcmp(s, "Async"))
337 - io->Async += strtoull(procfile_lineword(ff, i, 2), NULL, 10);
336 + else if(hash == Async_hash && !strcmp(s, "Async"))
337 + io->Async += strtoull(procfile_lineword(ff, i, 2), NULL, 10);
338
339 - else if(hash == Total_hash && !strcmp(s, "Total"))
340 - io->Total += strtoull(procfile_lineword(ff, i, 2), NULL, 10);
339 + else if(hash == Total_hash && !strcmp(s, "Total"))
340 + io->Total += strtoull(procfile_lineword(ff, i, 2), NULL, 10);
341 */
342 - }
342 + }
343
344 - io->updated = 1;
345 - // fprintf(stderr, "READ '%s': Read: %llu, Write: %llu, Sync: %llu, Async: %llu, Total: %llu\n", io->filename, io->Read, io->Write, io->Sync, io->Async, io->Total);
346 - }
344 + io->updated = 1;
345 + // fprintf(stderr, "READ '%s': Read: %llu, Write: %llu, Sync: %llu, Async: %llu, Total: %llu\n", io->filename, io->Read, io->Write, io->Sync, io->Async, io->Total);
346 + }
347 }
348
349 void cgroup_read_memory(struct memory *mem) {
350 - static procfile *ff = NULL;
351 -
352 - static uint32_t cache_hash = 0;
353 - static uint32_t rss_hash = 0;
354 - static uint32_t rss_huge_hash = 0;
355 - static uint32_t mapped_file_hash = 0;
356 - static uint32_t writeback_hash = 0;
357 - static uint32_t dirty_hash = 0;
358 - static uint32_t swap_hash = 0;
359 - static uint32_t pgpgin_hash = 0;
360 - static uint32_t pgpgout_hash = 0;
361 - static uint32_t pgfault_hash = 0;
362 - static uint32_t pgmajfault_hash = 0;
350 + static procfile *ff = NULL;
351 +
352 + static uint32_t cache_hash = 0;
353 + static uint32_t rss_hash = 0;
354 + static uint32_t rss_huge_hash = 0;
355 + static uint32_t mapped_file_hash = 0;
356 + static uint32_t writeback_hash = 0;
357 + static uint32_t dirty_hash = 0;
358 + static uint32_t swap_hash = 0;
359 + static uint32_t pgpgin_hash = 0;
360 + static uint32_t pgpgout_hash = 0;
361 + static uint32_t pgfault_hash = 0;
362 + static uint32_t pgmajfault_hash = 0;
363 /*
364 - static uint32_t inactive_anon_hash = 0;
365 - static uint32_t active_anon_hash = 0;
366 - static uint32_t inactive_file_hash = 0;
367 - static uint32_t active_file_hash = 0;
368 - static uint32_t unevictable_hash = 0;
369 - static uint32_t hierarchical_memory_limit_hash = 0;
370 - static uint32_t total_cache_hash = 0;
371 - static uint32_t total_rss_hash = 0;
372 - static uint32_t total_rss_huge_hash = 0;
373 - static uint32_t total_mapped_file_hash = 0;
374 - static uint32_t total_writeback_hash = 0;
375 - static uint32_t total_dirty_hash = 0;
376 - static uint32_t total_swap_hash = 0;
377 - static uint32_t total_pgpgin_hash = 0;
378 - static uint32_t total_pgpgout_hash = 0;
379 - static uint32_t total_pgfault_hash = 0;
380 - static uint32_t total_pgmajfault_hash = 0;
381 - static uint32_t total_inactive_anon_hash = 0;
382 - static uint32_t total_active_anon_hash = 0;
383 - static uint32_t total_inactive_file_hash = 0;
384 - static uint32_t total_active_file_hash = 0;
385 - static uint32_t total_unevictable_hash = 0;
364 + static uint32_t inactive_anon_hash = 0;
365 + static uint32_t active_anon_hash = 0;
366 + static uint32_t inactive_file_hash = 0;
367 + static uint32_t active_file_hash = 0;
368 + static uint32_t unevictable_hash = 0;
369 + static uint32_t hierarchical_memory_limit_hash = 0;
370 + static uint32_t total_cache_hash = 0;
371 + static uint32_t total_rss_hash = 0;
372 + static uint32_t total_rss_huge_hash = 0;
373 + static uint32_t total_mapped_file_hash = 0;
374 + static uint32_t total_writeback_hash = 0;
375 + static uint32_t total_dirty_hash = 0;
376 + static uint32_t total_swap_hash = 0;
377 + static uint32_t total_pgpgin_hash = 0;
378 + static uint32_t total_pgpgout_hash = 0;
379 + static uint32_t total_pgfault_hash = 0;
380 + static uint32_t total_pgmajfault_hash = 0;
381 + static uint32_t total_inactive_anon_hash = 0;
382 + static uint32_t total_active_anon_hash = 0;
383 + static uint32_t total_inactive_file_hash = 0;
384 + static uint32_t total_active_file_hash = 0;
385 + static uint32_t total_unevictable_hash = 0;
386 */
387 - if(unlikely(cache_hash == 0)) {
388 - cache_hash = simple_hash("cache");
389 - rss_hash = simple_hash("rss");
390 - rss_huge_hash = simple_hash("rss_huge");
391 - mapped_file_hash = simple_hash("mapped_file");
392 - writeback_hash = simple_hash("writeback");
393 - dirty_hash = simple_hash("dirty");
394 - swap_hash = simple_hash("swap");
395 - pgpgin_hash = simple_hash("pgpgin");
396 - pgpgout_hash = simple_hash("pgpgout");
397 - pgfault_hash = simple_hash("pgfault");
398 - pgmajfault_hash = simple_hash("pgmajfault");
387 + if(unlikely(cache_hash == 0)) {
388 + cache_hash = simple_hash("cache");
389 + rss_hash = simple_hash("rss");
390 + rss_huge_hash = simple_hash("rss_huge");
391 + mapped_file_hash = simple_hash("mapped_file");
392 + writeback_hash = simple_hash("writeback");
393 + dirty_hash = simple_hash("dirty");
394 + swap_hash = simple_hash("swap");
395 + pgpgin_hash = simple_hash("pgpgin");
396 + pgpgout_hash = simple_hash("pgpgout");
397 + pgfault_hash = simple_hash("pgfault");
398 + pgmajfault_hash = simple_hash("pgmajfault");
399 /*
400 - inactive_anon_hash = simple_hash("inactive_anon");
401 - active_anon_hash = simple_hash("active_anon");
402 - inactive_file_hash = simple_hash("inactive_file");
403 - active_file_hash = simple_hash("active_file");
404 - unevictable_hash = simple_hash("unevictable");
405 - hierarchical_memory_limit_hash = simple_hash("hierarchical_memory_limit");
406 - total_cache_hash = simple_hash("total_cache");
407 - total_rss_hash = simple_hash("total_rss");
408 - total_rss_huge_hash = simple_hash("total_rss_huge");
409 - total_mapped_file_hash = simple_hash("total_mapped_file");
410 - total_writeback_hash = simple_hash("total_writeback");
411 - total_dirty_hash = simple_hash("total_dirty");
412 - total_swap_hash = simple_hash("total_swap");
413 - total_pgpgin_hash = simple_hash("total_pgpgin");
414 - total_pgpgout_hash = simple_hash("total_pgpgout");
415 - total_pgfault_hash = simple_hash("total_pgfault");
416 - total_pgmajfault_hash = simple_hash("total_pgmajfault");
417 - total_inactive_anon_hash = simple_hash("total_inactive_anon");
418 - total_active_anon_hash = simple_hash("total_active_anon");
419 - total_inactive_file_hash = simple_hash("total_inactive_file");
420 - total_active_file_hash = simple_hash("total_active_file");
421 - total_unevictable_hash = simple_hash("total_unevictable");
400 + inactive_anon_hash = simple_hash("inactive_anon");
401 + active_anon_hash = simple_hash("active_anon");
402 + inactive_file_hash = simple_hash("inactive_file");
403 + active_file_hash = simple_hash("active_file");
404 + unevictable_hash = simple_hash("unevictable");
405 + hierarchical_memory_limit_hash = simple_hash("hierarchical_memory_limit");
406 + total_cache_hash = simple_hash("total_cache");
407 + total_rss_hash = simple_hash("total_rss");
408 + total_rss_huge_hash = simple_hash("total_rss_huge");
409 + total_mapped_file_hash = simple_hash("total_mapped_file");
410 + total_writeback_hash = simple_hash("total_writeback");
411 + total_dirty_hash = simple_hash("total_dirty");
412 + total_swap_hash = simple_hash("total_swap");
413 + total_pgpgin_hash = simple_hash("total_pgpgin");
414 + total_pgpgout_hash = simple_hash("total_pgpgout");
415 + total_pgfault_hash = simple_hash("total_pgfault");
416 + total_pgmajfault_hash = simple_hash("total_pgmajfault");
417 + total_inactive_anon_hash = simple_hash("total_inactive_anon");
418 + total_active_anon_hash = simple_hash("total_active_anon");
419 + total_inactive_file_hash = simple_hash("total_inactive_file");
420 + total_active_file_hash = simple_hash("total_active_file");
421 + total_unevictable_hash = simple_hash("total_unevictable");
422 */
423 - }
423 + }
424
425 - mem->updated = 0;
426 - if(mem->filename) {
427 - ff = procfile_reopen(ff, mem->filename, NULL, PROCFILE_FLAG_DEFAULT);
428 - if(!ff) return;
425 + mem->updated = 0;
426 + if(mem->filename) {
427 + ff = procfile_reopen(ff, mem->filename, NULL, PROCFILE_FLAG_DEFAULT);
428 + if(!ff) return;
429
430 - ff = procfile_readall(ff);
431 - if(!ff) return;
430 + ff = procfile_readall(ff);
431 + if(!ff) return;
432
433 - unsigned long i, lines = procfile_lines(ff);
433 + unsigned long i, lines = procfile_lines(ff);
434
435 - if(lines < 1) {
436 - error("File '%s' should have 1+ lines.", mem->filename);
437 - return;
438 - }
435 + if(lines < 1) {
436 + error("File '%s' should have 1+ lines.", mem->filename);
437 + return;
438 + }
439
440 - for(i = 0; i < lines ; i++) {
441 - char *s = procfile_lineword(ff, i, 0);
442 - uint32_t hash = simple_hash(s);
440 + for(i = 0; i < lines ; i++) {
441 + char *s = procfile_lineword(ff, i, 0);
442 + uint32_t hash = simple_hash(s);
443
444 - if(hash == cache_hash && !strcmp(s, "cache"))
445 - mem->cache = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
444 + if(hash == cache_hash && !strcmp(s, "cache"))
445 + mem->cache = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
446
447 - else if(hash == rss_hash && !strcmp(s, "rss"))
448 - mem->rss = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
447 + else if(hash == rss_hash && !strcmp(s, "rss"))
448 + mem->rss = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
449
450 - else if(hash == rss_huge_hash && !strcmp(s, "rss_huge"))
451 - mem->rss_huge = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
450 + else if(hash == rss_huge_hash && !strcmp(s, "rss_huge"))
451 + mem->rss_huge = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
452
453 - else if(hash == mapped_file_hash && !strcmp(s, "mapped_file"))
454 - mem->mapped_file = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
453 + else if(hash == mapped_file_hash && !strcmp(s, "mapped_file"))
454 + mem->mapped_file = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
455
456 - else if(hash == writeback_hash && !strcmp(s, "writeback"))
457 - mem->writeback = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
456 + else if(hash == writeback_hash && !strcmp(s, "writeback"))
457 + mem->writeback = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
458
459 - else if(hash == dirty_hash && !strcmp(s, "dirty")) {
460 - mem->dirty = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
461 - mem->has_dirty_swap = 1;
462 - }
459 + else if(hash == dirty_hash && !strcmp(s, "dirty")) {
460 + mem->dirty = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
461 + mem->has_dirty_swap = 1;
462 + }
463
464 - else if(hash == swap_hash && !strcmp(s, "swap")) {
465 - mem->swap = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
466 - mem->has_dirty_swap = 1;
467 - }
464 + else if(hash == swap_hash && !strcmp(s, "swap")) {
465 + mem->swap = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
466 + mem->has_dirty_swap = 1;
467 + }
468
469 - else if(hash == pgpgin_hash && !strcmp(s, "pgpgin"))
470 - mem->pgpgin = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
469 + else if(hash == pgpgin_hash && !strcmp(s, "pgpgin"))
470 + mem->pgpgin = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
471
472 - else if(hash == pgpgout_hash && !strcmp(s, "pgpgout"))
473 - mem->pgpgout = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
472 + else if(hash == pgpgout_hash && !strcmp(s, "pgpgout"))
473 + mem->pgpgout = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
474
475 - else if(hash == pgfault_hash && !strcmp(s, "pgfault"))
476 - mem->pgfault = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
475 + else if(hash == pgfault_hash && !strcmp(s, "pgfault"))
476 + mem->pgfault = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
477
478 - else if(hash == pgmajfault_hash && !strcmp(s, "pgmajfault"))
479 - mem->pgmajfault = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
478 + else if(hash == pgmajfault_hash && !strcmp(s, "pgmajfault"))
479 + mem->pgmajfault = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
480
481 /*
482 - else if(hash == inactive_anon_hash && !strcmp(s, "inactive_anon"))
483 - mem->inactive_anon = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
482 + else if(hash == inactive_anon_hash && !strcmp(s, "inactive_anon"))
483 + mem->inactive_anon = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
484
485 - else if(hash == active_anon_hash && !strcmp(s, "active_anon"))
486 - mem->active_anon = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
485 + else if(hash == active_anon_hash && !strcmp(s, "active_anon"))
486 + mem->active_anon = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
487
488 - else if(hash == inactive_file_hash && !strcmp(s, "inactive_file"))
489 - mem->inactive_file = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
488 + else if(hash == inactive_file_hash && !strcmp(s, "inactive_file"))
489 + mem->inactive_file = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
490
491 - else if(hash == active_file_hash && !strcmp(s, "active_file"))
492 - mem->active_file = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
491 + else if(hash == active_file_hash && !strcmp(s, "active_file"))
492 + mem->active_file = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
493
494 - else if(hash == unevictable_hash && !strcmp(s, "unevictable"))
495 - mem->unevictable = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
494 + else if(hash == unevictable_hash && !strcmp(s, "unevictable"))
495 + mem->unevictable = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
496
497 - else if(hash == hierarchical_memory_limit_hash && !strcmp(s, "hierarchical_memory_limit"))
498 - mem->hierarchical_memory_limit = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
497 + else if(hash == hierarchical_memory_limit_hash && !strcmp(s, "hierarchical_memory_limit"))
498 + mem->hierarchical_memory_limit = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
499
500 - else if(hash == total_cache_hash && !strcmp(s, "total_cache"))
501 - mem->total_cache = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
500 + else if(hash == total_cache_hash && !strcmp(s, "total_cache"))
501 + mem->total_cache = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
502
503 - else if(hash == total_rss_hash && !strcmp(s, "total_rss"))
504 - mem->total_rss = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
503 + else if(hash == total_rss_hash && !strcmp(s, "total_rss"))
504 + mem->total_rss = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
505
506 - else if(hash == total_rss_huge_hash && !strcmp(s, "total_rss_huge"))
507 - mem->total_rss_huge = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
506 + else if(hash == total_rss_huge_hash && !strcmp(s, "total_rss_huge"))
507 + mem->total_rss_huge = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
508
509 - else if(hash == total_mapped_file_hash && !strcmp(s, "total_mapped_file"))
510 - mem->total_mapped_file = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
509 + else if(hash == total_mapped_file_hash && !strcmp(s, "total_mapped_file"))
510 + mem->total_mapped_file = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
511
512 - else if(hash == total_writeback_hash && !strcmp(s, "total_writeback"))
513 - mem->total_writeback = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
512 + else if(hash == total_writeback_hash && !strcmp(s, "total_writeback"))
513 + mem->total_writeback = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
514
515 - else if(hash == total_dirty_hash && !strcmp(s, "total_dirty"))
516 - mem->total_dirty = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
515 + else if(hash == total_dirty_hash && !strcmp(s, "total_dirty"))
516 + mem->total_dirty = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
517
518 - else if(hash == total_swap_hash && !strcmp(s, "total_swap"))
519 - mem->total_swap = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
518 + else if(hash == total_swap_hash && !strcmp(s, "total_swap"))
519 + mem->total_swap = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
520
521 - else if(hash == total_pgpgin_hash && !strcmp(s, "total_pgpgin"))
522 - mem->total_pgpgin = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
521 + else if(hash == total_pgpgin_hash && !strcmp(s, "total_pgpgin"))
522 + mem->total_pgpgin = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
523
524 - else if(hash == total_pgpgout_hash && !strcmp(s, "total_pgpgout"))
525 - mem->total_pgpgout = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
524 + else if(hash == total_pgpgout_hash && !strcmp(s, "total_pgpgout"))
525 + mem->total_pgpgout = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
526
527 - else if(hash == total_pgfault_hash && !strcmp(s, "total_pgfault"))
528 - mem->total_pgfault = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
527 + else if(hash == total_pgfault_hash && !strcmp(s, "total_pgfault"))
528 + mem->total_pgfault = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
529
530 - else if(hash == total_pgmajfault_hash && !strcmp(s, "total_pgmajfault"))
531 - mem->total_pgmajfault = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
530 + else if(hash == total_pgmajfault_hash && !strcmp(s, "total_pgmajfault"))
531 + mem->total_pgmajfault = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
532
533 - else if(hash == total_inactive_anon_hash && !strcmp(s, "total_inactive_anon"))
534 - mem->total_inactive_anon = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
533 + else if(hash == total_inactive_anon_hash && !strcmp(s, "total_inactive_anon"))
534 + mem->total_inactive_anon = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
535
536 - else if(hash == total_active_anon_hash && !strcmp(s, "total_active_anon"))
537 - mem->total_active_anon = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
536 + else if(hash == total_active_anon_hash && !strcmp(s, "total_active_anon"))
537 + mem->total_active_anon = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
538
539 - else if(hash == total_inactive_file_hash && !strcmp(s, "total_inactive_file"))
540 - mem->total_inactive_file = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
539 + else if(hash == total_inactive_file_hash && !strcmp(s, "total_inactive_file"))
540 + mem->total_inactive_file = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
541
542 - else if(hash == total_active_file_hash && !strcmp(s, "total_active_file"))
543 - mem->total_active_file = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
542 + else if(hash == total_active_file_hash && !strcmp(s, "total_active_file"))
543 + mem->total_active_file = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
544
545 - else if(hash == total_unevictable_hash && !strcmp(s, "total_unevictable"))
546 - mem->total_unevictable = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
545 + else if(hash == total_unevictable_hash && !strcmp(s, "total_unevictable"))
546 + mem->total_unevictable = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
547 */
548 - }
548 + }
549
550 - // fprintf(stderr, "READ: '%s', cache: %llu, rss: %llu, rss_huge: %llu, mapped_file: %llu, writeback: %llu, dirty: %llu, swap: %llu, pgpgin: %llu, pgpgout: %llu, pgfault: %llu, pgmajfault: %llu, inactive_anon: %llu, active_anon: %llu, inactive_file: %llu, active_file: %llu, unevictable: %llu, hierarchical_memory_limit: %llu, total_cache: %llu, total_rss: %llu, total_rss_huge: %llu, total_mapped_file: %llu, total_writeback: %llu, total_dirty: %llu, total_swap: %llu, total_pgpgin: %llu, total_pgpgout: %llu, total_pgfault: %llu, total_pgmajfault: %llu, total_inactive_anon: %llu, total_active_anon: %llu, total_inactive_file: %llu, total_active_file: %llu, total_unevictable: %llu\n", mem->filename, mem->cache, mem->rss, mem->rss_huge, mem->mapped_file, mem->writeback, mem->dirty, mem->swap, mem->pgpgin, mem->pgpgout, mem->pgfault, mem->pgmajfault, mem->inactive_anon, mem->active_anon, mem->inactive_file, mem->active_file, mem->unevictable, mem->hierarchical_memory_limit, mem->total_cache, mem->total_rss, mem->total_rss_huge, mem->total_mapped_file, mem->total_writeback, mem->total_dirty, mem->total_swap, mem->total_pgpgin, mem->total_pgpgout, mem->total_pgfault, mem->total_pgmajfault, mem->total_inactive_anon, mem->total_active_anon, mem->total_inactive_file, mem->total_active_file, mem->total_unevictable);
550 + // fprintf(stderr, "READ: '%s', cache: %llu, rss: %llu, rss_huge: %llu, mapped_file: %llu, writeback: %llu, dirty: %llu, swap: %llu, pgpgin: %llu, pgpgout: %llu, pgfault: %llu, pgmajfault: %llu, inactive_anon: %llu, active_anon: %llu, inactive_file: %llu, active_file: %llu, unevictable: %llu, hierarchical_memory_limit: %llu, total_cache: %llu, total_rss: %llu, total_rss_huge: %llu, total_mapped_file: %llu, total_writeback: %llu, total_dirty: %llu, total_swap: %llu, total_pgpgin: %llu, total_pgpgout: %llu, total_pgfault: %llu, total_pgmajfault: %llu, total_inactive_anon: %llu, total_active_anon: %llu, total_inactive_file: %llu, total_active_file: %llu, total_unevictable: %llu\n", mem->filename, mem->cache, mem->rss, mem->rss_huge, mem->mapped_file, mem->writeback, mem->dirty, mem->swap, mem->pgpgin, mem->pgpgout, mem->pgfault, mem->pgmajfault, mem->inactive_anon, mem->active_anon, mem->inactive_file, mem->active_file, mem->unevictable, mem->hierarchical_memory_limit, mem->total_cache, mem->total_rss, mem->total_rss_huge, mem->total_mapped_file, mem->total_writeback, mem->total_dirty, mem->total_swap, mem->total_pgpgin, mem->total_pgpgout, mem->total_pgfault, mem->total_pgmajfault, mem->total_inactive_anon, mem->total_active_anon, mem->total_inactive_file, mem->total_active_file, mem->total_unevictable);
551
552 - mem->updated = 1;
553 - }
552 + mem->updated = 1;
553 + }
554 }
555
556 void cgroup_read(struct cgroup *cg) {
557 - debug(D_CGROUP, "reading metrics for cgroups '%s'", cg->id);
558 -
559 - cgroup_read_cpuacct_stat(&cg->cpuacct_stat);
560 - cgroup_read_cpuacct_usage(&cg->cpuacct_usage);
561 - cgroup_read_memory(&cg->memory);
562 - cgroup_read_blkio(&cg->io_service_bytes);
563 - cgroup_read_blkio(&cg->io_serviced);
564 - cgroup_read_blkio(&cg->throttle_io_service_bytes);
565 - cgroup_read_blkio(&cg->throttle_io_serviced);
566 - cgroup_read_blkio(&cg->io_merged);
567 - cgroup_read_blkio(&cg->io_queued);
557 + debug(D_CGROUP, "reading metrics for cgroups '%s'", cg->id);
558 +
559 + cgroup_read_cpuacct_stat(&cg->cpuacct_stat);
560 + cgroup_read_cpuacct_usage(&cg->cpuacct_usage);
561 + cgroup_read_memory(&cg->memory);
562 + cgroup_read_blkio(&cg->io_service_bytes);
563 + cgroup_read_blkio(&cg->io_serviced);
564 + cgroup_read_blkio(&cg->throttle_io_service_bytes);
565 + cgroup_read_blkio(&cg->throttle_io_serviced);
566 + cgroup_read_blkio(&cg->io_merged);
567 + cgroup_read_blkio(&cg->io_queued);
568 }
569
570 void read_all_cgroups(struct cgroup *root) {
571 - debug(D_CGROUP, "reading metrics for all cgroups");
571 + debug(D_CGROUP, "reading metrics for all cgroups");
572
573 - struct cgroup *cg;
573 + struct cgroup *cg;
574
575 - for(cg = root; cg ; cg = cg->next)
576 - if(cg->enabled && cg->available)
577 - cgroup_read(cg);
575 + for(cg = root; cg ; cg = cg->next)
576 + if(cg->enabled && cg->available)
577 + cgroup_read(cg);
578 }
579
580 // ----------------------------------------------------------------------------
@@ -583,167 +583,167 @@ void read_all_cgroups(struct cgroup *root) {
583 #define CGROUP_CHARTID_LINE_MAX 1024
584
585 void cgroup_get_chart_id(struct cgroup *cg) {
586 - debug(D_CGROUP, "getting the name of cgroup '%s'", cg->id);
586 + debug(D_CGROUP, "getting the name of cgroup '%s'", cg->id);
587
588 - pid_t cgroup_pid;
589 - char buffer[CGROUP_CHARTID_LINE_MAX + 1];
588 + pid_t cgroup_pid;
589 + char buffer[CGROUP_CHARTID_LINE_MAX + 1];
590
591 - snprintfz(buffer, CGROUP_CHARTID_LINE_MAX, "exec %s '%s'",
592 - config_get("plugin:cgroups", "script to get cgroup names", PLUGINS_DIR "/cgroup-name.sh"), cg->chart_id);
591 + snprintfz(buffer, CGROUP_CHARTID_LINE_MAX, "exec %s '%s'",
592 + config_get("plugin:cgroups", "script to get cgroup names", PLUGINS_DIR "/cgroup-name.sh"), cg->chart_id);
593
594 - debug(D_CGROUP, "executing command '%s' for cgroup '%s'", buffer, cg->id);
595 - FILE *fp = mypopen(buffer, &cgroup_pid);
596 - if(!fp) {
597 - error("CGROUP: Cannot popen(\"%s\", \"r\").", buffer);
598 - return;
599 - }
600 - debug(D_CGROUP, "reading from command '%s' for cgroup '%s'", buffer, cg->id);
601 - char *s = fgets(buffer, CGROUP_CHARTID_LINE_MAX, fp);
602 - debug(D_CGROUP, "closing command for cgroup '%s'", cg->id);
603 - mypclose(fp, cgroup_pid);
604 - debug(D_CGROUP, "closed command for cgroup '%s'", cg->id);
594 + debug(D_CGROUP, "executing command '%s' for cgroup '%s'", buffer, cg->id);
595 + FILE *fp = mypopen(buffer, &cgroup_pid);
596 + if(!fp) {
597 + error("CGROUP: Cannot popen(\"%s\", \"r\").", buffer);
598 + return;
599 + }
600 + debug(D_CGROUP, "reading from command '%s' for cgroup '%s'", buffer, cg->id);
601 + char *s = fgets(buffer, CGROUP_CHARTID_LINE_MAX, fp);
602 + debug(D_CGROUP, "closing command for cgroup '%s'", cg->id);
603 + mypclose(fp, cgroup_pid);
604 + debug(D_CGROUP, "closed command for cgroup '%s'", cg->id);
605
606 - if(s && *s && *s != '\n') {
607 - debug(D_CGROUP, "cgroup '%s' should be renamed to '%s'", cg->id, s);
606 + if(s && *s && *s != '\n') {
607 + debug(D_CGROUP, "cgroup '%s' should be renamed to '%s'", cg->id, s);
608
609 - trim(s);
609 + trim(s);
610
611 - freez(cg->chart_title);
612 - cg->chart_title = strdupz(s);
613 - netdata_fix_chart_name(cg->chart_title);
611 + freez(cg->chart_title);
612 + cg->chart_title = strdupz(s);
613 + netdata_fix_chart_name(cg->chart_title);
614
615 - freez(cg->chart_id);
616 - cg->chart_id = strdupz(s);
615 + freez(cg->chart_id);
616 + cg->chart_id = strdupz(s);
617
618 - netdata_fix_chart_id(cg->chart_id);
618 + netdata_fix_chart_id(cg->chart_id);
619
620 - debug(D_CGROUP, "cgroup '%s' renamed to '%s' (title: '%s')", cg->id, cg->chart_id, cg->chart_title);
621 - }
622 - else debug(D_CGROUP, "cgroup '%s' is not to be renamed (will be shown as '%s')", cg->id, cg->chart_id);
620 + debug(D_CGROUP, "cgroup '%s' renamed to '%s' (title: '%s')", cg->id, cg->chart_id, cg->chart_title);
621 + }
622 + else debug(D_CGROUP, "cgroup '%s' is not to be renamed (will be shown as '%s')", cg->id, cg->chart_id);
623 }
624
625 struct cgroup *cgroup_add(const char *id) {
626 - debug(D_CGROUP, "adding cgroup '%s'", id);
627 -
628 - if(cgroup_root_count >= cgroup_root_max) {
629 - info("Maximum number of cgroups reached (%d). Not adding cgroup '%s'", cgroup_root_count, id);
630 - return NULL;
631 - }
632 -
633 - int def = cgroup_enable_new_cgroups_detected_at_runtime;
634 - const char *chart_id = id;
635 - if(!*chart_id) {
636 - chart_id = "/";
637 -
638 - // disable by default the root cgroup
639 - def = 0;
640 - debug(D_CGROUP, "cgroup '%s' is the root container (by default %s)", id, (def)?"enabled":"disabled");
641 - }
642 - else {
643 - if(*chart_id == '/') chart_id++;
644 -
645 - size_t len = strlen(chart_id);
646 -
647 - // disable by default the parent cgroup
648 - // for known cgroup managers
649 - if(!strcmp(chart_id, "lxc") ||
650 - !strcmp(chart_id, "docker") ||
651 - !strcmp(chart_id, "libvirt") ||
652 - !strcmp(chart_id, "qemu") ||
653 - !strcmp(chart_id, "systemd") ||
654 - !strcmp(chart_id, "system.slice") ||
655 - !strcmp(chart_id, "machine.slice") ||
656 - !strcmp(chart_id, "init.scope") ||
657 - !strcmp(chart_id, "user") ||
658 - !strcmp(chart_id, "system") ||
659 - !strcmp(chart_id, "machine") ||
660 - // starts with them
661 - (len > 6 && !strncmp(chart_id, "user/", 6)) ||
662 - (len > 11 && !strncmp(chart_id, "user.slice/", 11)) ||
663 - // ends with them
664 - (len > 5 && !strncmp(&chart_id[len - 5], ".user", 5)) ||
665 - (len > 5 && !strncmp(&chart_id[len - 5], ".swap", 5)) ||
666 - (len > 6 && !strncmp(&chart_id[len - 6], ".slice", 6)) ||
667 - (len > 6 && !strncmp(&chart_id[len - 6], ".mount", 6)) ||
668 - (len > 8 && !strncmp(&chart_id[len - 8], ".session", 8)) ||
669 - (len > 8 && !strncmp(&chart_id[len - 8], ".service", 8)) ||
670 - (len > 10 && !strncmp(&chart_id[len - 10], ".partition", 10))
671 - ) {
672 - def = 0;
673 - debug(D_CGROUP, "cgroup '%s' is %s (by default)", id, (def)?"enabled":"disabled");
674 - }
675 - }
676 -
677 - struct cgroup *cg = callocz(1, sizeof(struct cgroup));
678 -
679 - debug(D_CGROUP, "adding cgroup '%s'", id);
680 -
681 - cg->id = strdupz(id);
682 - cg->hash = simple_hash(cg->id);
683 -
684 - cg->chart_id = strdupz(chart_id);
685 - cg->chart_title = strdupz(chart_id);
686 -
687 - if(!cgroup_root)
688 - cgroup_root = cg;
689 - else {
690 - // append it
691 - struct cgroup *e;
692 - for(e = cgroup_root; e->next ;e = e->next) ;
693 - e->next = cg;
694 - }
695 -
696 - cgroup_root_count++;
697 -
698 - // fix the name by calling the external script
699 - cgroup_get_chart_id(cg);
700 -
701 - char option[FILENAME_MAX + 1];
702 - snprintfz(option, FILENAME_MAX, "enable cgroup %s", cg->chart_title);
703 - cg->enabled = config_get_boolean("plugin:cgroups", option, def);
704 -
705 - debug(D_CGROUP, "Added cgroup '%s' with chart id '%s' and title '%s' as %s (default was %s)", cg->id, cg->chart_id, cg->chart_title, (cg->enabled)?"enabled":"disabled", (def)?"enabled":"disabled");
706 -
707 - return cg;
626 + debug(D_CGROUP, "adding cgroup '%s'", id);
627 +
628 + if(cgroup_root_count >= cgroup_root_max) {
629 + info("Maximum number of cgroups reached (%d). Not adding cgroup '%s'", cgroup_root_count, id);
630 + return NULL;
631 + }
632 +
633 + int def = cgroup_enable_new_cgroups_detected_at_runtime;
634 + const char *chart_id = id;
635 + if(!*chart_id) {
636 + chart_id = "/";
637 +
638 + // disable by default the root cgroup
639 + def = 0;
640 + debug(D_CGROUP, "cgroup '%s' is the root container (by default %s)", id, (def)?"enabled":"disabled");
641 + }
642 + else {
643 + if(*chart_id == '/') chart_id++;
644 +
645 + size_t len = strlen(chart_id);
646 +
647 + // disable by default the parent cgroup
648 + // for known cgroup managers
649 + if(!strcmp(chart_id, "lxc") ||
650 + !strcmp(chart_id, "docker") ||
651 + !strcmp(chart_id, "libvirt") ||
652 + !strcmp(chart_id, "qemu") ||
653 + !strcmp(chart_id, "systemd") ||
654 + !strcmp(chart_id, "system.slice") ||
655 + !strcmp(chart_id, "machine.slice") ||
656 + !strcmp(chart_id, "init.scope") ||
657 + !strcmp(chart_id, "user") ||
658 + !strcmp(chart_id, "system") ||
659 + !strcmp(chart_id, "machine") ||
660 + // starts with them
661 + (len > 6 && !strncmp(chart_id, "user/", 6)) ||
662 + (len > 11 && !strncmp(chart_id, "user.slice/", 11)) ||
663 + // ends with them
664 + (len > 5 && !strncmp(&chart_id[len - 5], ".user", 5)) ||
665 + (len > 5 && !strncmp(&chart_id[len - 5], ".swap", 5)) ||
666 + (len > 6 && !strncmp(&chart_id[len - 6], ".slice", 6)) ||
667 + (len > 6 && !strncmp(&chart_id[len - 6], ".mount", 6)) ||
668 + (len > 8 && !strncmp(&chart_id[len - 8], ".session", 8)) ||
669 + (len > 8 && !strncmp(&chart_id[len - 8], ".service", 8)) ||
670 + (len > 10 && !strncmp(&chart_id[len - 10], ".partition", 10))
671 + ) {
672 + def = 0;
673 + debug(D_CGROUP, "cgroup '%s' is %s (by default)", id, (def)?"enabled":"disabled");
674 + }
675 + }
676 +
677 + struct cgroup *cg = callocz(1, sizeof(struct cgroup));
678 +
679 + debug(D_CGROUP, "adding cgroup '%s'", id);
680 +
681 + cg->id = strdupz(id);
682 + cg->hash = simple_hash(cg->id);
683 +
684 + cg->chart_id = strdupz(chart_id);
685 + cg->chart_title = strdupz(chart_id);
686 +
687 + if(!cgroup_root)
688 + cgroup_root = cg;
689 + else {
690 + // append it
691 + struct cgroup *e;
692 + for(e = cgroup_root; e->next ;e = e->next) ;
693 + e->next = cg;
694 + }
695 +
696 + cgroup_root_count++;
697 +
698 + // fix the name by calling the external script
699 + cgroup_get_chart_id(cg);
700 +
701 + char option[FILENAME_MAX + 1];
702 + snprintfz(option, FILENAME_MAX, "enable cgroup %s", cg->chart_title);
703 + cg->enabled = config_get_boolean("plugin:cgroups", option, def);
704 +
705 + debug(D_CGROUP, "Added cgroup '%s' with chart id '%s' and title '%s' as %s (default was %s)", cg->id, cg->chart_id, cg->chart_title, (cg->enabled)?"enabled":"disabled", (def)?"enabled":"disabled");
706 +
707 + return cg;
708 }
709
710 void cgroup_free(struct cgroup *cg) {
711 - debug(D_CGROUP, "Removing cgroup '%s' with chart id '%s' (was %s and %s)", cg->id, cg->chart_id, (cg->enabled)?"enabled":"disabled", (cg->available)?"available":"not available");
712 -
713 - freez(cg->cpuacct_usage.cpu_percpu);
714 -
715 - freez(cg->cpuacct_stat.filename);
716 - freez(cg->cpuacct_usage.filename);
717 - freez(cg->memory.filename);
718 - freez(cg->io_service_bytes.filename);
719 - freez(cg->io_serviced.filename);
720 - freez(cg->throttle_io_service_bytes.filename);
721 - freez(cg->throttle_io_serviced.filename);
722 - freez(cg->io_merged.filename);
723 - freez(cg->io_queued.filename);
724 -
725 - freez(cg->id);
726 - freez(cg->chart_id);
727 - freez(cg->chart_title);
728 - freez(cg);
729 -
730 - cgroup_root_count--;
711 + debug(D_CGROUP, "Removing cgroup '%s' with chart id '%s' (was %s and %s)", cg->id, cg->chart_id, (cg->enabled)?"enabled":"disabled", (cg->available)?"available":"not available");
712 +
713 + freez(cg->cpuacct_usage.cpu_percpu);
714 +
715 + freez(cg->cpuacct_stat.filename);
716 + freez(cg->cpuacct_usage.filename);
717 + freez(cg->memory.filename);
718 + freez(cg->io_service_bytes.filename);
719 + freez(cg->io_serviced.filename);
720 + freez(cg->throttle_io_service_bytes.filename);
721 + freez(cg->throttle_io_serviced.filename);
722 + freez(cg->io_merged.filename);
723 + freez(cg->io_queued.filename);
724 +
725 + freez(cg->id);
726 + freez(cg->chart_id);
727 + freez(cg->chart_title);
728 + freez(cg);
729 +
730 + cgroup_root_count--;
731 }
732
733 // find if a given cgroup exists
734 struct cgroup *cgroup_find(const char *id) {
735 - debug(D_CGROUP, "searching for cgroup '%s'", id);
735 + debug(D_CGROUP, "searching for cgroup '%s'", id);
736
737 - uint32_t hash = simple_hash(id);
737 + uint32_t hash = simple_hash(id);
738
739 - struct cgroup *cg;
740 - for(cg = cgroup_root; cg ; cg = cg->next) {
741 - if(hash == cg->hash && strcmp(id, cg->id) == 0)
742 - break;
743 - }
739 + struct cgroup *cg;
740 + for(cg = cgroup_root; cg ; cg = cg->next) {
741 + if(hash == cg->hash && strcmp(id, cg->id) == 0)
742 + break;
743 + }
744
745 - debug(D_CGROUP, "cgroup_find('%s') %s", id, (cg)?"found":"not found");
746 - return cg;
745 + debug(D_CGROUP, "cgroup_find('%s') %s", id, (cg)?"found":"not found");
746 + return cg;
747 }
748
749 // ----------------------------------------------------------------------------
@@ -751,232 +751,232 @@ struct cgroup *cgroup_find(const char *id) {
751
752 // callback for find_file_in_subdirs()
753 void found_subdir_in_dir(const char *dir) {
754 - debug(D_CGROUP, "examining cgroup dir '%s'", dir);
755 -
756 - struct cgroup *cg = cgroup_find(dir);
757 - if(!cg) {
758 - if(*dir && cgroup_max_depth > 0) {
759 - int depth = 0;
760 - const char *s;
761 -
762 - for(s = dir; *s ;s++)
763 - if(unlikely(*s == '/'))
764 - depth++;
765 -
766 - if(depth > cgroup_max_depth) {
767 - info("cgroup '%s' is too deep (%d, while max is %d)", dir, depth, cgroup_max_depth);
768 - return;
769 - }
770 - }
771 - debug(D_CGROUP, "will add dir '%s' as cgroup", dir);
772 - cg = cgroup_add(dir);
773 - }
774 -
775 - if(cg) cg->available = 1;
754 + debug(D_CGROUP, "examining cgroup dir '%s'", dir);
755 +
756 + struct cgroup *cg = cgroup_find(dir);
757 + if(!cg) {
758 + if(*dir && cgroup_max_depth > 0) {
759 + int depth = 0;
760 + const char *s;
761 +
762 + for(s = dir; *s ;s++)
763 + if(unlikely(*s == '/'))
764 + depth++;
765 +
766 + if(depth > cgroup_max_depth) {
767 + info("cgroup '%s' is too deep (%d, while max is %d)", dir, depth, cgroup_max_depth);
768 + return;
769 + }
770 + }
771 + debug(D_CGROUP, "will add dir '%s' as cgroup", dir);
772 + cg = cgroup_add(dir);
773 + }
774 +
775 + if(cg) cg->available = 1;
776 }
777
778 void find_dir_in_subdirs(const char *base, const char *this, void (*callback)(const char *)) {
779 - debug(D_CGROUP, "searching for directories in '%s'", base);
780 -
781 - int enabled = -1;
782 - if(!this) this = base;
783 - size_t dirlen = strlen(this), baselen = strlen(base);
784 - const char *relative_path = &this[baselen];
785 -
786 - DIR *dir = opendir(this);
787 - if(!dir) {
788 - error("Cannot read cgroups directory '%s'", base);
789 - return;
790 - }
791 -
792 - callback(relative_path);
793 -
794 - struct dirent *de = NULL;
795 - while((de = readdir(dir))) {
796 - if(de->d_type == DT_DIR
797 - && (
798 - (de->d_name[0] == '.' && de->d_name[1] == '\0')
799 - || (de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0')
800 - ))
801 - continue;
802 -
803 - debug(D_CGROUP, "examining '%s/%s'", this, de->d_name);
804 -
805 - if(de->d_type == DT_DIR) {
806 - if(enabled == -1) {
807 - const char *r = relative_path;
808 - if(*r == '\0') r = "/";
809 - else if (*r == '/') r++;
810 -
811 - // we check for this option here
812 - // so that the config will not have settings
813 - // for leaf directories
814 - char option[FILENAME_MAX + 1];
815 - snprintfz(option, FILENAME_MAX, "search for cgroups under %s", r);
816 - option[FILENAME_MAX] = '\0';
817 - enabled = config_get_boolean("plugin:cgroups", option, 1);
818 - }
819 -
820 - if(enabled) {
821 - char *s = mallocz(dirlen + strlen(de->d_name) + 2);
779 + debug(D_CGROUP, "searching for directories in '%s'", base);
780 +
781 + int enabled = -1;
782 + if(!this) this = base;
783 + size_t dirlen = strlen(this), baselen = strlen(base);
784 + const char *relative_path = &this[baselen];
785 +
786 + DIR *dir = opendir(this);
787 + if(!dir) {
788 + error("Cannot read cgroups directory '%s'", base);
789 + return;
790 + }
791 +
792 + callback(relative_path);
793 +
794 + struct dirent *de = NULL;
795 + while((de = readdir(dir))) {
796 + if(de->d_type == DT_DIR
797 + && (
798 + (de->d_name[0] == '.' && de->d_name[1] == '\0')
799 + || (de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0')
800 + ))
801 + continue;
802 +
803 + debug(D_CGROUP, "examining '%s/%s'", this, de->d_name);
804 +
805 + if(de->d_type == DT_DIR) {
806 + if(enabled == -1) {
807 + const char *r = relative_path;
808 + if(*r == '\0') r = "/";
809 + else if (*r == '/') r++;
810 +
811 + // we check for this option here
812 + // so that the config will not have settings
813 + // for leaf directories
814 + char option[FILENAME_MAX + 1];
815 + snprintfz(option, FILENAME_MAX, "search for cgroups under %s", r);
816 + option[FILENAME_MAX] = '\0';
817 + enabled = config_get_boolean("plugin:cgroups", option, 1);
818 + }
819 +
820 + if(enabled) {
821 + char *s = mallocz(dirlen + strlen(de->d_name) + 2);
822 strcpy(s, this);
823 strcat(s, "/");
824 strcat(s, de->d_name);
825 find_dir_in_subdirs(base, s, callback);
826 freez(s);
827 - }
828 - }
829 - }
827 + }
828 + }
829 + }
830
831 - closedir(dir);
831 + closedir(dir);
832 }
833
834 void mark_all_cgroups_as_not_available() {
835 - debug(D_CGROUP, "marking all cgroups as not available");
835 + debug(D_CGROUP, "marking all cgroups as not available");
836
837 - struct cgroup *cg;
837 + struct cgroup *cg;
838
839 - // mark all as not available
840 - for(cg = cgroup_root; cg ; cg = cg->next)
841 - cg->available = 0;
839 + // mark all as not available
840 + for(cg = cgroup_root; cg ; cg = cg->next)
841 + cg->available = 0;
842 }
843
844 void cleanup_all_cgroups() {
845 - struct cgroup *cg = cgroup_root, *last = NULL;
846 -
847 - for(; cg ;) {
848 - if(!cg->available) {
849 -
850 - if(!last)
851 - cgroup_root = cg->next;
852 - else
853 - last->next = cg->next;
854 -
855 - cgroup_free(cg);
856 -
857 - if(!last)
858 - cg = cgroup_root;
859 - else
860 - cg = last->next;
861 - }
862 - else {
863 - last = cg;
864 - cg = cg->next;
865 - }
866 - }
845 + struct cgroup *cg = cgroup_root, *last = NULL;
846 +
847 + for(; cg ;) {
848 + if(!cg->available) {
849 +
850 + if(!last)
851 + cgroup_root = cg->next;
852 + else
853 + last->next = cg->next;
854 +
855 + cgroup_free(cg);
856 +
857 + if(!last)
858 + cg = cgroup_root;
859 + else
860 + cg = last->next;
861 + }
862 + else {
863 + last = cg;
864 + cg = cg->next;
865 + }
866 + }
867 }
868
869 void find_all_cgroups() {
870 - debug(D_CGROUP, "searching for cgroups");
871 -
872 - mark_all_cgroups_as_not_available();
873 -
874 - if(cgroup_enable_cpuacct_stat || cgroup_enable_cpuacct_usage)
875 - find_dir_in_subdirs(cgroup_cpuacct_base, NULL, found_subdir_in_dir);
876 -
877 - if(cgroup_enable_blkio)
878 - find_dir_in_subdirs(cgroup_blkio_base, NULL, found_subdir_in_dir);
879 -
880 - if(cgroup_enable_memory)
881 - find_dir_in_subdirs(cgroup_memory_base, NULL, found_subdir_in_dir);
882 -
883 - if(cgroup_enable_devices)
884 - find_dir_in_subdirs(cgroup_devices_base, NULL, found_subdir_in_dir);
885 -
886 - // remove any non-existing cgroups
887 - cleanup_all_cgroups();
888 -
889 - struct cgroup *cg;
890 - struct stat buf;
891 - for(cg = cgroup_root; cg ; cg = cg->next) {
892 - // fprintf(stderr, " >>> CGROUP '%s' (%u - %s) with name '%s'\n", cg->id, cg->hash, cg->available?"available":"stopped", cg->name);
893 -
894 - if(unlikely(!cg->available))
895 - continue;
896 -
897 - debug(D_CGROUP, "checking paths for cgroup '%s'", cg->id);
898 -
899 - // check for newly added cgroups
900 - // and update the filenames they read
901 - char filename[FILENAME_MAX + 1];
902 - if(cgroup_enable_cpuacct_stat && !cg->cpuacct_stat.filename) {
903 - snprintfz(filename, FILENAME_MAX, "%s%s/cpuacct.stat", cgroup_cpuacct_base, cg->id);
904 - if(stat(filename, &buf) != -1) {
905 - cg->cpuacct_stat.filename = strdupz(filename);
906 - debug(D_CGROUP, "cpuacct.stat filename for cgroup '%s': '%s'", cg->id, cg->cpuacct_stat.filename);
907 - }
908 - else debug(D_CGROUP, "cpuacct.stat file for cgroup '%s': '%s' does not exist.", cg->id, filename);
909 - }
910 - if(cgroup_enable_cpuacct_usage && !cg->cpuacct_usage.filename) {
911 - snprintfz(filename, FILENAME_MAX, "%s%s/cpuacct.usage_percpu", cgroup_cpuacct_base, cg->id);
912 - if(stat(filename, &buf) != -1) {
913 - cg->cpuacct_usage.filename = strdupz(filename);
914 - debug(D_CGROUP, "cpuacct.usage_percpu filename for cgroup '%s': '%s'", cg->id, cg->cpuacct_usage.filename);
915 - }
916 - else debug(D_CGROUP, "cpuacct.usage_percpu file for cgroup '%s': '%s' does not exist.", cg->id, filename);
917 - }
918 - if(cgroup_enable_memory && !cg->memory.filename) {
919 - snprintfz(filename, FILENAME_MAX, "%s%s/memory.stat", cgroup_memory_base, cg->id);
920 - if(stat(filename, &buf) != -1) {
921 - cg->memory.filename = strdupz(filename);
922 - debug(D_CGROUP, "memory.stat filename for cgroup '%s': '%s'", cg->id, cg->memory.filename);
923 - }
924 - else debug(D_CGROUP, "memory.stat file for cgroup '%s': '%s' does not exist.", cg->id, filename);
925 - }
926 - if(cgroup_enable_blkio) {
927 - if(!cg->io_service_bytes.filename) {
928 - snprintfz(filename, FILENAME_MAX, "%s%s/blkio.io_service_bytes", cgroup_blkio_base, cg->id);
929 - if(stat(filename, &buf) != -1) {
930 - cg->io_service_bytes.filename = strdupz(filename);
931 - debug(D_CGROUP, "io_service_bytes filename for cgroup '%s': '%s'", cg->id, cg->io_service_bytes.filename);
932 - }
933 - else debug(D_CGROUP, "io_service_bytes file for cgroup '%s': '%s' does not exist.", cg->id, filename);
934 - }
935 - if(!cg->io_serviced.filename) {
936 - snprintfz(filename, FILENAME_MAX, "%s%s/blkio.io_serviced", cgroup_blkio_base, cg->id);
937 - if(stat(filename, &buf) != -1) {
938 - cg->io_serviced.filename = strdupz(filename);
939 - debug(D_CGROUP, "io_serviced filename for cgroup '%s': '%s'", cg->id, cg->io_serviced.filename);
940 - }
941 - else debug(D_CGROUP, "io_serviced file for cgroup '%s': '%s' does not exist.", cg->id, filename);
942 - }
943 - if(!cg->throttle_io_service_bytes.filename) {
944 - snprintfz(filename, FILENAME_MAX, "%s%s/blkio.throttle.io_service_bytes", cgroup_blkio_base, cg->id);
945 - if(stat(filename, &buf) != -1) {
946 - cg->throttle_io_service_bytes.filename = strdupz(filename);
947 - debug(D_CGROUP, "throttle_io_service_bytes filename for cgroup '%s': '%s'", cg->id, cg->throttle_io_service_bytes.filename);
948 - }
949 - else debug(D_CGROUP, "throttle_io_service_bytes file for cgroup '%s': '%s' does not exist.", cg->id, filename);
950 - }
951 - if(!cg->throttle_io_serviced.filename) {
952 - snprintfz(filename, FILENAME_MAX, "%s%s/blkio.throttle.io_serviced", cgroup_blkio_base, cg->id);
953 - if(stat(filename, &buf) != -1) {
954 - cg->throttle_io_serviced.filename = strdupz(filename);
955 - debug(D_CGROUP, "throttle_io_serviced filename for cgroup '%s': '%s'", cg->id, cg->throttle_io_serviced.filename);
956 - }
957 - else debug(D_CGROUP, "throttle_io_serviced file for cgroup '%s': '%s' does not exist.", cg->id, filename);
958 - }
959 - if(!cg->io_merged.filename) {
960 - snprintfz(filename, FILENAME_MAX, "%s%s/blkio.io_merged", cgroup_blkio_base, cg->id);
961 - if(stat(filename, &buf) != -1) {
962 - cg->io_merged.filename = strdupz(filename);
963 - debug(D_CGROUP, "io_merged filename for cgroup '%s': '%s'", cg->id, cg->io_merged.filename);
964 - }
965 - else debug(D_CGROUP, "io_merged file for cgroup '%s': '%s' does not exist.", cg->id, filename);
966 - }
967 - if(!cg->io_queued.filename) {
968 - snprintfz(filename, FILENAME_MAX, "%s%s/blkio.io_queued", cgroup_blkio_base, cg->id);
969 - if(stat(filename, &buf) != -1) {
970 - cg->io_queued.filename = strdupz(filename);
971 - debug(D_CGROUP, "io_queued filename for cgroup '%s': '%s'", cg->id, cg->io_queued.filename);
972 - }
973 - else debug(D_CGROUP, "io_queued file for cgroup '%s': '%s' does not exist.", cg->id, filename);
974 - }
975 - }
976 - }
977 -
978 - debug(D_CGROUP, "done searching for cgroups");
979 - return;
870 + debug(D_CGROUP, "searching for cgroups");
871 +
872 + mark_all_cgroups_as_not_available();
873 +
874 + if(cgroup_enable_cpuacct_stat || cgroup_enable_cpuacct_usage)
875 + find_dir_in_subdirs(cgroup_cpuacct_base, NULL, found_subdir_in_dir);
876 +
877 + if(cgroup_enable_blkio)
878 + find_dir_in_subdirs(cgroup_blkio_base, NULL, found_subdir_in_dir);
879 +
880 + if(cgroup_enable_memory)
881 + find_dir_in_subdirs(cgroup_memory_base, NULL, found_subdir_in_dir);
882 +
883 + if(cgroup_enable_devices)
884 + find_dir_in_subdirs(cgroup_devices_base, NULL, found_subdir_in_dir);
885 +
886 + // remove any non-existing cgroups
887 + cleanup_all_cgroups();
888 +
889 + struct cgroup *cg;
890 + struct stat buf;
891 + for(cg = cgroup_root; cg ; cg = cg->next) {
892 + // fprintf(stderr, " >>> CGROUP '%s' (%u - %s) with name '%s'\n", cg->id, cg->hash, cg->available?"available":"stopped", cg->name);
893 +
894 + if(unlikely(!cg->available))
895 + continue;
896 +
897 + debug(D_CGROUP, "checking paths for cgroup '%s'", cg->id);
898 +
899 + // check for newly added cgroups
900 + // and update the filenames they read
901 + char filename[FILENAME_MAX + 1];
902 + if(cgroup_enable_cpuacct_stat && !cg->cpuacct_stat.filename) {
903 + snprintfz(filename, FILENAME_MAX, "%s%s/cpuacct.stat", cgroup_cpuacct_base, cg->id);
904 + if(stat(filename, &buf) != -1) {
905 + cg->cpuacct_stat.filename = strdupz(filename);
906 + debug(D_CGROUP, "cpuacct.stat filename for cgroup '%s': '%s'", cg->id, cg->cpuacct_stat.filename);
907 + }
908 + else debug(D_CGROUP, "cpuacct.stat file for cgroup '%s': '%s' does not exist.", cg->id, filename);
909 + }
910 + if(cgroup_enable_cpuacct_usage && !cg->cpuacct_usage.filename) {
911 + snprintfz(filename, FILENAME_MAX, "%s%s/cpuacct.usage_percpu", cgroup_cpuacct_base, cg->id);
912 + if(stat(filename, &buf) != -1) {
913 + cg->cpuacct_usage.filename = strdupz(filename);
914 + debug(D_CGROUP, "cpuacct.usage_percpu filename for cgroup '%s': '%s'", cg->id, cg->cpuacct_usage.filename);
915 + }
916 + else debug(D_CGROUP, "cpuacct.usage_percpu file for cgroup '%s': '%s' does not exist.", cg->id, filename);
917 + }
918 + if(cgroup_enable_memory && !cg->memory.filename) {
919 + snprintfz(filename, FILENAME_MAX, "%s%s/memory.stat", cgroup_memory_base, cg->id);
920 + if(stat(filename, &buf) != -1) {
921 + cg->memory.filename = strdupz(filename);
922 + debug(D_CGROUP, "memory.stat filename for cgroup '%s': '%s'", cg->id, cg->memory.filename);
923 + }
924 + else debug(D_CGROUP, "memory.stat file for cgroup '%s': '%s' does not exist.", cg->id, filename);
925 + }
926 + if(cgroup_enable_blkio) {
927 + if(!cg->io_service_bytes.filename) {
928 + snprintfz(filename, FILENAME_MAX, "%s%s/blkio.io_service_bytes", cgroup_blkio_base, cg->id);
929 + if(stat(filename, &buf) != -1) {
930 + cg->io_service_bytes.filename = strdupz(filename);
931 + debug(D_CGROUP, "io_service_bytes filename for cgroup '%s': '%s'", cg->id, cg->io_service_bytes.filename);
932 + }
933 + else debug(D_CGROUP, "io_service_bytes file for cgroup '%s': '%s' does not exist.", cg->id, filename);
934 + }
935 + if(!cg->io_serviced.filename) {
936 + snprintfz(filename, FILENAME_MAX, "%s%s/blkio.io_serviced", cgroup_blkio_base, cg->id);
937 + if(stat(filename, &buf) != -1) {
938 + cg->io_serviced.filename = strdupz(filename);
939 + debug(D_CGROUP, "io_serviced filename for cgroup '%s': '%s'", cg->id, cg->io_serviced.filename);
940 + }
941 + else debug(D_CGROUP, "io_serviced file for cgroup '%s': '%s' does not exist.", cg->id, filename);
942 + }
943 + if(!cg->throttle_io_service_bytes.filename) {
944 + snprintfz(filename, FILENAME_MAX, "%s%s/blkio.throttle.io_service_bytes", cgroup_blkio_base, cg->id);
945 + if(stat(filename, &buf) != -1) {
946 + cg->throttle_io_service_bytes.filename = strdupz(filename);
947 + debug(D_CGROUP, "throttle_io_service_bytes filename for cgroup '%s': '%s'", cg->id, cg->throttle_io_service_bytes.filename);
948 + }
949 + else debug(D_CGROUP, "throttle_io_service_bytes file for cgroup '%s': '%s' does not exist.", cg->id, filename);
950 + }
951 + if(!cg->throttle_io_serviced.filename) {
952 + snprintfz(filename, FILENAME_MAX, "%s%s/blkio.throttle.io_serviced", cgroup_blkio_base, cg->id);
953 + if(stat(filename, &buf) != -1) {
954 + cg->throttle_io_serviced.filename = strdupz(filename);
955 + debug(D_CGROUP, "throttle_io_serviced filename for cgroup '%s': '%s'", cg->id, cg->throttle_io_serviced.filename);
956 + }
957 + else debug(D_CGROUP, "throttle_io_serviced file for cgroup '%s': '%s' does not exist.", cg->id, filename);
958 + }
959 + if(!cg->io_merged.filename) {
960 + snprintfz(filename, FILENAME_MAX, "%s%s/blkio.io_merged", cgroup_blkio_base, cg->id);
961 + if(stat(filename, &buf) != -1) {
962 + cg->io_merged.filename = strdupz(filename);
963 + debug(D_CGROUP, "io_merged filename for cgroup '%s': '%s'", cg->id, cg->io_merged.filename);
964 + }
965 + else debug(D_CGROUP, "io_merged file for cgroup '%s': '%s' does not exist.", cg->id, filename);
966 + }
967 + if(!cg->io_queued.filename) {
968 + snprintfz(filename, FILENAME_MAX, "%s%s/blkio.io_queued", cgroup_blkio_base, cg->id);
969 + if(stat(filename, &buf) != -1) {
970 + cg->io_queued.filename = strdupz(filename);
971 + debug(D_CGROUP, "io_queued filename for cgroup '%s': '%s'", cg->id, cg->io_queued.filename);
972 + }
973 + else debug(D_CGROUP, "io_queued file for cgroup '%s': '%s' does not exist.", cg->id, filename);
974 + }
975 + }
976 + }
977 +
978 + debug(D_CGROUP, "done searching for cgroups");
979 + return;
980 }
981
982 // ----------------------------------------------------------------------------
@@ -985,349 +985,349 @@ void find_all_cgroups() {
985 #define CHART_TITLE_MAX 300
986
987 void update_cgroup_charts(int update_every) {
988 - debug(D_CGROUP, "updating cgroups charts");
989 -
990 - char type[RRD_ID_LENGTH_MAX + 1];
991 - char title[CHART_TITLE_MAX + 1];
992 -
993 - struct cgroup *cg;
994 - RRDSET *st;
995 -
996 - for(cg = cgroup_root; cg ; cg = cg->next) {
997 - if(!cg->available || !cg->enabled)
998 - continue;
999 -
1000 - if(cg->id[0] == '\0')
1001 - strcpy(type, "cgroup_root");
1002 - else if(cg->id[0] == '/')
1003 - snprintfz(type, RRD_ID_LENGTH_MAX, "cgroup_%s", cg->chart_id);
1004 - else
1005 - snprintfz(type, RRD_ID_LENGTH_MAX, "cgroup_%s", cg->chart_id);
1006 -
1007 - netdata_fix_chart_id(type);
1008 -
1009 - if(cg->cpuacct_stat.updated) {
1010 - st = rrdset_find_bytype(type, "cpu");
1011 - if(!st) {
1012 - snprintfz(title, CHART_TITLE_MAX, "CPU Usage for cgroup %s", cg->chart_title);
1013 - st = rrdset_create(type, "cpu", NULL, "cpu", "cgroup.cpu", title, "%", 40000, update_every, RRDSET_TYPE_STACKED);
1014 -
1015 - rrddim_add(st, "user", NULL, 100, hz, RRDDIM_INCREMENTAL);
1016 - rrddim_add(st, "system", NULL, 100, hz, RRDDIM_INCREMENTAL);
1017 - }
1018 - else rrdset_next(st);
1019 -
1020 - rrddim_set(st, "user", cg->cpuacct_stat.user);
1021 - rrddim_set(st, "system", cg->cpuacct_stat.system);
1022 - rrdset_done(st);
1023 - }
1024 -
1025 - if(cg->cpuacct_usage.updated) {
1026 - char id[RRD_ID_LENGTH_MAX + 1];
1027 - unsigned int i;
1028 -
1029 - st = rrdset_find_bytype(type, "cpu_per_core");
1030 - if(!st) {
1031 - snprintfz(title, CHART_TITLE_MAX, "CPU Usage Per Core for cgroup %s", cg->chart_title);
1032 - st = rrdset_create(type, "cpu_per_core", NULL, "cpu", "cgroup.cpu_per_core", title, "%", 40100, update_every, RRDSET_TYPE_STACKED);
1033 -
1034 - for(i = 0; i < cg->cpuacct_usage.cpus ;i++) {
1035 - snprintfz(id, CHART_TITLE_MAX, "cpu%u", i);
1036 - rrddim_add(st, id, NULL, 100, 1000000000, RRDDIM_INCREMENTAL);
1037 - }
1038 - }
1039 - else rrdset_next(st);
1040 -
1041 - for(i = 0; i < cg->cpuacct_usage.cpus ;i++) {
1042 - snprintfz(id, CHART_TITLE_MAX, "cpu%u", i);
1043 - rrddim_set(st, id, cg->cpuacct_usage.cpu_percpu[i]);
1044 - }
1045 - rrdset_done(st);
1046 - }
1047 -
1048 - if(cg->memory.updated) {
1049 - if(cg->memory.cache + cg->memory.rss + cg->memory.rss_huge + cg->memory.mapped_file > 0) {
1050 - st = rrdset_find_bytype(type, "mem");
1051 - if(!st) {
1052 - snprintfz(title, CHART_TITLE_MAX, "Memory Usage for cgroup %s", cg->chart_title);
1053 - st = rrdset_create(type, "mem", NULL, "mem", "cgroup.mem", title, "MB", 40200, update_every,
1054 - RRDSET_TYPE_STACKED);
1055 -
1056 - rrddim_add(st, "cache", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
1057 - rrddim_add(st, "rss", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
1058 - if(cg->memory.has_dirty_swap)
1059 - rrddim_add(st, "swap", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
1060 - rrddim_add(st, "rss_huge", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
1061 - rrddim_add(st, "mapped_file", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
1062 - }
1063 - else rrdset_next(st);
1064 -
1065 - rrddim_set(st, "cache", cg->memory.cache);
1066 - rrddim_set(st, "rss", cg->memory.rss);
1067 - if(cg->memory.has_dirty_swap)
1068 - rrddim_set(st, "swap", cg->memory.swap);
1069 - rrddim_set(st, "rss_huge", cg->memory.rss_huge);
1070 - rrddim_set(st, "mapped_file", cg->memory.mapped_file);
1071 - rrdset_done(st);
1072 - }
1073 -
1074 - st = rrdset_find_bytype(type, "writeback");
1075 - if(!st) {
1076 - snprintfz(title, CHART_TITLE_MAX, "Writeback Memory for cgroup %s", cg->chart_title);
1077 - st = rrdset_create(type, "writeback", NULL, "mem", "cgroup.writeback", title, "MB", 40300,
1078 - update_every, RRDSET_TYPE_AREA);
1079 -
1080 - if(cg->memory.has_dirty_swap)
1081 - rrddim_add(st, "dirty", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
1082 - rrddim_add(st, "writeback", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
1083 - }
1084 - else rrdset_next(st);
1085 -
1086 - if(cg->memory.has_dirty_swap)
1087 - rrddim_set(st, "dirty", cg->memory.dirty);
1088 - rrddim_set(st, "writeback", cg->memory.writeback);
1089 - rrdset_done(st);
1090 -
1091 - if(cg->memory.pgpgin + cg->memory.pgpgout > 0) {
1092 - st = rrdset_find_bytype(type, "mem_activity");
1093 - if(!st) {
1094 - snprintfz(title, CHART_TITLE_MAX, "Memory Activity for cgroup %s", cg->chart_title);
1095 - st = rrdset_create(type, "mem_activity", NULL, "mem", "cgroup.mem_activity", title, "MB/s",
1096 - 40400, update_every, RRDSET_TYPE_LINE);
1097 -
1098 - rrddim_add(st, "pgpgin", "in", sysconf(_SC_PAGESIZE), 1024 * 1024, RRDDIM_INCREMENTAL);
1099 - rrddim_add(st, "pgpgout", "out", -sysconf(_SC_PAGESIZE), 1024 * 1024, RRDDIM_INCREMENTAL);
1100 - }
1101 - else rrdset_next(st);
1102 -
1103 - rrddim_set(st, "pgpgin", cg->memory.pgpgin);
1104 - rrddim_set(st, "pgpgout", cg->memory.pgpgout);
1105 - rrdset_done(st);
1106 - }
1107 -
1108 - if(cg->memory.pgfault + cg->memory.pgmajfault > 0) {
1109 - st = rrdset_find_bytype(type, "pgfaults");
1110 - if(!st) {
1111 - snprintfz(title, CHART_TITLE_MAX, "Memory Page Faults for cgroup %s", cg->chart_title);
1112 - st = rrdset_create(type, "pgfaults", NULL, "mem", "cgroup.pgfaults", title, "MB/s", 40500,
1113 - update_every, RRDSET_TYPE_LINE);
1114 -
1115 - rrddim_add(st, "pgfault", NULL, sysconf(_SC_PAGESIZE), 1024 * 1024, RRDDIM_INCREMENTAL);
1116 - rrddim_add(st, "pgmajfault", "swap", -sysconf(_SC_PAGESIZE), 1024 * 1024, RRDDIM_INCREMENTAL);
1117 - }
1118 - else rrdset_next(st);
1119 -
1120 - rrddim_set(st, "pgfault", cg->memory.pgfault);
1121 - rrddim_set(st, "pgmajfault", cg->memory.pgmajfault);
1122 - rrdset_done(st);
1123 - }
1124 - }
1125 -
1126 - if(cg->io_service_bytes.updated && cg->io_service_bytes.Read + cg->io_service_bytes.Write > 0) {
1127 - st = rrdset_find_bytype(type, "io");
1128 - if(!st) {
1129 - snprintfz(title, CHART_TITLE_MAX, "I/O Bandwidth (all disks) for cgroup %s", cg->chart_title);
1130 - st = rrdset_create(type, "io", NULL, "disk", "cgroup.io", title, "KB/s", 41200,
1131 - update_every, RRDSET_TYPE_LINE);
1132 -
1133 - rrddim_add(st, "read", NULL, 1, 1024, RRDDIM_INCREMENTAL);
1134 - rrddim_add(st, "write", NULL, -1, 1024, RRDDIM_INCREMENTAL);
1135 - }
1136 - else rrdset_next(st);
1137 -
1138 - rrddim_set(st, "read", cg->io_service_bytes.Read);
1139 - rrddim_set(st, "write", cg->io_service_bytes.Write);
1140 - rrdset_done(st);
1141 - }
1142 -
1143 - if(cg->io_serviced.updated && cg->io_serviced.Read + cg->io_serviced.Write > 0) {
1144 - st = rrdset_find_bytype(type, "serviced_ops");
1145 - if(!st) {
1146 - snprintfz(title, CHART_TITLE_MAX, "Serviced I/O Operations (all disks) for cgroup %s", cg->chart_title);
1147 - st = rrdset_create(type, "serviced_ops", NULL, "disk", "cgroup.serviced_ops", title, "operations/s", 41200,
1148 - update_every, RRDSET_TYPE_LINE);
1149 -
1150 - rrddim_add(st, "read", NULL, 1, 1, RRDDIM_INCREMENTAL);
1151 - rrddim_add(st, "write", NULL, -1, 1, RRDDIM_INCREMENTAL);
1152 - }
1153 - else rrdset_next(st);
1154 -
1155 - rrddim_set(st, "read", cg->io_serviced.Read);
1156 - rrddim_set(st, "write", cg->io_serviced.Write);
1157 - rrdset_done(st);
1158 - }
1159 -
1160 - if(cg->throttle_io_service_bytes.updated && cg->throttle_io_service_bytes.Read + cg->throttle_io_service_bytes.Write > 0) {
1161 - st = rrdset_find_bytype(type, "io");
1162 - if(!st) {
1163 - snprintfz(title, CHART_TITLE_MAX, "Throttle I/O Bandwidth (all disks) for cgroup %s", cg->chart_title);
1164 - st = rrdset_create(type, "io", NULL, "disk", "cgroup.io", title, "KB/s", 41200,
1165 - update_every, RRDSET_TYPE_LINE);
1166 -
1167 - rrddim_add(st, "read", NULL, 1, 1024, RRDDIM_INCREMENTAL);
1168 - rrddim_add(st, "write", NULL, -1, 1024, RRDDIM_INCREMENTAL);
1169 - }
1170 - else rrdset_next(st);
1171 -
1172 - rrddim_set(st, "read", cg->throttle_io_service_bytes.Read);
1173 - rrddim_set(st, "write", cg->throttle_io_service_bytes.Write);
1174 - rrdset_done(st);
1175 - }
1176 -
1177 -
1178 - if(cg->throttle_io_serviced.updated && cg->throttle_io_serviced.Read + cg->throttle_io_serviced.Write > 0) {
1179 - st = rrdset_find_bytype(type, "throttle_serviced_ops");
1180 - if(!st) {
1181 - snprintfz(title, CHART_TITLE_MAX, "Throttle Serviced I/O Operations (all disks) for cgroup %s", cg->chart_title);
1182 - st = rrdset_create(type, "throttle_serviced_ops", NULL, "disk", "cgroup.throttle_serviced_ops", title, "operations/s", 41200,
1183 - update_every, RRDSET_TYPE_LINE);
1184 -
1185 - rrddim_add(st, "read", NULL, 1, 1, RRDDIM_INCREMENTAL);
1186 - rrddim_add(st, "write", NULL, -1, 1, RRDDIM_INCREMENTAL);
1187 - }
1188 - else rrdset_next(st);
1189 -
1190 - rrddim_set(st, "read", cg->throttle_io_serviced.Read);
1191 - rrddim_set(st, "write", cg->throttle_io_serviced.Write);
1192 - rrdset_done(st);
1193 - }
1194 -
1195 - if(cg->io_queued.updated) {
1196 - st = rrdset_find_bytype(type, "queued_ops");
1197 - if(!st) {
1198 - snprintfz(title, CHART_TITLE_MAX, "Queued I/O Operations (all disks) for cgroup %s", cg->chart_title);
1199 - st = rrdset_create(type, "queued_ops", NULL, "disk", "cgroup.queued_ops", title, "operations", 42000,
1200 - update_every, RRDSET_TYPE_LINE);
1201 -
1202 - rrddim_add(st, "read", NULL, 1, 1, RRDDIM_ABSOLUTE);
1203 - rrddim_add(st, "write", NULL, -1, 1, RRDDIM_ABSOLUTE);
1204 - }
1205 - else rrdset_next(st);
1206 -
1207 - rrddim_set(st, "read", cg->io_queued.Read);
1208 - rrddim_set(st, "write", cg->io_queued.Write);
1209 - rrdset_done(st);
1210 - }
1211 -
1212 - if(cg->io_merged.updated && cg->io_merged.Read + cg->io_merged.Write > 0) {
1213 - st = rrdset_find_bytype(type, "merged_ops");
1214 - if(!st) {
1215 - snprintfz(title, CHART_TITLE_MAX, "Merged I/O Operations (all disks) for cgroup %s", cg->chart_title);
1216 - st = rrdset_create(type, "merged_ops", NULL, "disk", "cgroup.merged_ops", title, "operations/s", 42100,
1217 - update_every, RRDSET_TYPE_LINE);
1218 -
1219 - rrddim_add(st, "read", NULL, 1, 1024, RRDDIM_INCREMENTAL);
1220 - rrddim_add(st, "write", NULL, -1, 1024, RRDDIM_INCREMENTAL);
1221 - }
1222 - else rrdset_next(st);
1223 -
1224 - rrddim_set(st, "read", cg->io_merged.Read);
1225 - rrddim_set(st, "write", cg->io_merged.Write);
1226 - rrdset_done(st);
1227 - }
1228 - }
1229 -
1230 - debug(D_CGROUP, "done updating cgroups charts");
988 + debug(D_CGROUP, "updating cgroups charts");
989 +
990 + char type[RRD_ID_LENGTH_MAX + 1];
991 + char title[CHART_TITLE_MAX + 1];
992 +
993 + struct cgroup *cg;
994 + RRDSET *st;
995 +
996 + for(cg = cgroup_root; cg ; cg = cg->next) {
997 + if(!cg->available || !cg->enabled)
998 + continue;
999 +
1000 + if(cg->id[0] == '\0')
1001 + strcpy(type, "cgroup_root");
1002 + else if(cg->id[0] == '/')
1003 + snprintfz(type, RRD_ID_LENGTH_MAX, "cgroup_%s", cg->chart_id);
1004 + else
1005 + snprintfz(type, RRD_ID_LENGTH_MAX, "cgroup_%s", cg->chart_id);
1006 +
1007 + netdata_fix_chart_id(type);
1008 +
1009 + if(cg->cpuacct_stat.updated) {
1010 + st = rrdset_find_bytype(type, "cpu");
1011 + if(!st) {
1012 + snprintfz(title, CHART_TITLE_MAX, "CPU Usage for cgroup %s", cg->chart_title);
1013 + st = rrdset_create(type, "cpu", NULL, "cpu", "cgroup.cpu", title, "%", 40000, update_every, RRDSET_TYPE_STACKED);
1014 +
1015 + rrddim_add(st, "user", NULL, 100, hz, RRDDIM_INCREMENTAL);
1016 + rrddim_add(st, "system", NULL, 100, hz, RRDDIM_INCREMENTAL);
1017 + }
1018 + else rrdset_next(st);
1019 +
1020 + rrddim_set(st, "user", cg->cpuacct_stat.user);
1021 + rrddim_set(st, "system", cg->cpuacct_stat.system);
1022 + rrdset_done(st);
1023 + }
1024 +
1025 + if(cg->cpuacct_usage.updated) {
1026 + char id[RRD_ID_LENGTH_MAX + 1];
1027 + unsigned int i;
1028 +
1029 + st = rrdset_find_bytype(type, "cpu_per_core");
1030 + if(!st) {
1031 + snprintfz(title, CHART_TITLE_MAX, "CPU Usage Per Core for cgroup %s", cg->chart_title);
1032 + st = rrdset_create(type, "cpu_per_core", NULL, "cpu", "cgroup.cpu_per_core", title, "%", 40100, update_every, RRDSET_TYPE_STACKED);
1033 +
1034 + for(i = 0; i < cg->cpuacct_usage.cpus ;i++) {
1035 + snprintfz(id, CHART_TITLE_MAX, "cpu%u", i);
1036 + rrddim_add(st, id, NULL, 100, 1000000000, RRDDIM_INCREMENTAL);
1037 + }
1038 + }
1039 + else rrdset_next(st);
1040 +
1041 + for(i = 0; i < cg->cpuacct_usage.cpus ;i++) {
1042 + snprintfz(id, CHART_TITLE_MAX, "cpu%u", i);
1043 + rrddim_set(st, id, cg->cpuacct_usage.cpu_percpu[i]);
1044 + }
1045 + rrdset_done(st);
1046 + }
1047 +
1048 + if(cg->memory.updated) {
1049 + if(cg->memory.cache + cg->memory.rss + cg->memory.rss_huge + cg->memory.mapped_file > 0) {
1050 + st = rrdset_find_bytype(type, "mem");
1051 + if(!st) {
1052 + snprintfz(title, CHART_TITLE_MAX, "Memory Usage for cgroup %s", cg->chart_title);
1053 + st = rrdset_create(type, "mem", NULL, "mem", "cgroup.mem", title, "MB", 40200, update_every,
1054 + RRDSET_TYPE_STACKED);
1055 +
1056 + rrddim_add(st, "cache", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
1057 + rrddim_add(st, "rss", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
1058 + if(cg->memory.has_dirty_swap)
1059 + rrddim_add(st, "swap", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
1060 + rrddim_add(st, "rss_huge", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
1061 + rrddim_add(st, "mapped_file", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
1062 + }
1063 + else rrdset_next(st);
1064 +
1065 + rrddim_set(st, "cache", cg->memory.cache);
1066 + rrddim_set(st, "rss", cg->memory.rss);
1067 + if(cg->memory.has_dirty_swap)
1068 + rrddim_set(st, "swap", cg->memory.swap);
1069 + rrddim_set(st, "rss_huge", cg->memory.rss_huge);
1070 + rrddim_set(st, "mapped_file", cg->memory.mapped_file);
1071 + rrdset_done(st);
1072 + }
1073 +
1074 + st = rrdset_find_bytype(type, "writeback");
1075 + if(!st) {
1076 + snprintfz(title, CHART_TITLE_MAX, "Writeback Memory for cgroup %s", cg->chart_title);
1077 + st = rrdset_create(type, "writeback", NULL, "mem", "cgroup.writeback", title, "MB", 40300,
1078 + update_every, RRDSET_TYPE_AREA);
1079 +
1080 + if(cg->memory.has_dirty_swap)
1081 + rrddim_add(st, "dirty", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
1082 + rrddim_add(st, "writeback", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
1083 + }
1084 + else rrdset_next(st);
1085 +
1086 + if(cg->memory.has_dirty_swap)
1087 + rrddim_set(st, "dirty", cg->memory.dirty);
1088 + rrddim_set(st, "writeback", cg->memory.writeback);
1089 + rrdset_done(st);
1090 +
1091 + if(cg->memory.pgpgin + cg->memory.pgpgout > 0) {
1092 + st = rrdset_find_bytype(type, "mem_activity");
1093 + if(!st) {
1094 + snprintfz(title, CHART_TITLE_MAX, "Memory Activity for cgroup %s", cg->chart_title);
1095 + st = rrdset_create(type, "mem_activity", NULL, "mem", "cgroup.mem_activity", title, "MB/s",
1096 + 40400, update_every, RRDSET_TYPE_LINE);
1097 +
1098 + rrddim_add(st, "pgpgin", "in", sysconf(_SC_PAGESIZE), 1024 * 1024, RRDDIM_INCREMENTAL);
1099 + rrddim_add(st, "pgpgout", "out", -sysconf(_SC_PAGESIZE), 1024 * 1024, RRDDIM_INCREMENTAL);
1100 + }
1101 + else rrdset_next(st);
1102 +
1103 + rrddim_set(st, "pgpgin", cg->memory.pgpgin);
1104 + rrddim_set(st, "pgpgout", cg->memory.pgpgout);
1105 + rrdset_done(st);
1106 + }
1107 +
1108 + if(cg->memory.pgfault + cg->memory.pgmajfault > 0) {
1109 + st = rrdset_find_bytype(type, "pgfaults");
1110 + if(!st) {
1111 + snprintfz(title, CHART_TITLE_MAX, "Memory Page Faults for cgroup %s", cg->chart_title);
1112 + st = rrdset_create(type, "pgfaults", NULL, "mem", "cgroup.pgfaults", title, "MB/s", 40500,
1113 + update_every, RRDSET_TYPE_LINE);
1114 +
1115 + rrddim_add(st, "pgfault", NULL, sysconf(_SC_PAGESIZE), 1024 * 1024, RRDDIM_INCREMENTAL);
1116 + rrddim_add(st, "pgmajfault", "swap", -sysconf(_SC_PAGESIZE), 1024 * 1024, RRDDIM_INCREMENTAL);
1117 + }
1118 + else rrdset_next(st);
1119 +
1120 + rrddim_set(st, "pgfault", cg->memory.pgfault);
1121 + rrddim_set(st, "pgmajfault", cg->memory.pgmajfault);
1122 + rrdset_done(st);
1123 + }
1124 + }
1125 +
1126 + if(cg->io_service_bytes.updated && cg->io_service_bytes.Read + cg->io_service_bytes.Write > 0) {
1127 + st = rrdset_find_bytype(type, "io");
1128 + if(!st) {
1129 + snprintfz(title, CHART_TITLE_MAX, "I/O Bandwidth (all disks) for cgroup %s", cg->chart_title);
1130 + st = rrdset_create(type, "io", NULL, "disk", "cgroup.io", title, "KB/s", 41200,
1131 + update_every, RRDSET_TYPE_LINE);
1132 +
1133 + rrddim_add(st, "read", NULL, 1, 1024, RRDDIM_INCREMENTAL);
1134 + rrddim_add(st, "write", NULL, -1, 1024, RRDDIM_INCREMENTAL);
1135 + }
1136 + else rrdset_next(st);
1137 +
1138 + rrddim_set(st, "read", cg->io_service_bytes.Read);
1139 + rrddim_set(st, "write", cg->io_service_bytes.Write);
1140 + rrdset_done(st);
1141 + }
1142 +
1143 + if(cg->io_serviced.updated && cg->io_serviced.Read + cg->io_serviced.Write > 0) {
1144 + st = rrdset_find_bytype(type, "serviced_ops");
1145 + if(!st) {
1146 + snprintfz(title, CHART_TITLE_MAX, "Serviced I/O Operations (all disks) for cgroup %s", cg->chart_title);
1147 + st = rrdset_create(type, "serviced_ops", NULL, "disk", "cgroup.serviced_ops", title, "operations/s", 41200,
1148 + update_every, RRDSET_TYPE_LINE);
1149 +
1150 + rrddim_add(st, "read", NULL, 1, 1, RRDDIM_INCREMENTAL);
1151 + rrddim_add(st, "write", NULL, -1, 1, RRDDIM_INCREMENTAL);
1152 + }
1153 + else rrdset_next(st);
1154 +
1155 + rrddim_set(st, "read", cg->io_serviced.Read);
1156 + rrddim_set(st, "write", cg->io_serviced.Write);
1157 + rrdset_done(st);
1158 + }
1159 +
1160 + if(cg->throttle_io_service_bytes.updated && cg->throttle_io_service_bytes.Read + cg->throttle_io_service_bytes.Write > 0) {
1161 + st = rrdset_find_bytype(type, "io");
1162 + if(!st) {
1163 + snprintfz(title, CHART_TITLE_MAX, "Throttle I/O Bandwidth (all disks) for cgroup %s", cg->chart_title);
1164 + st = rrdset_create(type, "io", NULL, "disk", "cgroup.io", title, "KB/s", 41200,
1165 + update_every, RRDSET_TYPE_LINE);
1166 +
1167 + rrddim_add(st, "read", NULL, 1, 1024, RRDDIM_INCREMENTAL);
1168 + rrddim_add(st, "write", NULL, -1, 1024, RRDDIM_INCREMENTAL);
1169 + }
1170 + else rrdset_next(st);
1171 +
1172 + rrddim_set(st, "read", cg->throttle_io_service_bytes.Read);
1173 + rrddim_set(st, "write", cg->throttle_io_service_bytes.Write);
1174 + rrdset_done(st);
1175 + }
1176 +
1177 +
1178 + if(cg->throttle_io_serviced.updated && cg->throttle_io_serviced.Read + cg->throttle_io_serviced.Write > 0) {
1179 + st = rrdset_find_bytype(type, "throttle_serviced_ops");
1180 + if(!st) {
1181 + snprintfz(title, CHART_TITLE_MAX, "Throttle Serviced I/O Operations (all disks) for cgroup %s", cg->chart_title);
1182 + st = rrdset_create(type, "throttle_serviced_ops", NULL, "disk", "cgroup.throttle_serviced_ops", title, "operations/s", 41200,
1183 + update_every, RRDSET_TYPE_LINE);
1184 +
1185 + rrddim_add(st, "read", NULL, 1, 1, RRDDIM_INCREMENTAL);
1186 + rrddim_add(st, "write", NULL, -1, 1, RRDDIM_INCREMENTAL);
1187 + }
1188 + else rrdset_next(st);
1189 +
1190 + rrddim_set(st, "read", cg->throttle_io_serviced.Read);
1191 + rrddim_set(st, "write", cg->throttle_io_serviced.Write);
1192 + rrdset_done(st);
1193 + }
1194 +
1195 + if(cg->io_queued.updated) {
1196 + st = rrdset_find_bytype(type, "queued_ops");
1197 + if(!st) {
1198 + snprintfz(title, CHART_TITLE_MAX, "Queued I/O Operations (all disks) for cgroup %s", cg->chart_title);
1199 + st = rrdset_create(type, "queued_ops", NULL, "disk", "cgroup.queued_ops", title, "operations", 42000,
1200 + update_every, RRDSET_TYPE_LINE);
1201 +
1202 + rrddim_add(st, "read", NULL, 1, 1, RRDDIM_ABSOLUTE);
1203 + rrddim_add(st, "write", NULL, -1, 1, RRDDIM_ABSOLUTE);
1204 + }
1205 + else rrdset_next(st);
1206 +
1207 + rrddim_set(st, "read", cg->io_queued.Read);
1208 + rrddim_set(st, "write", cg->io_queued.Write);
1209 + rrdset_done(st);
1210 + }
1211 +
1212 + if(cg->io_merged.updated && cg->io_merged.Read + cg->io_merged.Write > 0) {
1213 + st = rrdset_find_bytype(type, "merged_ops");
1214 + if(!st) {
1215 + snprintfz(title, CHART_TITLE_MAX, "Merged I/O Operations (all disks) for cgroup %s", cg->chart_title);
1216 + st = rrdset_create(type, "merged_ops", NULL, "disk", "cgroup.merged_ops", title, "operations/s", 42100,
1217 + update_every, RRDSET_TYPE_LINE);
1218 +
1219 + rrddim_add(st, "read", NULL, 1, 1024, RRDDIM_INCREMENTAL);
1220 + rrddim_add(st, "write", NULL, -1, 1024, RRDDIM_INCREMENTAL);
1221 + }
1222 + else rrdset_next(st);
1223 +
1224 + rrddim_set(st, "read", cg->io_merged.Read);
1225 + rrddim_set(st, "write", cg->io_merged.Write);
1226 + rrdset_done(st);
1227 + }
1228 + }
1229 +
1230 + debug(D_CGROUP, "done updating cgroups charts");
1231 }
1232
1233 // ----------------------------------------------------------------------------
1234 // cgroups main
1235
1236 int do_sys_fs_cgroup(int update_every, unsigned long long dt) {
1237 - (void)dt;
1237 + (void)dt;
1238
1239 - static int cgroup_global_config_read = 0;
1240 - static time_t last_run = 0;
1241 - time_t now = time(NULL);
1239 + static int cgroup_global_config_read = 0;
1240 + static time_t last_run = 0;
1241 + time_t now = time(NULL);
1242
1243 - if(unlikely(!cgroup_global_config_read)) {
1244 - read_cgroup_plugin_configuration();
1245 - cgroup_global_config_read = 1;
1246 - }
1243 + if(unlikely(!cgroup_global_config_read)) {
1244 + read_cgroup_plugin_configuration();
1245 + cgroup_global_config_read = 1;
1246 + }
1247
1248 - if(unlikely(cgroup_enable_new_cgroups_detected_at_runtime && now - last_run > cgroup_check_for_new_every)) {
1249 - find_all_cgroups();
1250 - last_run = now;
1251 - }
1248 + if(unlikely(cgroup_enable_new_cgroups_detected_at_runtime && now - last_run > cgroup_check_for_new_every)) {
1249 + find_all_cgroups();
1250 + last_run = now;
1251 + }
1252
1253 - read_all_cgroups(cgroup_root);
1254 - update_cgroup_charts(update_every);
1253 + read_all_cgroups(cgroup_root);
1254 + update_cgroup_charts(update_every);
1255
1256 - return 0;
1256 + return 0;
1257 }
1258
1259 void *cgroups_main(void *ptr)
1260 {
1261 - if(ptr) { ; }
1261 + if(ptr) { ; }
1262
1263 - info("CGROUP Plugin thread created with task id %d", gettid());
1263 + info("CGROUP Plugin thread created with task id %d", gettid());
1264
1265 - if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
1266 - error("Cannot set pthread cancel type to DEFERRED.");
1265 + if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
1266 + error("Cannot set pthread cancel type to DEFERRED.");
1267
1268 - if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
1269 - error("Cannot set pthread cancel state to ENABLE.");
1268 + if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
1269 + error("Cannot set pthread cancel state to ENABLE.");
1270
1271 - struct rusage thread;
1271 + struct rusage thread;
1272
1273 - // when ZERO, attempt to do it
1274 - int vdo_sys_fs_cgroup = 0;
1275 - int vdo_cpu_netdata = !config_get_boolean("plugin:cgroups", "cgroups plugin resources", 1);
1273 + // when ZERO, attempt to do it
1274 + int vdo_sys_fs_cgroup = 0;
1275 + int vdo_cpu_netdata = !config_get_boolean("plugin:cgroups", "cgroups plugin resources", 1);
1276
1277 - // keep track of the time each module was called
1278 - unsigned long long sutime_sys_fs_cgroup = 0ULL;
1277 + // keep track of the time each module was called
1278 + unsigned long long sutime_sys_fs_cgroup = 0ULL;
1279
1280 - // the next time we will run - aligned properly
1281 - unsigned long long sunext = (time(NULL) - (time(NULL) % rrd_update_every) + rrd_update_every) * 1000000ULL;
1282 - unsigned long long sunow;
1280 + // the next time we will run - aligned properly
1281 + unsigned long long sunext = (time(NULL) - (time(NULL) % rrd_update_every) + rrd_update_every) * 1000000ULL;
1282 + unsigned long long sunow;
1283
1284 - RRDSET *stcpu_thread = NULL;
1284 + RRDSET *stcpu_thread = NULL;
1285
1286 - for(;1;) {
1287 - if(unlikely(netdata_exit)) break;
1286 + for(;1;) {
1287 + if(unlikely(netdata_exit)) break;
1288
1289 - // delay until it is our time to run
1290 - while((sunow = time_usec()) < sunext)
1291 - sleep_usec(sunext - sunow);
1289 + // delay until it is our time to run
1290 + while((sunow = time_usec()) < sunext)
1291 + sleep_usec(sunext - sunow);
1292
1293 - // find the next time we need to run
1294 - while(time_usec() > sunext)
1295 - sunext += rrd_update_every * 1000000ULL;
1293 + // find the next time we need to run
1294 + while(time_usec() > sunext)
1295 + sunext += rrd_update_every * 1000000ULL;
1296
1297 - if(unlikely(netdata_exit)) break;
1297 + if(unlikely(netdata_exit)) break;
1298
1299 - // BEGIN -- the job to be done
1299 + // BEGIN -- the job to be done
1300
1301 - if(!vdo_sys_fs_cgroup) {
1302 - debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_sys_fs_cgroup().");
1303 - sunow = time_usec();
1304 - vdo_sys_fs_cgroup = do_sys_fs_cgroup(rrd_update_every, (sutime_sys_fs_cgroup > 0)?sunow - sutime_sys_fs_cgroup:0ULL);
1305 - sutime_sys_fs_cgroup = sunow;
1306 - }
1307 - if(unlikely(netdata_exit)) break;
1301 + if(!vdo_sys_fs_cgroup) {
1302 + debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_sys_fs_cgroup().");
1303 + sunow = time_usec();
1304 + vdo_sys_fs_cgroup = do_sys_fs_cgroup(rrd_update_every, (sutime_sys_fs_cgroup > 0)?sunow - sutime_sys_fs_cgroup:0ULL);
1305 + sutime_sys_fs_cgroup = sunow;
1306 + }
1307 + if(unlikely(netdata_exit)) break;
1308
1309 - // END -- the job is done
1309 + // END -- the job is done
1310
1311 - // --------------------------------------------------------------------
1311 + // --------------------------------------------------------------------
1312
1313 - if(!vdo_cpu_netdata) {
1314 - getrusage(RUSAGE_THREAD, &thread);
1313 + if(!vdo_cpu_netdata) {
1314 + getrusage(RUSAGE_THREAD, &thread);
1315
1316 - if(!stcpu_thread) stcpu_thread = rrdset_find("netdata.plugin_cgroups_cpu");
1317 - if(!stcpu_thread) {
1318 - stcpu_thread = rrdset_create("netdata", "plugin_cgroups_cpu", NULL, "proc.internal", NULL, "NetData CGroups Plugin CPU usage", "milliseconds/s", 132000, rrd_update_every, RRDSET_TYPE_STACKED);
1316 + if(!stcpu_thread) stcpu_thread = rrdset_find("netdata.plugin_cgroups_cpu");
1317 + if(!stcpu_thread) {
1318 + stcpu_thread = rrdset_create("netdata", "plugin_cgroups_cpu", NULL, "proc.internal", NULL, "NetData CGroups Plugin CPU usage", "milliseconds/s", 132000, rrd_update_every, RRDSET_TYPE_STACKED);
1319
1320 - rrddim_add(stcpu_thread, "user", NULL, 1, 1000, RRDDIM_INCREMENTAL);
1321 - rrddim_add(stcpu_thread, "system", NULL, 1, 1000, RRDDIM_INCREMENTAL);
1322 - }
1323 - else rrdset_next(stcpu_thread);
1320 + rrddim_add(stcpu_thread, "user", NULL, 1, 1000, RRDDIM_INCREMENTAL);
1321 + rrddim_add(stcpu_thread, "system", NULL, 1, 1000, RRDDIM_INCREMENTAL);
1322 + }
1323 + else rrdset_next(stcpu_thread);
1324
1325 - rrddim_set(stcpu_thread, "user" , thread.ru_utime.tv_sec * 1000000ULL + thread.ru_utime.tv_usec);
1326 - rrddim_set(stcpu_thread, "system", thread.ru_stime.tv_sec * 1000000ULL + thread.ru_stime.tv_usec);
1327 - rrdset_done(stcpu_thread);
1328 - }
1329 - }
1325 + rrddim_set(stcpu_thread, "user" , thread.ru_utime.tv_sec * 1000000ULL + thread.ru_utime.tv_usec);
1326 + rrddim_set(stcpu_thread, "system", thread.ru_stime.tv_sec * 1000000ULL + thread.ru_stime.tv_usec);
1327 + rrdset_done(stcpu_thread);
1328 + }
1329 + }
1330
1331 - pthread_exit(NULL);
1332 - return NULL;
1331 + pthread_exit(NULL);
1332 + return NULL;
1333 }
src/sys_kernel_mm_ksm.c
+98 -98
@@ -1,8 +1,8 @@
1 #include "common.h"
2
3 typedef struct ksm_name_value {
4 - char filename[FILENAME_MAX + 1];
5 - unsigned long long value;
4 + char filename[FILENAME_MAX + 1];
5 + unsigned long long value;
6 } KSM_NAME_VALUE;
7
8 #define PAGES_SHARED 0
@@ -12,127 +12,127 @@ typedef struct ksm_name_value {
12 #define PAGES_TO_SCAN 4
13
14 KSM_NAME_VALUE values[] = {
15 - [PAGES_SHARED] = { "/sys/kernel/mm/ksm/pages_shared", 0ULL },
16 - [PAGES_SHARING] = { "/sys/kernel/mm/ksm/pages_sharing", 0ULL },
17 - [PAGES_UNSHARED] = { "/sys/kernel/mm/ksm/pages_unshared", 0ULL },
18 - [PAGES_VOLATILE] = { "/sys/kernel/mm/ksm/pages_volatile", 0ULL },
19 - [PAGES_TO_SCAN] = { "/sys/kernel/mm/ksm/pages_to_scan", 0ULL },
15 + [PAGES_SHARED] = { "/sys/kernel/mm/ksm/pages_shared", 0ULL },
16 + [PAGES_SHARING] = { "/sys/kernel/mm/ksm/pages_sharing", 0ULL },
17 + [PAGES_UNSHARED] = { "/sys/kernel/mm/ksm/pages_unshared", 0ULL },
18 + [PAGES_VOLATILE] = { "/sys/kernel/mm/ksm/pages_volatile", 0ULL },
19 + [PAGES_TO_SCAN] = { "/sys/kernel/mm/ksm/pages_to_scan", 0ULL },
20 };
21
22 int do_sys_kernel_mm_ksm(int update_every, unsigned long long dt) {
23 - static procfile *ff_pages_shared = NULL, *ff_pages_sharing = NULL, *ff_pages_unshared = NULL, *ff_pages_volatile = NULL, *ff_pages_to_scan = NULL;
24 - static long page_size = -1;
23 + static procfile *ff_pages_shared = NULL, *ff_pages_sharing = NULL, *ff_pages_unshared = NULL, *ff_pages_volatile = NULL, *ff_pages_to_scan = NULL;
24 + static long page_size = -1;
25
26 - if(dt) {};
27 -
28 - if(page_size == -1)
29 - page_size = sysconf(_SC_PAGESIZE);
30 -
31 - if(!ff_pages_shared) {
32 - snprintfz(values[PAGES_SHARED].filename, FILENAME_MAX, "%s%s", global_host_prefix, "/sys/kernel/mm/ksm/pages_shared");
33 - snprintfz(values[PAGES_SHARED].filename, FILENAME_MAX, "%s", config_get("plugin:proc:/sys/kernel/mm/ksm", "/sys/kernel/mm/ksm/pages_shared", values[PAGES_SHARED].filename));
34 - ff_pages_shared = procfile_open(values[PAGES_SHARED].filename, " \t:", PROCFILE_FLAG_DEFAULT);
35 - }
26 + if(dt) {};
27 +
28 + if(page_size == -1)
29 + page_size = sysconf(_SC_PAGESIZE);
30 +
31 + if(!ff_pages_shared) {
32 + snprintfz(values[PAGES_SHARED].filename, FILENAME_MAX, "%s%s", global_host_prefix, "/sys/kernel/mm/ksm/pages_shared");
33 + snprintfz(values[PAGES_SHARED].filename, FILENAME_MAX, "%s", config_get("plugin:proc:/sys/kernel/mm/ksm", "/sys/kernel/mm/ksm/pages_shared", values[PAGES_SHARED].filename));
34 + ff_pages_shared = procfile_open(values[PAGES_SHARED].filename, " \t:", PROCFILE_FLAG_DEFAULT);
35 + }
36
37 - if(!ff_pages_sharing) {
38 - snprintfz(values[PAGES_SHARING].filename, FILENAME_MAX, "%s%s", global_host_prefix, "/sys/kernel/mm/ksm/pages_sharing");
39 - snprintfz(values[PAGES_SHARING].filename, FILENAME_MAX, "%s", config_get("plugin:proc:/sys/kernel/mm/ksm", "/sys/kernel/mm/ksm/pages_sharing", values[PAGES_SHARING].filename));
40 - ff_pages_sharing = procfile_open(values[PAGES_SHARING].filename, " \t:", PROCFILE_FLAG_DEFAULT);
41 - }
37 + if(!ff_pages_sharing) {
38 + snprintfz(values[PAGES_SHARING].filename, FILENAME_MAX, "%s%s", global_host_prefix, "/sys/kernel/mm/ksm/pages_sharing");
39 + snprintfz(values[PAGES_SHARING].filename, FILENAME_MAX, "%s", config_get("plugin:proc:/sys/kernel/mm/ksm", "/sys/kernel/mm/ksm/pages_sharing", values[PAGES_SHARING].filename));
40 + ff_pages_sharing = procfile_open(values[PAGES_SHARING].filename, " \t:", PROCFILE_FLAG_DEFAULT);
41 + }
42
43 - if(!ff_pages_unshared) {
44 - snprintfz(values[PAGES_UNSHARED].filename, FILENAME_MAX, "%s%s", global_host_prefix, "/sys/kernel/mm/ksm/pages_unshared");
45 - snprintfz(values[PAGES_UNSHARED].filename, FILENAME_MAX, "%s", config_get("plugin:proc:/sys/kernel/mm/ksm", "/sys/kernel/mm/ksm/pages_unshared", values[PAGES_UNSHARED].filename));
46 - ff_pages_unshared = procfile_open(values[PAGES_UNSHARED].filename, " \t:", PROCFILE_FLAG_DEFAULT);
47 - }
43 + if(!ff_pages_unshared) {
44 + snprintfz(values[PAGES_UNSHARED].filename, FILENAME_MAX, "%s%s", global_host_prefix, "/sys/kernel/mm/ksm/pages_unshared");
45 + snprintfz(values[PAGES_UNSHARED].filename, FILENAME_MAX, "%s", config_get("plugin:proc:/sys/kernel/mm/ksm", "/sys/kernel/mm/ksm/pages_unshared", values[PAGES_UNSHARED].filename));
46 + ff_pages_unshared = procfile_open(values[PAGES_UNSHARED].filename, " \t:", PROCFILE_FLAG_DEFAULT);
47 + }
48
49 - if(!ff_pages_volatile) {
50 - snprintfz(values[PAGES_VOLATILE].filename, FILENAME_MAX, "%s%s", global_host_prefix, "/sys/kernel/mm/ksm/pages_volatile");
51 - snprintfz(values[PAGES_VOLATILE].filename, FILENAME_MAX, "%s", config_get("plugin:proc:/sys/kernel/mm/ksm", "/sys/kernel/mm/ksm/pages_volatile", values[PAGES_VOLATILE].filename));
52 - ff_pages_volatile = procfile_open(values[PAGES_VOLATILE].filename, " \t:", PROCFILE_FLAG_DEFAULT);
53 - }
49 + if(!ff_pages_volatile) {
50 + snprintfz(values[PAGES_VOLATILE].filename, FILENAME_MAX, "%s%s", global_host_prefix, "/sys/kernel/mm/ksm/pages_volatile");
51 + snprintfz(values[PAGES_VOLATILE].filename, FILENAME_MAX, "%s", config_get("plugin:proc:/sys/kernel/mm/ksm", "/sys/kernel/mm/ksm/pages_volatile", values[PAGES_VOLATILE].filename));
52 + ff_pages_volatile = procfile_open(values[PAGES_VOLATILE].filename, " \t:", PROCFILE_FLAG_DEFAULT);
53 + }
54
55 - if(!ff_pages_to_scan) {
56 - snprintfz(values[PAGES_TO_SCAN].filename, FILENAME_MAX, "%s%s", global_host_prefix, "/sys/kernel/mm/ksm/pages_to_scan");
57 - snprintfz(values[PAGES_TO_SCAN].filename, FILENAME_MAX, "%s", config_get("plugin:proc:/sys/kernel/mm/ksm", "/sys/kernel/mm/ksm/pages_to_scan", values[PAGES_TO_SCAN].filename));
58 - ff_pages_to_scan = procfile_open(values[PAGES_TO_SCAN].filename, " \t:", PROCFILE_FLAG_DEFAULT);
59 - }
55 + if(!ff_pages_to_scan) {
56 + snprintfz(values[PAGES_TO_SCAN].filename, FILENAME_MAX, "%s%s", global_host_prefix, "/sys/kernel/mm/ksm/pages_to_scan");
57 + snprintfz(values[PAGES_TO_SCAN].filename, FILENAME_MAX, "%s", config_get("plugin:proc:/sys/kernel/mm/ksm", "/sys/kernel/mm/ksm/pages_to_scan", values[PAGES_TO_SCAN].filename));
58 + ff_pages_to_scan = procfile_open(values[PAGES_TO_SCAN].filename, " \t:", PROCFILE_FLAG_DEFAULT);
59 + }
60
61 - if(!ff_pages_shared || !ff_pages_sharing || !ff_pages_unshared || !ff_pages_volatile || !ff_pages_to_scan) return 1;
61 + if(!ff_pages_shared || !ff_pages_sharing || !ff_pages_unshared || !ff_pages_volatile || !ff_pages_to_scan) return 1;
62
63 - unsigned long long pages_shared = 0, pages_sharing = 0, pages_unshared = 0, pages_volatile = 0, pages_to_scan = 0, offered = 0, saved = 0;
63 + unsigned long long pages_shared = 0, pages_sharing = 0, pages_unshared = 0, pages_volatile = 0, pages_to_scan = 0, offered = 0, saved = 0;
64
65 - ff_pages_shared = procfile_readall(ff_pages_shared);
66 - if(!ff_pages_shared) return 0; // we return 0, so that we will retry to open it next time
67 - pages_shared = strtoull(procfile_lineword(ff_pages_shared, 0, 0), NULL, 10);
65 + ff_pages_shared = procfile_readall(ff_pages_shared);
66 + if(!ff_pages_shared) return 0; // we return 0, so that we will retry to open it next time
67 + pages_shared = strtoull(procfile_lineword(ff_pages_shared, 0, 0), NULL, 10);
68
69 - ff_pages_sharing = procfile_readall(ff_pages_sharing);
70 - if(!ff_pages_sharing) return 0; // we return 0, so that we will retry to open it next time
71 - pages_sharing = strtoull(procfile_lineword(ff_pages_sharing, 0, 0), NULL, 10);
69 + ff_pages_sharing = procfile_readall(ff_pages_sharing);
70 + if(!ff_pages_sharing) return 0; // we return 0, so that we will retry to open it next time
71 + pages_sharing = strtoull(procfile_lineword(ff_pages_sharing, 0, 0), NULL, 10);
72
73 - ff_pages_unshared = procfile_readall(ff_pages_unshared);
74 - if(!ff_pages_unshared) return 0; // we return 0, so that we will retry to open it next time
75 - pages_unshared = strtoull(procfile_lineword(ff_pages_unshared, 0, 0), NULL, 10);
73 + ff_pages_unshared = procfile_readall(ff_pages_unshared);
74 + if(!ff_pages_unshared) return 0; // we return 0, so that we will retry to open it next time
75 + pages_unshared = strtoull(procfile_lineword(ff_pages_unshared, 0, 0), NULL, 10);
76
77 - ff_pages_volatile = procfile_readall(ff_pages_volatile);
78 - if(!ff_pages_volatile) return 0; // we return 0, so that we will retry to open it next time
79 - pages_volatile = strtoull(procfile_lineword(ff_pages_volatile, 0, 0), NULL, 10);
77 + ff_pages_volatile = procfile_readall(ff_pages_volatile);
78 + if(!ff_pages_volatile) return 0; // we return 0, so that we will retry to open it next time
79 + pages_volatile = strtoull(procfile_lineword(ff_pages_volatile, 0, 0), NULL, 10);
80
81 - ff_pages_to_scan = procfile_readall(ff_pages_to_scan);
82 - if(!ff_pages_to_scan) return 0; // we return 0, so that we will retry to open it next time
83 - pages_to_scan = strtoull(procfile_lineword(ff_pages_to_scan, 0, 0), NULL, 10);
81 + ff_pages_to_scan = procfile_readall(ff_pages_to_scan);
82 + if(!ff_pages_to_scan) return 0; // we return 0, so that we will retry to open it next time
83 + pages_to_scan = strtoull(procfile_lineword(ff_pages_to_scan, 0, 0), NULL, 10);
84
85 - offered = pages_sharing + pages_shared + pages_unshared + pages_volatile;
86 - saved = pages_sharing - pages_shared;
85 + offered = pages_sharing + pages_shared + pages_unshared + pages_volatile;
86 + saved = pages_sharing - pages_shared;
87
88 - if(!offered || !pages_to_scan) return 0;
88 + if(!offered || !pages_to_scan) return 0;
89
90 - RRDSET *st;
90 + RRDSET *st;
91
92 - // --------------------------------------------------------------------
92 + // --------------------------------------------------------------------
93
94 - st = rrdset_find("mem.ksm");
95 - if(!st) {
96 - st = rrdset_create("mem", "ksm", NULL, "ksm", NULL, "Kernel Same Page Merging", "MB", 5000, update_every, RRDSET_TYPE_AREA);
94 + st = rrdset_find("mem.ksm");
95 + if(!st) {
96 + st = rrdset_create("mem", "ksm", NULL, "ksm", NULL, "Kernel Same Page Merging", "MB", 5000, update_every, RRDSET_TYPE_AREA);
97
98 - rrddim_add(st, "shared", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
99 - rrddim_add(st, "unshared", NULL, -1, 1024 * 1024, RRDDIM_ABSOLUTE);
100 - rrddim_add(st, "sharing", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
101 - rrddim_add(st, "volatile", NULL, -1, 1024 * 1024, RRDDIM_ABSOLUTE);
102 - rrddim_add(st, "to_scan", "to scan", -1, 1024 * 1024, RRDDIM_ABSOLUTE);
103 - }
104 - else rrdset_next(st);
98 + rrddim_add(st, "shared", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
99 + rrddim_add(st, "unshared", NULL, -1, 1024 * 1024, RRDDIM_ABSOLUTE);
100 + rrddim_add(st, "sharing", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
101 + rrddim_add(st, "volatile", NULL, -1, 1024 * 1024, RRDDIM_ABSOLUTE);
102 + rrddim_add(st, "to_scan", "to scan", -1, 1024 * 1024, RRDDIM_ABSOLUTE);
103 + }
104 + else rrdset_next(st);
105
106 - rrddim_set(st, "shared", pages_shared * page_size);
107 - rrddim_set(st, "unshared", pages_unshared * page_size);
108 - rrddim_set(st, "sharing", pages_sharing * page_size);
109 - rrddim_set(st, "volatile", pages_volatile * page_size);
110 - rrddim_set(st, "to_scan", pages_to_scan * page_size);
111 - rrdset_done(st);
106 + rrddim_set(st, "shared", pages_shared * page_size);
107 + rrddim_set(st, "unshared", pages_unshared * page_size);
108 + rrddim_set(st, "sharing", pages_sharing * page_size);
109 + rrddim_set(st, "volatile", pages_volatile * page_size);
110 + rrddim_set(st, "to_scan", pages_to_scan * page_size);
111 + rrdset_done(st);
112
113 - st = rrdset_find("mem.ksm_savings");
114 - if(!st) {
115 - st = rrdset_create("mem", "ksm_savings", NULL, "ksm", NULL, "Kernel Same Page Merging Savings", "MB", 5001, update_every, RRDSET_TYPE_AREA);
113 + st = rrdset_find("mem.ksm_savings");
114 + if(!st) {
115 + st = rrdset_create("mem", "ksm_savings", NULL, "ksm", NULL, "Kernel Same Page Merging Savings", "MB", 5001, update_every, RRDSET_TYPE_AREA);
116
117 - rrddim_add(st, "savings", NULL, -1, 1024 * 1024, RRDDIM_ABSOLUTE);
118 - rrddim_add(st, "offered", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
119 - }
120 - else rrdset_next(st);
117 + rrddim_add(st, "savings", NULL, -1, 1024 * 1024, RRDDIM_ABSOLUTE);
118 + rrddim_add(st, "offered", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
119 + }
120 + else rrdset_next(st);
121
122 - rrddim_set(st, "savings", saved * page_size);
123 - rrddim_set(st, "offered", offered * page_size);
124 - rrdset_done(st);
122 + rrddim_set(st, "savings", saved * page_size);
123 + rrddim_set(st, "offered", offered * page_size);
124 + rrdset_done(st);
125
126 - st = rrdset_find("mem.ksm_ratios");
127 - if(!st) {
128 - st = rrdset_create("mem", "ksm_ratios", NULL, "ksm", NULL, "Kernel Same Page Merging Effectiveness", "percentage", 5002, update_every, RRDSET_TYPE_LINE);
129 -
130 - rrddim_add(st, "savings", NULL, 1, 10000, RRDDIM_ABSOLUTE);
131 - }
132 - else rrdset_next(st);
133 -
134 - rrddim_set(st, "savings", (saved * 1000000) / offered);
135 - rrdset_done(st);
126 + st = rrdset_find("mem.ksm_ratios");
127 + if(!st) {
128 + st = rrdset_create("mem", "ksm_ratios", NULL, "ksm", NULL, "Kernel Same Page Merging Effectiveness", "percentage", 5002, update_every, RRDSET_TYPE_LINE);
129 +
130 + rrddim_add(st, "savings", NULL, 1, 10000, RRDDIM_ABSOLUTE);
131 + }
132 + else rrdset_next(st);
133 +
134 + rrddim_set(st, "savings", (saved * 1000000) / offered);
135 + rrdset_done(st);
136
137 - return 0;
137 + return 0;
138 }
src/unit_test.c
+702 -702
@@ -1,258 +1,258 @@
1 #include "common.h"
2
3 int check_storage_number(calculated_number n, int debug) {
4 - char buffer[100];
5 - uint32_t flags = SN_EXISTS;
6 -
7 - storage_number s = pack_storage_number(n, flags);
8 - calculated_number d = unpack_storage_number(s);
9 -
10 - if(!does_storage_number_exist(s)) {
11 - fprintf(stderr, "Exists flags missing for number " CALCULATED_NUMBER_FORMAT "!\n", n);
12 - return 5;
13 - }
14 -
15 - calculated_number ddiff = d - n;
16 - calculated_number dcdiff = ddiff * 100.0 / n;
17 -
18 - if(dcdiff < 0) dcdiff = -dcdiff;
19 -
20 - size_t len = print_calculated_number(buffer, d);
21 - calculated_number p = strtold(buffer, NULL);
22 - calculated_number pdiff = n - p;
23 - calculated_number pcdiff = pdiff * 100.0 / n;
24 - if(pcdiff < 0) pcdiff = -pcdiff;
25 -
26 - if(debug) {
27 - fprintf(stderr,
28 - CALCULATED_NUMBER_FORMAT " original\n"
29 - CALCULATED_NUMBER_FORMAT " packed and unpacked, (stored as 0x%08X, diff " CALCULATED_NUMBER_FORMAT ", " CALCULATED_NUMBER_FORMAT "%%)\n"
30 - "%s printed after unpacked (%zu bytes)\n"
31 - CALCULATED_NUMBER_FORMAT " re-parsed from printed (diff " CALCULATED_NUMBER_FORMAT ", " CALCULATED_NUMBER_FORMAT "%%)\n\n",
32 - n,
33 - d, s, ddiff, dcdiff,
34 - buffer,
35 - len, p, pdiff, pcdiff
36 - );
37 - if(len != strlen(buffer)) fprintf(stderr, "ERROR: printed number %s is reported to have length %zu but it has %zu\n", buffer, len, strlen(buffer));
38 - if(dcdiff > ACCURACY_LOSS) fprintf(stderr, "WARNING: packing number " CALCULATED_NUMBER_FORMAT " has accuracy loss %0.7Lf %%\n", n, dcdiff);
39 - if(pcdiff > ACCURACY_LOSS) fprintf(stderr, "WARNING: re-parsing the packed, unpacked and printed number " CALCULATED_NUMBER_FORMAT " has accuracy loss %0.7Lf %%\n", n, pcdiff);
40 - }
41 -
42 - if(len != strlen(buffer)) return 1;
43 - if(dcdiff > ACCURACY_LOSS) return 3;
44 - if(pcdiff > ACCURACY_LOSS) return 4;
45 - return 0;
4 + char buffer[100];
5 + uint32_t flags = SN_EXISTS;
6 +
7 + storage_number s = pack_storage_number(n, flags);
8 + calculated_number d = unpack_storage_number(s);
9 +
10 + if(!does_storage_number_exist(s)) {
11 + fprintf(stderr, "Exists flags missing for number " CALCULATED_NUMBER_FORMAT "!\n", n);
12 + return 5;
13 + }
14 +
15 + calculated_number ddiff = d - n;
16 + calculated_number dcdiff = ddiff * 100.0 / n;
17 +
18 + if(dcdiff < 0) dcdiff = -dcdiff;
19 +
20 + size_t len = print_calculated_number(buffer, d);
21 + calculated_number p = strtold(buffer, NULL);
22 + calculated_number pdiff = n - p;
23 + calculated_number pcdiff = pdiff * 100.0 / n;
24 + if(pcdiff < 0) pcdiff = -pcdiff;
25 +
26 + if(debug) {
27 + fprintf(stderr,
28 + CALCULATED_NUMBER_FORMAT " original\n"
29 + CALCULATED_NUMBER_FORMAT " packed and unpacked, (stored as 0x%08X, diff " CALCULATED_NUMBER_FORMAT ", " CALCULATED_NUMBER_FORMAT "%%)\n"
30 + "%s printed after unpacked (%zu bytes)\n"
31 + CALCULATED_NUMBER_FORMAT " re-parsed from printed (diff " CALCULATED_NUMBER_FORMAT ", " CALCULATED_NUMBER_FORMAT "%%)\n\n",
32 + n,
33 + d, s, ddiff, dcdiff,
34 + buffer,
35 + len, p, pdiff, pcdiff
36 + );
37 + if(len != strlen(buffer)) fprintf(stderr, "ERROR: printed number %s is reported to have length %zu but it has %zu\n", buffer, len, strlen(buffer));
38 + if(dcdiff > ACCURACY_LOSS) fprintf(stderr, "WARNING: packing number " CALCULATED_NUMBER_FORMAT " has accuracy loss %0.7Lf %%\n", n, dcdiff);
39 + if(pcdiff > ACCURACY_LOSS) fprintf(stderr, "WARNING: re-parsing the packed, unpacked and printed number " CALCULATED_NUMBER_FORMAT " has accuracy loss %0.7Lf %%\n", n, pcdiff);
40 + }
41 +
42 + if(len != strlen(buffer)) return 1;
43 + if(dcdiff > ACCURACY_LOSS) return 3;
44 + if(pcdiff > ACCURACY_LOSS) return 4;
45 + return 0;
46 }
47
48 void benchmark_storage_number(int loop, int multiplier) {
49 - int i, j;
50 - calculated_number n, d;
51 - storage_number s;
52 - unsigned long long user, system, total, mine, their;
49 + int i, j;
50 + calculated_number n, d;
51 + storage_number s;
52 + unsigned long long user, system, total, mine, their;
53
54 - char buffer[100];
54 + char buffer[100];
55
56 - struct rusage now, last;
56 + struct rusage now, last;
57
58 - fprintf(stderr, "\n\nBenchmarking %d numbers, please wait...\n\n", loop);
58 + fprintf(stderr, "\n\nBenchmarking %d numbers, please wait...\n\n", loop);
59
60 - // ------------------------------------------------------------------------
60 + // ------------------------------------------------------------------------
61
62 - fprintf(stderr, "SYSTEM LONG DOUBLE SIZE: %zu bytes\n", sizeof(calculated_number));
63 - fprintf(stderr, "NETDATA FLOATING POINT SIZE: %zu bytes\n", sizeof(storage_number));
62 + fprintf(stderr, "SYSTEM LONG DOUBLE SIZE: %zu bytes\n", sizeof(calculated_number));
63 + fprintf(stderr, "NETDATA FLOATING POINT SIZE: %zu bytes\n", sizeof(storage_number));
64
65 - mine = (calculated_number)sizeof(storage_number) * (calculated_number)loop;
66 - their = (calculated_number)sizeof(calculated_number) * (calculated_number)loop;
65 + mine = (calculated_number)sizeof(storage_number) * (calculated_number)loop;
66 + their = (calculated_number)sizeof(calculated_number) * (calculated_number)loop;
67
68 - if(mine > their) {
69 - fprintf(stderr, "\nNETDATA NEEDS %0.2Lf TIMES MORE MEMORY. Sorry!\n", (long double)(mine / their));
70 - }
71 - else {
72 - fprintf(stderr, "\nNETDATA INTERNAL FLOATING POINT ARITHMETICS NEEDS %0.2Lf TIMES LESS MEMORY.\n", (long double)(their / mine));
73 - }
68 + if(mine > their) {
69 + fprintf(stderr, "\nNETDATA NEEDS %0.2Lf TIMES MORE MEMORY. Sorry!\n", (long double)(mine / their));
70 + }
71 + else {
72 + fprintf(stderr, "\nNETDATA INTERNAL FLOATING POINT ARITHMETICS NEEDS %0.2Lf TIMES LESS MEMORY.\n", (long double)(their / mine));
73 + }
74
75 - fprintf(stderr, "\nNETDATA FLOATING POINT\n");
76 - fprintf(stderr, "MIN POSITIVE VALUE " CALCULATED_NUMBER_FORMAT "\n", (calculated_number)STORAGE_NUMBER_POSITIVE_MIN);
77 - fprintf(stderr, "MAX POSITIVE VALUE " CALCULATED_NUMBER_FORMAT "\n", (calculated_number)STORAGE_NUMBER_POSITIVE_MAX);
78 - fprintf(stderr, "MIN NEGATIVE VALUE " CALCULATED_NUMBER_FORMAT "\n", (calculated_number)STORAGE_NUMBER_NEGATIVE_MIN);
79 - fprintf(stderr, "MAX NEGATIVE VALUE " CALCULATED_NUMBER_FORMAT "\n", (calculated_number)STORAGE_NUMBER_NEGATIVE_MAX);
80 - fprintf(stderr, "Maximum accuracy loss: " CALCULATED_NUMBER_FORMAT "%%\n\n\n", (calculated_number)ACCURACY_LOSS);
75 + fprintf(stderr, "\nNETDATA FLOATING POINT\n");
76 + fprintf(stderr, "MIN POSITIVE VALUE " CALCULATED_NUMBER_FORMAT "\n", (calculated_number)STORAGE_NUMBER_POSITIVE_MIN);
77 + fprintf(stderr, "MAX POSITIVE VALUE " CALCULATED_NUMBER_FORMAT "\n", (calculated_number)STORAGE_NUMBER_POSITIVE_MAX);
78 + fprintf(stderr, "MIN NEGATIVE VALUE " CALCULATED_NUMBER_FORMAT "\n", (calculated_number)STORAGE_NUMBER_NEGATIVE_MIN);
79 + fprintf(stderr, "MAX NEGATIVE VALUE " CALCULATED_NUMBER_FORMAT "\n", (calculated_number)STORAGE_NUMBER_NEGATIVE_MAX);
80 + fprintf(stderr, "Maximum accuracy loss: " CALCULATED_NUMBER_FORMAT "%%\n\n\n", (calculated_number)ACCURACY_LOSS);
81
82 - // ------------------------------------------------------------------------
82 + // ------------------------------------------------------------------------
83
84 - fprintf(stderr, "INTERNAL LONG DOUBLE PRINTING: ");
85 - getrusage(RUSAGE_SELF, &last);
84 + fprintf(stderr, "INTERNAL LONG DOUBLE PRINTING: ");
85 + getrusage(RUSAGE_SELF, &last);
86
87 - // do the job
88 - for(j = 1; j < 11 ;j++) {
89 - n = STORAGE_NUMBER_POSITIVE_MIN * j;
87 + // do the job
88 + for(j = 1; j < 11 ;j++) {
89 + n = STORAGE_NUMBER_POSITIVE_MIN * j;
90
91 - for(i = 0; i < loop ;i++) {
92 - n *= multiplier;
93 - if(n > STORAGE_NUMBER_POSITIVE_MAX) n = STORAGE_NUMBER_POSITIVE_MIN;
91 + for(i = 0; i < loop ;i++) {
92 + n *= multiplier;
93 + if(n > STORAGE_NUMBER_POSITIVE_MAX) n = STORAGE_NUMBER_POSITIVE_MIN;
94
95 - print_calculated_number(buffer, n);
96 - }
97 - }
95 + print_calculated_number(buffer, n);
96 + }
97 + }
98
99 - getrusage(RUSAGE_SELF, &now);
100 - user = now.ru_utime.tv_sec * 1000000ULL + now.ru_utime.tv_usec - last.ru_utime.tv_sec * 1000000ULL + last.ru_utime.tv_usec;
101 - system = now.ru_stime.tv_sec * 1000000ULL + now.ru_stime.tv_usec - last.ru_stime.tv_sec * 1000000ULL + last.ru_stime.tv_usec;
102 - total = user + system;
103 - mine = total;
99 + getrusage(RUSAGE_SELF, &now);
100 + user = now.ru_utime.tv_sec * 1000000ULL + now.ru_utime.tv_usec - last.ru_utime.tv_sec * 1000000ULL + last.ru_utime.tv_usec;
101 + system = now.ru_stime.tv_sec * 1000000ULL + now.ru_stime.tv_usec - last.ru_stime.tv_sec * 1000000ULL + last.ru_stime.tv_usec;
102 + total = user + system;
103 + mine = total;
104
105 - fprintf(stderr, "user %0.5Lf, system %0.5Lf, total %0.5Lf\n", (long double)(user / 1000000.0), (long double)(system / 1000000.0), (long double)(total / 1000000.0));
105 + fprintf(stderr, "user %0.5Lf, system %0.5Lf, total %0.5Lf\n", (long double)(user / 1000000.0), (long double)(system / 1000000.0), (long double)(total / 1000000.0));
106
107 - // ------------------------------------------------------------------------
107 + // ------------------------------------------------------------------------
108
109 - fprintf(stderr, "SYSTEM LONG DOUBLE PRINTING: ");
110 - getrusage(RUSAGE_SELF, &last);
109 + fprintf(stderr, "SYSTEM LONG DOUBLE PRINTING: ");
110 + getrusage(RUSAGE_SELF, &last);
111
112 - // do the job
113 - for(j = 1; j < 11 ;j++) {
114 - n = STORAGE_NUMBER_POSITIVE_MIN * j;
112 + // do the job
113 + for(j = 1; j < 11 ;j++) {
114 + n = STORAGE_NUMBER_POSITIVE_MIN * j;
115
116 - for(i = 0; i < loop ;i++) {
117 - n *= multiplier;
118 - if(n > STORAGE_NUMBER_POSITIVE_MAX) n = STORAGE_NUMBER_POSITIVE_MIN;
119 - snprintfz(buffer, 100, CALCULATED_NUMBER_FORMAT, n);
120 - }
121 - }
116 + for(i = 0; i < loop ;i++) {
117 + n *= multiplier;
118 + if(n > STORAGE_NUMBER_POSITIVE_MAX) n = STORAGE_NUMBER_POSITIVE_MIN;
119 + snprintfz(buffer, 100, CALCULATED_NUMBER_FORMAT, n);
120 + }
121 + }
122
123 - getrusage(RUSAGE_SELF, &now);
124 - user = now.ru_utime.tv_sec * 1000000ULL + now.ru_utime.tv_usec - last.ru_utime.tv_sec * 1000000ULL + last.ru_utime.tv_usec;
125 - system = now.ru_stime.tv_sec * 1000000ULL + now.ru_stime.tv_usec - last.ru_stime.tv_sec * 1000000ULL + last.ru_stime.tv_usec;
126 - total = user + system;
127 - their = total;
123 + getrusage(RUSAGE_SELF, &now);
124 + user = now.ru_utime.tv_sec * 1000000ULL + now.ru_utime.tv_usec - last.ru_utime.tv_sec * 1000000ULL + last.ru_utime.tv_usec;
125 + system = now.ru_stime.tv_sec * 1000000ULL + now.ru_stime.tv_usec - last.ru_stime.tv_sec * 1000000ULL + last.ru_stime.tv_usec;
126 + total = user + system;
127 + their = total;
128
129 - fprintf(stderr, "user %0.5Lf, system %0.5Lf, total %0.5Lf\n", (long double)(user / 1000000.0), (long double)(system / 1000000.0), (long double)(total / 1000000.0));
129 + fprintf(stderr, "user %0.5Lf, system %0.5Lf, total %0.5Lf\n", (long double)(user / 1000000.0), (long double)(system / 1000000.0), (long double)(total / 1000000.0));
130
131 - if(mine > total) {
132 - fprintf(stderr, "NETDATA CODE IS SLOWER %0.2Lf %%\n", (long double)(mine * 100.0 / their - 100.0));
133 - }
134 - else {
135 - fprintf(stderr, "NETDATA CODE IS F A S T E R %0.2Lf %%\n", (long double)(their * 100.0 / mine - 100.0));
136 - }
131 + if(mine > total) {
132 + fprintf(stderr, "NETDATA CODE IS SLOWER %0.2Lf %%\n", (long double)(mine * 100.0 / their - 100.0));
133 + }
134 + else {
135 + fprintf(stderr, "NETDATA CODE IS F A S T E R %0.2Lf %%\n", (long double)(their * 100.0 / mine - 100.0));
136 + }
137
138 - // ------------------------------------------------------------------------
138 + // ------------------------------------------------------------------------
139
140 - fprintf(stderr, "\nINTERNAL LONG DOUBLE PRINTING WITH PACK / UNPACK: ");
141 - getrusage(RUSAGE_SELF, &last);
140 + fprintf(stderr, "\nINTERNAL LONG DOUBLE PRINTING WITH PACK / UNPACK: ");
141 + getrusage(RUSAGE_SELF, &last);
142
143 - // do the job
144 - for(j = 1; j < 11 ;j++) {
145 - n = STORAGE_NUMBER_POSITIVE_MIN * j;
143 + // do the job
144 + for(j = 1; j < 11 ;j++) {
145 + n = STORAGE_NUMBER_POSITIVE_MIN * j;
146
147 - for(i = 0; i < loop ;i++) {
148 - n *= multiplier;
149 - if(n > STORAGE_NUMBER_POSITIVE_MAX) n = STORAGE_NUMBER_POSITIVE_MIN;
147 + for(i = 0; i < loop ;i++) {
148 + n *= multiplier;
149 + if(n > STORAGE_NUMBER_POSITIVE_MAX) n = STORAGE_NUMBER_POSITIVE_MIN;
150
151 - s = pack_storage_number(n, 1);
152 - d = unpack_storage_number(s);
153 - print_calculated_number(buffer, d);
154 - }
155 - }
151 + s = pack_storage_number(n, 1);
152 + d = unpack_storage_number(s);
153 + print_calculated_number(buffer, d);
154 + }
155 + }
156
157 - getrusage(RUSAGE_SELF, &now);
158 - user = now.ru_utime.tv_sec * 1000000ULL + now.ru_utime.tv_usec - last.ru_utime.tv_sec * 1000000ULL + last.ru_utime.tv_usec;
159 - system = now.ru_stime.tv_sec * 1000000ULL + now.ru_stime.tv_usec - last.ru_stime.tv_sec * 1000000ULL + last.ru_stime.tv_usec;
160 - total = user + system;
161 - mine = total;
162 -
163 - fprintf(stderr, "user %0.5Lf, system %0.5Lf, total %0.5Lf\n", (long double)(user / 1000000.0), (long double)(system / 1000000.0), (long double)(total / 1000000.0));
157 + getrusage(RUSAGE_SELF, &now);
158 + user = now.ru_utime.tv_sec * 1000000ULL + now.ru_utime.tv_usec - last.ru_utime.tv_sec * 1000000ULL + last.ru_utime.tv_usec;
159 + system = now.ru_stime.tv_sec * 1000000ULL + now.ru_stime.tv_usec - last.ru_stime.tv_sec * 1000000ULL + last.ru_stime.tv_usec;
160 + total = user + system;
161 + mine = total;
162 +
163 + fprintf(stderr, "user %0.5Lf, system %0.5Lf, total %0.5Lf\n", (long double)(user / 1000000.0), (long double)(system / 1000000.0), (long double)(total / 1000000.0));
164
165 - if(mine > their) {
166 - fprintf(stderr, "WITH PACKING UNPACKING NETDATA CODE IS SLOWER %0.2Lf %%\n", (long double)(mine * 100.0 / their - 100.0));
167 - }
168 - else {
169 - fprintf(stderr, "EVEN WITH PACKING AND UNPACKING, NETDATA CODE IS F A S T E R %0.2Lf %%\n", (long double)(their * 100.0 / mine - 100.0));
170 - }
165 + if(mine > their) {
166 + fprintf(stderr, "WITH PACKING UNPACKING NETDATA CODE IS SLOWER %0.2Lf %%\n", (long double)(mine * 100.0 / their - 100.0));
167 + }
168 + else {
169 + fprintf(stderr, "EVEN WITH PACKING AND UNPACKING, NETDATA CODE IS F A S T E R %0.2Lf %%\n", (long double)(their * 100.0 / mine - 100.0));
170 + }
171
172 - // ------------------------------------------------------------------------
172 + // ------------------------------------------------------------------------
173
174 }
175
176 static int check_storage_number_exists() {
177 - uint32_t flags = SN_EXISTS;
178 -
179 -
180 - for(flags = 0; flags < 7 ; flags++) {
181 - if(get_storage_number_flags(flags << 24) != flags << 24) {
182 - fprintf(stderr, "Flag 0x%08x is not checked correctly. It became 0x%08x\n", flags << 24, get_storage_number_flags(flags << 24));
183 - return 1;
184 - }
185 - }
186 -
187 - flags = SN_EXISTS;
188 - calculated_number n = 0.0;
189 -
190 - storage_number s = pack_storage_number(n, flags);
191 - calculated_number d = unpack_storage_number(s);
192 - if(get_storage_number_flags(s) != flags) {
193 - fprintf(stderr, "Wrong flags. Given %08x, Got %08x!\n", flags, get_storage_number_flags(s));
194 - return 1;
195 - }
196 - if(n != d) {
197 - fprintf(stderr, "Wrong number returned. Expected " CALCULATED_NUMBER_FORMAT ", returned " CALCULATED_NUMBER_FORMAT "!\n", n, d);
198 - return 1;
199 - }
200 -
201 - return 0;
177 + uint32_t flags = SN_EXISTS;
178 +
179 +
180 + for(flags = 0; flags < 7 ; flags++) {
181 + if(get_storage_number_flags(flags << 24) != flags << 24) {
182 + fprintf(stderr, "Flag 0x%08x is not checked correctly. It became 0x%08x\n", flags << 24, get_storage_number_flags(flags << 24));
183 + return 1;
184 + }
185 + }
186 +
187 + flags = SN_EXISTS;
188 + calculated_number n = 0.0;
189 +
190 + storage_number s = pack_storage_number(n, flags);
191 + calculated_number d = unpack_storage_number(s);
192 + if(get_storage_number_flags(s) != flags) {
193 + fprintf(stderr, "Wrong flags. Given %08x, Got %08x!\n", flags, get_storage_number_flags(s));
194 + return 1;
195 + }
196 + if(n != d) {
197 + fprintf(stderr, "Wrong number returned. Expected " CALCULATED_NUMBER_FORMAT ", returned " CALCULATED_NUMBER_FORMAT "!\n", n, d);
198 + return 1;
199 + }
200 +
201 + return 0;
202 }
203
204 int unit_test_storage()
205 {
206 - if(check_storage_number_exists()) return 0;
206 + if(check_storage_number_exists()) return 0;
207
208 - calculated_number c, a = 0;
209 - int i, j, g, r = 0;
208 + calculated_number c, a = 0;
209 + int i, j, g, r = 0;
210
211 - for(g = -1; g <= 1 ; g++) {
212 - a = 0;
211 + for(g = -1; g <= 1 ; g++) {
212 + a = 0;
213
214 - if(!g) continue;
214 + if(!g) continue;
215
216 - for(j = 0; j < 9 ;j++) {
217 - a += 0.0000001;
218 - c = a * g;
219 - for(i = 0; i < 21 ;i++, c *= 10) {
220 - if(c > 0 && c < STORAGE_NUMBER_POSITIVE_MIN) continue;
221 - if(c < 0 && c > STORAGE_NUMBER_NEGATIVE_MAX) continue;
216 + for(j = 0; j < 9 ;j++) {
217 + a += 0.0000001;
218 + c = a * g;
219 + for(i = 0; i < 21 ;i++, c *= 10) {
220 + if(c > 0 && c < STORAGE_NUMBER_POSITIVE_MIN) continue;
221 + if(c < 0 && c > STORAGE_NUMBER_NEGATIVE_MAX) continue;
222
223 - if(check_storage_number(c, 1)) return 1;
224 - }
225 - }
226 - }
223 + if(check_storage_number(c, 1)) return 1;
224 + }
225 + }
226 + }
227
228 - benchmark_storage_number(1000000, 2);
229 - return r;
228 + benchmark_storage_number(1000000, 2);
229 + return r;
230 }
231
232
233 // --------------------------------------------------------------------------------------------------------------------
234
235 struct feed_values {
236 - unsigned long long microseconds;
237 - collected_number value;
236 + unsigned long long microseconds;
237 + collected_number value;
238 };
239
240 struct test {
241 - char name[100];
242 - char description[1024];
241 + char name[100];
242 + char description[1024];
243
244 - int update_every;
245 - unsigned long long multiplier;
246 - unsigned long long divisor;
247 - int algorithm;
244 + int update_every;
245 + unsigned long long multiplier;
246 + unsigned long long divisor;
247 + int algorithm;
248
249 - unsigned long feed_entries;
250 - unsigned long result_entries;
251 - struct feed_values *feed;
252 - calculated_number *results;
249 + unsigned long feed_entries;
250 + unsigned long result_entries;
251 + struct feed_values *feed;
252 + calculated_number *results;
253
254 - collected_number *feed2;
255 - calculated_number *results2;
254 + collected_number *feed2;
255 + calculated_number *results2;
256 };
257
258 // --------------------------------------------------------------------------------------------------------------------
@@ -260,35 +260,35 @@ struct test {
260 // test absolute values stored
261
262 struct feed_values test1_feed[] = {
263 - { 0, 10 },
264 - { 1000000, 20 },
265 - { 1000000, 30 },
266 - { 1000000, 40 },
267 - { 1000000, 50 },
268 - { 1000000, 60 },
269 - { 1000000, 70 },
270 - { 1000000, 80 },
271 - { 1000000, 90 },
272 - { 1000000, 100 },
263 + { 0, 10 },
264 + { 1000000, 20 },
265 + { 1000000, 30 },
266 + { 1000000, 40 },
267 + { 1000000, 50 },
268 + { 1000000, 60 },
269 + { 1000000, 70 },
270 + { 1000000, 80 },
271 + { 1000000, 90 },
272 + { 1000000, 100 },
273 };
274
275 calculated_number test1_results[] = {
276 - 20, 30, 40, 50, 60, 70, 80, 90, 100
276 + 20, 30, 40, 50, 60, 70, 80, 90, 100
277 };
278
279 struct test test1 = {
280 - "test1", // name
281 - "test absolute values stored at exactly second boundaries",
282 - 1, // update_every
283 - 1, // multiplier
284 - 1, // divisor
285 - RRDDIM_ABSOLUTE, // algorithm
286 - 10, // feed entries
287 - 9, // result entries
288 - test1_feed, // feed
289 - test1_results, // results
290 - NULL, // feed2
291 - NULL // results2
280 + "test1", // name
281 + "test absolute values stored at exactly second boundaries",
282 + 1, // update_every
283 + 1, // multiplier
284 + 1, // divisor
285 + RRDDIM_ABSOLUTE, // algorithm
286 + 10, // feed entries
287 + 9, // result entries
288 + test1_feed, // feed
289 + test1_results, // results
290 + NULL, // feed2
291 + NULL // results2
292 };
293
294 // --------------------------------------------------------------------------------------------------------------------
@@ -296,667 +296,667 @@ struct test test1 = {
296 // test absolute values stored in the middle of second boundaries
297
298 struct feed_values test2_feed[] = {
299 - { 500000, 10 },
300 - { 1000000, 20 },
301 - { 1000000, 30 },
302 - { 1000000, 40 },
303 - { 1000000, 50 },
304 - { 1000000, 60 },
305 - { 1000000, 70 },
306 - { 1000000, 80 },
307 - { 1000000, 90 },
308 - { 1000000, 100 },
299 + { 500000, 10 },
300 + { 1000000, 20 },
301 + { 1000000, 30 },
302 + { 1000000, 40 },
303 + { 1000000, 50 },
304 + { 1000000, 60 },
305 + { 1000000, 70 },
306 + { 1000000, 80 },
307 + { 1000000, 90 },
308 + { 1000000, 100 },
309 };
310
311 calculated_number test2_results[] = {
312 - 20, 30, 40, 50, 60, 70, 80, 90, 100
312 + 20, 30, 40, 50, 60, 70, 80, 90, 100
313 };
314
315 struct test test2 = {
316 - "test2", // name
317 - "test absolute values stored in the middle of second boundaries",
318 - 1, // update_every
319 - 1, // multiplier
320 - 1, // divisor
321 - RRDDIM_ABSOLUTE, // algorithm
322 - 10, // feed entries
323 - 9, // result entries
324 - test2_feed, // feed
325 - test2_results, // results
326 - NULL, // feed2
327 - NULL // results2
316 + "test2", // name
317 + "test absolute values stored in the middle of second boundaries",
318 + 1, // update_every
319 + 1, // multiplier
320 + 1, // divisor
321 + RRDDIM_ABSOLUTE, // algorithm
322 + 10, // feed entries
323 + 9, // result entries
324 + test2_feed, // feed
325 + test2_results, // results
326 + NULL, // feed2
327 + NULL // results2
328 };
329
330 // --------------------------------------------------------------------------------------------------------------------
331 // test3
332
333 struct feed_values test3_feed[] = {
334 - { 0, 10 },
335 - { 1000000, 20 },
336 - { 1000000, 30 },
337 - { 1000000, 40 },
338 - { 1000000, 50 },
339 - { 1000000, 60 },
340 - { 1000000, 70 },
341 - { 1000000, 80 },
342 - { 1000000, 90 },
343 - { 1000000, 100 },
334 + { 0, 10 },
335 + { 1000000, 20 },
336 + { 1000000, 30 },
337 + { 1000000, 40 },
338 + { 1000000, 50 },
339 + { 1000000, 60 },
340 + { 1000000, 70 },
341 + { 1000000, 80 },
342 + { 1000000, 90 },
343 + { 1000000, 100 },
344 };
345
346 calculated_number test3_results[] = {
347 - 10, 10, 10, 10, 10, 10, 10, 10, 10
347 + 10, 10, 10, 10, 10, 10, 10, 10, 10
348 };
349
350 struct test test3 = {
351 - "test3", // name
352 - "test incremental values stored at exactly second boundaries",
353 - 1, // update_every
354 - 1, // multiplier
355 - 1, // divisor
356 - RRDDIM_INCREMENTAL, // algorithm
357 - 10, // feed entries
358 - 9, // result entries
359 - test3_feed, // feed
360 - test3_results, // results
361 - NULL, // feed2
362 - NULL // results2
351 + "test3", // name
352 + "test incremental values stored at exactly second boundaries",
353 + 1, // update_every
354 + 1, // multiplier
355 + 1, // divisor
356 + RRDDIM_INCREMENTAL, // algorithm
357 + 10, // feed entries
358 + 9, // result entries
359 + test3_feed, // feed
360 + test3_results, // results
361 + NULL, // feed2
362 + NULL // results2
363 };
364
365 // --------------------------------------------------------------------------------------------------------------------
366 // test4
367
368 struct feed_values test4_feed[] = {
369 - { 500000, 10 },
370 - { 1000000, 20 },
371 - { 1000000, 30 },
372 - { 1000000, 40 },
373 - { 1000000, 50 },
374 - { 1000000, 60 },
375 - { 1000000, 70 },
376 - { 1000000, 80 },
377 - { 1000000, 90 },
378 - { 1000000, 100 },
369 + { 500000, 10 },
370 + { 1000000, 20 },
371 + { 1000000, 30 },
372 + { 1000000, 40 },
373 + { 1000000, 50 },
374 + { 1000000, 60 },
375 + { 1000000, 70 },
376 + { 1000000, 80 },
377 + { 1000000, 90 },
378 + { 1000000, 100 },
379 };
380
381 calculated_number test4_results[] = {
382 - 5, 10, 10, 10, 10, 10, 10, 10, 10
382 + 5, 10, 10, 10, 10, 10, 10, 10, 10
383 };
384
385 struct test test4 = {
386 - "test4", // name
387 - "test incremental values stored in the middle of second boundaries",
388 - 1, // update_every
389 - 1, // multiplier
390 - 1, // divisor
391 - RRDDIM_INCREMENTAL, // algorithm
392 - 10, // feed entries
393 - 9, // result entries
394 - test4_feed, // feed
395 - test4_results, // results
396 - NULL, // feed2
397 - NULL // results2
386 + "test4", // name
387 + "test incremental values stored in the middle of second boundaries",
388 + 1, // update_every
389 + 1, // multiplier
390 + 1, // divisor
391 + RRDDIM_INCREMENTAL, // algorithm
392 + 10, // feed entries
393 + 9, // result entries
394 + test4_feed, // feed
395 + test4_results, // results
396 + NULL, // feed2
397 + NULL // results2
398 };
399
400 // --------------------------------------------------------------------------------------------------------------------
401 // test5
402
403 struct feed_values test5_feed[] = {
404 - { 500000, 1000 },
405 - { 1000000, 2000 },
406 - { 1000000, 2000 },
407 - { 1000000, 2000 },
408 - { 1000000, 3000 },
409 - { 1000000, 2000 },
410 - { 1000000, 2000 },
411 - { 1000000, 2000 },
412 - { 1000000, 2000 },
413 - { 1000000, 2000 },
404 + { 500000, 1000 },
405 + { 1000000, 2000 },
406 + { 1000000, 2000 },
407 + { 1000000, 2000 },
408 + { 1000000, 3000 },
409 + { 1000000, 2000 },
410 + { 1000000, 2000 },
411 + { 1000000, 2000 },
412 + { 1000000, 2000 },
413 + { 1000000, 2000 },
414 };
415
416 calculated_number test5_results[] = {
417 - 500, 500, 0, 500, 500, 0, 0, 0, 0
417 + 500, 500, 0, 500, 500, 0, 0, 0, 0
418 };
419
420 struct test test5 = {
421 - "test5", // name
422 - "test incremental values ups and downs",
423 - 1, // update_every
424 - 1, // multiplier
425 - 1, // divisor
426 - RRDDIM_INCREMENTAL, // algorithm
427 - 10, // feed entries
428 - 9, // result entries
429 - test5_feed, // feed
430 - test5_results, // results
431 - NULL, // feed2
432 - NULL // results2
421 + "test5", // name
422 + "test incremental values ups and downs",
423 + 1, // update_every
424 + 1, // multiplier
425 + 1, // divisor
426 + RRDDIM_INCREMENTAL, // algorithm
427 + 10, // feed entries
428 + 9, // result entries
429 + test5_feed, // feed
430 + test5_results, // results
431 + NULL, // feed2
432 + NULL // results2
433 };
434
435 // --------------------------------------------------------------------------------------------------------------------
436 // test6
437
438 struct feed_values test6_feed[] = {
439 - { 250000, 1000 },
440 - { 250000, 2000 },
441 - { 250000, 3000 },
442 - { 250000, 4000 },
443 - { 250000, 5000 },
444 - { 250000, 6000 },
445 - { 250000, 7000 },
446 - { 250000, 8000 },
447 - { 250000, 9000 },
448 - { 250000, 10000 },
449 - { 250000, 11000 },
450 - { 250000, 12000 },
451 - { 250000, 13000 },
452 - { 250000, 14000 },
453 - { 250000, 15000 },
454 - { 250000, 16000 },
439 + { 250000, 1000 },
440 + { 250000, 2000 },
441 + { 250000, 3000 },
442 + { 250000, 4000 },
443 + { 250000, 5000 },
444 + { 250000, 6000 },
445 + { 250000, 7000 },
446 + { 250000, 8000 },
447 + { 250000, 9000 },
448 + { 250000, 10000 },
449 + { 250000, 11000 },
450 + { 250000, 12000 },
451 + { 250000, 13000 },
452 + { 250000, 14000 },
453 + { 250000, 15000 },
454 + { 250000, 16000 },
455 };
456
457 calculated_number test6_results[] = {
458 - 3000, 4000, 4000, 4000
458 + 3000, 4000, 4000, 4000
459 };
460
461 struct test test6 = {
462 - "test6", // name
463 - "test incremental values updated within the same second",
464 - 1, // update_every
465 - 1, // multiplier
466 - 1, // divisor
467 - RRDDIM_INCREMENTAL, // algorithm
468 - 16, // feed entries
469 - 4, // result entries
470 - test6_feed, // feed
471 - test6_results, // results
472 - NULL, // feed2
473 - NULL // results2
462 + "test6", // name
463 + "test incremental values updated within the same second",
464 + 1, // update_every
465 + 1, // multiplier
466 + 1, // divisor
467 + RRDDIM_INCREMENTAL, // algorithm
468 + 16, // feed entries
469 + 4, // result entries
470 + test6_feed, // feed
471 + test6_results, // results
472 + NULL, // feed2
473 + NULL // results2
474 };
475
476 // --------------------------------------------------------------------------------------------------------------------
477 // test7
478
479 struct feed_values test7_feed[] = {
480 - { 500000, 1000 },
481 - { 2000000, 2000 },
482 - { 2000000, 3000 },
483 - { 2000000, 4000 },
484 - { 2000000, 5000 },
485 - { 2000000, 6000 },
486 - { 2000000, 7000 },
487 - { 2000000, 8000 },
488 - { 2000000, 9000 },
489 - { 2000000, 10000 },
480 + { 500000, 1000 },
481 + { 2000000, 2000 },
482 + { 2000000, 3000 },
483 + { 2000000, 4000 },
484 + { 2000000, 5000 },
485 + { 2000000, 6000 },
486 + { 2000000, 7000 },
487 + { 2000000, 8000 },
488 + { 2000000, 9000 },
489 + { 2000000, 10000 },
490 };
491
492 calculated_number test7_results[] = {
493 - 250, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500
493 + 250, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500
494 };
495
496 struct test test7 = {
497 - "test7", // name
498 - "test incremental values updated in long durations",
499 - 1, // update_every
500 - 1, // multiplier
501 - 1, // divisor
502 - RRDDIM_INCREMENTAL, // algorithm
503 - 10, // feed entries
504 - 18, // result entries
505 - test7_feed, // feed
506 - test7_results, // results
507 - NULL, // feed2
508 - NULL // results2
497 + "test7", // name
498 + "test incremental values updated in long durations",
499 + 1, // update_every
500 + 1, // multiplier
501 + 1, // divisor
502 + RRDDIM_INCREMENTAL, // algorithm
503 + 10, // feed entries
504 + 18, // result entries
505 + test7_feed, // feed
506 + test7_results, // results
507 + NULL, // feed2
508 + NULL // results2
509 };
510
511 // --------------------------------------------------------------------------------------------------------------------
512 // test8
513
514 struct feed_values test8_feed[] = {
515 - { 500000, 1000 },
516 - { 2000000, 2000 },
517 - { 2000000, 3000 },
518 - { 2000000, 4000 },
519 - { 2000000, 5000 },
520 - { 2000000, 6000 },
515 + { 500000, 1000 },
516 + { 2000000, 2000 },
517 + { 2000000, 3000 },
518 + { 2000000, 4000 },
519 + { 2000000, 5000 },
520 + { 2000000, 6000 },
521 };
522
523 calculated_number test8_results[] = {
524 - 1250, 2000, 2250, 3000, 3250, 4000, 4250, 5000, 5250, 6000
524 + 1250, 2000, 2250, 3000, 3250, 4000, 4250, 5000, 5250, 6000
525 };
526
527 struct test test8 = {
528 - "test8", // name
529 - "test absolute values updated in long durations",
530 - 1, // update_every
531 - 1, // multiplier
532 - 1, // divisor
533 - RRDDIM_ABSOLUTE, // algorithm
534 - 6, // feed entries
535 - 10, // result entries
536 - test8_feed, // feed
537 - test8_results, // results
538 - NULL, // feed2
539 - NULL // results2
528 + "test8", // name
529 + "test absolute values updated in long durations",
530 + 1, // update_every
531 + 1, // multiplier
532 + 1, // divisor
533 + RRDDIM_ABSOLUTE, // algorithm
534 + 6, // feed entries
535 + 10, // result entries
536 + test8_feed, // feed
537 + test8_results, // results
538 + NULL, // feed2
539 + NULL // results2
540 };
541
542 // --------------------------------------------------------------------------------------------------------------------
543 // test9
544
545 struct feed_values test9_feed[] = {
546 - { 250000, 1000 },
547 - { 250000, 2000 },
548 - { 250000, 3000 },
549 - { 250000, 4000 },
550 - { 250000, 5000 },
551 - { 250000, 6000 },
552 - { 250000, 7000 },
553 - { 250000, 8000 },
554 - { 250000, 9000 },
555 - { 250000, 10000 },
556 - { 250000, 11000 },
557 - { 250000, 12000 },
558 - { 250000, 13000 },
559 - { 250000, 14000 },
560 - { 250000, 15000 },
561 - { 250000, 16000 },
546 + { 250000, 1000 },
547 + { 250000, 2000 },
548 + { 250000, 3000 },
549 + { 250000, 4000 },
550 + { 250000, 5000 },
551 + { 250000, 6000 },
552 + { 250000, 7000 },
553 + { 250000, 8000 },
554 + { 250000, 9000 },
555 + { 250000, 10000 },
556 + { 250000, 11000 },
557 + { 250000, 12000 },
558 + { 250000, 13000 },
559 + { 250000, 14000 },
560 + { 250000, 15000 },
561 + { 250000, 16000 },
562 };
563
564 calculated_number test9_results[] = {
565 - 4000, 8000, 12000, 16000
565 + 4000, 8000, 12000, 16000
566 };
567
568 struct test test9 = {
569 - "test9", // name
570 - "test absolute values updated within the same second",
571 - 1, // update_every
572 - 1, // multiplier
573 - 1, // divisor
574 - RRDDIM_ABSOLUTE, // algorithm
575 - 16, // feed entries
576 - 4, // result entries
577 - test9_feed, // feed
578 - test9_results, // results
579 - NULL, // feed2
580 - NULL // results2
569 + "test9", // name
570 + "test absolute values updated within the same second",
571 + 1, // update_every
572 + 1, // multiplier
573 + 1, // divisor
574 + RRDDIM_ABSOLUTE, // algorithm
575 + 16, // feed entries
576 + 4, // result entries
577 + test9_feed, // feed
578 + test9_results, // results
579 + NULL, // feed2
580 + NULL // results2
581 };
582
583 // --------------------------------------------------------------------------------------------------------------------
584 // test10
585
586 struct feed_values test10_feed[] = {
587 - { 500000, 1000 },
588 - { 600000, 1000 + 600 },
589 - { 200000, 1600 + 200 },
590 - { 1000000, 1800 + 1000 },
591 - { 200000, 2800 + 200 },
592 - { 2000000, 3000 + 2000 },
593 - { 600000, 5000 + 600 },
594 - { 400000, 5600 + 400 },
595 - { 900000, 6000 + 900 },
596 - { 1000000, 6900 + 1000 },
587 + { 500000, 1000 },
588 + { 600000, 1000 + 600 },
589 + { 200000, 1600 + 200 },
590 + { 1000000, 1800 + 1000 },
591 + { 200000, 2800 + 200 },
592 + { 2000000, 3000 + 2000 },
593 + { 600000, 5000 + 600 },
594 + { 400000, 5600 + 400 },
595 + { 900000, 6000 + 900 },
596 + { 1000000, 6900 + 1000 },
597 };
598
599 calculated_number test10_results[] = {
600 - 500, 1000, 1000, 1000, 1000, 1000, 1000
600 + 500, 1000, 1000, 1000, 1000, 1000, 1000
601 };
602
603 struct test test10 = {
604 - "test10", // name
605 - "test incremental values updated in short and long durations",
606 - 1, // update_every
607 - 1, // multiplier
608 - 1, // divisor
609 - RRDDIM_INCREMENTAL, // algorithm
610 - 10, // feed entries
611 - 7, // result entries
612 - test10_feed, // feed
613 - test10_results, // results
614 - NULL, // feed2
615 - NULL // results2
604 + "test10", // name
605 + "test incremental values updated in short and long durations",
606 + 1, // update_every
607 + 1, // multiplier
608 + 1, // divisor
609 + RRDDIM_INCREMENTAL, // algorithm
610 + 10, // feed entries
611 + 7, // result entries
612 + test10_feed, // feed
613 + test10_results, // results
614 + NULL, // feed2
615 + NULL // results2
616 };
617
618 // --------------------------------------------------------------------------------------------------------------------
619 // test11
620
621 struct feed_values test11_feed[] = {
622 - { 0, 10 },
623 - { 1000000, 20 },
624 - { 1000000, 30 },
625 - { 1000000, 40 },
626 - { 1000000, 50 },
627 - { 1000000, 60 },
628 - { 1000000, 70 },
629 - { 1000000, 80 },
630 - { 1000000, 90 },
631 - { 1000000, 100 },
622 + { 0, 10 },
623 + { 1000000, 20 },
624 + { 1000000, 30 },
625 + { 1000000, 40 },
626 + { 1000000, 50 },
627 + { 1000000, 60 },
628 + { 1000000, 70 },
629 + { 1000000, 80 },
630 + { 1000000, 90 },
631 + { 1000000, 100 },
632 };
633
634 collected_number test11_feed2[] = {
635 - 10, 20, 30, 40, 50, 60, 70, 80, 90, 100
635 + 10, 20, 30, 40, 50, 60, 70, 80, 90, 100
636 };
637
638 calculated_number test11_results[] = {
639 - 50, 50, 50, 50, 50, 50, 50, 50, 50
639 + 50, 50, 50, 50, 50, 50, 50, 50, 50
640 };
641
642 calculated_number test11_results2[] = {
643 - 50, 50, 50, 50, 50, 50, 50, 50, 50
643 + 50, 50, 50, 50, 50, 50, 50, 50, 50
644 };
645
646 struct test test11 = {
647 - "test11", // name
648 - "test percentage-of-incremental-row with equal values",
649 - 1, // update_every
650 - 1, // multiplier
651 - 1, // divisor
652 - RRDDIM_PCENT_OVER_DIFF_TOTAL, // algorithm
653 - 10, // feed entries
654 - 9, // result entries
655 - test11_feed, // feed
656 - test11_results, // results
657 - test11_feed2, // feed2
658 - test11_results2 // results2
647 + "test11", // name
648 + "test percentage-of-incremental-row with equal values",
649 + 1, // update_every
650 + 1, // multiplier
651 + 1, // divisor
652 + RRDDIM_PCENT_OVER_DIFF_TOTAL, // algorithm
653 + 10, // feed entries
654 + 9, // result entries
655 + test11_feed, // feed
656 + test11_results, // results
657 + test11_feed2, // feed2
658 + test11_results2 // results2
659 };
660
661 // --------------------------------------------------------------------------------------------------------------------
662 // test12
663
664 struct feed_values test12_feed[] = {
665 - { 0, 10 },
666 - { 1000000, 20 },
667 - { 1000000, 30 },
668 - { 1000000, 40 },
669 - { 1000000, 50 },
670 - { 1000000, 60 },
671 - { 1000000, 70 },
672 - { 1000000, 80 },
673 - { 1000000, 90 },
674 - { 1000000, 100 },
665 + { 0, 10 },
666 + { 1000000, 20 },
667 + { 1000000, 30 },
668 + { 1000000, 40 },
669 + { 1000000, 50 },
670 + { 1000000, 60 },
671 + { 1000000, 70 },
672 + { 1000000, 80 },
673 + { 1000000, 90 },
674 + { 1000000, 100 },
675 };
676
677 collected_number test12_feed2[] = {
678 - 10*3, 20*3, 30*3, 40*3, 50*3, 60*3, 70*3, 80*3, 90*3, 100*3
678 + 10*3, 20*3, 30*3, 40*3, 50*3, 60*3, 70*3, 80*3, 90*3, 100*3
679 };
680
681 calculated_number test12_results[] = {
682 - 25, 25, 25, 25, 25, 25, 25, 25, 25
682 + 25, 25, 25, 25, 25, 25, 25, 25, 25
683 };
684
685 calculated_number test12_results2[] = {
686 - 75, 75, 75, 75, 75, 75, 75, 75, 75
686 + 75, 75, 75, 75, 75, 75, 75, 75, 75
687 };
688
689 struct test test12 = {
690 - "test12", // name
691 - "test percentage-of-incremental-row with equal values",
692 - 1, // update_every
693 - 1, // multiplier
694 - 1, // divisor
695 - RRDDIM_PCENT_OVER_DIFF_TOTAL, // algorithm
696 - 10, // feed entries
697 - 9, // result entries
698 - test12_feed, // feed
699 - test12_results, // results
700 - test12_feed2, // feed2
701 - test12_results2 // results2
690 + "test12", // name
691 + "test percentage-of-incremental-row with equal values",
692 + 1, // update_every
693 + 1, // multiplier
694 + 1, // divisor
695 + RRDDIM_PCENT_OVER_DIFF_TOTAL, // algorithm
696 + 10, // feed entries
697 + 9, // result entries
698 + test12_feed, // feed
699 + test12_results, // results
700 + test12_feed2, // feed2
701 + test12_results2 // results2
702 };
703
704 // --------------------------------------------------------------------------------------------------------------------
705 // test13
706
707 struct feed_values test13_feed[] = {
708 - { 500000, 1000 },
709 - { 600000, 1000 + 600 },
710 - { 200000, 1600 + 200 },
711 - { 1000000, 1800 + 1000 },
712 - { 200000, 2800 + 200 },
713 - { 2000000, 3000 + 2000 },
714 - { 600000, 5000 + 600 },
715 - { 400000, 5600 + 400 },
716 - { 900000, 6000 + 900 },
717 - { 1000000, 6900 + 1000 },
708 + { 500000, 1000 },
709 + { 600000, 1000 + 600 },
710 + { 200000, 1600 + 200 },
711 + { 1000000, 1800 + 1000 },
712 + { 200000, 2800 + 200 },
713 + { 2000000, 3000 + 2000 },
714 + { 600000, 5000 + 600 },
715 + { 400000, 5600 + 400 },
716 + { 900000, 6000 + 900 },
717 + { 1000000, 6900 + 1000 },
718 };
719
720 calculated_number test13_results[] = {
721 - 83.3333300, 100, 100, 100, 100, 100, 100
721 + 83.3333300, 100, 100, 100, 100, 100, 100
722 };
723
724 struct test test13 = {
725 - "test13", // name
726 - "test incremental values updated in short and long durations",
727 - 1, // update_every
728 - 1, // multiplier
729 - 1, // divisor
730 - RRDDIM_PCENT_OVER_DIFF_TOTAL, // algorithm
731 - 10, // feed entries
732 - 7, // result entries
733 - test13_feed, // feed
734 - test13_results, // results
735 - NULL, // feed2
736 - NULL // results2
725 + "test13", // name
726 + "test incremental values updated in short and long durations",
727 + 1, // update_every
728 + 1, // multiplier
729 + 1, // divisor
730 + RRDDIM_PCENT_OVER_DIFF_TOTAL, // algorithm
731 + 10, // feed entries
732 + 7, // result entries
733 + test13_feed, // feed
734 + test13_results, // results
735 + NULL, // feed2
736 + NULL // results2
737 };
738
739 // --------------------------------------------------------------------------------------------------------------------
740
741 int run_test(struct test *test)
742 {
743 - fprintf(stderr, "\nRunning test '%s':\n%s\n", test->name, test->description);
744 -
745 - rrd_memory_mode = RRD_MEMORY_MODE_RAM;
746 - rrd_update_every = test->update_every;
747 -
748 - char name[101];
749 - snprintfz(name, 100, "unittest-%s", test->name);
750 -
751 - // create the chart
752 - RRDSET *st = rrdset_create("netdata", name, name, "netdata", NULL, "Unit Testing", "a value", 1, 1, RRDSET_TYPE_LINE);
753 - RRDDIM *rd = rrddim_add(st, "dim1", NULL, test->multiplier, test->divisor, test->algorithm);
754 -
755 - RRDDIM *rd2 = NULL;
756 - if(test->feed2)
757 - rd2 = rrddim_add(st, "dim2", NULL, test->multiplier, test->divisor, test->algorithm);
758 -
759 - st->debug = 1;
760 -
761 - // feed it with the test data
762 - unsigned long c;
763 - for(c = 0; c < test->feed_entries; c++) {
764 - if(debug_flags) fprintf(stderr, "\n\n");
765 -
766 - if(c) {
767 - fprintf(stderr, " > %s: feeding position %lu, after %llu microseconds\n", test->name, c+1, test->feed[c].microseconds);
768 - rrdset_next_usec(st, test->feed[c].microseconds);
769 - }
770 - else {
771 - fprintf(stderr, " > %s: feeding position %lu\n", test->name, c+1);
772 - }
773 -
774 - fprintf(stderr, " >> %s with value " COLLECTED_NUMBER_FORMAT "\n", rd->name, test->feed[c].value);
775 - rrddim_set(st, "dim1", test->feed[c].value);
776 -
777 - if(rd2) {
778 - fprintf(stderr, " >> %s with value " COLLECTED_NUMBER_FORMAT "\n", rd2->name, test->feed2[c]);
779 - rrddim_set(st, "dim2", test->feed2[c]);
780 - }
781 -
782 - rrdset_done(st);
783 -
784 - // align the first entry to second boundary
785 - if(!c) {
786 - fprintf(stderr, " > %s: fixing first collection time to be %llu microseconds to second boundary\n", test->name, test->feed[c].microseconds);
787 - rd->last_collected_time.tv_usec = st->last_collected_time.tv_usec = st->last_updated.tv_usec = test->feed[c].microseconds;
788 - }
789 - }
790 -
791 - // check the result
792 - int errors = 0;
793 -
794 - if(st->counter != test->result_entries) {
795 - fprintf(stderr, " %s stored %lu entries, but we were expecting %lu, ### E R R O R ###\n", test->name, st->counter, test->result_entries);
796 - errors++;
797 - }
798 -
799 - unsigned long max = (st->counter < test->result_entries)?st->counter:test->result_entries;
800 - for(c = 0 ; c < max ; c++) {
801 - calculated_number v = unpack_storage_number(rd->values[c]);
802 - calculated_number n = test->results[c];
803 - int same = (roundl(v * 10000000.0) == roundl(n * 10000000.0))?1:0;
804 - fprintf(stderr, " %s/%s: checking position %lu, expecting value " CALCULATED_NUMBER_FORMAT ", found " CALCULATED_NUMBER_FORMAT ", %s\n", test->name, rd->name, c+1, n, v, (same)?"OK":"### E R R O R ###");
805 - if(!same) errors++;
806 -
807 - if(rd2) {
808 - v = unpack_storage_number(rd2->values[c]);
809 - n = test->results2[c];
810 - same = (roundl(v * 10000000.0) == roundl(n * 10000000.0))?1:0;
811 - fprintf(stderr, " %s/%s: checking position %lu, expecting value " CALCULATED_NUMBER_FORMAT ", found " CALCULATED_NUMBER_FORMAT ", %s\n", test->name, rd2->name, c+1, n, v, (same)?"OK":"### E R R O R ###");
812 - if(!same) errors++;
813 - }
814 - }
815 -
816 - return errors;
743 + fprintf(stderr, "\nRunning test '%s':\n%s\n", test->name, test->description);
744 +
745 + rrd_memory_mode = RRD_MEMORY_MODE_RAM;
746 + rrd_update_every = test->update_every;
747 +
748 + char name[101];
749 + snprintfz(name, 100, "unittest-%s", test->name);
750 +
751 + // create the chart
752 + RRDSET *st = rrdset_create("netdata", name, name, "netdata", NULL, "Unit Testing", "a value", 1, 1, RRDSET_TYPE_LINE);
753 + RRDDIM *rd = rrddim_add(st, "dim1", NULL, test->multiplier, test->divisor, test->algorithm);
754 +
755 + RRDDIM *rd2 = NULL;
756 + if(test->feed2)
757 + rd2 = rrddim_add(st, "dim2", NULL, test->multiplier, test->divisor, test->algorithm);
758 +
759 + st->debug = 1;
760 +
761 + // feed it with the test data
762 + unsigned long c;
763 + for(c = 0; c < test->feed_entries; c++) {
764 + if(debug_flags) fprintf(stderr, "\n\n");
765 +
766 + if(c) {
767 + fprintf(stderr, " > %s: feeding position %lu, after %llu microseconds\n", test->name, c+1, test->feed[c].microseconds);
768 + rrdset_next_usec(st, test->feed[c].microseconds);
769 + }
770 + else {
771 + fprintf(stderr, " > %s: feeding position %lu\n", test->name, c+1);
772 + }
773 +
774 + fprintf(stderr, " >> %s with value " COLLECTED_NUMBER_FORMAT "\n", rd->name, test->feed[c].value);
775 + rrddim_set(st, "dim1", test->feed[c].value);
776 +
777 + if(rd2) {
778 + fprintf(stderr, " >> %s with value " COLLECTED_NUMBER_FORMAT "\n", rd2->name, test->feed2[c]);
779 + rrddim_set(st, "dim2", test->feed2[c]);
780 + }
781 +
782 + rrdset_done(st);
783 +
784 + // align the first entry to second boundary
785 + if(!c) {
786 + fprintf(stderr, " > %s: fixing first collection time to be %llu microseconds to second boundary\n", test->name, test->feed[c].microseconds);
787 + rd->last_collected_time.tv_usec = st->last_collected_time.tv_usec = st->last_updated.tv_usec = test->feed[c].microseconds;
788 + }
789 + }
790 +
791 + // check the result
792 + int errors = 0;
793 +
794 + if(st->counter != test->result_entries) {
795 + fprintf(stderr, " %s stored %lu entries, but we were expecting %lu, ### E R R O R ###\n", test->name, st->counter, test->result_entries);
796 + errors++;
797 + }
798 +
799 + unsigned long max = (st->counter < test->result_entries)?st->counter:test->result_entries;
800 + for(c = 0 ; c < max ; c++) {
801 + calculated_number v = unpack_storage_number(rd->values[c]);
802 + calculated_number n = test->results[c];
803 + int same = (roundl(v * 10000000.0) == roundl(n * 10000000.0))?1:0;
804 + fprintf(stderr, " %s/%s: checking position %lu, expecting value " CALCULATED_NUMBER_FORMAT ", found " CALCULATED_NUMBER_FORMAT ", %s\n", test->name, rd->name, c+1, n, v, (same)?"OK":"### E R R O R ###");
805 + if(!same) errors++;
806 +
807 + if(rd2) {
808 + v = unpack_storage_number(rd2->values[c]);
809 + n = test->results2[c];
810 + same = (roundl(v * 10000000.0) == roundl(n * 10000000.0))?1:0;
811 + fprintf(stderr, " %s/%s: checking position %lu, expecting value " CALCULATED_NUMBER_FORMAT ", found " CALCULATED_NUMBER_FORMAT ", %s\n", test->name, rd2->name, c+1, n, v, (same)?"OK":"### E R R O R ###");
812 + if(!same) errors++;
813 + }
814 + }
815 +
816 + return errors;
817 }
818
819 int run_all_mockup_tests(void)
820 {
821 - if(run_test(&test1))
822 - return 1;
821 + if(run_test(&test1))
822 + return 1;
823
824 - if(run_test(&test2))
825 - return 1;
824 + if(run_test(&test2))
825 + return 1;
826
827 - if(run_test(&test3))
828 - return 1;
827 + if(run_test(&test3))
828 + return 1;
829
830 - if(run_test(&test4))
831 - return 1;
830 + if(run_test(&test4))
831 + return 1;
832
833 - if(run_test(&test5))
834 - return 1;
833 + if(run_test(&test5))
834 + return 1;
835
836 - if(run_test(&test6))
837 - return 1;
836 + if(run_test(&test6))
837 + return 1;
838
839 - if(run_test(&test7))
840 - return 1;
839 + if(run_test(&test7))
840 + return 1;
841
842 - if(run_test(&test8))
843 - return 1;
842 + if(run_test(&test8))
843 + return 1;
844
845 - if(run_test(&test9))
846 - return 1;
845 + if(run_test(&test9))
846 + return 1;
847
848 - if(run_test(&test10))
849 - return 1;
848 + if(run_test(&test10))
849 + return 1;
850
851 - if(run_test(&test11))
852 - return 1;
851 + if(run_test(&test11))
852 + return 1;
853
854 - if(run_test(&test12))
855 - return 1;
854 + if(run_test(&test12))
855 + return 1;
856
857 - if(run_test(&test13))
858 - return 1;
857 + if(run_test(&test13))
858 + return 1;
859
860 - return 0;
860 + return 0;
861 }
862
863 int unit_test(long delay, long shift)
864 {
865 - static int repeat = 0;
866 - repeat++;
867 -
868 - char name[101];
869 - snprintfz(name, 100, "unittest-%d-%ld-%ld", repeat, delay, shift);
870 -
871 - //debug_flags = 0xffffffff;
872 - rrd_memory_mode = RRD_MEMORY_MODE_RAM;
873 - rrd_update_every = 1;
874 -
875 - int do_abs = 1;
876 - int do_inc = 1;
877 - int do_abst = 0;
878 - int do_absi = 0;
879 -
880 - RRDSET *st = rrdset_create("netdata", name, name, "netdata", NULL, "Unit Testing", "a value", 1, 1, RRDSET_TYPE_LINE);
881 - st->debug = 1;
882 -
883 - RRDDIM *rdabs = NULL;
884 - RRDDIM *rdinc = NULL;
885 - RRDDIM *rdabst = NULL;
886 - RRDDIM *rdabsi = NULL;
887 -
888 - if(do_abs) rdabs = rrddim_add(st, "absolute", "absolute", 1, 1, RRDDIM_ABSOLUTE);
889 - if(do_inc) rdinc = rrddim_add(st, "incremental", "incremental", 1, 1, RRDDIM_INCREMENTAL);
890 - if(do_abst) rdabst = rrddim_add(st, "percentage-of-absolute-row", "percentage-of-absolute-row", 1, 1, RRDDIM_PCENT_OVER_ROW_TOTAL);
891 - if(do_absi) rdabsi = rrddim_add(st, "percentage-of-incremental-row", "percentage-of-incremental-row", 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
892 -
893 - long increment = 1000;
894 - collected_number i = 0;
895 -
896 - unsigned long c, dimensions = 0;
897 - RRDDIM *rd;
898 - for(rd = st->dimensions ; rd ; rd = rd->next) dimensions++;
899 -
900 - for(c = 0; c < 20 ;c++) {
901 - i += increment;
902 -
903 - fprintf(stderr, "\n\nLOOP = %lu, DELAY = %ld, VALUE = " COLLECTED_NUMBER_FORMAT "\n", c, delay, i);
904 - if(c) {
905 - rrdset_next_usec(st, delay);
906 - }
907 - if(do_abs) rrddim_set(st, "absolute", i);
908 - if(do_inc) rrddim_set(st, "incremental", i);
909 - if(do_abst) rrddim_set(st, "percentage-of-absolute-row", i);
910 - if(do_absi) rrddim_set(st, "percentage-of-incremental-row", i);
911 -
912 - if(!c) {
913 - gettimeofday(&st->last_collected_time, NULL);
914 - st->last_collected_time.tv_usec = shift;
915 - }
916 -
917 - // prevent it from deleting the dimensions
918 - for(rd = st->dimensions ; rd ; rd = rd->next)
919 - rd->last_collected_time.tv_sec = st->last_collected_time.tv_sec;
920 -
921 - rrdset_done(st);
922 - }
923 -
924 - unsigned long oincrement = increment;
925 - increment = increment * st->update_every * 1000000 / delay;
926 - fprintf(stderr, "\n\nORIGINAL INCREMENT: %lu, INCREMENT %ld, DELAY %ld, SHIFT %ld\n", oincrement * 10, increment * 10, delay, shift);
927 -
928 - int ret = 0;
929 - storage_number sn;
930 - calculated_number cn, v;
931 - for(c = 0 ; c < st->counter ; c++) {
932 - fprintf(stderr, "\nPOSITION: c = %lu, EXPECTED VALUE %lu\n", c, (oincrement + c * increment + increment * (1000000 - shift) / 1000000 )* 10);
933 -
934 - for(rd = st->dimensions ; rd ; rd = rd->next) {
935 - sn = rd->values[c];
936 - cn = unpack_storage_number(sn);
937 - fprintf(stderr, "\t %s " CALCULATED_NUMBER_FORMAT " (PACKED AS " STORAGE_NUMBER_FORMAT ") -> ", rd->id, cn, sn);
938 -
939 - if(rd == rdabs) v =
940 - ( oincrement
941 - // + (increment * (1000000 - shift) / 1000000)
942 - + (c + 1) * increment
943 - );
944 -
945 - else if(rd == rdinc) v = (c?(increment):(increment * (1000000 - shift) / 1000000));
946 - else if(rd == rdabst) v = oincrement / dimensions / 10;
947 - else if(rd == rdabsi) v = oincrement / dimensions / 10;
948 - else v = 0;
949 -
950 - if(v == cn) fprintf(stderr, "passed.\n");
951 - else {
952 - fprintf(stderr, "ERROR! (expected " CALCULATED_NUMBER_FORMAT ")\n", v);
953 - ret = 1;
954 - }
955 - }
956 - }
957 -
958 - if(ret)
959 - fprintf(stderr, "\n\nUNIT TEST(%ld, %ld) FAILED\n\n", delay, shift);
960 -
961 - return ret;
865 + static int repeat = 0;
866 + repeat++;
867 +
868 + char name[101];
869 + snprintfz(name, 100, "unittest-%d-%ld-%ld", repeat, delay, shift);
870 +
871 + //debug_flags = 0xffffffff;
872 + rrd_memory_mode = RRD_MEMORY_MODE_RAM;
873 + rrd_update_every = 1;
874 +
875 + int do_abs = 1;
876 + int do_inc = 1;
877 + int do_abst = 0;
878 + int do_absi = 0;
879 +
880 + RRDSET *st = rrdset_create("netdata", name, name, "netdata", NULL, "Unit Testing", "a value", 1, 1, RRDSET_TYPE_LINE);
881 + st->debug = 1;
882 +
883 + RRDDIM *rdabs = NULL;
884 + RRDDIM *rdinc = NULL;
885 + RRDDIM *rdabst = NULL;
886 + RRDDIM *rdabsi = NULL;
887 +
888 + if(do_abs) rdabs = rrddim_add(st, "absolute", "absolute", 1, 1, RRDDIM_ABSOLUTE);
889 + if(do_inc) rdinc = rrddim_add(st, "incremental", "incremental", 1, 1, RRDDIM_INCREMENTAL);
890 + if(do_abst) rdabst = rrddim_add(st, "percentage-of-absolute-row", "percentage-of-absolute-row", 1, 1, RRDDIM_PCENT_OVER_ROW_TOTAL);
891 + if(do_absi) rdabsi = rrddim_add(st, "percentage-of-incremental-row", "percentage-of-incremental-row", 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
892 +
893 + long increment = 1000;
894 + collected_number i = 0;
895 +
896 + unsigned long c, dimensions = 0;
897 + RRDDIM *rd;
898 + for(rd = st->dimensions ; rd ; rd = rd->next) dimensions++;
899 +
900 + for(c = 0; c < 20 ;c++) {
901 + i += increment;
902 +
903 + fprintf(stderr, "\n\nLOOP = %lu, DELAY = %ld, VALUE = " COLLECTED_NUMBER_FORMAT "\n", c, delay, i);
904 + if(c) {
905 + rrdset_next_usec(st, delay);
906 + }
907 + if(do_abs) rrddim_set(st, "absolute", i);
908 + if(do_inc) rrddim_set(st, "incremental", i);
909 + if(do_abst) rrddim_set(st, "percentage-of-absolute-row", i);
910 + if(do_absi) rrddim_set(st, "percentage-of-incremental-row", i);
911 +
912 + if(!c) {
913 + gettimeofday(&st->last_collected_time, NULL);
914 + st->last_collected_time.tv_usec = shift;
915 + }
916 +
917 + // prevent it from deleting the dimensions
918 + for(rd = st->dimensions ; rd ; rd = rd->next)
919 + rd->last_collected_time.tv_sec = st->last_collected_time.tv_sec;
920 +
921 + rrdset_done(st);
922 + }
923 +
924 + unsigned long oincrement = increment;
925 + increment = increment * st->update_every * 1000000 / delay;
926 + fprintf(stderr, "\n\nORIGINAL INCREMENT: %lu, INCREMENT %ld, DELAY %ld, SHIFT %ld\n", oincrement * 10, increment * 10, delay, shift);
927 +
928 + int ret = 0;
929 + storage_number sn;
930 + calculated_number cn, v;
931 + for(c = 0 ; c < st->counter ; c++) {
932 + fprintf(stderr, "\nPOSITION: c = %lu, EXPECTED VALUE %lu\n", c, (oincrement + c * increment + increment * (1000000 - shift) / 1000000 )* 10);
933 +
934 + for(rd = st->dimensions ; rd ; rd = rd->next) {
935 + sn = rd->values[c];
936 + cn = unpack_storage_number(sn);
937 + fprintf(stderr, "\t %s " CALCULATED_NUMBER_FORMAT " (PACKED AS " STORAGE_NUMBER_FORMAT ") -> ", rd->id, cn, sn);
938 +
939 + if(rd == rdabs) v =
940 + ( oincrement
941 + // + (increment * (1000000 - shift) / 1000000)
942 + + (c + 1) * increment
943 + );
944 +
945 + else if(rd == rdinc) v = (c?(increment):(increment * (1000000 - shift) / 1000000));
946 + else if(rd == rdabst) v = oincrement / dimensions / 10;
947 + else if(rd == rdabsi) v = oincrement / dimensions / 10;
948 + else v = 0;
949 +
950 + if(v == cn) fprintf(stderr, "passed.\n");
951 + else {
952 + fprintf(stderr, "ERROR! (expected " CALCULATED_NUMBER_FORMAT ")\n", v);
953 + ret = 1;
954 + }
955 + }
956 + }
957 +
958 + if(ret)
959 + fprintf(stderr, "\n\nUNIT TEST(%ld, %ld) FAILED\n\n", delay, shift);
960 +
961 + return ret;
962 }
src/url.c
+39 -39
@@ -6,72 +6,72 @@
6
7 /* Converts a hex character to its integer value */
8 char from_hex(char ch) {
9 - return (char)(isdigit(ch) ? ch - '0' : tolower(ch) - 'a' + 10);
9 + return (char)(isdigit(ch) ? ch - '0' : tolower(ch) - 'a' + 10);
10 }
11
12 /* Converts an integer value to its hex character*/
13 char to_hex(char code) {
14 - static char hex[] = "0123456789abcdef";
15 - return hex[code & 15];
14 + static char hex[] = "0123456789abcdef";
15 + return hex[code & 15];
16 }
17
18 /* Returns a url-encoded version of str */
19 /* IMPORTANT: be sure to free() the returned string after use */
20 char *url_encode(char *str) {
21 - char *buf, *pbuf;
21 + char *buf, *pbuf;
22
23 - pbuf = buf = mallocz(strlen(str) * 3 + 1);
23 + pbuf = buf = mallocz(strlen(str) * 3 + 1);
24
25 - while (*str) {
26 - if (isalnum(*str) || *str == '-' || *str == '_' || *str == '.' || *str == '~')
27 - *pbuf++ = *str;
25 + while (*str) {
26 + if (isalnum(*str) || *str == '-' || *str == '_' || *str == '.' || *str == '~')
27 + *pbuf++ = *str;
28
29 - else if (*str == ' ')
30 - *pbuf++ = '+';
29 + else if (*str == ' ')
30 + *pbuf++ = '+';
31
32 - else
33 - *pbuf++ = '%', *pbuf++ = to_hex(*str >> 4), *pbuf++ = to_hex(*str & 15);
32 + else
33 + *pbuf++ = '%', *pbuf++ = to_hex(*str >> 4), *pbuf++ = to_hex(*str & 15);
34
35 - str++;
36 - }
37 - *pbuf = '\0';
35 + str++;
36 + }
37 + *pbuf = '\0';
38
39 - pbuf = strdupz(buf);
40 - freez(buf);
41 - return pbuf;
39 + pbuf = strdupz(buf);
40 + freez(buf);
41 + return pbuf;
42 }
43
44 /* Returns a url-decoded version of str */
45 /* IMPORTANT: be sure to free() the returned string after use */
46 char *url_decode(char *str) {
47 - size_t size = strlen(str) + 1;
47 + size_t size = strlen(str) + 1;
48
49 - char *buf = mallocz(size);
50 - return url_decode_r(buf, str, size);
49 + char *buf = mallocz(size);
50 + return url_decode_r(buf, str, size);
51 }
52
53 char *url_decode_r(char *to, char *url, size_t size) {
54 - char *s = url, // source
55 - *d = to, // destination
56 - *e = &to[size - 1]; // destination end
54 + char *s = url, // source
55 + *d = to, // destination
56 + *e = &to[size - 1]; // destination end
57
58 - while(*s && d < e) {
59 - if(unlikely(*s == '%')) {
60 - if(likely(s[1] && s[2])) {
61 - *d++ = from_hex(s[1]) << 4 | from_hex(s[2]);
62 - s += 2;
63 - }
64 - }
65 - else if(unlikely(*s == '+'))
66 - *d++ = ' ';
58 + while(*s && d < e) {
59 + if(unlikely(*s == '%')) {
60 + if(likely(s[1] && s[2])) {
61 + *d++ = from_hex(s[1]) << 4 | from_hex(s[2]);
62 + s += 2;
63 + }
64 + }
65 + else if(unlikely(*s == '+'))
66 + *d++ = ' ';
67
68 - else
69 - *d++ = *s;
68 + else
69 + *d++ = *s;
70
71 - s++;
72 - }
71 + s++;
72 + }
73
74 - *d = '\0';
74 + *d = '\0';
75
76 - return to;
76 + return to;
77 }
src/web_buffer.c
+163 -163
@@ -4,8 +4,8 @@
4
5 static inline void buffer_overflow_init(BUFFER *b)
6 {
7 - b->buffer[b->size] = '\0';
8 - strcpy(&b->buffer[b->size + 1], BUFFER_OVERFLOW_EOF);
7 + b->buffer[b->size] = '\0';
8 + strcpy(&b->buffer[b->size + 1], BUFFER_OVERFLOW_EOF);
9 }
10
11 #ifdef NETDATA_INTERNAL_CHECKS
@@ -16,49 +16,49 @@ static inline void buffer_overflow_init(BUFFER *b)
16
17 static inline void _buffer_overflow_check(BUFFER *b, const char *file, const char *function, const unsigned long line)
18 {
19 - if(b->len > b->size) {
20 - error("BUFFER: length %zu is above size %zu, at line %lu, at function %s() of file '%s'.", b->len, b->size, line, function, file);
21 - b->len = b->size;
22 - }
23 -
24 - if(b->buffer[b->size] != '\0' || strcmp(&b->buffer[b->size + 1], BUFFER_OVERFLOW_EOF)) {
25 - error("BUFFER: detected overflow at line %lu, at function %s() of file '%s'.", line, function, file);
26 - buffer_overflow_init(b);
27 - }
19 + if(b->len > b->size) {
20 + error("BUFFER: length %zu is above size %zu, at line %lu, at function %s() of file '%s'.", b->len, b->size, line, function, file);
21 + b->len = b->size;
22 + }
23 +
24 + if(b->buffer[b->size] != '\0' || strcmp(&b->buffer[b->size + 1], BUFFER_OVERFLOW_EOF)) {
25 + error("BUFFER: detected overflow at line %lu, at function %s() of file '%s'.", line, function, file);
26 + buffer_overflow_init(b);
27 + }
28 }
29
30
31 void buffer_reset(BUFFER *wb)
32 {
33 - buffer_flush(wb);
33 + buffer_flush(wb);
34
35 - wb->contenttype = CT_TEXT_PLAIN;
36 - wb->options = 0;
37 - wb->date = 0;
35 + wb->contenttype = CT_TEXT_PLAIN;
36 + wb->options = 0;
37 + wb->date = 0;
38
39 - buffer_overflow_check(wb);
39 + buffer_overflow_check(wb);
40 }
41
42 const char *buffer_tostring(BUFFER *wb)
43 {
44 - buffer_need_bytes(wb, 1);
45 - wb->buffer[wb->len] = '\0';
44 + buffer_need_bytes(wb, 1);
45 + wb->buffer[wb->len] = '\0';
46
47 - buffer_overflow_check(wb);
47 + buffer_overflow_check(wb);
48
49 - return(wb->buffer);
49 + return(wb->buffer);
50 }
51
52 void buffer_char_replace(BUFFER *wb, char from, char to)
53 {
54 - char *s = wb->buffer, *end = &wb->buffer[wb->len];
54 + char *s = wb->buffer, *end = &wb->buffer[wb->len];
55
56 - while(s != end) {
57 - if(*s == from) *s = to;
58 - s++;
59 - }
56 + while(s != end) {
57 + if(*s == from) *s = to;
58 + s++;
59 + }
60
61 - buffer_overflow_check(wb);
61 + buffer_overflow_check(wb);
62 }
63
64 // This trick seems to give an 80% speed increase in 32bit systems
@@ -67,171 +67,171 @@ void buffer_char_replace(BUFFER *wb, char from, char to)
67 // print_calculated_number_lu_r() to print the rest with 32 bit arithmetic.
68
69 inline char *print_number_lu_r(char *str, unsigned long uvalue) {
70 - char *wstr = str;
70 + char *wstr = str;
71
72 - // print each digit
73 - do *wstr++ = (char)('0' + (uvalue % 10)); while(uvalue /= 10);
74 - return wstr;
72 + // print each digit
73 + do *wstr++ = (char)('0' + (uvalue % 10)); while(uvalue /= 10);
74 + return wstr;
75 }
76
77 inline char *print_number_llu_r(char *str, unsigned long long uvalue) {
78 - char *wstr = str;
78 + char *wstr = str;
79
80 - // print each digit
81 - do *wstr++ = (char)('0' + (uvalue % 10)); while((uvalue /= 10) && uvalue > (unsigned long long)0xffffffff);
82 - if(uvalue) return print_number_lu_r(wstr, uvalue);
83 - return wstr;
80 + // print each digit
81 + do *wstr++ = (char)('0' + (uvalue % 10)); while((uvalue /= 10) && uvalue > (unsigned long long)0xffffffff);
82 + if(uvalue) return print_number_lu_r(wstr, uvalue);
83 + return wstr;
84 }
85
86 void buffer_print_llu(BUFFER *wb, unsigned long long uvalue)
87 {
88 - buffer_need_bytes(wb, 50);
88 + buffer_need_bytes(wb, 50);
89
90 - char *str = &wb->buffer[wb->len];
91 - char *wstr = str;
90 + char *str = &wb->buffer[wb->len];
91 + char *wstr = str;
92
93 #ifdef ENVIRONMENT32
94 - if(uvalue > (unsigned long long)0xffffffff)
95 - wstr = print_number_llu_r(wstr, uvalue);
96 - else
97 - wstr = print_number_lu_r(wstr, uvalue);
94 + if(uvalue > (unsigned long long)0xffffffff)
95 + wstr = print_number_llu_r(wstr, uvalue);
96 + else
97 + wstr = print_number_lu_r(wstr, uvalue);
98 #else
99 - do *wstr++ = (char)('0' + (uvalue % 10)); while(uvalue /= 10);
99 + do *wstr++ = (char)('0' + (uvalue % 10)); while(uvalue /= 10);
100 #endif
101
102 - // terminate it
103 - *wstr = '\0';
102 + // terminate it
103 + *wstr = '\0';
104
105 - // reverse it
106 - char *begin = str, *end = wstr - 1, aux;
107 - while (end > begin) aux = *end, *end-- = *begin, *begin++ = aux;
105 + // reverse it
106 + char *begin = str, *end = wstr - 1, aux;
107 + while (end > begin) aux = *end, *end-- = *begin, *begin++ = aux;
108
109 - // return the buffer length
110 - wb->len += wstr - str;
109 + // return the buffer length
110 + wb->len += wstr - str;
111 }
112
113 void buffer_strcat(BUFFER *wb, const char *txt)
114 {
115 - if(unlikely(!txt || !*txt)) return;
116 -
117 - buffer_need_bytes(wb, 1);
118 -
119 - char *s = &wb->buffer[wb->len], *start, *end = &wb->buffer[wb->size];
120 - long len = wb->len;
121 -
122 - start = s;
123 - while(*txt && s != end)
124 - *s++ = *txt++;
125 -
126 - len += s - start;
127 -
128 - wb->len = len;
129 - buffer_overflow_check(wb);
130 -
131 - if(*txt) {
132 - debug(D_WEB_BUFFER, "strcat(): increasing web_buffer at position %zu, size = %zu\n", wb->len, wb->size);
133 - len = strlen(txt);
134 - buffer_increase(wb, len);
135 - buffer_strcat(wb, txt);
136 - }
137 - else {
138 - // terminate the string
139 - // without increasing the length
140 - buffer_need_bytes(wb, (size_t)1);
141 - wb->buffer[wb->len] = '\0';
142 - }
115 + if(unlikely(!txt || !*txt)) return;
116 +
117 + buffer_need_bytes(wb, 1);
118 +
119 + char *s = &wb->buffer[wb->len], *start, *end = &wb->buffer[wb->size];
120 + long len = wb->len;
121 +
122 + start = s;
123 + while(*txt && s != end)
124 + *s++ = *txt++;
125 +
126 + len += s - start;
127 +
128 + wb->len = len;
129 + buffer_overflow_check(wb);
130 +
131 + if(*txt) {
132 + debug(D_WEB_BUFFER, "strcat(): increasing web_buffer at position %zu, size = %zu\n", wb->len, wb->size);
133 + len = strlen(txt);
134 + buffer_increase(wb, len);
135 + buffer_strcat(wb, txt);
136 + }
137 + else {
138 + // terminate the string
139 + // without increasing the length
140 + buffer_need_bytes(wb, (size_t)1);
141 + wb->buffer[wb->len] = '\0';
142 + }
143 }
144
145
146 void buffer_snprintf(BUFFER *wb, size_t len, const char *fmt, ...)
147 {
148 - if(unlikely(!fmt || !*fmt)) return;
148 + if(unlikely(!fmt || !*fmt)) return;
149
150 - buffer_need_bytes(wb, len + 1);
150 + buffer_need_bytes(wb, len + 1);
151
152 - va_list args;
153 - va_start(args, fmt);
154 - wb->len += vsnprintfz(&wb->buffer[wb->len], len, fmt, args);
155 - va_end(args);
152 + va_list args;
153 + va_start(args, fmt);
154 + wb->len += vsnprintfz(&wb->buffer[wb->len], len, fmt, args);
155 + va_end(args);
156
157 - buffer_overflow_check(wb);
157 + buffer_overflow_check(wb);
158
159 - // the buffer is \0 terminated by vsnprintfz
159 + // the buffer is \0 terminated by vsnprintfz
160 }
161
162 void buffer_vsprintf(BUFFER *wb, const char *fmt, va_list args)
163 {
164 - if(unlikely(!fmt || !*fmt)) return;
164 + if(unlikely(!fmt || !*fmt)) return;
165
166 - buffer_need_bytes(wb, 2);
166 + buffer_need_bytes(wb, 2);
167
168 - size_t len = wb->size - wb->len - 1;
168 + size_t len = wb->size - wb->len - 1;
169
170 - wb->len += vsnprintfz(&wb->buffer[wb->len], len, fmt, args);
170 + wb->len += vsnprintfz(&wb->buffer[wb->len], len, fmt, args);
171
172 - buffer_overflow_check(wb);
172 + buffer_overflow_check(wb);
173
174 - // the buffer is \0 terminated by vsnprintfz
174 + // the buffer is \0 terminated by vsnprintfz
175 }
176
177 void buffer_sprintf(BUFFER *wb, const char *fmt, ...)
178 {
179 - if(unlikely(!fmt || !*fmt)) return;
179 + if(unlikely(!fmt || !*fmt)) return;
180
181 - buffer_need_bytes(wb, 2);
181 + buffer_need_bytes(wb, 2);
182
183 - size_t len = wb->size - wb->len - 1;
184 - size_t wrote;
183 + size_t len = wb->size - wb->len - 1;
184 + size_t wrote;
185
186 - va_list args;
187 - va_start(args, fmt);
188 - wrote = (size_t) vsnprintfz(&wb->buffer[wb->len], len, fmt, args);
189 - va_end(args);
186 + va_list args;
187 + va_start(args, fmt);
188 + wrote = (size_t) vsnprintfz(&wb->buffer[wb->len], len, fmt, args);
189 + va_end(args);
190
191 - if(unlikely(wrote >= len)) {
192 - // there is bug in vsnprintf() and it returns
193 - // a number higher to len, but it does not
194 - // overflow the buffer.
195 - // our buffer overflow detector will log it
196 - // if it does.
197 - buffer_overflow_check(wb);
191 + if(unlikely(wrote >= len)) {
192 + // there is bug in vsnprintf() and it returns
193 + // a number higher to len, but it does not
194 + // overflow the buffer.
195 + // our buffer overflow detector will log it
196 + // if it does.
197 + buffer_overflow_check(wb);
198
199 - debug(D_WEB_BUFFER, "web_buffer_sprintf(): increasing web_buffer at position %zu, size = %zu\n", wb->len, wb->size);
200 - buffer_need_bytes(wb, len + WEB_DATA_LENGTH_INCREASE_STEP);
199 + debug(D_WEB_BUFFER, "web_buffer_sprintf(): increasing web_buffer at position %zu, size = %zu\n", wb->len, wb->size);
200 + buffer_need_bytes(wb, len + WEB_DATA_LENGTH_INCREASE_STEP);
201
202 - va_start(args, fmt);
203 - buffer_vsprintf(wb, fmt, args);
204 - va_end(args);
205 - }
206 - else
207 - wb->len += wrote;
202 + va_start(args, fmt);
203 + buffer_vsprintf(wb, fmt, args);
204 + va_end(args);
205 + }
206 + else
207 + wb->len += wrote;
208
209 - // the buffer is \0 terminated by vsnprintf
209 + // the buffer is \0 terminated by vsnprintf
210 }
211
212
213 void buffer_rrd_value(BUFFER *wb, calculated_number value)
214 {
215 - buffer_need_bytes(wb, 50);
216 - wb->len += print_calculated_number(&wb->buffer[wb->len], value);
215 + buffer_need_bytes(wb, 50);
216 + wb->len += print_calculated_number(&wb->buffer[wb->len], value);
217
218 - // terminate it
219 - buffer_need_bytes(wb, 1);
220 - wb->buffer[wb->len] = '\0';
218 + // terminate it
219 + buffer_need_bytes(wb, 1);
220 + wb->buffer[wb->len] = '\0';
221
222 - buffer_overflow_check(wb);
222 + buffer_overflow_check(wb);
223 }
224
225 // generate a javascript date, the fastest possible way...
226 void buffer_jsdate(BUFFER *wb, int year, int month, int day, int hours, int minutes, int seconds)
227 {
228 // 10 20 30 = 35
229 - // 01234567890123456789012345678901234
230 - // Date(2014,04,01,03,28,20)
229 + // 01234567890123456789012345678901234
230 + // Date(2014,04,01,03,28,20)
231
232 - buffer_need_bytes(wb, 30);
232 + buffer_need_bytes(wb, 30);
233
234 - char *b = &wb->buffer[wb->len], *p;
234 + char *b = &wb->buffer[wb->len], *p;
235 unsigned int *q = (unsigned int *)b;
236
237 #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
@@ -270,23 +270,23 @@ void buffer_jsdate(BUFFER *wb, int year, int month, int day, int hours, int minu
270 *r++ = 0x2900; // ")\0"
271 #endif
272
273 - wb->len += (size_t)((char *)r - b - 1);
273 + wb->len += (size_t)((char *)r - b - 1);
274
275 - // terminate it
276 - wb->buffer[wb->len] = '\0';
277 - buffer_overflow_check(wb);
275 + // terminate it
276 + wb->buffer[wb->len] = '\0';
277 + buffer_overflow_check(wb);
278 }
279
280 // generate a date, the fastest possible way...
281 void buffer_date(BUFFER *wb, int year, int month, int day, int hours, int minutes, int seconds)
282 {
283 - // 10 20 30 = 35
284 - // 01234567890123456789012345678901234
285 - // 2014-04-01 03:28:20
283 + // 10 20 30 = 35
284 + // 01234567890123456789012345678901234
285 + // 2014-04-01 03:28:20
286
287 - buffer_need_bytes(wb, 36);
287 + buffer_need_bytes(wb, 36);
288
289 - char *b = &wb->buffer[wb->len];
289 + char *b = &wb->buffer[wb->len];
290 char *p = b;
291
292 *p++ = '0' + year / 1000; year %= 1000;
@@ -310,56 +310,56 @@ void buffer_date(BUFFER *wb, int year, int month, int day, int hours, int minute
310 *p++ = '0' + seconds % 10;
311 *p = '\0';
312
313 - wb->len += (size_t)(p - b);
313 + wb->len += (size_t)(p - b);
314
315 - // terminate it
316 - wb->buffer[wb->len] = '\0';
317 - buffer_overflow_check(wb);
315 + // terminate it
316 + wb->buffer[wb->len] = '\0';
317 + buffer_overflow_check(wb);
318 }
319
320 BUFFER *buffer_create(size_t size)
321 {
322 - BUFFER *b;
322 + BUFFER *b;
323
324 - debug(D_WEB_BUFFER, "Creating new web buffer of size %zu.", size);
324 + debug(D_WEB_BUFFER, "Creating new web buffer of size %zu.", size);
325
326 - b = callocz(1, sizeof(BUFFER));
327 - b->buffer = mallocz(size + sizeof(BUFFER_OVERFLOW_EOF) + 2);
328 - b->buffer[0] = '\0';
329 - b->size = size;
330 - b->contenttype = CT_TEXT_PLAIN;
331 - buffer_overflow_init(b);
332 - buffer_overflow_check(b);
326 + b = callocz(1, sizeof(BUFFER));
327 + b->buffer = mallocz(size + sizeof(BUFFER_OVERFLOW_EOF) + 2);
328 + b->buffer[0] = '\0';
329 + b->size = size;
330 + b->contenttype = CT_TEXT_PLAIN;
331 + buffer_overflow_init(b);
332 + buffer_overflow_check(b);
333
334 - return(b);
334 + return(b);
335 }
336
337 void buffer_free(BUFFER *b)
338 {
339 - buffer_overflow_check(b);
339 + buffer_overflow_check(b);
340
341 - debug(D_WEB_BUFFER, "Freeing web buffer of size %zu.", b->size);
341 + debug(D_WEB_BUFFER, "Freeing web buffer of size %zu.", b->size);
342
343 - freez(b->buffer);
344 - freez(b);
343 + freez(b->buffer);
344 + freez(b);
345 }
346
347 void buffer_increase(BUFFER *b, size_t free_size_required)
348 {
349 - buffer_overflow_check(b);
349 + buffer_overflow_check(b);
350
351 - size_t left = b->size - b->len;
351 + size_t left = b->size - b->len;
352
353 - if(left >= free_size_required) return;
353 + if(left >= free_size_required) return;
354
355 - size_t increase = free_size_required - left;
356 - if(increase < WEB_DATA_LENGTH_INCREASE_STEP) increase = WEB_DATA_LENGTH_INCREASE_STEP;
355 + size_t increase = free_size_required - left;
356 + if(increase < WEB_DATA_LENGTH_INCREASE_STEP) increase = WEB_DATA_LENGTH_INCREASE_STEP;
357
358 - debug(D_WEB_BUFFER, "Increasing data buffer from size %zu to %zu.", b->size, b->size + increase);
358 + debug(D_WEB_BUFFER, "Increasing data buffer from size %zu to %zu.", b->size, b->size + increase);
359
360 - b->buffer = reallocz(b->buffer, b->size + increase + sizeof(BUFFER_OVERFLOW_EOF) + 2);
361 - b->size += increase;
360 + b->buffer = reallocz(b->buffer, b->size + increase + sizeof(BUFFER_OVERFLOW_EOF) + 2);
361 + b->size += increase;
362
363 - buffer_overflow_init(b);
364 - buffer_overflow_check(b);
363 + buffer_overflow_init(b);
364 + buffer_overflow_check(b);
365 }
src/web_buffer.h
+29 -29
@@ -4,40 +4,40 @@
4 #define WEB_DATA_LENGTH_INCREASE_STEP 1024
5
6 typedef struct web_buffer {
7 - size_t size; // allocation size of buffer
8 - size_t len; // current data length in buffer
9 - char *buffer; // the buffer
10 - uint8_t contenttype;
11 - uint8_t options;
12 - time_t date; // the date this content has been generated
7 + size_t size; // allocation size of buffer
8 + size_t len; // current data length in buffer
9 + char *buffer; // the buffer
10 + uint8_t contenttype;
11 + uint8_t options;
12 + time_t date; // the date this content has been generated
13 } BUFFER;
14
15 // options
16 -#define WB_CONTENT_CACHEABLE 1
17 -#define WB_CONTENT_NO_CACHEABLE 2
16 +#define WB_CONTENT_CACHEABLE 1
17 +#define WB_CONTENT_NO_CACHEABLE 2
18
19 // content-types
20 -#define CT_APPLICATION_JSON 1
21 -#define CT_TEXT_PLAIN 2
22 -#define CT_TEXT_HTML 3
23 -#define CT_APPLICATION_X_JAVASCRIPT 4
24 -#define CT_TEXT_CSS 5
25 -#define CT_TEXT_XML 6
26 -#define CT_APPLICATION_XML 7
27 -#define CT_TEXT_XSL 8
28 -#define CT_APPLICATION_OCTET_STREAM 9
29 -#define CT_APPLICATION_X_FONT_TRUETYPE 10
30 -#define CT_APPLICATION_X_FONT_OPENTYPE 11
31 -#define CT_APPLICATION_FONT_WOFF 12
32 -#define CT_APPLICATION_FONT_WOFF2 13
33 -#define CT_APPLICATION_VND_MS_FONTOBJ 14
34 -#define CT_IMAGE_SVG_XML 15
35 -#define CT_IMAGE_PNG 16
36 -#define CT_IMAGE_JPG 17
37 -#define CT_IMAGE_GIF 18
38 -#define CT_IMAGE_XICON 19
39 -#define CT_IMAGE_ICNS 20
40 -#define CT_IMAGE_BMP 21
20 +#define CT_APPLICATION_JSON 1
21 +#define CT_TEXT_PLAIN 2
22 +#define CT_TEXT_HTML 3
23 +#define CT_APPLICATION_X_JAVASCRIPT 4
24 +#define CT_TEXT_CSS 5
25 +#define CT_TEXT_XML 6
26 +#define CT_APPLICATION_XML 7
27 +#define CT_TEXT_XSL 8
28 +#define CT_APPLICATION_OCTET_STREAM 9
29 +#define CT_APPLICATION_X_FONT_TRUETYPE 10
30 +#define CT_APPLICATION_X_FONT_OPENTYPE 11
31 +#define CT_APPLICATION_FONT_WOFF 12
32 +#define CT_APPLICATION_FONT_WOFF2 13
33 +#define CT_APPLICATION_VND_MS_FONTOBJ 14
34 +#define CT_IMAGE_SVG_XML 15
35 +#define CT_IMAGE_PNG 16
36 +#define CT_IMAGE_JPG 17
37 +#define CT_IMAGE_GIF 18
38 +#define CT_IMAGE_XICON 19
39 +#define CT_IMAGE_ICNS 20
40 +#define CT_IMAGE_BMP 21
41
42 #define buffer_strlen(wb) ((wb)->len)
43 extern const char *buffer_tostring(BUFFER *wb);
src/web_buffer_svg.c
+533 -533
@@ -9,559 +9,559 @@
9 */
10
11 double verdana11_widths[256] = {
12 - [0] = 0.0,
13 - [1] = 0.0,
14 - [2] = 0.0,
15 - [3] = 0.0,
16 - [4] = 0.0,
17 - [5] = 0.0,
18 - [6] = 0.0,
19 - [7] = 0.0,
20 - [8] = 0.0,
21 - [9] = 0.0,
22 - [10] = 0.0,
23 - [11] = 0.0,
24 - [12] = 0.0,
25 - [13] = 0.0,
26 - [14] = 0.0,
27 - [15] = 0.0,
28 - [16] = 0.0,
29 - [17] = 0.0,
30 - [18] = 0.0,
31 - [19] = 0.0,
32 - [20] = 0.0,
33 - [21] = 0.0,
34 - [22] = 0.0,
35 - [23] = 0.0,
36 - [24] = 0.0,
37 - [25] = 0.0,
38 - [26] = 0.0,
39 - [27] = 0.0,
40 - [28] = 0.0,
41 - [29] = 0.0,
42 - [30] = 0.0,
43 - [31] = 0.0,
44 - [32] = 3.8671874999999996, //
45 - [33] = 4.3291015625, // !
46 - [34] = 5.048828125, // "
47 - [35] = 9.001953125, // #
48 - [36] = 6.9931640625, // $
49 - [37] = 11.837890625, // %
50 - [38] = 7.992187499999999, // &
51 - [39] = 2.9541015625, // '
52 - [40] = 4.9951171875, // (
53 - [41] = 4.9951171875, // )
54 - [42] = 6.9931640625, // *
55 - [43] = 9.001953125, // +
56 - [44] = 4.00146484375, // ,
57 - [45] = 4.9951171875, // -
58 - [46] = 4.00146484375, // .
59 - [47] = 4.9951171875, // /
60 - [48] = 6.9931640625, // 0
61 - [49] = 6.9931640625, // 1
62 - [50] = 6.9931640625, // 2
63 - [51] = 6.9931640625, // 3
64 - [52] = 6.9931640625, // 4
65 - [53] = 6.9931640625, // 5
66 - [54] = 6.9931640625, // 6
67 - [55] = 6.9931640625, // 7
68 - [56] = 6.9931640625, // 8
69 - [57] = 6.9931640625, // 9
70 - [58] = 4.9951171875, // :
71 - [59] = 4.9951171875, // ;
72 - [60] = 9.001953125, // <
73 - [61] = 9.001953125, // =
74 - [62] = 9.001953125, // >
75 - [63] = 5.99951171875, // ?
76 - [64] = 11.0, // @
77 - [65] = 7.51953125, // A
78 - [66] = 7.541015625, // B
79 - [67] = 7.680664062499999, // C
80 - [68] = 8.4755859375, // D
81 - [69] = 6.95556640625, // E
82 - [70] = 6.32177734375, // F
83 - [71] = 8.529296875, // G
84 - [72] = 8.26611328125, // H
85 - [73] = 4.6298828125, // I
86 - [74] = 5.00048828125, // J
87 - [75] = 7.62158203125, // K
88 - [76] = 6.123046875, // L
89 - [77] = 9.2705078125, // M
90 - [78] = 8.228515625, // N
91 - [79] = 8.658203125, // O
92 - [80] = 6.63330078125, // P
93 - [81] = 8.658203125, // Q
94 - [82] = 7.6484375, // R
95 - [83] = 7.51953125, // S
96 - [84] = 6.7783203125, // T
97 - [85] = 8.05126953125, // U
98 - [86] = 7.51953125, // V
99 - [87] = 10.87646484375, // W
100 - [88] = 7.53564453125, // X
101 - [89] = 6.767578125, // Y
102 - [90] = 7.53564453125, // Z
103 - [91] = 4.9951171875, // [
104 - [92] = 4.9951171875, // backslash
105 - [93] = 4.9951171875, // ]
106 - [94] = 9.001953125, // ^
107 - [95] = 6.9931640625, // _
108 - [96] = 6.9931640625, // `
109 - [97] = 6.6064453125, // a
110 - [98] = 6.853515625, // b
111 - [99] = 5.73095703125, // c
112 - [100] = 6.853515625, // d
113 - [101] = 6.552734375, // e
114 - [102] = 3.8671874999999996, // f
115 - [103] = 6.853515625, // g
116 - [104] = 6.9609375, // h
117 - [105] = 3.0185546875, // i
118 - [106] = 3.78662109375, // j
119 - [107] = 6.509765625, // k
120 - [108] = 3.0185546875, // l
121 - [109] = 10.69921875, // m
122 - [110] = 6.9609375, // n
123 - [111] = 6.67626953125, // o
124 - [112] = 6.853515625, // p
125 - [113] = 6.853515625, // q
126 - [114] = 4.6943359375, // r
127 - [115] = 5.73095703125, // s
128 - [116] = 4.33447265625, // t
129 - [117] = 6.9609375, // u
130 - [118] = 6.509765625, // v
131 - [119] = 9.001953125, // w
132 - [120] = 6.509765625, // x
133 - [121] = 6.509765625, // y
134 - [122] = 5.779296875, // z
135 - [123] = 6.982421875, // {
136 - [124] = 4.9951171875, // |
137 - [125] = 6.982421875, // }
138 - [126] = 9.001953125, // ~
139 - [127] = 0.0,
140 - [128] = 0.0,
141 - [129] = 0.0,
142 - [130] = 0.0,
143 - [131] = 0.0,
144 - [132] = 0.0,
145 - [133] = 0.0,
146 - [134] = 0.0,
147 - [135] = 0.0,
148 - [136] = 0.0,
149 - [137] = 0.0,
150 - [138] = 0.0,
151 - [139] = 0.0,
152 - [140] = 0.0,
153 - [141] = 0.0,
154 - [142] = 0.0,
155 - [143] = 0.0,
156 - [144] = 0.0,
157 - [145] = 0.0,
158 - [146] = 0.0,
159 - [147] = 0.0,
160 - [148] = 0.0,
161 - [149] = 0.0,
162 - [150] = 0.0,
163 - [151] = 0.0,
164 - [152] = 0.0,
165 - [153] = 0.0,
166 - [154] = 0.0,
167 - [155] = 0.0,
168 - [156] = 0.0,
169 - [157] = 0.0,
170 - [158] = 0.0,
171 - [159] = 0.0,
172 - [160] = 0.0,
173 - [161] = 0.0,
174 - [162] = 0.0,
175 - [163] = 0.0,
176 - [164] = 0.0,
177 - [165] = 0.0,
178 - [166] = 0.0,
179 - [167] = 0.0,
180 - [168] = 0.0,
181 - [169] = 0.0,
182 - [170] = 0.0,
183 - [171] = 0.0,
184 - [172] = 0.0,
185 - [173] = 0.0,
186 - [174] = 0.0,
187 - [175] = 0.0,
188 - [176] = 0.0,
189 - [177] = 0.0,
190 - [178] = 0.0,
191 - [179] = 0.0,
192 - [180] = 0.0,
193 - [181] = 0.0,
194 - [182] = 0.0,
195 - [183] = 0.0,
196 - [184] = 0.0,
197 - [185] = 0.0,
198 - [186] = 0.0,
199 - [187] = 0.0,
200 - [188] = 0.0,
201 - [189] = 0.0,
202 - [190] = 0.0,
203 - [191] = 0.0,
204 - [192] = 0.0,
205 - [193] = 0.0,
206 - [194] = 0.0,
207 - [195] = 0.0,
208 - [196] = 0.0,
209 - [197] = 0.0,
210 - [198] = 0.0,
211 - [199] = 0.0,
212 - [200] = 0.0,
213 - [201] = 0.0,
214 - [202] = 0.0,
215 - [203] = 0.0,
216 - [204] = 0.0,
217 - [205] = 0.0,
218 - [206] = 0.0,
219 - [207] = 0.0,
220 - [208] = 0.0,
221 - [209] = 0.0,
222 - [210] = 0.0,
223 - [211] = 0.0,
224 - [212] = 0.0,
225 - [213] = 0.0,
226 - [214] = 0.0,
227 - [215] = 0.0,
228 - [216] = 0.0,
229 - [217] = 0.0,
230 - [218] = 0.0,
231 - [219] = 0.0,
232 - [220] = 0.0,
233 - [221] = 0.0,
234 - [222] = 0.0,
235 - [223] = 0.0,
236 - [224] = 0.0,
237 - [225] = 0.0,
238 - [226] = 0.0,
239 - [227] = 0.0,
240 - [228] = 0.0,
241 - [229] = 0.0,
242 - [230] = 0.0,
243 - [231] = 0.0,
244 - [232] = 0.0,
245 - [233] = 0.0,
246 - [234] = 0.0,
247 - [235] = 0.0,
248 - [236] = 0.0,
249 - [237] = 0.0,
250 - [238] = 0.0,
251 - [239] = 0.0,
252 - [240] = 0.0,
253 - [241] = 0.0,
254 - [242] = 0.0,
255 - [243] = 0.0,
256 - [244] = 0.0,
257 - [245] = 0.0,
258 - [246] = 0.0,
259 - [247] = 0.0,
260 - [248] = 0.0,
261 - [249] = 0.0,
262 - [250] = 0.0,
263 - [251] = 0.0,
264 - [252] = 0.0,
265 - [253] = 0.0,
266 - [254] = 0.0,
267 - [255] = 0.0
12 + [0] = 0.0,
13 + [1] = 0.0,
14 + [2] = 0.0,
15 + [3] = 0.0,
16 + [4] = 0.0,
17 + [5] = 0.0,
18 + [6] = 0.0,
19 + [7] = 0.0,
20 + [8] = 0.0,
21 + [9] = 0.0,
22 + [10] = 0.0,
23 + [11] = 0.0,
24 + [12] = 0.0,
25 + [13] = 0.0,
26 + [14] = 0.0,
27 + [15] = 0.0,
28 + [16] = 0.0,
29 + [17] = 0.0,
30 + [18] = 0.0,
31 + [19] = 0.0,
32 + [20] = 0.0,
33 + [21] = 0.0,
34 + [22] = 0.0,
35 + [23] = 0.0,
36 + [24] = 0.0,
37 + [25] = 0.0,
38 + [26] = 0.0,
39 + [27] = 0.0,
40 + [28] = 0.0,
41 + [29] = 0.0,
42 + [30] = 0.0,
43 + [31] = 0.0,
44 + [32] = 3.8671874999999996, //
45 + [33] = 4.3291015625, // !
46 + [34] = 5.048828125, // "
47 + [35] = 9.001953125, // #
48 + [36] = 6.9931640625, // $
49 + [37] = 11.837890625, // %
50 + [38] = 7.992187499999999, // &
51 + [39] = 2.9541015625, // '
52 + [40] = 4.9951171875, // (
53 + [41] = 4.9951171875, // )
54 + [42] = 6.9931640625, // *
55 + [43] = 9.001953125, // +
56 + [44] = 4.00146484375, // ,
57 + [45] = 4.9951171875, // -
58 + [46] = 4.00146484375, // .
59 + [47] = 4.9951171875, // /
60 + [48] = 6.9931640625, // 0
61 + [49] = 6.9931640625, // 1
62 + [50] = 6.9931640625, // 2
63 + [51] = 6.9931640625, // 3
64 + [52] = 6.9931640625, // 4
65 + [53] = 6.9931640625, // 5
66 + [54] = 6.9931640625, // 6
67 + [55] = 6.9931640625, // 7
68 + [56] = 6.9931640625, // 8
69 + [57] = 6.9931640625, // 9
70 + [58] = 4.9951171875, // :
71 + [59] = 4.9951171875, // ;
72 + [60] = 9.001953125, // <
73 + [61] = 9.001953125, // =
74 + [62] = 9.001953125, // >
75 + [63] = 5.99951171875, // ?
76 + [64] = 11.0, // @
77 + [65] = 7.51953125, // A
78 + [66] = 7.541015625, // B
79 + [67] = 7.680664062499999, // C
80 + [68] = 8.4755859375, // D
81 + [69] = 6.95556640625, // E
82 + [70] = 6.32177734375, // F
83 + [71] = 8.529296875, // G
84 + [72] = 8.26611328125, // H
85 + [73] = 4.6298828125, // I
86 + [74] = 5.00048828125, // J
87 + [75] = 7.62158203125, // K
88 + [76] = 6.123046875, // L
89 + [77] = 9.2705078125, // M
90 + [78] = 8.228515625, // N
91 + [79] = 8.658203125, // O
92 + [80] = 6.63330078125, // P
93 + [81] = 8.658203125, // Q
94 + [82] = 7.6484375, // R
95 + [83] = 7.51953125, // S
96 + [84] = 6.7783203125, // T
97 + [85] = 8.05126953125, // U
98 + [86] = 7.51953125, // V
99 + [87] = 10.87646484375, // W
100 + [88] = 7.53564453125, // X
101 + [89] = 6.767578125, // Y
102 + [90] = 7.53564453125, // Z
103 + [91] = 4.9951171875, // [
104 + [92] = 4.9951171875, // backslash
105 + [93] = 4.9951171875, // ]
106 + [94] = 9.001953125, // ^
107 + [95] = 6.9931640625, // _
108 + [96] = 6.9931640625, // `
109 + [97] = 6.6064453125, // a
110 + [98] = 6.853515625, // b
111 + [99] = 5.73095703125, // c
112 + [100] = 6.853515625, // d
113 + [101] = 6.552734375, // e
114 + [102] = 3.8671874999999996, // f
115 + [103] = 6.853515625, // g
116 + [104] = 6.9609375, // h
117 + [105] = 3.0185546875, // i
118 + [106] = 3.78662109375, // j
119 + [107] = 6.509765625, // k
120 + [108] = 3.0185546875, // l
121 + [109] = 10.69921875, // m
122 + [110] = 6.9609375, // n
123 + [111] = 6.67626953125, // o
124 + [112] = 6.853515625, // p
125 + [113] = 6.853515625, // q
126 + [114] = 4.6943359375, // r
127 + [115] = 5.73095703125, // s
128 + [116] = 4.33447265625, // t
129 + [117] = 6.9609375, // u
130 + [118] = 6.509765625, // v
131 + [119] = 9.001953125, // w
132 + [120] = 6.509765625, // x
133 + [121] = 6.509765625, // y
134 + [122] = 5.779296875, // z
135 + [123] = 6.982421875, // {
136 + [124] = 4.9951171875, // |
137 + [125] = 6.982421875, // }
138 + [126] = 9.001953125, // ~
139 + [127] = 0.0,
140 + [128] = 0.0,
141 + [129] = 0.0,
142 + [130] = 0.0,
143 + [131] = 0.0,
144 + [132] = 0.0,
145 + [133] = 0.0,
146 + [134] = 0.0,
147 + [135] = 0.0,
148 + [136] = 0.0,
149 + [137] = 0.0,
150 + [138] = 0.0,
151 + [139] = 0.0,
152 + [140] = 0.0,
153 + [141] = 0.0,
154 + [142] = 0.0,
155 + [143] = 0.0,
156 + [144] = 0.0,
157 + [145] = 0.0,
158 + [146] = 0.0,
159 + [147] = 0.0,
160 + [148] = 0.0,
161 + [149] = 0.0,
162 + [150] = 0.0,
163 + [151] = 0.0,
164 + [152] = 0.0,
165 + [153] = 0.0,
166 + [154] = 0.0,
167 + [155] = 0.0,
168 + [156] = 0.0,
169 + [157] = 0.0,
170 + [158] = 0.0,
171 + [159] = 0.0,
172 + [160] = 0.0,
173 + [161] = 0.0,
174 + [162] = 0.0,
175 + [163] = 0.0,
176 + [164] = 0.0,
177 + [165] = 0.0,
178 + [166] = 0.0,
179 + [167] = 0.0,
180 + [168] = 0.0,
181 + [169] = 0.0,
182 + [170] = 0.0,
183 + [171] = 0.0,
184 + [172] = 0.0,
185 + [173] = 0.0,
186 + [174] = 0.0,
187 + [175] = 0.0,
188 + [176] = 0.0,
189 + [177] = 0.0,
190 + [178] = 0.0,
191 + [179] = 0.0,
192 + [180] = 0.0,
193 + [181] = 0.0,
194 + [182] = 0.0,
195 + [183] = 0.0,
196 + [184] = 0.0,
197 + [185] = 0.0,
198 + [186] = 0.0,
199 + [187] = 0.0,
200 + [188] = 0.0,
201 + [189] = 0.0,
202 + [190] = 0.0,
203 + [191] = 0.0,
204 + [192] = 0.0,
205 + [193] = 0.0,
206 + [194] = 0.0,
207 + [195] = 0.0,
208 + [196] = 0.0,
209 + [197] = 0.0,
210 + [198] = 0.0,
211 + [199] = 0.0,
212 + [200] = 0.0,
213 + [201] = 0.0,
214 + [202] = 0.0,
215 + [203] = 0.0,
216 + [204] = 0.0,
217 + [205] = 0.0,
218 + [206] = 0.0,
219 + [207] = 0.0,
220 + [208] = 0.0,
221 + [209] = 0.0,
222 + [210] = 0.0,
223 + [211] = 0.0,
224 + [212] = 0.0,
225 + [213] = 0.0,
226 + [214] = 0.0,
227 + [215] = 0.0,
228 + [216] = 0.0,
229 + [217] = 0.0,
230 + [218] = 0.0,
231 + [219] = 0.0,
232 + [220] = 0.0,
233 + [221] = 0.0,
234 + [222] = 0.0,
235 + [223] = 0.0,
236 + [224] = 0.0,
237 + [225] = 0.0,
238 + [226] = 0.0,
239 + [227] = 0.0,
240 + [228] = 0.0,
241 + [229] = 0.0,
242 + [230] = 0.0,
243 + [231] = 0.0,
244 + [232] = 0.0,
245 + [233] = 0.0,
246 + [234] = 0.0,
247 + [235] = 0.0,
248 + [236] = 0.0,
249 + [237] = 0.0,
250 + [238] = 0.0,
251 + [239] = 0.0,
252 + [240] = 0.0,
253 + [241] = 0.0,
254 + [242] = 0.0,
255 + [243] = 0.0,
256 + [244] = 0.0,
257 + [245] = 0.0,
258 + [246] = 0.0,
259 + [247] = 0.0,
260 + [248] = 0.0,
261 + [249] = 0.0,
262 + [250] = 0.0,
263 + [251] = 0.0,
264 + [252] = 0.0,
265 + [253] = 0.0,
266 + [254] = 0.0,
267 + [255] = 0.0
268 };
269
270 // find the width of the string using the verdana 11points font
271 // re-write the string in place, skiping zero-length characters
272 static inline int verdana11_width(char *s) {
273 - double w = 0.0;
274 - char *d = s;
275 -
276 - while(*s) {
277 - double t = verdana11_widths[(unsigned char)*s];
278 - if(t == 0.0)
279 - s++;
280 - else {
281 - w += t + VERDANA_KERNING;
282 - if(d != s)
283 - *d++ = *s++;
284 - else
285 - d = ++s;
286 - }
287 - }
288 -
289 - *d = '\0';
290 - w -= VERDANA_KERNING;
291 - return ceil(w);
273 + double w = 0.0;
274 + char *d = s;
275 +
276 + while(*s) {
277 + double t = verdana11_widths[(unsigned char)*s];
278 + if(t == 0.0)
279 + s++;
280 + else {
281 + w += t + VERDANA_KERNING;
282 + if(d != s)
283 + *d++ = *s++;
284 + else
285 + d = ++s;
286 + }
287 + }
288 +
289 + *d = '\0';
290 + w -= VERDANA_KERNING;
291 + return ceil(w);
292 }
293
294 static inline size_t escape_xmlz(char *dst, const char *src, size_t len) {
295 - size_t i = len;
296 -
297 - // required escapes from
298 - // https://github.com/badges/shields/blob/master/badge.js
299 - while(*src && i) {
300 - switch(*src) {
301 - case '\\':
302 - *dst++ = '/';
303 - src++;
304 - i--;
305 - break;
306 -
307 - case '&':
308 - if(i > 5) {
309 - strcpy(dst, "&amp;");
310 - i -= 5;
311 - dst += 5;
312 - src++;
313 - }
314 - else goto cleanup;
315 - break;
316 -
317 - case '<':
318 - if(i > 4) {
319 - strcpy(dst, "&lt;");
320 - i -= 4;
321 - dst += 4;
322 - src++;
323 - }
324 - else goto cleanup;
325 - break;
326 -
327 - case '>':
328 - if(i > 4) {
329 - strcpy(dst, "&gt;");
330 - i -= 4;
331 - dst += 4;
332 - src++;
333 - }
334 - else goto cleanup;
335 - break;
336 -
337 - case '"':
338 - if(i > 6) {
339 - strcpy(dst, "&quot;");
340 - i -= 6;
341 - dst += 6;
342 - src++;
343 - }
344 - else goto cleanup;
345 - break;
346 -
347 - case '\'':
348 - if(i > 6) {
349 - strcpy(dst, "&apos;");
350 - i -= 6;
351 - dst += 6;
352 - src++;
353 - }
354 - else goto cleanup;
355 - break;
356 -
357 - default:
358 - i--;
359 - *dst++ = *src++;
360 - break;
361 - }
362 - }
295 + size_t i = len;
296 +
297 + // required escapes from
298 + // https://github.com/badges/shields/blob/master/badge.js
299 + while(*src && i) {
300 + switch(*src) {
301 + case '\\':
302 + *dst++ = '/';
303 + src++;
304 + i--;
305 + break;
306 +
307 + case '&':
308 + if(i > 5) {
309 + strcpy(dst, "&amp;");
310 + i -= 5;
311 + dst += 5;
312 + src++;
313 + }
314 + else goto cleanup;
315 + break;
316 +
317 + case '<':
318 + if(i > 4) {
319 + strcpy(dst, "&lt;");
320 + i -= 4;
321 + dst += 4;
322 + src++;
323 + }
324 + else goto cleanup;
325 + break;
326 +
327 + case '>':
328 + if(i > 4) {
329 + strcpy(dst, "&gt;");
330 + i -= 4;
331 + dst += 4;
332 + src++;
333 + }
334 + else goto cleanup;
335 + break;
336 +
337 + case '"':
338 + if(i > 6) {
339 + strcpy(dst, "&quot;");
340 + i -= 6;
341 + dst += 6;
342 + src++;
343 + }
344 + else goto cleanup;
345 + break;
346 +
347 + case '\'':
348 + if(i > 6) {
349 + strcpy(dst, "&apos;");
350 + i -= 6;
351 + dst += 6;
352 + src++;
353 + }
354 + else goto cleanup;
355 + break;
356 +
357 + default:
358 + i--;
359 + *dst++ = *src++;
360 + break;
361 + }
362 + }
363
364 cleanup:
365 - *dst = '\0';
366 - return len - i;
365 + *dst = '\0';
366 + return len - i;
367 }
368
369 static inline const char *fix_units(const char *units) {
370 - if(!units || !*units || !strcmp(units, "empty") || !strcmp(units, "null")) return "";
371 - if(!strcmp(units, "percentage") || !strcmp(units, "percent") || !strcmp(units, "pcent")) return "%";
372 - return units;
370 + if(!units || !*units || !strcmp(units, "empty") || !strcmp(units, "null")) return "";
371 + if(!strcmp(units, "percentage") || !strcmp(units, "percent") || !strcmp(units, "pcent")) return "%";
372 + return units;
373 }
374
375 static inline const char *color_map(const char *color) {
376 - // colors from:
377 - // https://github.com/badges/shields/blob/master/colorscheme.json
378 - if(!strcmp(color, "brightgreen")) return "#4c1";
379 - else if(!strcmp(color, "green")) return "#97CA00";
380 - else if(!strcmp(color, "yellow")) return "#dfb317";
381 - else if(!strcmp(color, "yellowgreen")) return "#a4a61d";
382 - else if(!strcmp(color, "orange")) return "#fe7d37";
383 - else if(!strcmp(color, "red")) return "#e05d44";
384 - else if(!strcmp(color, "blue")) return "#007ec6";
385 - else if(!strcmp(color, "grey")) return "#555";
386 - else if(!strcmp(color, "gray")) return "#555";
387 - else if(!strcmp(color, "lightgrey")) return "#9f9f9f";
388 - else if(!strcmp(color, "lightgray")) return "#9f9f9f";
389 - return color;
376 + // colors from:
377 + // https://github.com/badges/shields/blob/master/colorscheme.json
378 + if(!strcmp(color, "brightgreen")) return "#4c1";
379 + else if(!strcmp(color, "green")) return "#97CA00";
380 + else if(!strcmp(color, "yellow")) return "#dfb317";
381 + else if(!strcmp(color, "yellowgreen")) return "#a4a61d";
382 + else if(!strcmp(color, "orange")) return "#fe7d37";
383 + else if(!strcmp(color, "red")) return "#e05d44";
384 + else if(!strcmp(color, "blue")) return "#007ec6";
385 + else if(!strcmp(color, "grey")) return "#555";
386 + else if(!strcmp(color, "gray")) return "#555";
387 + else if(!strcmp(color, "lightgrey")) return "#9f9f9f";
388 + else if(!strcmp(color, "lightgray")) return "#9f9f9f";
389 + return color;
390 }
391
392 static inline void calc_colorz(const char *color, char *final, size_t len, calculated_number value, int value_is_null) {
393 - char color_buffer[256 + 1] = "";
394 - char value_buffer[256 + 1] = "";
395 - char comparison = '>';
396 -
397 - // example input:
398 - // color<max|color>min|color:null...
399 -
400 - const char *c = color;
401 - while(*c) {
402 - char *dc = color_buffer, *dv = NULL;
403 - size_t ci = 0, vi = 0;
404 -
405 - const char *t = c;
406 -
407 - while(*t && *t != '|') {
408 - switch(*t) {
409 - case ':':
410 - comparison = '=';
411 - dv = value_buffer;
412 - break;
413 -
414 - case '}':
415 - case ')':
416 - case '>':
417 - if(t[1] == '=') {
418 - comparison = ')';
419 - t++;
420 - }
421 - else
422 - comparison = '>';
423 - dv = value_buffer;
424 - break;
425 -
426 - case '{':
427 - case '(':
428 - case '<':
429 - if(t[1] == '=') {
430 - comparison = '(';
431 - t++;
432 - }
433 - else
434 - comparison = '<';
435 - dv = value_buffer;
436 - break;
437 -
438 - default:
439 - if(dv) {
440 - if(vi < 256) {
441 - vi++;
442 - *dv++ = *t;
443 - }
444 - }
445 - else {
446 - if(ci < 256) {
447 - ci++;
448 - *dc++ = *t;
449 - }
450 - }
451 - break;
452 - }
453 -
454 - t++;
455 - }
456 -
457 - // prepare for next iteration
458 - if(*t == '|') t++;
459 - c = t;
460 -
461 - // do the math
462 - *dc = '\0';
463 - if(dv) {
464 - *dv = '\0';
465 -
466 - if(value_is_null) {
467 - if(!*value_buffer || !strcmp(value_buffer, "null"))
468 - break;
469 - }
470 - else {
471 - calculated_number v = strtold(value_buffer, NULL);
472 -
473 - if(comparison == '<' && value < v) break;
474 - else if(comparison == '(' && value <= v) break;
475 - else if(comparison == '>' && value > v) break;
476 - else if(comparison == ')' && value >= v) break;
477 - else if(comparison == '=' && value == v) break;
478 - }
479 - }
480 - else
481 - break;
482 - }
483 -
484 - const char *b;
485 - if(color_buffer[0])
486 - b = color_buffer;
487 - else
488 - b = color;
489 -
490 - strncpyz(final, b, len);
393 + char color_buffer[256 + 1] = "";
394 + char value_buffer[256 + 1] = "";
395 + char comparison = '>';
396 +
397 + // example input:
398 + // color<max|color>min|color:null...
399 +
400 + const char *c = color;
401 + while(*c) {
402 + char *dc = color_buffer, *dv = NULL;
403 + size_t ci = 0, vi = 0;
404 +
405 + const char *t = c;
406 +
407 + while(*t && *t != '|') {
408 + switch(*t) {
409 + case ':':
410 + comparison = '=';
411 + dv = value_buffer;
412 + break;
413 +
414 + case '}':
415 + case ')':
416 + case '>':
417 + if(t[1] == '=') {
418 + comparison = ')';
419 + t++;
420 + }
421 + else
422 + comparison = '>';
423 + dv = value_buffer;
424 + break;
425 +
426 + case '{':
427 + case '(':
428 + case '<':
429 + if(t[1] == '=') {
430 + comparison = '(';
431 + t++;
432 + }
433 + else
434 + comparison = '<';
435 + dv = value_buffer;
436 + break;
437 +
438 + default:
439 + if(dv) {
440 + if(vi < 256) {
441 + vi++;
442 + *dv++ = *t;
443 + }
444 + }
445 + else {
446 + if(ci < 256) {
447 + ci++;
448 + *dc++ = *t;
449 + }
450 + }
451 + break;
452 + }
453 +
454 + t++;
455 + }
456 +
457 + // prepare for next iteration
458 + if(*t == '|') t++;
459 + c = t;
460 +
461 + // do the math
462 + *dc = '\0';
463 + if(dv) {
464 + *dv = '\0';
465 +
466 + if(value_is_null) {
467 + if(!*value_buffer || !strcmp(value_buffer, "null"))
468 + break;
469 + }
470 + else {
471 + calculated_number v = strtold(value_buffer, NULL);
472 +
473 + if(comparison == '<' && value < v) break;
474 + else if(comparison == '(' && value <= v) break;
475 + else if(comparison == '>' && value > v) break;
476 + else if(comparison == ')' && value >= v) break;
477 + else if(comparison == '=' && value == v) break;
478 + }
479 + }
480 + else
481 + break;
482 + }
483 +
484 + const char *b;
485 + if(color_buffer[0])
486 + b = color_buffer;
487 + else
488 + b = color;
489 +
490 + strncpyz(final, b, len);
491 }
492
493 void buffer_svg(BUFFER *wb, const char *label, calculated_number value, const char *units, const char *label_color, const char *value_color, int value_is_null, int precision) {
494 - char label_buffer[256 + 1], value_string[512 + 1], value_color_buffer[256 + 1];
495 - char label_escaped[256 + 1], value_escaped[512 + 1], label_color_escaped[256 + 1], value_color_escaped[256 + 1];
496 - int label_width, value_width, total_width;
497 -
498 - if(!label_color || !*label_color) label_color = "#555";
499 - if(!value_color || !*value_color) value_color = (value_is_null)?"#999":"#4c1";
500 -
501 - units = fix_units(units);
502 - calc_colorz(value_color, value_color_buffer, 256, value, value_is_null);
503 -
504 - char *separator = "";
505 - if(isalnum(*units)) separator = " ";
506 -
507 - if(value_is_null)
508 - strcpy(value_string, "-");
509 - else if(precision < 0) {
510 - calculated_number abs = (value < (calculated_number)0)?-value:value;
511 - if(abs > (calculated_number)1000.0) snprintfz(value_string, 512, "%0.0Lf%s%s", (long double)value, separator, units);
512 - else if(abs > (calculated_number)100.0) snprintfz(value_string, 512, "%0.1Lf%s%s", (long double)value, separator, units);
513 - else if(abs > (calculated_number)1.0) snprintfz(value_string, 512, "%0.2Lf%s%s", (long double)value, separator, units);
514 - else if(abs > (calculated_number)0.1) snprintfz(value_string, 512, "%0.3Lf%s%s", (long double)value, separator, units);
515 - else snprintfz(value_string, 512, "%0.4Lf%s%s", (long double)value, separator, units);
516 - }
517 - else {
518 - if(precision > 50) precision = 50;
519 - snprintfz(value_string, 512, "%0.*Lf%s%s", precision, (long double)value, separator, units);
520 - }
521 -
522 - // we need to copy the label, since verdana11_width may write to it
523 - strncpyz(label_buffer, label, 256);
524 -
525 - label_width = verdana11_width(label_buffer) + (BADGE_HORIZONTAL_PADDING * 2);
526 - value_width = verdana11_width(value_string) + (BADGE_HORIZONTAL_PADDING * 2);
527 - total_width = label_width + value_width;
528 -
529 - escape_xmlz(label_escaped, label_buffer, 256);
530 - escape_xmlz(value_escaped, value_string, 256);
531 - escape_xmlz(label_color_escaped, color_map(label_color), 256);
532 - escape_xmlz(value_color_escaped, color_map(value_color_buffer), 256);
533 -
534 - wb->contenttype = CT_IMAGE_SVG_XML;
535 -
536 - // svg template from:
537 - // https://raw.githubusercontent.com/badges/shields/master/templates/flat-template.svg
538 - buffer_sprintf(wb,
539 - "<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" width=\"%d\" height=\"20\">"
540 - "<linearGradient id=\"smooth\" x2=\"0\" y2=\"100%%\">"
541 - "<stop offset=\"0\" stop-color=\"#bbb\" stop-opacity=\".1\"/>"
542 - "<stop offset=\"1\" stop-opacity=\".1\"/>"
543 - "</linearGradient>"
544 - "<mask id=\"round\">"
545 - "<rect width=\"%d\" height=\"20\" rx=\"3\" fill=\"#fff\"/>"
546 - "</mask>"
547 - "<g mask=\"url(#round)\">"
548 - "<rect width=\"%d\" height=\"20\" fill=\"%s\"/>"
549 - "<rect x=\"%d\" width=\"%d\" height=\"20\" fill=\"%s\"/>"
550 - "<rect width=\"%d\" height=\"20\" fill=\"url(#smooth)\"/>"
551 - "</g>"
552 - "<g fill=\"#fff\" text-anchor=\"middle\" font-family=\"DejaVu Sans,Verdana,Geneva,sans-serif\" font-size=\"11\">"
553 - "<text x=\"%d\" y=\"15\" fill=\"#010101\" fill-opacity=\".3\">%s</text>"
554 - "<text x=\"%d\" y=\"14\">%s</text>"
555 - "<text x=\"%d\" y=\"15\" fill=\"#010101\" fill-opacity=\".3\">%s</text>"
556 - "<text x=\"%d\" y=\"14\">%s</text>"
557 - "</g>"
558 - "</svg>",
559 - total_width, total_width,
560 - label_width, label_color_escaped,
561 - label_width, value_width, value_color_escaped,
562 - total_width,
563 - label_width / 2, label_escaped,
564 - label_width / 2, label_escaped,
565 - label_width + value_width / 2 -1, value_escaped,
566 - label_width + value_width / 2 -1, value_escaped);
494 + char label_buffer[256 + 1], value_string[512 + 1], value_color_buffer[256 + 1];
495 + char label_escaped[256 + 1], value_escaped[512 + 1], label_color_escaped[256 + 1], value_color_escaped[256 + 1];
496 + int label_width, value_width, total_width;
497 +
498 + if(!label_color || !*label_color) label_color = "#555";
499 + if(!value_color || !*value_color) value_color = (value_is_null)?"#999":"#4c1";
500 +
501 + units = fix_units(units);
502 + calc_colorz(value_color, value_color_buffer, 256, value, value_is_null);
503 +
504 + char *separator = "";
505 + if(isalnum(*units)) separator = " ";
506 +
507 + if(value_is_null)
508 + strcpy(value_string, "-");
509 + else if(precision < 0) {
510 + calculated_number abs = (value < (calculated_number)0)?-value:value;
511 + if(abs > (calculated_number)1000.0) snprintfz(value_string, 512, "%0.0Lf%s%s", (long double)value, separator, units);
512 + else if(abs > (calculated_number)100.0) snprintfz(value_string, 512, "%0.1Lf%s%s", (long double)value, separator, units);
513 + else if(abs > (calculated_number)1.0) snprintfz(value_string, 512, "%0.2Lf%s%s", (long double)value, separator, units);
514 + else if(abs > (calculated_number)0.1) snprintfz(value_string, 512, "%0.3Lf%s%s", (long double)value, separator, units);
515 + else snprintfz(value_string, 512, "%0.4Lf%s%s", (long double)value, separator, units);
516 + }
517 + else {
518 + if(precision > 50) precision = 50;
519 + snprintfz(value_string, 512, "%0.*Lf%s%s", precision, (long double)value, separator, units);
520 + }
521 +
522 + // we need to copy the label, since verdana11_width may write to it
523 + strncpyz(label_buffer, label, 256);
524 +
525 + label_width = verdana11_width(label_buffer) + (BADGE_HORIZONTAL_PADDING * 2);
526 + value_width = verdana11_width(value_string) + (BADGE_HORIZONTAL_PADDING * 2);
527 + total_width = label_width + value_width;
528 +
529 + escape_xmlz(label_escaped, label_buffer, 256);
530 + escape_xmlz(value_escaped, value_string, 256);
531 + escape_xmlz(label_color_escaped, color_map(label_color), 256);
532 + escape_xmlz(value_color_escaped, color_map(value_color_buffer), 256);
533 +
534 + wb->contenttype = CT_IMAGE_SVG_XML;
535 +
536 + // svg template from:
537 + // https://raw.githubusercontent.com/badges/shields/master/templates/flat-template.svg
538 + buffer_sprintf(wb,
539 + "<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" width=\"%d\" height=\"20\">"
540 + "<linearGradient id=\"smooth\" x2=\"0\" y2=\"100%%\">"
541 + "<stop offset=\"0\" stop-color=\"#bbb\" stop-opacity=\".1\"/>"
542 + "<stop offset=\"1\" stop-opacity=\".1\"/>"
543 + "</linearGradient>"
544 + "<mask id=\"round\">"
545 + "<rect width=\"%d\" height=\"20\" rx=\"3\" fill=\"#fff\"/>"
546 + "</mask>"
547 + "<g mask=\"url(#round)\">"
548 + "<rect width=\"%d\" height=\"20\" fill=\"%s\"/>"
549 + "<rect x=\"%d\" width=\"%d\" height=\"20\" fill=\"%s\"/>"
550 + "<rect width=\"%d\" height=\"20\" fill=\"url(#smooth)\"/>"
551 + "</g>"
552 + "<g fill=\"#fff\" text-anchor=\"middle\" font-family=\"DejaVu Sans,Verdana,Geneva,sans-serif\" font-size=\"11\">"
553 + "<text x=\"%d\" y=\"15\" fill=\"#010101\" fill-opacity=\".3\">%s</text>"
554 + "<text x=\"%d\" y=\"14\">%s</text>"
555 + "<text x=\"%d\" y=\"15\" fill=\"#010101\" fill-opacity=\".3\">%s</text>"
556 + "<text x=\"%d\" y=\"14\">%s</text>"
557 + "</g>"
558 + "</svg>",
559 + total_width, total_width,
560 + label_width, label_color_escaped,
561 + label_width, value_width, value_color_escaped,
562 + total_width,
563 + label_width / 2, label_escaped,
564 + label_width / 2, label_escaped,
565 + label_width + value_width / 2 -1, value_escaped,
566 + label_width + value_width / 2 -1, value_escaped);
567 }
src/web_client.c
+2182 -2182
@@ -16,125 +16,125 @@ unsigned long long web_clients_count = 0;
16
17 inline int web_client_crock_socket(struct web_client *w) {
18 #ifdef TCP_CORK
19 - if(likely(!w->tcp_cork && w->ofd != -1)) {
20 - w->tcp_cork = 1;
21 - if(unlikely(setsockopt(w->ofd, IPPROTO_TCP, TCP_CORK, (char *) &w->tcp_cork, sizeof(int)) != 0)) {
22 - error("%llu: failed to enable TCP_CORK on socket.", w->id);
23 - w->tcp_cork = 0;
24 - return -1;
25 - }
26 - }
19 + if(likely(!w->tcp_cork && w->ofd != -1)) {
20 + w->tcp_cork = 1;
21 + if(unlikely(setsockopt(w->ofd, IPPROTO_TCP, TCP_CORK, (char *) &w->tcp_cork, sizeof(int)) != 0)) {
22 + error("%llu: failed to enable TCP_CORK on socket.", w->id);
23 + w->tcp_cork = 0;
24 + return -1;
25 + }
26 + }
27 #endif /* TCP_CORK */
28
29 - return 0;
29 + return 0;
30 }
31
32 inline int web_client_uncrock_socket(struct web_client *w) {
33 #ifdef TCP_CORK
34 - if(likely(w->tcp_cork && w->ofd != -1)) {
35 - w->tcp_cork = 0;
36 - if(unlikely(setsockopt(w->ofd, IPPROTO_TCP, TCP_CORK, (char *) &w->tcp_cork, sizeof(int)) != 0)) {
37 - error("%llu: failed to disable TCP_CORK on socket.", w->id);
38 - w->tcp_cork = 1;
39 - return -1;
40 - }
41 - }
34 + if(likely(w->tcp_cork && w->ofd != -1)) {
35 + w->tcp_cork = 0;
36 + if(unlikely(setsockopt(w->ofd, IPPROTO_TCP, TCP_CORK, (char *) &w->tcp_cork, sizeof(int)) != 0)) {
37 + error("%llu: failed to disable TCP_CORK on socket.", w->id);
38 + w->tcp_cork = 1;
39 + return -1;
40 + }
41 + }
42 #endif /* TCP_CORK */
43
44 - return 0;
44 + return 0;
45 }
46
47 struct web_client *web_client_create(int listener)
48 {
49 - struct web_client *w;
50 -
51 - w = callocz(1, sizeof(struct web_client));
52 - w->id = ++web_clients_count;
53 - w->mode = WEB_CLIENT_MODE_NORMAL;
54 -
55 - {
56 - struct sockaddr *sadr;
57 - socklen_t addrlen;
58 -
59 - sadr = (struct sockaddr*) &w->clientaddr;
60 - addrlen = sizeof(w->clientaddr);
61 -
62 - w->ifd = accept4(listener, sadr, &addrlen, SOCK_NONBLOCK);
63 - if (w->ifd == -1) {
64 - error("%llu: Cannot accept new incoming connection.", w->id);
65 - freez(w);
66 - return NULL;
67 - }
68 - w->ofd = w->ifd;
69 -
70 - if(getnameinfo(sadr, addrlen, w->client_ip, NI_MAXHOST, w->client_port, NI_MAXSERV, NI_NUMERICHOST | NI_NUMERICSERV) != 0) {
71 - error("Cannot getnameinfo() on received client connection.");
72 - strncpyz(w->client_ip, "UNKNOWN", NI_MAXHOST);
73 - strncpyz(w->client_port, "UNKNOWN", NI_MAXSERV);
74 - }
75 - w->client_ip[NI_MAXHOST] = '\0';
76 - w->client_port[NI_MAXSERV] = '\0';
77 -
78 - switch(sadr->sa_family) {
79 - case AF_INET:
80 - debug(D_WEB_CLIENT_ACCESS, "%llu: New IPv4 web client from %s port %s on socket %d.", w->id, w->client_ip, w->client_port, w->ifd);
81 - break;
82 -
83 - case AF_INET6:
84 - if(strncmp(w->client_ip, "::ffff:", 7) == 0) {
85 - memmove(w->client_ip, &w->client_ip[7], strlen(&w->client_ip[7]) + 1);
86 - debug(D_WEB_CLIENT_ACCESS, "%llu: New IPv4 web client from %s port %s on socket %d.", w->id, w->client_ip, w->client_port, w->ifd);
87 - }
88 - else
89 - debug(D_WEB_CLIENT_ACCESS, "%llu: New IPv6 web client from %s port %s on socket %d.", w->id, w->client_ip, w->client_port, w->ifd);
90 - break;
91 -
92 - default:
93 - debug(D_WEB_CLIENT_ACCESS, "%llu: New UNKNOWN web client from %s port %s on socket %d.", w->id, w->client_ip, w->client_port, w->ifd);
94 - break;
95 - }
96 -
97 - int flag = 1;
98 - if(setsockopt(w->ofd, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int)) != 0)
99 - error("%llu: failed to enable TCP_NODELAY on socket.", w->id);
100 -
101 - flag = 1;
102 - if(setsockopt(w->ifd, SOL_SOCKET, SO_KEEPALIVE, (char *) &flag, sizeof(int)) != 0)
103 - error("%llu: Cannot set SO_KEEPALIVE on socket.", w->id);
104 - }
105 -
106 - w->response.data = buffer_create(INITIAL_WEB_DATA_LENGTH);
107 - w->response.header = buffer_create(HTTP_RESPONSE_HEADER_SIZE);
108 - w->response.header_output = buffer_create(HTTP_RESPONSE_HEADER_SIZE);
109 - w->origin[0] = '*';
110 - w->wait_receive = 1;
111 -
112 - if(web_clients) web_clients->prev = w;
113 - w->next = web_clients;
114 - web_clients = w;
49 + struct web_client *w;
50 +
51 + w = callocz(1, sizeof(struct web_client));
52 + w->id = ++web_clients_count;
53 + w->mode = WEB_CLIENT_MODE_NORMAL;
54 +
55 + {
56 + struct sockaddr *sadr;
57 + socklen_t addrlen;
58 +
59 + sadr = (struct sockaddr*) &w->clientaddr;
60 + addrlen = sizeof(w->clientaddr);
61 +
62 + w->ifd = accept4(listener, sadr, &addrlen, SOCK_NONBLOCK);
63 + if (w->ifd == -1) {
64 + error("%llu: Cannot accept new incoming connection.", w->id);
65 + freez(w);
66 + return NULL;
67 + }
68 + w->ofd = w->ifd;
69 +
70 + if(getnameinfo(sadr, addrlen, w->client_ip, NI_MAXHOST, w->client_port, NI_MAXSERV, NI_NUMERICHOST | NI_NUMERICSERV) != 0) {
71 + error("Cannot getnameinfo() on received client connection.");
72 + strncpyz(w->client_ip, "UNKNOWN", NI_MAXHOST);
73 + strncpyz(w->client_port, "UNKNOWN", NI_MAXSERV);
74 + }
75 + w->client_ip[NI_MAXHOST] = '\0';
76 + w->client_port[NI_MAXSERV] = '\0';
77 +
78 + switch(sadr->sa_family) {
79 + case AF_INET:
80 + debug(D_WEB_CLIENT_ACCESS, "%llu: New IPv4 web client from %s port %s on socket %d.", w->id, w->client_ip, w->client_port, w->ifd);
81 + break;
82 +
83 + case AF_INET6:
84 + if(strncmp(w->client_ip, "::ffff:", 7) == 0) {
85 + memmove(w->client_ip, &w->client_ip[7], strlen(&w->client_ip[7]) + 1);
86 + debug(D_WEB_CLIENT_ACCESS, "%llu: New IPv4 web client from %s port %s on socket %d.", w->id, w->client_ip, w->client_port, w->ifd);
87 + }
88 + else
89 + debug(D_WEB_CLIENT_ACCESS, "%llu: New IPv6 web client from %s port %s on socket %d.", w->id, w->client_ip, w->client_port, w->ifd);
90 + break;
91 +
92 + default:
93 + debug(D_WEB_CLIENT_ACCESS, "%llu: New UNKNOWN web client from %s port %s on socket %d.", w->id, w->client_ip, w->client_port, w->ifd);
94 + break;
95 + }
96 +
97 + int flag = 1;
98 + if(setsockopt(w->ofd, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int)) != 0)
99 + error("%llu: failed to enable TCP_NODELAY on socket.", w->id);
100 +
101 + flag = 1;
102 + if(setsockopt(w->ifd, SOL_SOCKET, SO_KEEPALIVE, (char *) &flag, sizeof(int)) != 0)
103 + error("%llu: Cannot set SO_KEEPALIVE on socket.", w->id);
104 + }
105 +
106 + w->response.data = buffer_create(INITIAL_WEB_DATA_LENGTH);
107 + w->response.header = buffer_create(HTTP_RESPONSE_HEADER_SIZE);
108 + w->response.header_output = buffer_create(HTTP_RESPONSE_HEADER_SIZE);
109 + w->origin[0] = '*';
110 + w->wait_receive = 1;
111 +
112 + if(web_clients) web_clients->prev = w;
113 + w->next = web_clients;
114 + web_clients = w;
115
116 web_client_connected();
117
118 - return(w);
118 + return(w);
119 }
120
121 void web_client_reset(struct web_client *w) {
122 - web_client_uncrock_socket(w);
122 + web_client_uncrock_socket(w);
123
124 - debug(D_WEB_CLIENT, "%llu: Reseting client.", w->id);
124 + debug(D_WEB_CLIENT, "%llu: Reseting client.", w->id);
125
126 - if(likely(w->last_url[0])) {
127 - struct timeval tv;
128 - gettimeofday(&tv, NULL);
126 + if(likely(w->last_url[0])) {
127 + struct timeval tv;
128 + gettimeofday(&tv, NULL);
129
130 - size_t size = (w->mode == WEB_CLIENT_MODE_FILECOPY)?w->response.rlen:w->response.data->len;
131 - size_t sent = size;
130 + size_t size = (w->mode == WEB_CLIENT_MODE_FILECOPY)?w->response.rlen:w->response.data->len;
131 + size_t sent = size;
132 #ifdef NETDATA_WITH_ZLIB
133 - if(likely(w->response.zoutput)) sent = (size_t)w->response.zstream.total_out;
133 + if(likely(w->response.zoutput)) sent = (size_t)w->response.zstream.total_out;
134 #endif
135
136 - // --------------------------------------------------------------------
137 - // global statistics
136 + // --------------------------------------------------------------------
137 + // global statistics
138
139 finished_web_request_statistics(usec_dt(&tv, &w->tv_in),
140 w->stats_received_bytes,
@@ -142,1439 +142,1439 @@ void web_client_reset(struct web_client *w) {
142 size,
143 sent);
144
145 - w->stats_received_bytes = 0;
146 - w->stats_sent_bytes = 0;
147 -
148 -
149 - // --------------------------------------------------------------------
150 - // access log
151 -
152 - log_access("%llu: (sent/all = %zu/%zu bytes %0.0f%%, prep/sent/total = %0.2f/%0.2f/%0.2f ms) %s: %d '%s'",
153 - w->id,
154 - sent, size, -((size > 0) ? ((size - sent) / (double) size * 100.0) : 0.0),
155 - usec_dt(&w->tv_ready, &w->tv_in) / 1000.0,
156 - usec_dt(&tv, &w->tv_ready) / 1000.0,
157 - usec_dt(&tv, &w->tv_in) / 1000.0,
158 - (w->mode == WEB_CLIENT_MODE_FILECOPY) ? "filecopy" : ((w->mode == WEB_CLIENT_MODE_OPTIONS)
159 - ? "options" : "data"),
160 - w->response.code,
161 - w->last_url
162 - );
163 - }
164 -
165 - if(unlikely(w->mode == WEB_CLIENT_MODE_FILECOPY)) {
166 - if(w->ifd != w->ofd) {
167 - debug(D_WEB_CLIENT, "%llu: Closing filecopy input file descriptor %d.", w->id, w->ifd);
168 - if(w->ifd != -1) close(w->ifd);
169 - w->ifd = w->ofd;
170 - }
171 - }
172 -
173 - w->last_url[0] = '\0';
174 - w->cookie1[0] = '\0';
175 - w->cookie2[0] = '\0';
176 - w->origin[0] = '*';
177 - w->origin[1] = '\0';
178 -
179 - w->mode = WEB_CLIENT_MODE_NORMAL;
180 -
181 - w->tcp_cork = 0;
182 - w->donottrack = 0;
183 - w->tracking_required = 0;
184 - w->keepalive = 0;
185 - w->decoded_url[0] = '\0';
186 -
187 - buffer_reset(w->response.header_output);
188 - buffer_reset(w->response.header);
189 - buffer_reset(w->response.data);
190 - w->response.rlen = 0;
191 - w->response.sent = 0;
192 - w->response.code = 0;
193 -
194 - w->wait_receive = 1;
195 - w->wait_send = 0;
196 -
197 - w->response.zoutput = 0;
198 -
199 - // if we had enabled compression, release it
145 + w->stats_received_bytes = 0;
146 + w->stats_sent_bytes = 0;
147 +
148 +
149 + // --------------------------------------------------------------------
150 + // access log
151 +
152 + log_access("%llu: (sent/all = %zu/%zu bytes %0.0f%%, prep/sent/total = %0.2f/%0.2f/%0.2f ms) %s: %d '%s'",
153 + w->id,
154 + sent, size, -((size > 0) ? ((size - sent) / (double) size * 100.0) : 0.0),
155 + usec_dt(&w->tv_ready, &w->tv_in) / 1000.0,
156 + usec_dt(&tv, &w->tv_ready) / 1000.0,
157 + usec_dt(&tv, &w->tv_in) / 1000.0,
158 + (w->mode == WEB_CLIENT_MODE_FILECOPY) ? "filecopy" : ((w->mode == WEB_CLIENT_MODE_OPTIONS)
159 + ? "options" : "data"),
160 + w->response.code,
161 + w->last_url
162 + );
163 + }
164 +
165 + if(unlikely(w->mode == WEB_CLIENT_MODE_FILECOPY)) {
166 + if(w->ifd != w->ofd) {
167 + debug(D_WEB_CLIENT, "%llu: Closing filecopy input file descriptor %d.", w->id, w->ifd);
168 + if(w->ifd != -1) close(w->ifd);
169 + w->ifd = w->ofd;
170 + }
171 + }
172 +
173 + w->last_url[0] = '\0';
174 + w->cookie1[0] = '\0';
175 + w->cookie2[0] = '\0';
176 + w->origin[0] = '*';
177 + w->origin[1] = '\0';
178 +
179 + w->mode = WEB_CLIENT_MODE_NORMAL;
180 +
181 + w->tcp_cork = 0;
182 + w->donottrack = 0;
183 + w->tracking_required = 0;
184 + w->keepalive = 0;
185 + w->decoded_url[0] = '\0';
186 +
187 + buffer_reset(w->response.header_output);
188 + buffer_reset(w->response.header);
189 + buffer_reset(w->response.data);
190 + w->response.rlen = 0;
191 + w->response.sent = 0;
192 + w->response.code = 0;
193 +
194 + w->wait_receive = 1;
195 + w->wait_send = 0;
196 +
197 + w->response.zoutput = 0;
198 +
199 + // if we had enabled compression, release it
200 #ifdef NETDATA_WITH_ZLIB
201 - if(w->response.zinitialized) {
202 - debug(D_DEFLATE, "%llu: Freeing compression resources.", w->id);
203 - deflateEnd(&w->response.zstream);
204 - w->response.zsent = 0;
205 - w->response.zhave = 0;
206 - w->response.zstream.avail_in = 0;
207 - w->response.zstream.avail_out = 0;
208 - w->response.zstream.total_in = 0;
209 - w->response.zstream.total_out = 0;
210 - w->response.zinitialized = 0;
211 - }
201 + if(w->response.zinitialized) {
202 + debug(D_DEFLATE, "%llu: Freeing compression resources.", w->id);
203 + deflateEnd(&w->response.zstream);
204 + w->response.zsent = 0;
205 + w->response.zhave = 0;
206 + w->response.zstream.avail_in = 0;
207 + w->response.zstream.avail_out = 0;
208 + w->response.zstream.total_in = 0;
209 + w->response.zstream.total_out = 0;
210 + w->response.zinitialized = 0;
211 + }
212 #endif // NETDATA_WITH_ZLIB
213 }
214
215 struct web_client *web_client_free(struct web_client *w) {
216 - web_client_reset(w);
216 + web_client_reset(w);
217
218 - struct web_client *n = w->next;
219 - if(w == web_clients) web_clients = n;
218 + struct web_client *n = w->next;
219 + if(w == web_clients) web_clients = n;
220
221 - debug(D_WEB_CLIENT_ACCESS, "%llu: Closing web client from %s port %s.", w->id, w->client_ip, w->client_port);
221 + debug(D_WEB_CLIENT_ACCESS, "%llu: Closing web client from %s port %s.", w->id, w->client_ip, w->client_port);
222
223 - if(w->prev) w->prev->next = w->next;
224 - if(w->next) w->next->prev = w->prev;
225 - if(w->response.header_output) buffer_free(w->response.header_output);
226 - if(w->response.header) buffer_free(w->response.header);
227 - if(w->response.data) buffer_free(w->response.data);
228 - if(w->ifd != -1) close(w->ifd);
229 - if(w->ofd != -1 && w->ofd != w->ifd) close(w->ofd);
230 - freez(w);
223 + if(w->prev) w->prev->next = w->next;
224 + if(w->next) w->next->prev = w->prev;
225 + if(w->response.header_output) buffer_free(w->response.header_output);
226 + if(w->response.header) buffer_free(w->response.header);
227 + if(w->response.data) buffer_free(w->response.data);
228 + if(w->ifd != -1) close(w->ifd);
229 + if(w->ofd != -1 && w->ofd != w->ifd) close(w->ofd);
230 + freez(w);
231
232 web_client_disconnected();
233
234 - return(n);
234 + return(n);
235 }
236
237 uid_t web_files_uid(void) {
238 - static char *web_owner = NULL;
239 - static uid_t owner_uid = 0;
240 -
241 - if(unlikely(!web_owner)) {
242 - web_owner = config_get("global", "web files owner", config_get("global", "run as user", ""));
243 - if(!web_owner || !*web_owner)
244 - owner_uid = geteuid();
245 - else {
246 - // getpwnam() is not thread safe,
247 - // but we have called this function once
248 - // while single threaded
249 - struct passwd *pw = getpwnam(web_owner);
250 - if(!pw) {
251 - error("User '%s' is not present. Ignoring option.", web_owner);
252 - owner_uid = geteuid();
253 - }
254 - else {
255 - debug(D_WEB_CLIENT, "Web files owner set to %s.", web_owner);
256 - owner_uid = pw->pw_uid;
257 - }
258 - }
259 - }
260 -
261 - return(owner_uid);
238 + static char *web_owner = NULL;
239 + static uid_t owner_uid = 0;
240 +
241 + if(unlikely(!web_owner)) {
242 + web_owner = config_get("global", "web files owner", config_get("global", "run as user", ""));
243 + if(!web_owner || !*web_owner)
244 + owner_uid = geteuid();
245 + else {
246 + // getpwnam() is not thread safe,
247 + // but we have called this function once
248 + // while single threaded
249 + struct passwd *pw = getpwnam(web_owner);
250 + if(!pw) {
251 + error("User '%s' is not present. Ignoring option.", web_owner);
252 + owner_uid = geteuid();
253 + }
254 + else {
255 + debug(D_WEB_CLIENT, "Web files owner set to %s.", web_owner);
256 + owner_uid = pw->pw_uid;
257 + }
258 + }
259 + }
260 +
261 + return(owner_uid);
262 }
263
264 gid_t web_files_gid(void) {
265 - static char *web_group = NULL;
266 - static gid_t owner_gid = 0;
267 -
268 - if(unlikely(!web_group)) {
269 - web_group = config_get("global", "web files group", config_get("global", "web files owner", ""));
270 - if(!web_group || !*web_group)
271 - owner_gid = getegid();
272 - else {
273 - // getgrnam() is not thread safe,
274 - // but we have called this function once
275 - // while single threaded
276 - struct group *gr = getgrnam(web_group);
277 - if(!gr) {
278 - error("Group '%s' is not present. Ignoring option.", web_group);
279 - owner_gid = getegid();
280 - }
281 - else {
282 - debug(D_WEB_CLIENT, "Web files group set to %s.", web_group);
283 - owner_gid = gr->gr_gid;
284 - }
285 - }
286 - }
287 -
288 - return(owner_gid);
265 + static char *web_group = NULL;
266 + static gid_t owner_gid = 0;
267 +
268 + if(unlikely(!web_group)) {
269 + web_group = config_get("global", "web files group", config_get("global", "web files owner", ""));
270 + if(!web_group || !*web_group)
271 + owner_gid = getegid();
272 + else {
273 + // getgrnam() is not thread safe,
274 + // but we have called this function once
275 + // while single threaded
276 + struct group *gr = getgrnam(web_group);
277 + if(!gr) {
278 + error("Group '%s' is not present. Ignoring option.", web_group);
279 + owner_gid = getegid();
280 + }
281 + else {
282 + debug(D_WEB_CLIENT, "Web files group set to %s.", web_group);
283 + owner_gid = gr->gr_gid;
284 + }
285 + }
286 + }
287 +
288 + return(owner_gid);
289 }
290
291 int mysendfile(struct web_client *w, char *filename)
292 {
293 - static char *web_dir = NULL;
294 -
295 - // initialize our static data
296 - if(unlikely(!web_dir)) web_dir = config_get("global", "web files directory", WEB_DIR);
297 -
298 - debug(D_WEB_CLIENT, "%llu: Looking for file '%s/%s'", w->id, web_dir, filename);
299 -
300 - // skip leading slashes
301 - while (*filename == '/') filename++;
302 -
303 - // if the filename contain known paths, skip them
304 - if(strncmp(filename, WEB_PATH_FILE "/", strlen(WEB_PATH_FILE) + 1) == 0)
305 - filename = &filename[strlen(WEB_PATH_FILE) + 1];
306 -
307 - char *s;
308 - for(s = filename; *s ;s++) {
309 - if( !isalnum(*s) && *s != '/' && *s != '.' && *s != '-' && *s != '_') {
310 - debug(D_WEB_CLIENT_ACCESS, "%llu: File '%s' is not acceptable.", w->id, filename);
311 - buffer_sprintf(w->response.data, "File '%s' cannot be served. Filename contains invalid character '%c'", filename, *s);
312 - return 400;
313 - }
314 - }
315 -
316 - // if the filename contains a .. refuse to serve it
317 - if(strstr(filename, "..") != 0) {
318 - debug(D_WEB_CLIENT_ACCESS, "%llu: File '%s' is not acceptable.", w->id, filename);
319 - buffer_sprintf(w->response.data, "File '%s' cannot be served. Relative filenames with '..' in them are not supported.", filename);
320 - return 400;
321 - }
322 -
323 - // access the file
324 - char webfilename[FILENAME_MAX + 1];
325 - snprintfz(webfilename, FILENAME_MAX, "%s/%s", web_dir, filename);
326 -
327 - // check if the file exists
328 - struct stat stat;
329 - if(lstat(webfilename, &stat) != 0) {
330 - debug(D_WEB_CLIENT_ACCESS, "%llu: File '%s' is not found.", w->id, webfilename);
331 - buffer_sprintf(w->response.data, "File '%s' does not exist, or is not accessible.", webfilename);
332 - return 404;
333 - }
334 -
335 - // check if the file is owned by expected user
336 - if(stat.st_uid != web_files_uid()) {
337 - error("%llu: File '%s' is owned by user %u (expected user %u). Access Denied.", w->id, webfilename, stat.st_uid, web_files_uid());
338 - buffer_sprintf(w->response.data, "Access to file '%s' is not permitted.", webfilename);
339 - return 403;
340 - }
341 -
342 - // check if the file is owned by expected group
343 - if(stat.st_gid != web_files_gid()) {
344 - error("%llu: File '%s' is owned by group %u (expected group %u). Access Denied.", w->id, webfilename, stat.st_gid, web_files_gid());
345 - buffer_sprintf(w->response.data, "Access to file '%s' is not permitted.", webfilename);
346 - return 403;
347 - }
348 -
349 - if((stat.st_mode & S_IFMT) == S_IFDIR) {
350 - snprintfz(webfilename, FILENAME_MAX, "%s/index.html", filename);
351 - return mysendfile(w, webfilename);
352 - }
353 -
354 - if((stat.st_mode & S_IFMT) != S_IFREG) {
355 - error("%llu: File '%s' is not a regular file. Access Denied.", w->id, webfilename);
356 - buffer_sprintf(w->response.data, "Access to file '%s' is not permitted.", webfilename);
357 - return 403;
358 - }
359 -
360 - // open the file
361 - w->ifd = open(webfilename, O_NONBLOCK, O_RDONLY);
362 - if(w->ifd == -1) {
363 - w->ifd = w->ofd;
364 -
365 - if(errno == EBUSY || errno == EAGAIN) {
366 - error("%llu: File '%s' is busy, sending 307 Moved Temporarily to force retry.", w->id, webfilename);
367 - buffer_sprintf(w->response.header, "Location: /" WEB_PATH_FILE "/%s\r\n", filename);
368 - buffer_sprintf(w->response.data, "The file '%s' is currently busy. Please try again later.", webfilename);
369 - return 307;
370 - }
371 - else {
372 - error("%llu: Cannot open file '%s'.", w->id, webfilename);
373 - buffer_sprintf(w->response.data, "Cannot open file '%s'.", webfilename);
374 - return 404;
375 - }
376 - }
377 - if(fcntl(w->ifd, F_SETFL, O_NONBLOCK) < 0)
378 - error("%llu: Cannot set O_NONBLOCK on file '%s'.", w->id, webfilename);
379 -
380 - // pick a Content-Type for the file
381 - if(strstr(filename, ".html") != NULL) w->response.data->contenttype = CT_TEXT_HTML;
382 - else if(strstr(filename, ".js") != NULL) w->response.data->contenttype = CT_APPLICATION_X_JAVASCRIPT;
383 - else if(strstr(filename, ".css") != NULL) w->response.data->contenttype = CT_TEXT_CSS;
384 - else if(strstr(filename, ".xml") != NULL) w->response.data->contenttype = CT_TEXT_XML;
385 - else if(strstr(filename, ".xsl") != NULL) w->response.data->contenttype = CT_TEXT_XSL;
386 - else if(strstr(filename, ".txt") != NULL) w->response.data->contenttype = CT_TEXT_PLAIN;
387 - else if(strstr(filename, ".svg") != NULL) w->response.data->contenttype = CT_IMAGE_SVG_XML;
388 - else if(strstr(filename, ".ttf") != NULL) w->response.data->contenttype = CT_APPLICATION_X_FONT_TRUETYPE;
389 - else if(strstr(filename, ".otf") != NULL) w->response.data->contenttype = CT_APPLICATION_X_FONT_OPENTYPE;
390 - else if(strstr(filename, ".woff2")!= NULL) w->response.data->contenttype = CT_APPLICATION_FONT_WOFF2;
391 - else if(strstr(filename, ".woff") != NULL) w->response.data->contenttype = CT_APPLICATION_FONT_WOFF;
392 - else if(strstr(filename, ".eot") != NULL) w->response.data->contenttype = CT_APPLICATION_VND_MS_FONTOBJ;
393 - else if(strstr(filename, ".png") != NULL) w->response.data->contenttype = CT_IMAGE_PNG;
394 - else if(strstr(filename, ".jpg") != NULL) w->response.data->contenttype = CT_IMAGE_JPG;
395 - else if(strstr(filename, ".jpeg") != NULL) w->response.data->contenttype = CT_IMAGE_JPG;
396 - else if(strstr(filename, ".gif") != NULL) w->response.data->contenttype = CT_IMAGE_GIF;
397 - else if(strstr(filename, ".bmp") != NULL) w->response.data->contenttype = CT_IMAGE_BMP;
398 - else if(strstr(filename, ".ico") != NULL) w->response.data->contenttype = CT_IMAGE_XICON;
399 - else if(strstr(filename, ".icns") != NULL) w->response.data->contenttype = CT_IMAGE_ICNS;
400 - else w->response.data->contenttype = CT_APPLICATION_OCTET_STREAM;
401 -
402 - debug(D_WEB_CLIENT_ACCESS, "%llu: Sending file '%s' (%ld bytes, ifd %d, ofd %d).", w->id, webfilename, stat.st_size, w->ifd, w->ofd);
403 -
404 - w->mode = WEB_CLIENT_MODE_FILECOPY;
405 - w->wait_receive = 1;
406 - w->wait_send = 0;
407 - buffer_flush(w->response.data);
408 - w->response.rlen = stat.st_size;
409 - w->response.data->date = stat.st_mtim.tv_sec;
410 -
411 - return 200;
293 + static char *web_dir = NULL;
294 +
295 + // initialize our static data
296 + if(unlikely(!web_dir)) web_dir = config_get("global", "web files directory", WEB_DIR);
297 +
298 + debug(D_WEB_CLIENT, "%llu: Looking for file '%s/%s'", w->id, web_dir, filename);
299 +
300 + // skip leading slashes
301 + while (*filename == '/') filename++;
302 +
303 + // if the filename contain known paths, skip them
304 + if(strncmp(filename, WEB_PATH_FILE "/", strlen(WEB_PATH_FILE) + 1) == 0)
305 + filename = &filename[strlen(WEB_PATH_FILE) + 1];
306 +
307 + char *s;
308 + for(s = filename; *s ;s++) {
309 + if( !isalnum(*s) && *s != '/' && *s != '.' && *s != '-' && *s != '_') {
310 + debug(D_WEB_CLIENT_ACCESS, "%llu: File '%s' is not acceptable.", w->id, filename);
311 + buffer_sprintf(w->response.data, "File '%s' cannot be served. Filename contains invalid character '%c'", filename, *s);
312 + return 400;
313 + }
314 + }
315 +
316 + // if the filename contains a .. refuse to serve it
317 + if(strstr(filename, "..") != 0) {
318 + debug(D_WEB_CLIENT_ACCESS, "%llu: File '%s' is not acceptable.", w->id, filename);
319 + buffer_sprintf(w->response.data, "File '%s' cannot be served. Relative filenames with '..' in them are not supported.", filename);
320 + return 400;
321 + }
322 +
323 + // access the file
324 + char webfilename[FILENAME_MAX + 1];
325 + snprintfz(webfilename, FILENAME_MAX, "%s/%s", web_dir, filename);
326 +
327 + // check if the file exists
328 + struct stat stat;
329 + if(lstat(webfilename, &stat) != 0) {
330 + debug(D_WEB_CLIENT_ACCESS, "%llu: File '%s' is not found.", w->id, webfilename);
331 + buffer_sprintf(w->response.data, "File '%s' does not exist, or is not accessible.", webfilename);
332 + return 404;
333 + }
334 +
335 + // check if the file is owned by expected user
336 + if(stat.st_uid != web_files_uid()) {
337 + error("%llu: File '%s' is owned by user %u (expected user %u). Access Denied.", w->id, webfilename, stat.st_uid, web_files_uid());
338 + buffer_sprintf(w->response.data, "Access to file '%s' is not permitted.", webfilename);
339 + return 403;
340 + }
341 +
342 + // check if the file is owned by expected group
343 + if(stat.st_gid != web_files_gid()) {
344 + error("%llu: File '%s' is owned by group %u (expected group %u). Access Denied.", w->id, webfilename, stat.st_gid, web_files_gid());
345 + buffer_sprintf(w->response.data, "Access to file '%s' is not permitted.", webfilename);
346 + return 403;
347 + }
348 +
349 + if((stat.st_mode & S_IFMT) == S_IFDIR) {
350 + snprintfz(webfilename, FILENAME_MAX, "%s/index.html", filename);
351 + return mysendfile(w, webfilename);
352 + }
353 +
354 + if((stat.st_mode & S_IFMT) != S_IFREG) {
355 + error("%llu: File '%s' is not a regular file. Access Denied.", w->id, webfilename);
356 + buffer_sprintf(w->response.data, "Access to file '%s' is not permitted.", webfilename);
357 + return 403;
358 + }
359 +
360 + // open the file
361 + w->ifd = open(webfilename, O_NONBLOCK, O_RDONLY);
362 + if(w->ifd == -1) {
363 + w->ifd = w->ofd;
364 +
365 + if(errno == EBUSY || errno == EAGAIN) {
366 + error("%llu: File '%s' is busy, sending 307 Moved Temporarily to force retry.", w->id, webfilename);
367 + buffer_sprintf(w->response.header, "Location: /" WEB_PATH_FILE "/%s\r\n", filename);
368 + buffer_sprintf(w->response.data, "The file '%s' is currently busy. Please try again later.", webfilename);
369 + return 307;
370 + }
371 + else {
372 + error("%llu: Cannot open file '%s'.", w->id, webfilename);
373 + buffer_sprintf(w->response.data, "Cannot open file '%s'.", webfilename);
374 + return 404;
375 + }
376 + }
377 + if(fcntl(w->ifd, F_SETFL, O_NONBLOCK) < 0)
378 + error("%llu: Cannot set O_NONBLOCK on file '%s'.", w->id, webfilename);
379 +
380 + // pick a Content-Type for the file
381 + if(strstr(filename, ".html") != NULL) w->response.data->contenttype = CT_TEXT_HTML;
382 + else if(strstr(filename, ".js") != NULL) w->response.data->contenttype = CT_APPLICATION_X_JAVASCRIPT;
383 + else if(strstr(filename, ".css") != NULL) w->response.data->contenttype = CT_TEXT_CSS;
384 + else if(strstr(filename, ".xml") != NULL) w->response.data->contenttype = CT_TEXT_XML;
385 + else if(strstr(filename, ".xsl") != NULL) w->response.data->contenttype = CT_TEXT_XSL;
386 + else if(strstr(filename, ".txt") != NULL) w->response.data->contenttype = CT_TEXT_PLAIN;
387 + else if(strstr(filename, ".svg") != NULL) w->response.data->contenttype = CT_IMAGE_SVG_XML;
388 + else if(strstr(filename, ".ttf") != NULL) w->response.data->contenttype = CT_APPLICATION_X_FONT_TRUETYPE;
389 + else if(strstr(filename, ".otf") != NULL) w->response.data->contenttype = CT_APPLICATION_X_FONT_OPENTYPE;
390 + else if(strstr(filename, ".woff2")!= NULL) w->response.data->contenttype = CT_APPLICATION_FONT_WOFF2;
391 + else if(strstr(filename, ".woff") != NULL) w->response.data->contenttype = CT_APPLICATION_FONT_WOFF;
392 + else if(strstr(filename, ".eot") != NULL) w->response.data->contenttype = CT_APPLICATION_VND_MS_FONTOBJ;
393 + else if(strstr(filename, ".png") != NULL) w->response.data->contenttype = CT_IMAGE_PNG;
394 + else if(strstr(filename, ".jpg") != NULL) w->response.data->contenttype = CT_IMAGE_JPG;
395 + else if(strstr(filename, ".jpeg") != NULL) w->response.data->contenttype = CT_IMAGE_JPG;
396 + else if(strstr(filename, ".gif") != NULL) w->response.data->contenttype = CT_IMAGE_GIF;
397 + else if(strstr(filename, ".bmp") != NULL) w->response.data->contenttype = CT_IMAGE_BMP;
398 + else if(strstr(filename, ".ico") != NULL) w->response.data->contenttype = CT_IMAGE_XICON;
399 + else if(strstr(filename, ".icns") != NULL) w->response.data->contenttype = CT_IMAGE_ICNS;
400 + else w->response.data->contenttype = CT_APPLICATION_OCTET_STREAM;
401 +
402 + debug(D_WEB_CLIENT_ACCESS, "%llu: Sending file '%s' (%ld bytes, ifd %d, ofd %d).", w->id, webfilename, stat.st_size, w->ifd, w->ofd);
403 +
404 + w->mode = WEB_CLIENT_MODE_FILECOPY;
405 + w->wait_receive = 1;
406 + w->wait_send = 0;
407 + buffer_flush(w->response.data);
408 + w->response.rlen = stat.st_size;
409 + w->response.data->date = stat.st_mtim.tv_sec;
410 +
411 + return 200;
412 }
413
414
415 #ifdef NETDATA_WITH_ZLIB
416 void web_client_enable_deflate(struct web_client *w, int gzip) {
417 - if(unlikely(w->response.zinitialized)) {
418 - error("%llu: Compression has already be initialized for this client.", w->id);
419 - return;
420 - }
421 -
422 - if(unlikely(w->response.sent)) {
423 - error("%llu: Cannot enable compression in the middle of a conversation.", w->id);
424 - return;
425 - }
426 -
427 - w->response.zstream.zalloc = Z_NULL;
428 - w->response.zstream.zfree = Z_NULL;
429 - w->response.zstream.opaque = Z_NULL;
430 -
431 - w->response.zstream.next_in = (Bytef *)w->response.data->buffer;
432 - w->response.zstream.avail_in = 0;
433 - w->response.zstream.total_in = 0;
434 -
435 - w->response.zstream.next_out = w->response.zbuffer;
436 - w->response.zstream.avail_out = 0;
437 - w->response.zstream.total_out = 0;
438 -
439 - w->response.zstream.zalloc = Z_NULL;
440 - w->response.zstream.zfree = Z_NULL;
441 - w->response.zstream.opaque = Z_NULL;
442 -
443 -// if(deflateInit(&w->response.zstream, Z_DEFAULT_COMPRESSION) != Z_OK) {
444 -// error("%llu: Failed to initialize zlib. Proceeding without compression.", w->id);
445 -// return;
446 -// }
447 -
448 - // Select GZIP compression: windowbits = 15 + 16 = 31
449 - if(deflateInit2(&w->response.zstream, web_gzip_level, Z_DEFLATED, 15 + ((gzip)?16:0), 8, web_gzip_strategy) != Z_OK) {
450 - error("%llu: Failed to initialize zlib. Proceeding without compression.", w->id);
451 - return;
452 - }
453 -
454 - w->response.zsent = 0;
455 - w->response.zoutput = 1;
456 - w->response.zinitialized = 1;
457 -
458 - debug(D_DEFLATE, "%llu: Initialized compression.", w->id);
417 + if(unlikely(w->response.zinitialized)) {
418 + error("%llu: Compression has already be initialized for this client.", w->id);
419 + return;
420 + }
421 +
422 + if(unlikely(w->response.sent)) {
423 + error("%llu: Cannot enable compression in the middle of a conversation.", w->id);
424 + return;
425 + }
426 +
427 + w->response.zstream.zalloc = Z_NULL;
428 + w->response.zstream.zfree = Z_NULL;
429 + w->response.zstream.opaque = Z_NULL;
430 +
431 + w->response.zstream.next_in = (Bytef *)w->response.data->buffer;
432 + w->response.zstream.avail_in = 0;
433 + w->response.zstream.total_in = 0;
434 +
435 + w->response.zstream.next_out = w->response.zbuffer;
436 + w->response.zstream.avail_out = 0;
437 + w->response.zstream.total_out = 0;
438 +
439 + w->response.zstream.zalloc = Z_NULL;
440 + w->response.zstream.zfree = Z_NULL;
441 + w->response.zstream.opaque = Z_NULL;
442 +
443 +// if(deflateInit(&w->response.zstream, Z_DEFAULT_COMPRESSION) != Z_OK) {
444 +// error("%llu: Failed to initialize zlib. Proceeding without compression.", w->id);
445 +// return;
446 +// }
447 +
448 + // Select GZIP compression: windowbits = 15 + 16 = 31
449 + if(deflateInit2(&w->response.zstream, web_gzip_level, Z_DEFLATED, 15 + ((gzip)?16:0), 8, web_gzip_strategy) != Z_OK) {
450 + error("%llu: Failed to initialize zlib. Proceeding without compression.", w->id);
451 + return;
452 + }
453 +
454 + w->response.zsent = 0;
455 + w->response.zoutput = 1;
456 + w->response.zinitialized = 1;
457 +
458 + debug(D_DEFLATE, "%llu: Initialized compression.", w->id);
459 }
460 #endif // NETDATA_WITH_ZLIB
461
462 uint32_t web_client_api_request_v1_data_options(char *o)
463 {
464 - uint32_t ret = 0x00000000;
465 - char *tok;
466 -
467 - while(o && *o && (tok = mystrsep(&o, ", |"))) {
468 - if(!*tok) continue;
469 -
470 - if(!strcmp(tok, "nonzero"))
471 - ret |= RRDR_OPTION_NONZERO;
472 - else if(!strcmp(tok, "flip") || !strcmp(tok, "reversed") || !strcmp(tok, "reverse"))
473 - ret |= RRDR_OPTION_REVERSED;
474 - else if(!strcmp(tok, "jsonwrap"))
475 - ret |= RRDR_OPTION_JSON_WRAP;
476 - else if(!strcmp(tok, "min2max"))
477 - ret |= RRDR_OPTION_MIN2MAX;
478 - else if(!strcmp(tok, "ms") || !strcmp(tok, "milliseconds"))
479 - ret |= RRDR_OPTION_MILLISECONDS;
480 - else if(!strcmp(tok, "abs") || !strcmp(tok, "absolute") || !strcmp(tok, "absolute_sum") || !strcmp(tok, "absolute-sum"))
481 - ret |= RRDR_OPTION_ABSOLUTE;
482 - else if(!strcmp(tok, "seconds"))
483 - ret |= RRDR_OPTION_SECONDS;
484 - else if(!strcmp(tok, "null2zero"))
485 - ret |= RRDR_OPTION_NULL2ZERO;
486 - else if(!strcmp(tok, "objectrows"))
487 - ret |= RRDR_OPTION_OBJECTSROWS;
488 - else if(!strcmp(tok, "google_json"))
489 - ret |= RRDR_OPTION_GOOGLE_JSON;
490 - else if(!strcmp(tok, "percentage"))
491 - ret |= RRDR_OPTION_PERCENTAGE;
492 - else if(!strcmp(tok, "unaligned"))
493 - ret |= RRDR_OPTION_NOT_ALIGNED;
494 - }
495 -
496 - return ret;
464 + uint32_t ret = 0x00000000;
465 + char *tok;
466 +
467 + while(o && *o && (tok = mystrsep(&o, ", |"))) {
468 + if(!*tok) continue;
469 +
470 + if(!strcmp(tok, "nonzero"))
471 + ret |= RRDR_OPTION_NONZERO;
472 + else if(!strcmp(tok, "flip") || !strcmp(tok, "reversed") || !strcmp(tok, "reverse"))
473 + ret |= RRDR_OPTION_REVERSED;
474 + else if(!strcmp(tok, "jsonwrap"))
475 + ret |= RRDR_OPTION_JSON_WRAP;
476 + else if(!strcmp(tok, "min2max"))
477 + ret |= RRDR_OPTION_MIN2MAX;
478 + else if(!strcmp(tok, "ms") || !strcmp(tok, "milliseconds"))
479 + ret |= RRDR_OPTION_MILLISECONDS;
480 + else if(!strcmp(tok, "abs") || !strcmp(tok, "absolute") || !strcmp(tok, "absolute_sum") || !strcmp(tok, "absolute-sum"))
481 + ret |= RRDR_OPTION_ABSOLUTE;
482 + else if(!strcmp(tok, "seconds"))
483 + ret |= RRDR_OPTION_SECONDS;
484 + else if(!strcmp(tok, "null2zero"))
485 + ret |= RRDR_OPTION_NULL2ZERO;
486 + else if(!strcmp(tok, "objectrows"))
487 + ret |= RRDR_OPTION_OBJECTSROWS;
488 + else if(!strcmp(tok, "google_json"))
489 + ret |= RRDR_OPTION_GOOGLE_JSON;
490 + else if(!strcmp(tok, "percentage"))
491 + ret |= RRDR_OPTION_PERCENTAGE;
492 + else if(!strcmp(tok, "unaligned"))
493 + ret |= RRDR_OPTION_NOT_ALIGNED;
494 + }
495 +
496 + return ret;
497 }
498
499 uint32_t web_client_api_request_v1_data_format(char *name)
500 {
501 - if(!strcmp(name, DATASOURCE_FORMAT_DATATABLE_JSON)) // datatable
502 - return DATASOURCE_DATATABLE_JSON;
501 + if(!strcmp(name, DATASOURCE_FORMAT_DATATABLE_JSON)) // datatable
502 + return DATASOURCE_DATATABLE_JSON;
503
504 - else if(!strcmp(name, DATASOURCE_FORMAT_DATATABLE_JSONP)) // datasource
505 - return DATASOURCE_DATATABLE_JSONP;
504 + else if(!strcmp(name, DATASOURCE_FORMAT_DATATABLE_JSONP)) // datasource
505 + return DATASOURCE_DATATABLE_JSONP;
506
507 - else if(!strcmp(name, DATASOURCE_FORMAT_JSON)) // json
508 - return DATASOURCE_JSON;
507 + else if(!strcmp(name, DATASOURCE_FORMAT_JSON)) // json
508 + return DATASOURCE_JSON;
509
510 - else if(!strcmp(name, DATASOURCE_FORMAT_JSONP)) // jsonp
511 - return DATASOURCE_JSONP;
510 + else if(!strcmp(name, DATASOURCE_FORMAT_JSONP)) // jsonp
511 + return DATASOURCE_JSONP;
512
513 - else if(!strcmp(name, DATASOURCE_FORMAT_SSV)) // ssv
514 - return DATASOURCE_SSV;
513 + else if(!strcmp(name, DATASOURCE_FORMAT_SSV)) // ssv
514 + return DATASOURCE_SSV;
515
516 - else if(!strcmp(name, DATASOURCE_FORMAT_CSV)) // csv
517 - return DATASOURCE_CSV;
516 + else if(!strcmp(name, DATASOURCE_FORMAT_CSV)) // csv
517 + return DATASOURCE_CSV;
518
519 - else if(!strcmp(name, DATASOURCE_FORMAT_TSV) || !strcmp(name, "tsv-excel")) // tsv
520 - return DATASOURCE_TSV;
519 + else if(!strcmp(name, DATASOURCE_FORMAT_TSV) || !strcmp(name, "tsv-excel")) // tsv
520 + return DATASOURCE_TSV;
521
522 - else if(!strcmp(name, DATASOURCE_FORMAT_HTML)) // html
523 - return DATASOURCE_HTML;
522 + else if(!strcmp(name, DATASOURCE_FORMAT_HTML)) // html
523 + return DATASOURCE_HTML;
524
525 - else if(!strcmp(name, DATASOURCE_FORMAT_JS_ARRAY)) // array
526 - return DATASOURCE_JS_ARRAY;
525 + else if(!strcmp(name, DATASOURCE_FORMAT_JS_ARRAY)) // array
526 + return DATASOURCE_JS_ARRAY;
527
528 - else if(!strcmp(name, DATASOURCE_FORMAT_SSV_COMMA)) // ssvcomma
529 - return DATASOURCE_SSV_COMMA;
528 + else if(!strcmp(name, DATASOURCE_FORMAT_SSV_COMMA)) // ssvcomma
529 + return DATASOURCE_SSV_COMMA;
530
531 - else if(!strcmp(name, DATASOURCE_FORMAT_CSV_JSON_ARRAY)) // csvjsonarray
532 - return DATASOURCE_CSV_JSON_ARRAY;
531 + else if(!strcmp(name, DATASOURCE_FORMAT_CSV_JSON_ARRAY)) // csvjsonarray
532 + return DATASOURCE_CSV_JSON_ARRAY;
533
534 - return DATASOURCE_JSON;
534 + return DATASOURCE_JSON;
535 }
536
537 uint32_t web_client_api_request_v1_data_google_format(char *name)
538 {
539 - if(!strcmp(name, "json"))
540 - return DATASOURCE_DATATABLE_JSONP;
539 + if(!strcmp(name, "json"))
540 + return DATASOURCE_DATATABLE_JSONP;
541
542 - else if(!strcmp(name, "html"))
543 - return DATASOURCE_HTML;
542 + else if(!strcmp(name, "html"))
543 + return DATASOURCE_HTML;
544
545 - else if(!strcmp(name, "csv"))
546 - return DATASOURCE_CSV;
545 + else if(!strcmp(name, "csv"))
546 + return DATASOURCE_CSV;
547
548 - else if(!strcmp(name, "tsv-excel"))
549 - return DATASOURCE_TSV;
548 + else if(!strcmp(name, "tsv-excel"))
549 + return DATASOURCE_TSV;
550
551 - return DATASOURCE_JSON;
551 + return DATASOURCE_JSON;
552 }
553
554 int web_client_api_request_v1_data_group(char *name, int def)
555 {
556 - if(!strcmp(name, "max"))
557 - return GROUP_MAX;
556 + if(!strcmp(name, "max"))
557 + return GROUP_MAX;
558
559 - else if(!strcmp(name, "average"))
560 - return GROUP_AVERAGE;
559 + else if(!strcmp(name, "average"))
560 + return GROUP_AVERAGE;
561
562 - else if(!strcmp(name, "sum"))
563 - return GROUP_SUM;
562 + else if(!strcmp(name, "sum"))
563 + return GROUP_SUM;
564
565 - else if(!strcmp(name, "incremental-sum"))
566 - return GROUP_INCREMENTAL_SUM;
565 + else if(!strcmp(name, "incremental-sum"))
566 + return GROUP_INCREMENTAL_SUM;
567
568 - return def;
568 + return def;
569 }
570
571 int web_client_api_request_v1_charts(struct web_client *w, char *url)
572 {
573 - if(url) { ; }
573 + if(url) { ; }
574
575 - buffer_flush(w->response.data);
576 - w->response.data->contenttype = CT_APPLICATION_JSON;
577 - rrd_stats_api_v1_charts(w->response.data);
578 - return 200;
575 + buffer_flush(w->response.data);
576 + w->response.data->contenttype = CT_APPLICATION_JSON;
577 + rrd_stats_api_v1_charts(w->response.data);
578 + return 200;
579 }
580
581 int web_client_api_request_v1_chart(struct web_client *w, char *url)
582 {
583 - int ret = 400;
584 - char *chart = NULL;
585 -
586 - buffer_flush(w->response.data);
587 -
588 - while(url) {
589 - char *value = mystrsep(&url, "?&[]");
590 - if(!value || !*value) continue;
591 -
592 - char *name = mystrsep(&value, "=");
593 - if(!name || !*name) continue;
594 - if(!value || !*value) continue;
595 -
596 - // name and value are now the parameters
597 - // they are not null and not empty
598 -
599 - if(!strcmp(name, "chart")) chart = value;
600 - //else {
601 - /// buffer_sprintf(w->response.data, "Unknown parameter '%s' in request.", name);
602 - // goto cleanup;
603 - //}
604 - }
605 -
606 - if(!chart || !*chart) {
607 - buffer_sprintf(w->response.data, "No chart id is given at the request.");
608 - goto cleanup;
609 - }
610 -
611 - RRDSET *st = rrdset_find(chart);
612 - if(!st) st = rrdset_find_byname(chart);
613 - if(!st) {
614 - buffer_sprintf(w->response.data, "Chart '%s' is not found.", chart);
615 - ret = 404;
616 - goto cleanup;
617 - }
618 -
619 - w->response.data->contenttype = CT_APPLICATION_JSON;
620 - rrd_stats_api_v1_chart(st, w->response.data);
621 - return 200;
583 + int ret = 400;
584 + char *chart = NULL;
585 +
586 + buffer_flush(w->response.data);
587 +
588 + while(url) {
589 + char *value = mystrsep(&url, "?&[]");
590 + if(!value || !*value) continue;
591 +
592 + char *name = mystrsep(&value, "=");
593 + if(!name || !*name) continue;
594 + if(!value || !*value) continue;
595 +
596 + // name and value are now the parameters
597 + // they are not null and not empty
598 +
599 + if(!strcmp(name, "chart")) chart = value;
600 + //else {
601 + /// buffer_sprintf(w->response.data, "Unknown parameter '%s' in request.", name);
602 + // goto cleanup;
603 + //}
604 + }
605 +
606 + if(!chart || !*chart) {
607 + buffer_sprintf(w->response.data, "No chart id is given at the request.");
608 + goto cleanup;
609 + }
610 +
611 + RRDSET *st = rrdset_find(chart);
612 + if(!st) st = rrdset_find_byname(chart);
613 + if(!st) {
614 + buffer_sprintf(w->response.data, "Chart '%s' is not found.", chart);
615 + ret = 404;
616 + goto cleanup;
617 + }
618 +
619 + w->response.data->contenttype = CT_APPLICATION_JSON;
620 + rrd_stats_api_v1_chart(st, w->response.data);
621 + return 200;
622
623 cleanup:
624 - return ret;
624 + return ret;
625 }
626
627 int web_client_api_v1_badge(struct web_client *w, char *url) {
628 - int ret = 400;
629 - buffer_flush(w->response.data);
630 -
631 - BUFFER *dimensions = NULL;
632 -
633 - const char *chart = NULL
634 - , *before_str = NULL
635 - , *after_str = NULL
636 - , *points_str = NULL
637 - , *multiply_str = NULL
638 - , *divide_str = NULL
639 - , *label = NULL
640 - , *units = NULL
641 - , *label_color = NULL
642 - , *value_color = NULL
643 - , *refresh_str = NULL
644 - , *precision_str = NULL;
645 -
646 - int group = GROUP_AVERAGE;
647 - uint32_t options = 0x00000000;
648 -
649 - while(url) {
650 - char *value = mystrsep(&url, "/?&[]");
651 - if(!value || !*value) continue;
652 -
653 - char *name = mystrsep(&value, "=");
654 - if(!name || !*name) continue;
655 - if(!value || !*value) continue;
656 -
657 - debug(D_WEB_CLIENT, "%llu: API v1 badge.svg query param '%s' with value '%s'", w->id, name, value);
658 -
659 - // name and value are now the parameters
660 - // they are not null and not empty
661 -
662 - if(!strcmp(name, "chart")) chart = value;
663 - else if(!strcmp(name, "dimension") || !strcmp(name, "dim") || !strcmp(name, "dimensions") || !strcmp(name, "dims")) {
664 - if(!dimensions)
665 - dimensions = buffer_create(100);
628 + int ret = 400;
629 + buffer_flush(w->response.data);
630 +
631 + BUFFER *dimensions = NULL;
632 +
633 + const char *chart = NULL
634 + , *before_str = NULL
635 + , *after_str = NULL
636 + , *points_str = NULL
637 + , *multiply_str = NULL
638 + , *divide_str = NULL
639 + , *label = NULL
640 + , *units = NULL
641 + , *label_color = NULL
642 + , *value_color = NULL
643 + , *refresh_str = NULL
644 + , *precision_str = NULL;
645 +
646 + int group = GROUP_AVERAGE;
647 + uint32_t options = 0x00000000;
648 +
649 + while(url) {
650 + char *value = mystrsep(&url, "/?&[]");
651 + if(!value || !*value) continue;
652 +
653 + char *name = mystrsep(&value, "=");
654 + if(!name || !*name) continue;
655 + if(!value || !*value) continue;
656 +
657 + debug(D_WEB_CLIENT, "%llu: API v1 badge.svg query param '%s' with value '%s'", w->id, name, value);
658 +
659 + // name and value are now the parameters
660 + // they are not null and not empty
661 +
662 + if(!strcmp(name, "chart")) chart = value;
663 + else if(!strcmp(name, "dimension") || !strcmp(name, "dim") || !strcmp(name, "dimensions") || !strcmp(name, "dims")) {
664 + if(!dimensions)
665 + dimensions = buffer_create(100);
666
667 buffer_strcat(dimensions, "|");
668 buffer_strcat(dimensions, value);
669 - }
670 - else if(!strcmp(name, "after")) after_str = value;
671 - else if(!strcmp(name, "before")) before_str = value;
672 - else if(!strcmp(name, "points")) points_str = value;
673 - else if(!strcmp(name, "group")) {
674 - group = web_client_api_request_v1_data_group(value, GROUP_AVERAGE);
675 - }
676 - else if(!strcmp(name, "options")) {
677 - options |= web_client_api_request_v1_data_options(value);
678 - }
679 - else if(!strcmp(name, "label")) label = value;
680 - else if(!strcmp(name, "units")) units = value;
681 - else if(!strcmp(name, "label_color")) label_color = value;
682 - else if(!strcmp(name, "value_color")) value_color = value;
683 - else if(!strcmp(name, "multiply")) multiply_str = value;
684 - else if(!strcmp(name, "divide")) divide_str = value;
685 - else if(!strcmp(name, "refresh")) refresh_str = value;
686 - else if(!strcmp(name, "precision")) precision_str = value;
687 - }
688 -
689 - if(!chart || !*chart) {
690 - buffer_sprintf(w->response.data, "No chart id is given at the request.");
691 - goto cleanup;
692 - }
693 -
694 - RRDSET *st = rrdset_find(chart);
695 - if(!st) st = rrdset_find_byname(chart);
696 - if(!st) {
697 - buffer_svg(w->response.data, "chart not found", 0, "", NULL, NULL, 1, -1);
698 - ret = 200;
699 - goto cleanup;
700 - }
701 -
702 - long long multiply = (multiply_str && *multiply_str )?atol(multiply_str):1;
703 - long long divide = (divide_str && *divide_str )?atol(divide_str):1;
704 - long long before = (before_str && *before_str )?atol(before_str):0;
705 - long long after = (after_str && *after_str )?atol(after_str):-st->update_every;
706 - int points = (points_str && *points_str )?atoi(points_str):1;
707 - int precision = (precision_str && *precision_str)?atoi(precision_str):-1;
708 -
709 - if(!multiply) multiply = 1;
710 - if(!divide) divide = 1;
711 -
712 - int refresh = 0;
713 - if(refresh_str && *refresh_str) {
714 - if(!strcmp(refresh_str, "auto")) {
715 - if(options & RRDR_OPTION_NOT_ALIGNED)
716 - refresh = st->update_every;
717 - else {
718 - refresh = (before - after);
719 - if(refresh < 0) refresh = -refresh;
720 - }
721 - }
722 - else {
723 - refresh = atoi(refresh_str);
724 - if(refresh < 0) refresh = -refresh;
725 - }
726 - }
727 -
728 - if(!label) {
729 - if(dimensions) {
730 - const char *dim = buffer_tostring(dimensions);
731 - if(*dim == '|') dim++;
732 - label = dim;
733 - }
734 - else
735 - label = st->name;
736 - }
737 - if(!units) {
738 - if(options & RRDR_OPTION_PERCENTAGE)
739 - units="%";
740 - else
741 - units = st->units;
742 - }
743 -
744 - debug(D_WEB_CLIENT, "%llu: API command 'badge.svg' for chart '%s', dimensions '%s', after '%lld', before '%lld', points '%d', group '%d', options '0x%08x'"
745 - , w->id
746 - , chart
747 - , (dimensions)?buffer_tostring(dimensions):""
748 - , after
749 - , before
750 - , points
751 - , group
752 - , options
753 - );
754 -
755 - time_t latest_timestamp = 0;
756 - int value_is_null = 1;
757 - calculated_number n = 0;
758 - ret = 500;
759 -
760 - // if the collected value is too old, don't calculate its value
761 - if(rrdset_last_entry_t(st) >= (time(NULL) - (st->update_every * st->gap_when_lost_iterations_above)))
762 - ret = rrd2value(st, w->response.data, &n, dimensions, points, after, before, group, options, &latest_timestamp, &value_is_null);
763 -
764 - // if the value cannot be calculated, show empty badge
765 - if(ret != 200) {
766 - value_is_null = 1;
767 - n = 0;
768 - ret = 200;
769 - }
770 - else if(refresh > 0)
771 - buffer_sprintf(w->response.header, "Refresh: %d\r\n", refresh);
772 -
773 - // render the badge
774 - buffer_svg(w->response.data, label, n * multiply / divide, units, label_color, value_color, value_is_null, precision);
669 + }
670 + else if(!strcmp(name, "after")) after_str = value;
671 + else if(!strcmp(name, "before")) before_str = value;
672 + else if(!strcmp(name, "points")) points_str = value;
673 + else if(!strcmp(name, "group")) {
674 + group = web_client_api_request_v1_data_group(value, GROUP_AVERAGE);
675 + }
676 + else if(!strcmp(name, "options")) {
677 + options |= web_client_api_request_v1_data_options(value);
678 + }
679 + else if(!strcmp(name, "label")) label = value;
680 + else if(!strcmp(name, "units")) units = value;
681 + else if(!strcmp(name, "label_color")) label_color = value;
682 + else if(!strcmp(name, "value_color")) value_color = value;
683 + else if(!strcmp(name, "multiply")) multiply_str = value;
684 + else if(!strcmp(name, "divide")) divide_str = value;
685 + else if(!strcmp(name, "refresh")) refresh_str = value;
686 + else if(!strcmp(name, "precision")) precision_str = value;
687 + }
688 +
689 + if(!chart || !*chart) {
690 + buffer_sprintf(w->response.data, "No chart id is given at the request.");
691 + goto cleanup;
692 + }
693 +
694 + RRDSET *st = rrdset_find(chart);
695 + if(!st) st = rrdset_find_byname(chart);
696 + if(!st) {
697 + buffer_svg(w->response.data, "chart not found", 0, "", NULL, NULL, 1, -1);
698 + ret = 200;
699 + goto cleanup;
700 + }
701 +
702 + long long multiply = (multiply_str && *multiply_str )?atol(multiply_str):1;
703 + long long divide = (divide_str && *divide_str )?atol(divide_str):1;
704 + long long before = (before_str && *before_str )?atol(before_str):0;
705 + long long after = (after_str && *after_str )?atol(after_str):-st->update_every;
706 + int points = (points_str && *points_str )?atoi(points_str):1;
707 + int precision = (precision_str && *precision_str)?atoi(precision_str):-1;
708 +
709 + if(!multiply) multiply = 1;
710 + if(!divide) divide = 1;
711 +
712 + int refresh = 0;
713 + if(refresh_str && *refresh_str) {
714 + if(!strcmp(refresh_str, "auto")) {
715 + if(options & RRDR_OPTION_NOT_ALIGNED)
716 + refresh = st->update_every;
717 + else {
718 + refresh = (before - after);
719 + if(refresh < 0) refresh = -refresh;
720 + }
721 + }
722 + else {
723 + refresh = atoi(refresh_str);
724 + if(refresh < 0) refresh = -refresh;
725 + }
726 + }
727 +
728 + if(!label) {
729 + if(dimensions) {
730 + const char *dim = buffer_tostring(dimensions);
731 + if(*dim == '|') dim++;
732 + label = dim;
733 + }
734 + else
735 + label = st->name;
736 + }
737 + if(!units) {
738 + if(options & RRDR_OPTION_PERCENTAGE)
739 + units="%";
740 + else
741 + units = st->units;
742 + }
743 +
744 + debug(D_WEB_CLIENT, "%llu: API command 'badge.svg' for chart '%s', dimensions '%s', after '%lld', before '%lld', points '%d', group '%d', options '0x%08x'"
745 + , w->id
746 + , chart
747 + , (dimensions)?buffer_tostring(dimensions):""
748 + , after
749 + , before
750 + , points
751 + , group
752 + , options
753 + );
754 +
755 + time_t latest_timestamp = 0;
756 + int value_is_null = 1;
757 + calculated_number n = 0;
758 + ret = 500;
759 +
760 + // if the collected value is too old, don't calculate its value
761 + if(rrdset_last_entry_t(st) >= (time(NULL) - (st->update_every * st->gap_when_lost_iterations_above)))
762 + ret = rrd2value(st, w->response.data, &n, dimensions, points, after, before, group, options, &latest_timestamp, &value_is_null);
763 +
764 + // if the value cannot be calculated, show empty badge
765 + if(ret != 200) {
766 + value_is_null = 1;
767 + n = 0;
768 + ret = 200;
769 + }
770 + else if(refresh > 0)
771 + buffer_sprintf(w->response.header, "Refresh: %d\r\n", refresh);
772 +
773 + // render the badge
774 + buffer_svg(w->response.data, label, n * multiply / divide, units, label_color, value_color, value_is_null, precision);
775
776 cleanup:
777 - if(dimensions)
778 - buffer_free(dimensions);
779 - return ret;
777 + if(dimensions)
778 + buffer_free(dimensions);
779 + return ret;
780 }
781
782 // returns the HTTP code
783 int web_client_api_request_v1_data(struct web_client *w, char *url)
784 {
785 - debug(D_WEB_CLIENT, "%llu: API v1 data with URL '%s'", w->id, url);
785 + debug(D_WEB_CLIENT, "%llu: API v1 data with URL '%s'", w->id, url);
786
787 - int ret = 400;
788 - BUFFER *dimensions = NULL;
787 + int ret = 400;
788 + BUFFER *dimensions = NULL;
789
790 - buffer_flush(w->response.data);
790 + buffer_flush(w->response.data);
791
792 - char *google_version = "0.6",
793 - *google_reqId = "0",
794 - *google_sig = "0",
795 - *google_out = "json",
796 - *responseHandler = NULL,
797 - *outFileName = NULL;
792 + char *google_version = "0.6",
793 + *google_reqId = "0",
794 + *google_sig = "0",
795 + *google_out = "json",
796 + *responseHandler = NULL,
797 + *outFileName = NULL;
798
799 - time_t last_timestamp_in_data = 0, google_timestamp = 0;
799 + time_t last_timestamp_in_data = 0, google_timestamp = 0;
800
801 - char *chart = NULL
802 - , *before_str = NULL
803 - , *after_str = NULL
804 - , *points_str = NULL;
801 + char *chart = NULL
802 + , *before_str = NULL
803 + , *after_str = NULL
804 + , *points_str = NULL;
805
806 - int group = GROUP_AVERAGE;
807 - uint32_t format = DATASOURCE_JSON;
808 - uint32_t options = 0x00000000;
806 + int group = GROUP_AVERAGE;
807 + uint32_t format = DATASOURCE_JSON;
808 + uint32_t options = 0x00000000;
809
810 - while(url) {
811 - char *value = mystrsep(&url, "?&[]");
812 - if(!value || !*value) continue;
810 + while(url) {
811 + char *value = mystrsep(&url, "?&[]");
812 + if(!value || !*value) continue;
813
814 - char *name = mystrsep(&value, "=");
815 - if(!name || !*name) continue;
816 - if(!value || !*value) continue;
814 + char *name = mystrsep(&value, "=");
815 + if(!name || !*name) continue;
816 + if(!value || !*value) continue;
817
818 - debug(D_WEB_CLIENT, "%llu: API v1 data query param '%s' with value '%s'", w->id, name, value);
818 + debug(D_WEB_CLIENT, "%llu: API v1 data query param '%s' with value '%s'", w->id, name, value);
819
820 - // name and value are now the parameters
821 - // they are not null and not empty
820 + // name and value are now the parameters
821 + // they are not null and not empty
822
823 - if(!strcmp(name, "chart")) chart = value;
824 - else if(!strcmp(name, "dimension") || !strcmp(name, "dim") || !strcmp(name, "dimensions") || !strcmp(name, "dims")) {
825 - if(!dimensions) dimensions = buffer_create(100);
823 + if(!strcmp(name, "chart")) chart = value;
824 + else if(!strcmp(name, "dimension") || !strcmp(name, "dim") || !strcmp(name, "dimensions") || !strcmp(name, "dims")) {
825 + if(!dimensions) dimensions = buffer_create(100);
826 buffer_strcat(dimensions, "|");
827 buffer_strcat(dimensions, value);
828 - }
829 - else if(!strcmp(name, "after")) after_str = value;
830 - else if(!strcmp(name, "before")) before_str = value;
831 - else if(!strcmp(name, "points")) points_str = value;
832 - else if(!strcmp(name, "group")) {
833 - group = web_client_api_request_v1_data_group(value, GROUP_AVERAGE);
834 - }
835 - else if(!strcmp(name, "format")) {
836 - format = web_client_api_request_v1_data_format(value);
837 - }
838 - else if(!strcmp(name, "options")) {
839 - options |= web_client_api_request_v1_data_options(value);
840 - }
841 - else if(!strcmp(name, "callback")) {
842 - responseHandler = value;
843 - }
844 - else if(!strcmp(name, "filename")) {
845 - outFileName = value;
846 - }
847 - else if(!strcmp(name, "tqx")) {
848 - // parse Google Visualization API options
849 - // https://developers.google.com/chart/interactive/docs/dev/implementing_data_source
850 - char *tqx_name, *tqx_value;
851 -
852 - while(value) {
853 - tqx_value = mystrsep(&value, ";");
854 - if(!tqx_value || !*tqx_value) continue;
855 -
856 - tqx_name = mystrsep(&tqx_value, ":");
857 - if(!tqx_name || !*tqx_name) continue;
858 - if(!tqx_value || !*tqx_value) continue;
859 -
860 - if(!strcmp(tqx_name, "version"))
861 - google_version = tqx_value;
862 - else if(!strcmp(tqx_name, "reqId"))
863 - google_reqId = tqx_value;
864 - else if(!strcmp(tqx_name, "sig")) {
865 - google_sig = tqx_value;
866 - google_timestamp = strtoul(google_sig, NULL, 0);
867 - }
868 - else if(!strcmp(tqx_name, "out")) {
869 - google_out = tqx_value;
870 - format = web_client_api_request_v1_data_google_format(google_out);
871 - }
872 - else if(!strcmp(tqx_name, "responseHandler"))
873 - responseHandler = tqx_value;
874 - else if(!strcmp(tqx_name, "outFileName"))
875 - outFileName = tqx_value;
876 - }
877 - }
878 - }
879 -
880 - if(!chart || !*chart) {
881 - buffer_sprintf(w->response.data, "No chart id is given at the request.");
882 - goto cleanup;
883 - }
884 -
885 - RRDSET *st = rrdset_find(chart);
886 - if(!st) st = rrdset_find_byname(chart);
887 - if(!st) {
888 - buffer_sprintf(w->response.data, "Chart '%s' is not found.", chart);
889 - ret = 404;
890 - goto cleanup;
891 - }
892 -
893 - long long before = (before_str && *before_str)?atol(before_str):0;
894 - long long after = (after_str && *after_str) ?atol(after_str):0;
895 - int points = (points_str && *points_str)?atoi(points_str):0;
896 -
897 - debug(D_WEB_CLIENT, "%llu: API command 'data' for chart '%s', dimensions '%s', after '%lld', before '%lld', points '%d', group '%d', format '%u', options '0x%08x'"
898 - , w->id
899 - , chart
900 - , (dimensions)?buffer_tostring(dimensions):""
901 - , after
902 - , before
903 - , points
904 - , group
905 - , format
906 - , options
907 - );
908 -
909 - if(outFileName && *outFileName) {
910 - buffer_sprintf(w->response.header, "Content-Disposition: attachment; filename=\"%s\"\r\n", outFileName);
911 - debug(D_WEB_CLIENT, "%llu: generating outfilename header: '%s'", w->id, outFileName);
912 - }
913 -
914 - if(format == DATASOURCE_DATATABLE_JSONP) {
915 - if(responseHandler == NULL)
916 - responseHandler = "google.visualization.Query.setResponse";
917 -
918 - debug(D_WEB_CLIENT_ACCESS, "%llu: GOOGLE JSON/JSONP: version = '%s', reqId = '%s', sig = '%s', out = '%s', responseHandler = '%s', outFileName = '%s'",
919 - w->id, google_version, google_reqId, google_sig, google_out, responseHandler, outFileName
920 - );
921 -
922 - buffer_sprintf(w->response.data,
923 - "%s({version:'%s',reqId:'%s',status:'ok',sig:'%ld',table:",
924 - responseHandler, google_version, google_reqId, st->last_updated.tv_sec);
925 - }
926 - else if(format == DATASOURCE_JSONP) {
927 - if(responseHandler == NULL)
928 - responseHandler = "callback";
929 -
930 - buffer_strcat(w->response.data, responseHandler);
931 - buffer_strcat(w->response.data, "(");
932 - }
933 -
934 - ret = rrd2format(st, w->response.data, dimensions, format, points, after, before, group, options, &last_timestamp_in_data);
935 -
936 - if(format == DATASOURCE_DATATABLE_JSONP) {
937 - if(google_timestamp < last_timestamp_in_data)
938 - buffer_strcat(w->response.data, "});");
939 -
940 - else {
941 - // the client already has the latest data
942 - buffer_flush(w->response.data);
943 - buffer_sprintf(w->response.data,
944 - "%s({version:'%s',reqId:'%s',status:'error',errors:[{reason:'not_modified',message:'Data not modified'}]});",
945 - responseHandler, google_version, google_reqId);
946 - }
947 - }
948 - else if(format == DATASOURCE_JSONP)
949 - buffer_strcat(w->response.data, ");");
828 + }
829 + else if(!strcmp(name, "after")) after_str = value;
830 + else if(!strcmp(name, "before")) before_str = value;
831 + else if(!strcmp(name, "points")) points_str = value;
832 + else if(!strcmp(name, "group")) {
833 + group = web_client_api_request_v1_data_group(value, GROUP_AVERAGE);
834 + }
835 + else if(!strcmp(name, "format")) {
836 + format = web_client_api_request_v1_data_format(value);
837 + }
838 + else if(!strcmp(name, "options")) {
839 + options |= web_client_api_request_v1_data_options(value);
840 + }
841 + else if(!strcmp(name, "callback")) {
842 + responseHandler = value;
843 + }
844 + else if(!strcmp(name, "filename")) {
845 + outFileName = value;
846 + }
847 + else if(!strcmp(name, "tqx")) {
848 + // parse Google Visualization API options
849 + // https://developers.google.com/chart/interactive/docs/dev/implementing_data_source
850 + char *tqx_name, *tqx_value;
851 +
852 + while(value) {
853 + tqx_value = mystrsep(&value, ";");
854 + if(!tqx_value || !*tqx_value) continue;
855 +
856 + tqx_name = mystrsep(&tqx_value, ":");
857 + if(!tqx_name || !*tqx_name) continue;
858 + if(!tqx_value || !*tqx_value) continue;
859 +
860 + if(!strcmp(tqx_name, "version"))
861 + google_version = tqx_value;
862 + else if(!strcmp(tqx_name, "reqId"))
863 + google_reqId = tqx_value;
864 + else if(!strcmp(tqx_name, "sig")) {
865 + google_sig = tqx_value;
866 + google_timestamp = strtoul(google_sig, NULL, 0);
867 + }
868 + else if(!strcmp(tqx_name, "out")) {
869 + google_out = tqx_value;
870 + format = web_client_api_request_v1_data_google_format(google_out);
871 + }
872 + else if(!strcmp(tqx_name, "responseHandler"))
873 + responseHandler = tqx_value;
874 + else if(!strcmp(tqx_name, "outFileName"))
875 + outFileName = tqx_value;
876 + }
877 + }
878 + }
879 +
880 + if(!chart || !*chart) {
881 + buffer_sprintf(w->response.data, "No chart id is given at the request.");
882 + goto cleanup;
883 + }
884 +
885 + RRDSET *st = rrdset_find(chart);
886 + if(!st) st = rrdset_find_byname(chart);
887 + if(!st) {
888 + buffer_sprintf(w->response.data, "Chart '%s' is not found.", chart);
889 + ret = 404;
890 + goto cleanup;
891 + }
892 +
893 + long long before = (before_str && *before_str)?atol(before_str):0;
894 + long long after = (after_str && *after_str) ?atol(after_str):0;
895 + int points = (points_str && *points_str)?atoi(points_str):0;
896 +
897 + debug(D_WEB_CLIENT, "%llu: API command 'data' for chart '%s', dimensions '%s', after '%lld', before '%lld', points '%d', group '%d', format '%u', options '0x%08x'"
898 + , w->id
899 + , chart
900 + , (dimensions)?buffer_tostring(dimensions):""
901 + , after
902 + , before
903 + , points
904 + , group
905 + , format
906 + , options
907 + );
908 +
909 + if(outFileName && *outFileName) {
910 + buffer_sprintf(w->response.header, "Content-Disposition: attachment; filename=\"%s\"\r\n", outFileName);
911 + debug(D_WEB_CLIENT, "%llu: generating outfilename header: '%s'", w->id, outFileName);
912 + }
913 +
914 + if(format == DATASOURCE_DATATABLE_JSONP) {
915 + if(responseHandler == NULL)
916 + responseHandler = "google.visualization.Query.setResponse";
917 +
918 + debug(D_WEB_CLIENT_ACCESS, "%llu: GOOGLE JSON/JSONP: version = '%s', reqId = '%s', sig = '%s', out = '%s', responseHandler = '%s', outFileName = '%s'",
919 + w->id, google_version, google_reqId, google_sig, google_out, responseHandler, outFileName
920 + );
921 +
922 + buffer_sprintf(w->response.data,
923 + "%s({version:'%s',reqId:'%s',status:'ok',sig:'%ld',table:",
924 + responseHandler, google_version, google_reqId, st->last_updated.tv_sec);
925 + }
926 + else if(format == DATASOURCE_JSONP) {
927 + if(responseHandler == NULL)
928 + responseHandler = "callback";
929 +
930 + buffer_strcat(w->response.data, responseHandler);
931 + buffer_strcat(w->response.data, "(");
932 + }
933 +
934 + ret = rrd2format(st, w->response.data, dimensions, format, points, after, before, group, options, &last_timestamp_in_data);
935 +
936 + if(format == DATASOURCE_DATATABLE_JSONP) {
937 + if(google_timestamp < last_timestamp_in_data)
938 + buffer_strcat(w->response.data, "});");
939 +
940 + else {
941 + // the client already has the latest data
942 + buffer_flush(w->response.data);
943 + buffer_sprintf(w->response.data,
944 + "%s({version:'%s',reqId:'%s',status:'error',errors:[{reason:'not_modified',message:'Data not modified'}]});",
945 + responseHandler, google_version, google_reqId);
946 + }
947 + }
948 + else if(format == DATASOURCE_JSONP)
949 + buffer_strcat(w->response.data, ");");
950
951 cleanup:
952 - if(dimensions) buffer_free(dimensions);
953 - return ret;
952 + if(dimensions) buffer_free(dimensions);
953 + return ret;
954 }
955
956 int web_client_api_request_v1_registry(struct web_client *w, char *url)
957 {
958 - static uint32_t hash_action = 0, hash_access = 0, hash_hello = 0, hash_delete = 0, hash_search = 0,
959 - hash_switch = 0, hash_machine = 0, hash_url = 0, hash_name = 0, hash_delete_url = 0, hash_for = 0,
960 - hash_to = 0 /*, hash_redirects = 0 */;
961 -
962 - if(unlikely(!hash_action)) {
963 - hash_action = simple_hash("action");
964 - hash_access = simple_hash("access");
965 - hash_hello = simple_hash("hello");
966 - hash_delete = simple_hash("delete");
967 - hash_search = simple_hash("search");
968 - hash_switch = simple_hash("switch");
969 - hash_machine = simple_hash("machine");
970 - hash_url = simple_hash("url");
971 - hash_name = simple_hash("name");
972 - hash_delete_url = simple_hash("delete_url");
973 - hash_for = simple_hash("for");
974 - hash_to = simple_hash("to");
958 + static uint32_t hash_action = 0, hash_access = 0, hash_hello = 0, hash_delete = 0, hash_search = 0,
959 + hash_switch = 0, hash_machine = 0, hash_url = 0, hash_name = 0, hash_delete_url = 0, hash_for = 0,
960 + hash_to = 0 /*, hash_redirects = 0 */;
961 +
962 + if(unlikely(!hash_action)) {
963 + hash_action = simple_hash("action");
964 + hash_access = simple_hash("access");
965 + hash_hello = simple_hash("hello");
966 + hash_delete = simple_hash("delete");
967 + hash_search = simple_hash("search");
968 + hash_switch = simple_hash("switch");
969 + hash_machine = simple_hash("machine");
970 + hash_url = simple_hash("url");
971 + hash_name = simple_hash("name");
972 + hash_delete_url = simple_hash("delete_url");
973 + hash_for = simple_hash("for");
974 + hash_to = simple_hash("to");
975 /*
976 - hash_redirects = simple_hash("redirects");
976 + hash_redirects = simple_hash("redirects");
977 */
978 - }
979 -
980 - char person_guid[36 + 1] = "";
981 -
982 - debug(D_WEB_CLIENT, "%llu: API v1 registry with URL '%s'", w->id, url);
983 -
984 - // FIXME
985 - // The browser may send multiple cookies with our id
986 -
987 - char *cookie = strstr(w->response.data->buffer, NETDATA_REGISTRY_COOKIE_NAME "=");
988 - if(cookie)
989 - strncpyz(person_guid, &cookie[sizeof(NETDATA_REGISTRY_COOKIE_NAME)], 36);
990 -
991 - char action = '\0';
992 - char *machine_guid = NULL,
993 - *machine_url = NULL,
994 - *url_name = NULL,
995 - *search_machine_guid = NULL,
996 - *delete_url = NULL,
997 - *to_person_guid = NULL;
978 + }
979 +
980 + char person_guid[36 + 1] = "";
981 +
982 + debug(D_WEB_CLIENT, "%llu: API v1 registry with URL '%s'", w->id, url);
983 +
984 + // FIXME
985 + // The browser may send multiple cookies with our id
986 +
987 + char *cookie = strstr(w->response.data->buffer, NETDATA_REGISTRY_COOKIE_NAME "=");
988 + if(cookie)
989 + strncpyz(person_guid, &cookie[sizeof(NETDATA_REGISTRY_COOKIE_NAME)], 36);
990 +
991 + char action = '\0';
992 + char *machine_guid = NULL,
993 + *machine_url = NULL,
994 + *url_name = NULL,
995 + *search_machine_guid = NULL,
996 + *delete_url = NULL,
997 + *to_person_guid = NULL;
998 /*
999 - int redirects = 0;
999 + int redirects = 0;
1000 */
1001
1002 - while(url) {
1003 - char *value = mystrsep(&url, "?&[]");
1004 - if (!value || !*value) continue;
1002 + while(url) {
1003 + char *value = mystrsep(&url, "?&[]");
1004 + if (!value || !*value) continue;
1005
1006 - char *name = mystrsep(&value, "=");
1007 - if (!name || !*name) continue;
1008 - if (!value || !*value) continue;
1006 + char *name = mystrsep(&value, "=");
1007 + if (!name || !*name) continue;
1008 + if (!value || !*value) continue;
1009
1010 - debug(D_WEB_CLIENT, "%llu: API v1 registry query param '%s' with value '%s'", w->id, name, value);
1010 + debug(D_WEB_CLIENT, "%llu: API v1 registry query param '%s' with value '%s'", w->id, name, value);
1011
1012 - uint32_t hash = simple_hash(name);
1012 + uint32_t hash = simple_hash(name);
1013
1014 - if(hash == hash_action && !strcmp(name, "action")) {
1015 - uint32_t vhash = simple_hash(value);
1014 + if(hash == hash_action && !strcmp(name, "action")) {
1015 + uint32_t vhash = simple_hash(value);
1016
1017 - if(vhash == hash_access && !strcmp(value, "access")) action = 'A';
1018 - else if(vhash == hash_hello && !strcmp(value, "hello")) action = 'H';
1019 - else if(vhash == hash_delete && !strcmp(value, "delete")) action = 'D';
1020 - else if(vhash == hash_search && !strcmp(value, "search")) action = 'S';
1021 - else if(vhash == hash_switch && !strcmp(value, "switch")) action = 'W';
1017 + if(vhash == hash_access && !strcmp(value, "access")) action = 'A';
1018 + else if(vhash == hash_hello && !strcmp(value, "hello")) action = 'H';
1019 + else if(vhash == hash_delete && !strcmp(value, "delete")) action = 'D';
1020 + else if(vhash == hash_search && !strcmp(value, "search")) action = 'S';
1021 + else if(vhash == hash_switch && !strcmp(value, "switch")) action = 'W';
1022 #ifdef NETDATA_INTERNAL_CHECKS
1023 else error("unknown registry action '%s'", value);
1024 #endif /* NETDATA_INTERNAL_CHECKS */
1025 - }
1025 + }
1026 /*
1027 - else if(hash == hash_redirects && !strcmp(name, "redirects"))
1028 - redirects = atoi(value);
1027 + else if(hash == hash_redirects && !strcmp(name, "redirects"))
1028 + redirects = atoi(value);
1029 */
1030 - else if(hash == hash_machine && !strcmp(name, "machine"))
1031 - machine_guid = value;
1032 -
1033 - else if(hash == hash_url && !strcmp(name, "url"))
1034 - machine_url = value;
1035 -
1036 - else if(action == 'A') {
1037 - if(hash == hash_name && !strcmp(name, "name"))
1038 - url_name = value;
1039 - }
1040 - else if(action == 'D') {
1041 - if(hash == hash_delete_url && !strcmp(name, "delete_url"))
1042 - delete_url = value;
1043 - }
1044 - else if(action == 'S') {
1045 - if(hash == hash_for && !strcmp(name, "for"))
1046 - search_machine_guid = value;
1047 - }
1048 - else if(action == 'W') {
1049 - if(hash == hash_to && !strcmp(name, "to"))
1050 - to_person_guid = value;
1051 - }
1030 + else if(hash == hash_machine && !strcmp(name, "machine"))
1031 + machine_guid = value;
1032 +
1033 + else if(hash == hash_url && !strcmp(name, "url"))
1034 + machine_url = value;
1035 +
1036 + else if(action == 'A') {
1037 + if(hash == hash_name && !strcmp(name, "name"))
1038 + url_name = value;
1039 + }
1040 + else if(action == 'D') {
1041 + if(hash == hash_delete_url && !strcmp(name, "delete_url"))
1042 + delete_url = value;
1043 + }
1044 + else if(action == 'S') {
1045 + if(hash == hash_for && !strcmp(name, "for"))
1046 + search_machine_guid = value;
1047 + }
1048 + else if(action == 'W') {
1049 + if(hash == hash_to && !strcmp(name, "to"))
1050 + to_person_guid = value;
1051 + }
1052 #ifdef NETDATA_INTERNAL_CHECKS
1053 - else error("unused registry URL parameter '%s' with value '%s'", name, value);
1053 + else error("unused registry URL parameter '%s' with value '%s'", name, value);
1054 #endif /* NETDATA_INTERNAL_CHECKS */
1055 - }
1056 -
1057 - if(web_donotrack_comply && w->donottrack) {
1058 - buffer_flush(w->response.data);
1059 - buffer_sprintf(w->response.data, "Your web browser is sending 'DNT: 1' (Do Not Track). The registry requires persistent cookies on your browser to work.");
1060 - return 400;
1061 - }
1062 -
1063 - if(action == 'A' && (!machine_guid || !machine_url || !url_name)) {
1064 - buffer_flush(w->response.data);
1065 - buffer_sprintf(w->response.data, "Invalid registry request - access requires these parameters: machine ('%s'), url ('%s'), name ('%s')",
1066 - machine_guid?machine_guid:"UNSET", machine_url?machine_url:"UNSET", url_name?url_name:"UNSET");
1067 - return 400;
1068 - }
1069 - else if(action == 'D' && (!machine_guid || !machine_url || !delete_url)) {
1070 - buffer_flush(w->response.data);
1071 - buffer_sprintf(w->response.data, "Invalid registry request - delete requires these parameters: machine ('%s'), url ('%s'), delete_url ('%s')",
1072 - machine_guid?machine_guid:"UNSET", machine_url?machine_url:"UNSET", delete_url?delete_url:"UNSET");
1073 - return 400;
1074 - }
1075 - else if(action == 'S' && (!machine_guid || !machine_url || !search_machine_guid)) {
1076 - buffer_flush(w->response.data);
1077 - buffer_sprintf(w->response.data, "Invalid registry request - search requires these parameters: machine ('%s'), url ('%s'), for ('%s')",
1078 - machine_guid?machine_guid:"UNSET", machine_url?machine_url:"UNSET", search_machine_guid?search_machine_guid:"UNSET");
1079 - return 400;
1080 - }
1081 - else if(action == 'W' && (!machine_guid || !machine_url || !to_person_guid)) {
1082 - buffer_flush(w->response.data);
1083 - buffer_sprintf(w->response.data, "Invalid registry request - switching identity requires these parameters: machine ('%s'), url ('%s'), to ('%s')",
1084 - machine_guid?machine_guid:"UNSET", machine_url?machine_url:"UNSET", to_person_guid?to_person_guid:"UNSET");
1085 - return 400;
1086 - }
1087 -
1088 - switch(action) {
1089 - case 'A':
1090 - w->tracking_required = 1;
1091 - if(registry_verify_cookies_redirects() > 0 && (!cookie || !person_guid[0])) {
1092 - buffer_flush(w->response.data);
1093 -
1094 - registry_set_cookie(w, "give-me-back-this-cookie-please");
1095 - w->response.data->contenttype = CT_APPLICATION_JSON;
1096 - buffer_sprintf(w->response.data, "{ \"status\": \"redirect\", \"registry\": \"%s\" }", registry_to_announce());
1097 - return 200;
1055 + }
1056 +
1057 + if(web_donotrack_comply && w->donottrack) {
1058 + buffer_flush(w->response.data);
1059 + buffer_sprintf(w->response.data, "Your web browser is sending 'DNT: 1' (Do Not Track). The registry requires persistent cookies on your browser to work.");
1060 + return 400;
1061 + }
1062 +
1063 + if(action == 'A' && (!machine_guid || !machine_url || !url_name)) {
1064 + buffer_flush(w->response.data);
1065 + buffer_sprintf(w->response.data, "Invalid registry request - access requires these parameters: machine ('%s'), url ('%s'), name ('%s')",
1066 + machine_guid?machine_guid:"UNSET", machine_url?machine_url:"UNSET", url_name?url_name:"UNSET");
1067 + return 400;
1068 + }
1069 + else if(action == 'D' && (!machine_guid || !machine_url || !delete_url)) {
1070 + buffer_flush(w->response.data);
1071 + buffer_sprintf(w->response.data, "Invalid registry request - delete requires these parameters: machine ('%s'), url ('%s'), delete_url ('%s')",
1072 + machine_guid?machine_guid:"UNSET", machine_url?machine_url:"UNSET", delete_url?delete_url:"UNSET");
1073 + return 400;
1074 + }
1075 + else if(action == 'S' && (!machine_guid || !machine_url || !search_machine_guid)) {
1076 + buffer_flush(w->response.data);
1077 + buffer_sprintf(w->response.data, "Invalid registry request - search requires these parameters: machine ('%s'), url ('%s'), for ('%s')",
1078 + machine_guid?machine_guid:"UNSET", machine_url?machine_url:"UNSET", search_machine_guid?search_machine_guid:"UNSET");
1079 + return 400;
1080 + }
1081 + else if(action == 'W' && (!machine_guid || !machine_url || !to_person_guid)) {
1082 + buffer_flush(w->response.data);
1083 + buffer_sprintf(w->response.data, "Invalid registry request - switching identity requires these parameters: machine ('%s'), url ('%s'), to ('%s')",
1084 + machine_guid?machine_guid:"UNSET", machine_url?machine_url:"UNSET", to_person_guid?to_person_guid:"UNSET");
1085 + return 400;
1086 + }
1087 +
1088 + switch(action) {
1089 + case 'A':
1090 + w->tracking_required = 1;
1091 + if(registry_verify_cookies_redirects() > 0 && (!cookie || !person_guid[0])) {
1092 + buffer_flush(w->response.data);
1093 +
1094 + registry_set_cookie(w, "give-me-back-this-cookie-please");
1095 + w->response.data->contenttype = CT_APPLICATION_JSON;
1096 + buffer_sprintf(w->response.data, "{ \"status\": \"redirect\", \"registry\": \"%s\" }", registry_to_announce());
1097 + return 200;
1098
1099 /*
1100 * it seems that web browsers are ignoring 307 (Moved Temporarily)
1101 * under certain conditions, when using CORS
1102 * so this is commented and we use application level redirects instead
1103 *
1104 - redirects++;
1105 -
1106 - if(redirects > registry_verify_cookies_redirects()) {
1107 - buffer_flush(w->response.data);
1108 - buffer_sprintf(w->response.data, "Your browser does not support cookies");
1109 - return 400;
1110 - }
1111 -
1112 - char *encoded_url = url_encode(machine_url);
1113 - if(!encoded_url) {
1114 - error("%llu: Cannot URL encode string '%s'", w->id, machine_url);
1115 - return 500;
1116 - }
1117 -
1118 - char *encoded_name = url_encode(url_name);
1119 - if(!encoded_name) {
1120 - free(encoded_url);
1121 - error("%llu: Cannot URL encode string '%s'", w->id, url_name);
1122 - return 500;
1123 - }
1124 -
1125 - char *encoded_guid = url_encode(machine_guid);
1126 - if(!encoded_guid) {
1127 - free(encoded_url);
1128 - free(encoded_name);
1129 - error("%llu: Cannot URL encode string '%s'", w->id, machine_guid);
1130 - return 500;
1131 - }
1132 -
1133 - buffer_sprintf(w->response.header, "Location: %s/api/v1/registry?action=access&machine=%s&name=%s&url=%s&redirects=%d\r\n",
1134 - registry_to_announce(), encoded_guid, encoded_name, encoded_url, redirects);
1135 -
1136 - free(encoded_guid);
1137 - free(encoded_name);
1138 - free(encoded_url);
1139 - return 307
1104 + redirects++;
1105 +
1106 + if(redirects > registry_verify_cookies_redirects()) {
1107 + buffer_flush(w->response.data);
1108 + buffer_sprintf(w->response.data, "Your browser does not support cookies");
1109 + return 400;
1110 + }
1111 +
1112 + char *encoded_url = url_encode(machine_url);
1113 + if(!encoded_url) {
1114 + error("%llu: Cannot URL encode string '%s'", w->id, machine_url);
1115 + return 500;
1116 + }
1117 +
1118 + char *encoded_name = url_encode(url_name);
1119 + if(!encoded_name) {
1120 + free(encoded_url);
1121 + error("%llu: Cannot URL encode string '%s'", w->id, url_name);
1122 + return 500;
1123 + }
1124 +
1125 + char *encoded_guid = url_encode(machine_guid);
1126 + if(!encoded_guid) {
1127 + free(encoded_url);
1128 + free(encoded_name);
1129 + error("%llu: Cannot URL encode string '%s'", w->id, machine_guid);
1130 + return 500;
1131 + }
1132 +
1133 + buffer_sprintf(w->response.header, "Location: %s/api/v1/registry?action=access&machine=%s&name=%s&url=%s&redirects=%d\r\n",
1134 + registry_to_announce(), encoded_guid, encoded_name, encoded_url, redirects);
1135 +
1136 + free(encoded_guid);
1137 + free(encoded_name);
1138 + free(encoded_url);
1139 + return 307
1140 */
1141 - }
1142 - return registry_request_access_json(w, person_guid, machine_guid, machine_url, url_name, time(NULL));
1141 + }
1142 + return registry_request_access_json(w, person_guid, machine_guid, machine_url, url_name, time(NULL));
1143
1144 - case 'D':
1145 - w->tracking_required = 1;
1146 - return registry_request_delete_json(w, person_guid, machine_guid, machine_url, delete_url, time(NULL));
1144 + case 'D':
1145 + w->tracking_required = 1;
1146 + return registry_request_delete_json(w, person_guid, machine_guid, machine_url, delete_url, time(NULL));
1147
1148 - case 'S':
1149 - w->tracking_required = 1;
1150 - return registry_request_search_json(w, person_guid, machine_guid, machine_url, search_machine_guid, time(NULL));
1148 + case 'S':
1149 + w->tracking_required = 1;
1150 + return registry_request_search_json(w, person_guid, machine_guid, machine_url, search_machine_guid, time(NULL));
1151
1152 - case 'W':
1153 - w->tracking_required = 1;
1154 - return registry_request_switch_json(w, person_guid, machine_guid, machine_url, to_person_guid, time(NULL));
1152 + case 'W':
1153 + w->tracking_required = 1;
1154 + return registry_request_switch_json(w, person_guid, machine_guid, machine_url, to_person_guid, time(NULL));
1155
1156 - case 'H':
1157 - return registry_request_hello_json(w);
1156 + case 'H':
1157 + return registry_request_hello_json(w);
1158
1159 - default:
1160 - buffer_flush(w->response.data);
1161 - buffer_sprintf(w->response.data, "Invalid registry request - you need to set an action: hello, access, delete, search");
1162 - return 400;
1163 - }
1159 + default:
1160 + buffer_flush(w->response.data);
1161 + buffer_sprintf(w->response.data, "Invalid registry request - you need to set an action: hello, access, delete, search");
1162 + return 400;
1163 + }
1164
1165 - buffer_flush(w->response.data);
1166 - buffer_sprintf(w->response.data, "Invalid or no registry action.");
1167 - return 400;
1165 + buffer_flush(w->response.data);
1166 + buffer_sprintf(w->response.data, "Invalid or no registry action.");
1167 + return 400;
1168 }
1169
1170 int web_client_api_request_v1(struct web_client *w, char *url) {
1171 - static uint32_t hash_data = 0, hash_chart = 0, hash_charts = 0, hash_registry = 0, hash_badge = 0;
1172 -
1173 - if(unlikely(hash_data == 0)) {
1174 - hash_data = simple_hash("data");
1175 - hash_chart = simple_hash("chart");
1176 - hash_charts = simple_hash("charts");
1177 - hash_registry = simple_hash("registry");
1178 - hash_badge = simple_hash("badge.svg");
1179 - }
1180 -
1181 - // get the command
1182 - char *tok = mystrsep(&url, "/?&");
1183 - if(tok && *tok) {
1184 - debug(D_WEB_CLIENT, "%llu: Searching for API v1 command '%s'.", w->id, tok);
1185 - uint32_t hash = simple_hash(tok);
1186 -
1187 - if(hash == hash_data && !strcmp(tok, "data"))
1188 - return web_client_api_request_v1_data(w, url);
1189 -
1190 - else if(hash == hash_chart && !strcmp(tok, "chart"))
1191 - return web_client_api_request_v1_chart(w, url);
1192 -
1193 - else if(hash == hash_charts && !strcmp(tok, "charts"))
1194 - return web_client_api_request_v1_charts(w, url);
1195 -
1196 - else if(hash == hash_registry && !strcmp(tok, "registry"))
1197 - return web_client_api_request_v1_registry(w, url);
1198 -
1199 - else if(hash == hash_badge && !strcmp(tok, "badge.svg"))
1200 - return web_client_api_v1_badge(w, url);
1201 -
1202 - else {
1203 - buffer_flush(w->response.data);
1204 - buffer_sprintf(w->response.data, "Unsupported v1 API command: %s", tok);
1205 - return 404;
1206 - }
1207 - }
1208 - else {
1209 - buffer_flush(w->response.data);
1210 - buffer_sprintf(w->response.data, "API v1 command?");
1211 - return 400;
1212 - }
1171 + static uint32_t hash_data = 0, hash_chart = 0, hash_charts = 0, hash_registry = 0, hash_badge = 0;
1172 +
1173 + if(unlikely(hash_data == 0)) {
1174 + hash_data = simple_hash("data");
1175 + hash_chart = simple_hash("chart");
1176 + hash_charts = simple_hash("charts");
1177 + hash_registry = simple_hash("registry");
1178 + hash_badge = simple_hash("badge.svg");
1179 + }
1180 +
1181 + // get the command
1182 + char *tok = mystrsep(&url, "/?&");
1183 + if(tok && *tok) {
1184 + debug(D_WEB_CLIENT, "%llu: Searching for API v1 command '%s'.", w->id, tok);
1185 + uint32_t hash = simple_hash(tok);
1186 +
1187 + if(hash == hash_data && !strcmp(tok, "data"))
1188 + return web_client_api_request_v1_data(w, url);
1189 +
1190 + else if(hash == hash_chart && !strcmp(tok, "chart"))
1191 + return web_client_api_request_v1_chart(w, url);
1192 +
1193 + else if(hash == hash_charts && !strcmp(tok, "charts"))
1194 + return web_client_api_request_v1_charts(w, url);
1195 +
1196 + else if(hash == hash_registry && !strcmp(tok, "registry"))
1197 + return web_client_api_request_v1_registry(w, url);
1198 +
1199 + else if(hash == hash_badge && !strcmp(tok, "badge.svg"))
1200 + return web_client_api_v1_badge(w, url);
1201 +
1202 + else {
1203 + buffer_flush(w->response.data);
1204 + buffer_sprintf(w->response.data, "Unsupported v1 API command: %s", tok);
1205 + return 404;
1206 + }
1207 + }
1208 + else {
1209 + buffer_flush(w->response.data);
1210 + buffer_sprintf(w->response.data, "API v1 command?");
1211 + return 400;
1212 + }
1213 }
1214
1215 int web_client_api_request(struct web_client *w, char *url)
1216 {
1217 - // get the api version
1218 - char *tok = mystrsep(&url, "/?&");
1219 - if(tok && *tok) {
1220 - debug(D_WEB_CLIENT, "%llu: Searching for API version '%s'.", w->id, tok);
1221 - if(strcmp(tok, "v1") == 0)
1222 - return web_client_api_request_v1(w, url);
1223 - else {
1224 - buffer_flush(w->response.data);
1225 - buffer_sprintf(w->response.data, "Unsupported API version: %s", tok);
1226 - return 404;
1227 - }
1228 - }
1229 - else {
1230 - buffer_flush(w->response.data);
1231 - buffer_sprintf(w->response.data, "Which API version?");
1232 - return 400;
1233 - }
1217 + // get the api version
1218 + char *tok = mystrsep(&url, "/?&");
1219 + if(tok && *tok) {
1220 + debug(D_WEB_CLIENT, "%llu: Searching for API version '%s'.", w->id, tok);
1221 + if(strcmp(tok, "v1") == 0)
1222 + return web_client_api_request_v1(w, url);
1223 + else {
1224 + buffer_flush(w->response.data);
1225 + buffer_sprintf(w->response.data, "Unsupported API version: %s", tok);
1226 + return 404;
1227 + }
1228 + }
1229 + else {
1230 + buffer_flush(w->response.data);
1231 + buffer_sprintf(w->response.data, "Which API version?");
1232 + return 400;
1233 + }
1234 }
1235
1236 int web_client_api_old_data_request(struct web_client *w, char *url, int datasource_type)
1237 {
1238 - RRDSET *st = NULL;
1239 -
1240 - char *args = strchr(url, '?');
1241 - if(args) {
1242 - *args='\0';
1243 - args = &args[1];
1244 - }
1245 -
1246 - // get the name of the data to show
1247 - char *tok = mystrsep(&url, "/");
1248 - if(!tok) tok = "";
1249 -
1250 - // do we have such a data set?
1251 - if(*tok) {
1252 - debug(D_WEB_CLIENT, "%llu: Searching for RRD data with name '%s'.", w->id, tok);
1253 - st = rrdset_find_byname(tok);
1254 - if(!st) st = rrdset_find(tok);
1255 - }
1256 -
1257 - if(!st) {
1258 - // we don't have it
1259 - // try to send a file with that name
1260 - buffer_flush(w->response.data);
1261 - return(mysendfile(w, tok));
1262 - }
1263 -
1264 - // we have it
1265 - debug(D_WEB_CLIENT, "%llu: Found RRD data with name '%s'.", w->id, tok);
1266 -
1267 - // how many entries does the client want?
1268 - int lines = rrd_default_history_entries;
1269 - int group_count = 1;
1270 - time_t after = 0, before = 0;
1271 - int group_method = GROUP_AVERAGE;
1272 - int nonzero = 0;
1273 -
1274 - if(url) {
1275 - // parse the lines required
1276 - tok = mystrsep(&url, "/");
1277 - if(tok) lines = atoi(tok);
1278 - if(lines < 1) lines = 1;
1279 - }
1280 - if(url) {
1281 - // parse the group count required
1282 - tok = mystrsep(&url, "/");
1283 - if(tok && *tok) group_count = atoi(tok);
1284 - if(group_count < 1) group_count = 1;
1285 - //if(group_count > save_history / 20) group_count = save_history / 20;
1286 - }
1287 - if(url) {
1288 - // parse the grouping method required
1289 - tok = mystrsep(&url, "/");
1290 - if(tok && *tok) {
1291 - if(strcmp(tok, "max") == 0) group_method = GROUP_MAX;
1292 - else if(strcmp(tok, "average") == 0) group_method = GROUP_AVERAGE;
1293 - else if(strcmp(tok, "sum") == 0) group_method = GROUP_SUM;
1294 - else debug(D_WEB_CLIENT, "%llu: Unknown group method '%s'", w->id, tok);
1295 - }
1296 - }
1297 - if(url) {
1298 - // parse after time
1299 - tok = mystrsep(&url, "/");
1300 - if(tok && *tok) after = strtoul(tok, NULL, 10);
1301 - if(after < 0) after = 0;
1302 - }
1303 - if(url) {
1304 - // parse before time
1305 - tok = mystrsep(&url, "/");
1306 - if(tok && *tok) before = strtoul(tok, NULL, 10);
1307 - if(before < 0) before = 0;
1308 - }
1309 - if(url) {
1310 - // parse nonzero
1311 - tok = mystrsep(&url, "/");
1312 - if(tok && *tok && strcmp(tok, "nonzero") == 0) nonzero = 1;
1313 - }
1314 -
1315 - w->response.data->contenttype = CT_APPLICATION_JSON;
1316 - buffer_flush(w->response.data);
1317 -
1318 - char *google_version = "0.6";
1319 - char *google_reqId = "0";
1320 - char *google_sig = "0";
1321 - char *google_out = "json";
1322 - char *google_responseHandler = "google.visualization.Query.setResponse";
1323 - char *google_outFileName = NULL;
1324 - time_t last_timestamp_in_data = 0;
1325 - if(datasource_type == DATASOURCE_DATATABLE_JSON || datasource_type == DATASOURCE_DATATABLE_JSONP) {
1326 -
1327 - w->response.data->contenttype = CT_APPLICATION_X_JAVASCRIPT;
1328 -
1329 - while(args) {
1330 - tok = mystrsep(&args, "&");
1331 - if(tok && *tok) {
1332 - char *name = mystrsep(&tok, "=");
1333 - if(name && *name && strcmp(name, "tqx") == 0) {
1334 - char *key = mystrsep(&tok, ":");
1335 - char *value = mystrsep(&tok, ";");
1336 - if(key && value && *key && *value) {
1337 - if(strcmp(key, "version") == 0)
1338 - google_version = value;
1339 -
1340 - else if(strcmp(key, "reqId") == 0)
1341 - google_reqId = value;
1342 -
1343 - else if(strcmp(key, "sig") == 0)
1344 - google_sig = value;
1345 -
1346 - else if(strcmp(key, "out") == 0)
1347 - google_out = value;
1348 -
1349 - else if(strcmp(key, "responseHandler") == 0)
1350 - google_responseHandler = value;
1351 -
1352 - else if(strcmp(key, "outFileName") == 0)
1353 - google_outFileName = value;
1354 - }
1355 - }
1356 - }
1357 - }
1358 -
1359 - debug(D_WEB_CLIENT_ACCESS, "%llu: GOOGLE JSONP: version = '%s', reqId = '%s', sig = '%s', out = '%s', responseHandler = '%s', outFileName = '%s'",
1360 - w->id, google_version, google_reqId, google_sig, google_out, google_responseHandler, google_outFileName
1361 - );
1362 -
1363 - if(datasource_type == DATASOURCE_DATATABLE_JSONP) {
1364 - last_timestamp_in_data = strtoul(google_sig, NULL, 0);
1365 -
1366 - // check the client wants json
1367 - if(strcmp(google_out, "json") != 0) {
1368 - buffer_sprintf(w->response.data,
1369 - "%s({version:'%s',reqId:'%s',status:'error',errors:[{reason:'invalid_query',message:'output format is not supported',detailed_message:'the format %s requested is not supported by netdata.'}]});",
1370 - google_responseHandler, google_version, google_reqId, google_out);
1371 - return 200;
1372 - }
1373 - }
1374 - }
1375 -
1376 - if(datasource_type == DATASOURCE_DATATABLE_JSONP) {
1377 - buffer_sprintf(w->response.data,
1378 - "%s({version:'%s',reqId:'%s',status:'ok',sig:'%ld',table:",
1379 - google_responseHandler, google_version, google_reqId, st->last_updated.tv_sec);
1380 - }
1381 -
1382 - debug(D_WEB_CLIENT_ACCESS, "%llu: Sending RRD data '%s' (id %s, %d lines, %d group, %d group_method, %ld after, %ld before).",
1383 - w->id, st->name, st->id, lines, group_count, group_method, after, before);
1384 -
1385 - time_t timestamp_in_data = rrd_stats_json(datasource_type, st, w->response.data, lines, group_count, group_method, (unsigned long)after, (unsigned long)before, nonzero);
1386 -
1387 - if(datasource_type == DATASOURCE_DATATABLE_JSONP) {
1388 - if(timestamp_in_data > last_timestamp_in_data)
1389 - buffer_strcat(w->response.data, "});");
1390 -
1391 - else {
1392 - // the client already has the latest data
1393 - buffer_flush(w->response.data);
1394 - buffer_sprintf(w->response.data,
1395 - "%s({version:'%s',reqId:'%s',status:'error',errors:[{reason:'not_modified',message:'Data not modified'}]});",
1396 - google_responseHandler, google_version, google_reqId);
1397 - }
1398 - }
1399 -
1400 - return 200;
1238 + RRDSET *st = NULL;
1239 +
1240 + char *args = strchr(url, '?');
1241 + if(args) {
1242 + *args='\0';
1243 + args = &args[1];
1244 + }
1245 +
1246 + // get the name of the data to show
1247 + char *tok = mystrsep(&url, "/");
1248 + if(!tok) tok = "";
1249 +
1250 + // do we have such a data set?
1251 + if(*tok) {
1252 + debug(D_WEB_CLIENT, "%llu: Searching for RRD data with name '%s'.", w->id, tok);
1253 + st = rrdset_find_byname(tok);
1254 + if(!st) st = rrdset_find(tok);
1255 + }
1256 +
1257 + if(!st) {
1258 + // we don't have it
1259 + // try to send a file with that name
1260 + buffer_flush(w->response.data);
1261 + return(mysendfile(w, tok));
1262 + }
1263 +
1264 + // we have it
1265 + debug(D_WEB_CLIENT, "%llu: Found RRD data with name '%s'.", w->id, tok);
1266 +
1267 + // how many entries does the client want?
1268 + int lines = rrd_default_history_entries;
1269 + int group_count = 1;
1270 + time_t after = 0, before = 0;
1271 + int group_method = GROUP_AVERAGE;
1272 + int nonzero = 0;
1273 +
1274 + if(url) {
1275 + // parse the lines required
1276 + tok = mystrsep(&url, "/");
1277 + if(tok) lines = atoi(tok);
1278 + if(lines < 1) lines = 1;
1279 + }
1280 + if(url) {
1281 + // parse the group count required
1282 + tok = mystrsep(&url, "/");
1283 + if(tok && *tok) group_count = atoi(tok);
1284 + if(group_count < 1) group_count = 1;
1285 + //if(group_count > save_history / 20) group_count = save_history / 20;
1286 + }
1287 + if(url) {
1288 + // parse the grouping method required
1289 + tok = mystrsep(&url, "/");
1290 + if(tok && *tok) {
1291 + if(strcmp(tok, "max") == 0) group_method = GROUP_MAX;
1292 + else if(strcmp(tok, "average") == 0) group_method = GROUP_AVERAGE;
1293 + else if(strcmp(tok, "sum") == 0) group_method = GROUP_SUM;
1294 + else debug(D_WEB_CLIENT, "%llu: Unknown group method '%s'", w->id, tok);
1295 + }
1296 + }
1297 + if(url) {
1298 + // parse after time
1299 + tok = mystrsep(&url, "/");
1300 + if(tok && *tok) after = strtoul(tok, NULL, 10);
1301 + if(after < 0) after = 0;
1302 + }
1303 + if(url) {
1304 + // parse before time
1305 + tok = mystrsep(&url, "/");
1306 + if(tok && *tok) before = strtoul(tok, NULL, 10);
1307 + if(before < 0) before = 0;
1308 + }
1309 + if(url) {
1310 + // parse nonzero
1311 + tok = mystrsep(&url, "/");
1312 + if(tok && *tok && strcmp(tok, "nonzero") == 0) nonzero = 1;
1313 + }
1314 +
1315 + w->response.data->contenttype = CT_APPLICATION_JSON;
1316 + buffer_flush(w->response.data);
1317 +
1318 + char *google_version = "0.6";
1319 + char *google_reqId = "0";
1320 + char *google_sig = "0";
1321 + char *google_out = "json";
1322 + char *google_responseHandler = "google.visualization.Query.setResponse";
1323 + char *google_outFileName = NULL;
1324 + time_t last_timestamp_in_data = 0;
1325 + if(datasource_type == DATASOURCE_DATATABLE_JSON || datasource_type == DATASOURCE_DATATABLE_JSONP) {
1326 +
1327 + w->response.data->contenttype = CT_APPLICATION_X_JAVASCRIPT;
1328 +
1329 + while(args) {
1330 + tok = mystrsep(&args, "&");
1331 + if(tok && *tok) {
1332 + char *name = mystrsep(&tok, "=");
1333 + if(name && *name && strcmp(name, "tqx") == 0) {
1334 + char *key = mystrsep(&tok, ":");
1335 + char *value = mystrsep(&tok, ";");
1336 + if(key && value && *key && *value) {
1337 + if(strcmp(key, "version") == 0)
1338 + google_version = value;
1339 +
1340 + else if(strcmp(key, "reqId") == 0)
1341 + google_reqId = value;
1342 +
1343 + else if(strcmp(key, "sig") == 0)
1344 + google_sig = value;
1345 +
1346 + else if(strcmp(key, "out") == 0)
1347 + google_out = value;
1348 +
1349 + else if(strcmp(key, "responseHandler") == 0)
1350 + google_responseHandler = value;
1351 +
1352 + else if(strcmp(key, "outFileName") == 0)
1353 + google_outFileName = value;
1354 + }
1355 + }
1356 + }
1357 + }
1358 +
1359 + debug(D_WEB_CLIENT_ACCESS, "%llu: GOOGLE JSONP: version = '%s', reqId = '%s', sig = '%s', out = '%s', responseHandler = '%s', outFileName = '%s'",
1360 + w->id, google_version, google_reqId, google_sig, google_out, google_responseHandler, google_outFileName
1361 + );
1362 +
1363 + if(datasource_type == DATASOURCE_DATATABLE_JSONP) {
1364 + last_timestamp_in_data = strtoul(google_sig, NULL, 0);
1365 +
1366 + // check the client wants json
1367 + if(strcmp(google_out, "json") != 0) {
1368 + buffer_sprintf(w->response.data,
1369 + "%s({version:'%s',reqId:'%s',status:'error',errors:[{reason:'invalid_query',message:'output format is not supported',detailed_message:'the format %s requested is not supported by netdata.'}]});",
1370 + google_responseHandler, google_version, google_reqId, google_out);
1371 + return 200;
1372 + }
1373 + }
1374 + }
1375 +
1376 + if(datasource_type == DATASOURCE_DATATABLE_JSONP) {
1377 + buffer_sprintf(w->response.data,
1378 + "%s({version:'%s',reqId:'%s',status:'ok',sig:'%ld',table:",
1379 + google_responseHandler, google_version, google_reqId, st->last_updated.tv_sec);
1380 + }
1381 +
1382 + debug(D_WEB_CLIENT_ACCESS, "%llu: Sending RRD data '%s' (id %s, %d lines, %d group, %d group_method, %ld after, %ld before).",
1383 + w->id, st->name, st->id, lines, group_count, group_method, after, before);
1384 +
1385 + time_t timestamp_in_data = rrd_stats_json(datasource_type, st, w->response.data, lines, group_count, group_method, (unsigned long)after, (unsigned long)before, nonzero);
1386 +
1387 + if(datasource_type == DATASOURCE_DATATABLE_JSONP) {
1388 + if(timestamp_in_data > last_timestamp_in_data)
1389 + buffer_strcat(w->response.data, "});");
1390 +
1391 + else {
1392 + // the client already has the latest data
1393 + buffer_flush(w->response.data);
1394 + buffer_sprintf(w->response.data,
1395 + "%s({version:'%s',reqId:'%s',status:'error',errors:[{reason:'not_modified',message:'Data not modified'}]});",
1396 + google_responseHandler, google_version, google_reqId);
1397 + }
1398 + }
1399 +
1400 + return 200;
1401 }
1402
1403 const char *web_content_type_to_string(uint8_t contenttype) {
1404 - switch(contenttype) {
1405 - case CT_TEXT_HTML:
1406 - return "text/html; charset=utf-8";
1404 + switch(contenttype) {
1405 + case CT_TEXT_HTML:
1406 + return "text/html; charset=utf-8";
1407
1408 - case CT_APPLICATION_XML:
1409 - return "application/xml; charset=utf-8";
1408 + case CT_APPLICATION_XML:
1409 + return "application/xml; charset=utf-8";
1410
1411 - case CT_APPLICATION_JSON:
1412 - return "application/json; charset=utf-8";
1411 + case CT_APPLICATION_JSON:
1412 + return "application/json; charset=utf-8";
1413
1414 - case CT_APPLICATION_X_JAVASCRIPT:
1415 - return "application/x-javascript; charset=utf-8";
1414 + case CT_APPLICATION_X_JAVASCRIPT:
1415 + return "application/x-javascript; charset=utf-8";
1416
1417 - case CT_TEXT_CSS:
1418 - return "text/css; charset=utf-8";
1417 + case CT_TEXT_CSS:
1418 + return "text/css; charset=utf-8";
1419
1420 - case CT_TEXT_XML:
1421 - return "text/xml; charset=utf-8";
1420 + case CT_TEXT_XML:
1421 + return "text/xml; charset=utf-8";
1422
1423 - case CT_TEXT_XSL:
1424 - return "text/xsl; charset=utf-8";
1423 + case CT_TEXT_XSL:
1424 + return "text/xsl; charset=utf-8";
1425
1426 - case CT_APPLICATION_OCTET_STREAM:
1427 - return "application/octet-stream";
1426 + case CT_APPLICATION_OCTET_STREAM:
1427 + return "application/octet-stream";
1428
1429 - case CT_IMAGE_SVG_XML:
1430 - return "image/svg+xml";
1429 + case CT_IMAGE_SVG_XML:
1430 + return "image/svg+xml";
1431
1432 - case CT_APPLICATION_X_FONT_TRUETYPE:
1433 - return "application/x-font-truetype";
1432 + case CT_APPLICATION_X_FONT_TRUETYPE:
1433 + return "application/x-font-truetype";
1434
1435 - case CT_APPLICATION_X_FONT_OPENTYPE:
1436 - return "application/x-font-opentype";
1435 + case CT_APPLICATION_X_FONT_OPENTYPE:
1436 + return "application/x-font-opentype";
1437
1438 - case CT_APPLICATION_FONT_WOFF:
1439 - return "application/font-woff";
1438 + case CT_APPLICATION_FONT_WOFF:
1439 + return "application/font-woff";
1440
1441 - case CT_APPLICATION_FONT_WOFF2:
1442 - return "application/font-woff2";
1441 + case CT_APPLICATION_FONT_WOFF2:
1442 + return "application/font-woff2";
1443
1444 - case CT_APPLICATION_VND_MS_FONTOBJ:
1445 - return "application/vnd.ms-fontobject";
1444 + case CT_APPLICATION_VND_MS_FONTOBJ:
1445 + return "application/vnd.ms-fontobject";
1446
1447 - case CT_IMAGE_PNG:
1448 - return "image/png";
1447 + case CT_IMAGE_PNG:
1448 + return "image/png";
1449
1450 - case CT_IMAGE_JPG:
1451 - return "image/jpeg";
1450 + case CT_IMAGE_JPG:
1451 + return "image/jpeg";
1452
1453 - case CT_IMAGE_GIF:
1454 - return "image/gif";
1453 + case CT_IMAGE_GIF:
1454 + return "image/gif";
1455
1456 - case CT_IMAGE_XICON:
1457 - return "image/x-icon";
1456 + case CT_IMAGE_XICON:
1457 + return "image/x-icon";
1458
1459 - case CT_IMAGE_BMP:
1460 - return "image/bmp";
1459 + case CT_IMAGE_BMP:
1460 + return "image/bmp";
1461
1462 - case CT_IMAGE_ICNS:
1463 - return "image/icns";
1462 + case CT_IMAGE_ICNS:
1463 + return "image/icns";
1464
1465 - default:
1466 - case CT_TEXT_PLAIN:
1467 - return "text/plain; charset=utf-8";
1468 - }
1465 + default:
1466 + case CT_TEXT_PLAIN:
1467 + return "text/plain; charset=utf-8";
1468 + }
1469 }
1470
1471
1472 const char *web_response_code_to_string(int code) {
1473 - switch(code) {
1474 - case 200:
1475 - return "OK";
1473 + switch(code) {
1474 + case 200:
1475 + return "OK";
1476
1477 - case 307:
1478 - return "Temporary Redirect";
1477 + case 307:
1478 + return "Temporary Redirect";
1479
1480 - case 400:
1481 - return "Bad Request";
1480 + case 400:
1481 + return "Bad Request";
1482
1483 - case 403:
1484 - return "Forbidden";
1483 + case 403:
1484 + return "Forbidden";
1485
1486 - case 404:
1487 - return "Not Found";
1486 + case 404:
1487 + return "Not Found";
1488
1489 - case 412:
1490 - return "Preconditions Failed";
1489 + case 412:
1490 + return "Preconditions Failed";
1491
1492 - default:
1493 - if(code >= 100 && code < 200)
1494 - return "Informational";
1492 + default:
1493 + if(code >= 100 && code < 200)
1494 + return "Informational";
1495
1496 - if(code >= 200 && code < 300)
1497 - return "Successful";
1496 + if(code >= 200 && code < 300)
1497 + return "Successful";
1498
1499 - if(code >= 300 && code < 400)
1500 - return "Redirection";
1499 + if(code >= 300 && code < 400)
1500 + return "Redirection";
1501
1502 - if(code >= 400 && code < 500)
1503 - return "Bad Request";
1502 + if(code >= 400 && code < 500)
1503 + return "Bad Request";
1504
1505 - if(code >= 500 && code < 600)
1506 - return "Server Error";
1505 + if(code >= 500 && code < 600)
1506 + return "Server Error";
1507
1508 - return "Undefined Error";
1509 - }
1508 + return "Undefined Error";
1509 + }
1510 }
1511
1512 static inline char *http_header_parse(struct web_client *w, char *s) {
1513 - static uint32_t hash_origin = 0, hash_connection = 0, hash_accept_encoding = 0, hash_donottrack = 0;
1514 -
1515 - if(unlikely(!hash_origin)) {
1516 - hash_origin = simple_uhash("Origin");
1517 - hash_connection = simple_uhash("Connection");
1518 - hash_accept_encoding = simple_uhash("Accept-Encoding");
1519 - hash_donottrack = simple_uhash("DNT");
1520 - }
1521 -
1522 - char *e = s;
1523 -
1524 - // find the :
1525 - while(*e && *e != ':') e++;
1526 - if(!*e) return e;
1527 -
1528 - // get the name
1529 - *e = '\0';
1530 -
1531 - // find the value
1532 - char *v = e + 1, *ve;
1533 -
1534 - // skip leading spaces from value
1535 - while(*v == ' ') v++;
1536 - ve = v;
1537 -
1538 - // find the \r
1539 - while(*ve && *ve != '\r') ve++;
1540 - if(!*ve || ve[1] != '\n') {
1541 - *e = ':';
1542 - return ve;
1543 - }
1544 -
1545 - // terminate the value
1546 - *ve = '\0';
1547 -
1548 - // fprintf(stderr, "HEADER: '%s' = '%s'\n", s, v);
1549 - uint32_t hash = simple_uhash(s);
1550 -
1551 - if(hash == hash_origin && !strcasecmp(s, "Origin"))
1552 - strncpyz(w->origin, v, ORIGIN_MAX);
1553 -
1554 - else if(hash == hash_connection && !strcasecmp(s, "Connection")) {
1555 - if(strcasestr(v, "keep-alive"))
1556 - w->keepalive = 1;
1557 - }
1558 - else if(web_donotrack_comply && hash == hash_donottrack && !strcasecmp(s, "DNT")) {
1559 - if(*v == '0') w->donottrack = 0;
1560 - else if(*v == '1') w->donottrack = 1;
1561 - }
1513 + static uint32_t hash_origin = 0, hash_connection = 0, hash_accept_encoding = 0, hash_donottrack = 0;
1514 +
1515 + if(unlikely(!hash_origin)) {
1516 + hash_origin = simple_uhash("Origin");
1517 + hash_connection = simple_uhash("Connection");
1518 + hash_accept_encoding = simple_uhash("Accept-Encoding");
1519 + hash_donottrack = simple_uhash("DNT");
1520 + }
1521 +
1522 + char *e = s;
1523 +
1524 + // find the :
1525 + while(*e && *e != ':') e++;
1526 + if(!*e) return e;
1527 +
1528 + // get the name
1529 + *e = '\0';
1530 +
1531 + // find the value
1532 + char *v = e + 1, *ve;
1533 +
1534 + // skip leading spaces from value
1535 + while(*v == ' ') v++;
1536 + ve = v;
1537 +
1538 + // find the \r
1539 + while(*ve && *ve != '\r') ve++;
1540 + if(!*ve || ve[1] != '\n') {
1541 + *e = ':';
1542 + return ve;
1543 + }
1544 +
1545 + // terminate the value
1546 + *ve = '\0';
1547 +
1548 + // fprintf(stderr, "HEADER: '%s' = '%s'\n", s, v);
1549 + uint32_t hash = simple_uhash(s);
1550 +
1551 + if(hash == hash_origin && !strcasecmp(s, "Origin"))
1552 + strncpyz(w->origin, v, ORIGIN_MAX);
1553 +
1554 + else if(hash == hash_connection && !strcasecmp(s, "Connection")) {
1555 + if(strcasestr(v, "keep-alive"))
1556 + w->keepalive = 1;
1557 + }
1558 + else if(web_donotrack_comply && hash == hash_donottrack && !strcasecmp(s, "DNT")) {
1559 + if(*v == '0') w->donottrack = 0;
1560 + else if(*v == '1') w->donottrack = 1;
1561 + }
1562 #ifdef NETDATA_WITH_ZLIB
1563 - else if(hash == hash_accept_encoding && !strcasecmp(s, "Accept-Encoding")) {
1564 - if(web_enable_gzip) {
1565 - if(strcasestr(v, "gzip"))
1566 - web_client_enable_deflate(w, 1);
1567 - //
1568 - // does not seem to work
1569 - // else if(strcasestr(v, "deflate"))
1570 - // web_client_enable_deflate(w, 0);
1571 - }
1572 - }
1563 + else if(hash == hash_accept_encoding && !strcasecmp(s, "Accept-Encoding")) {
1564 + if(web_enable_gzip) {
1565 + if(strcasestr(v, "gzip"))
1566 + web_client_enable_deflate(w, 1);
1567 + //
1568 + // does not seem to work
1569 + // else if(strcasestr(v, "deflate"))
1570 + // web_client_enable_deflate(w, 0);
1571 + }
1572 + }
1573 #endif /* NETDATA_WITH_ZLIB */
1574
1575 - *e = ':';
1576 - *ve = '\r';
1577 - return ve;
1575 + *e = ':';
1576 + *ve = '\r';
1577 + return ve;
1578 }
1579
1580 // http_request_validate()
@@ -1584,760 +1584,760 @@ static inline char *http_header_parse(struct web_client *w, char *s) {
1584 // < 0 : request is incomplete - wait for more data
1585
1586 static inline int http_request_validate(struct web_client *w) {
1587 - char *s = w->response.data->buffer, *encoded_url = NULL;
1588 -
1589 - // is is a valid request?
1590 - if(!strncmp(s, "GET ", 4)) {
1591 - encoded_url = s = &s[4];
1592 - w->mode = WEB_CLIENT_MODE_NORMAL;
1593 - }
1594 - else if(!strncmp(s, "OPTIONS ", 8)) {
1595 - encoded_url = s = &s[8];
1596 - w->mode = WEB_CLIENT_MODE_OPTIONS;
1597 - }
1598 - else {
1599 - w->wait_receive = 0;
1600 - return 1;
1601 - }
1602 -
1603 - // find the SPACE + "HTTP/"
1604 - while(*s) {
1605 - // find the next space
1606 - while (*s && *s != ' ') s++;
1607 -
1608 - // is it SPACE + "HTTP/" ?
1609 - if(*s && !strncmp(s, " HTTP/", 6)) break;
1610 - else s++;
1611 - }
1612 -
1613 - // incomplete requests
1614 - if(unlikely(!*s)) {
1615 - w->wait_receive = 1;
1616 - return -2;
1617 - }
1618 -
1619 - // we have the end of encoded_url - remember it
1620 - char *ue = s;
1621 -
1622 - // make sure we have complete request
1623 - // complete requests contain: \r\n\r\n
1624 - while(*s) {
1625 - // find a line feed
1626 - while(*s && *s++ != '\r');
1627 -
1628 - // did we reach the end?
1629 - if(unlikely(!*s)) break;
1630 -
1631 - // is it \r\n ?
1632 - if(likely(*s++ == '\n')) {
1633 -
1634 - // is it again \r\n ? (header end)
1635 - if(unlikely(*s == '\r' && s[1] == '\n')) {
1636 - // a valid complete HTTP request found
1637 -
1638 - *ue = '\0';
1639 - url_decode_r(w->decoded_url, encoded_url, URL_MAX + 1);
1640 - *ue = ' ';
1641 -
1642 - // copy the URL - we are going to overwrite parts of it
1643 - // FIXME -- we should avoid it
1644 - strncpyz(w->last_url, w->decoded_url, URL_MAX);
1645 -
1646 - w->wait_receive = 0;
1647 - return 0;
1648 - }
1649 -
1650 - // another header line
1651 - s = http_header_parse(w, s);
1652 - }
1653 - }
1654 -
1655 - // incomplete request
1656 - w->wait_receive = 1;
1657 - return -3;
1587 + char *s = w->response.data->buffer, *encoded_url = NULL;
1588 +
1589 + // is is a valid request?
1590 + if(!strncmp(s, "GET ", 4)) {
1591 + encoded_url = s = &s[4];
1592 + w->mode = WEB_CLIENT_MODE_NORMAL;
1593 + }
1594 + else if(!strncmp(s, "OPTIONS ", 8)) {
1595 + encoded_url = s = &s[8];
1596 + w->mode = WEB_CLIENT_MODE_OPTIONS;
1597 + }
1598 + else {
1599 + w->wait_receive = 0;
1600 + return 1;
1601 + }
1602 +
1603 + // find the SPACE + "HTTP/"
1604 + while(*s) {
1605 + // find the next space
1606 + while (*s && *s != ' ') s++;
1607 +
1608 + // is it SPACE + "HTTP/" ?
1609 + if(*s && !strncmp(s, " HTTP/", 6)) break;
1610 + else s++;
1611 + }
1612 +
1613 + // incomplete requests
1614 + if(unlikely(!*s)) {
1615 + w->wait_receive = 1;
1616 + return -2;
1617 + }
1618 +
1619 + // we have the end of encoded_url - remember it
1620 + char *ue = s;
1621 +
1622 + // make sure we have complete request
1623 + // complete requests contain: \r\n\r\n
1624 + while(*s) {
1625 + // find a line feed
1626 + while(*s && *s++ != '\r');
1627 +
1628 + // did we reach the end?
1629 + if(unlikely(!*s)) break;
1630 +
1631 + // is it \r\n ?
1632 + if(likely(*s++ == '\n')) {
1633 +
1634 + // is it again \r\n ? (header end)
1635 + if(unlikely(*s == '\r' && s[1] == '\n')) {
1636 + // a valid complete HTTP request found
1637 +
1638 + *ue = '\0';
1639 + url_decode_r(w->decoded_url, encoded_url, URL_MAX + 1);
1640 + *ue = ' ';
1641 +
1642 + // copy the URL - we are going to overwrite parts of it
1643 + // FIXME -- we should avoid it
1644 + strncpyz(w->last_url, w->decoded_url, URL_MAX);
1645 +
1646 + w->wait_receive = 0;
1647 + return 0;
1648 + }
1649 +
1650 + // another header line
1651 + s = http_header_parse(w, s);
1652 + }
1653 + }
1654 +
1655 + // incomplete request
1656 + w->wait_receive = 1;
1657 + return -3;
1658 }
1659
1660 void web_client_process(struct web_client *w) {
1661 - static uint32_t hash_api = 0, hash_netdata_conf = 0, hash_data = 0, hash_datasource = 0, hash_graph = 0,
1662 - hash_list = 0, hash_all_json = 0, hash_exit = 0, hash_debug = 0, hash_mirror = 0;
1661 + static uint32_t hash_api = 0, hash_netdata_conf = 0, hash_data = 0, hash_datasource = 0, hash_graph = 0,
1662 + hash_list = 0, hash_all_json = 0, hash_exit = 0, hash_debug = 0, hash_mirror = 0;
1663
1664 // start timing us
1665 gettimeofday(&w->tv_in, NULL);
1666
1667 if(unlikely(!hash_api)) {
1668 - hash_api = simple_hash("api");
1669 - hash_netdata_conf = simple_hash("netdata.conf");
1670 - hash_data = simple_hash(WEB_PATH_DATA);
1671 - hash_datasource = simple_hash(WEB_PATH_DATASOURCE);
1672 - hash_graph = simple_hash(WEB_PATH_GRAPH);
1673 - hash_list = simple_hash("list");
1674 - hash_all_json = simple_hash("all.json");
1675 - hash_exit = simple_hash("exit");
1676 - hash_debug = simple_hash("debug");
1677 - hash_mirror = simple_hash("mirror");
1678 - }
1679 -
1680 - int code = 500;
1681 - ssize_t bytes;
1682 -
1683 - int what_to_do = http_request_validate(w);
1684 -
1685 - // wait for more data
1686 - if(what_to_do < 0) {
1687 - if(w->response.data->len > TOO_BIG_REQUEST) {
1688 - strcpy(w->last_url, "too big request");
1689 -
1690 - debug(D_WEB_CLIENT_ACCESS, "%llu: Received request is too big (%zu bytes).", w->id, w->response.data->len);
1691 -
1692 - code = 400;
1693 - buffer_flush(w->response.data);
1694 - buffer_sprintf(w->response.data, "Received request is too big (%zu bytes).\r\n", w->response.data->len);
1695 - }
1696 - else {
1697 - // wait for more data
1698 - return;
1699 - }
1700 - }
1701 - else if(what_to_do > 0) {
1702 - // strcpy(w->last_url, "not a valid request");
1703 -
1704 - debug(D_WEB_CLIENT_ACCESS, "%llu: Cannot understand '%s'.", w->id, w->response.data->buffer);
1705 -
1706 - code = 500;
1707 - buffer_flush(w->response.data);
1708 - buffer_strcat(w->response.data, "I don't understand you...\r\n");
1709 - }
1710 - else { // what_to_do == 0
1711 - if(w->mode == WEB_CLIENT_MODE_OPTIONS) {
1712 - code = 200;
1713 - w->response.data->contenttype = CT_TEXT_PLAIN;
1714 - buffer_flush(w->response.data);
1715 - buffer_strcat(w->response.data, "OK");
1716 - }
1717 - else {
1718 - char *url = w->decoded_url;
1719 - char *tok = mystrsep(&url, "/?");
1720 - if(tok && *tok) {
1721 - uint32_t hash = simple_hash(tok);
1722 - debug(D_WEB_CLIENT, "%llu: Processing command '%s'.", w->id, tok);
1723 -
1724 - if(hash == hash_api && strcmp(tok, "api") == 0) {
1725 - // the client is requesting api access
1726 - code = web_client_api_request(w, url);
1727 - }
1728 - else if(hash == hash_netdata_conf && strcmp(tok, "netdata.conf") == 0) {
1729 - code = 200;
1730 - debug(D_WEB_CLIENT_ACCESS, "%llu: Sending netdata.conf ...", w->id);
1731 -
1732 - w->response.data->contenttype = CT_TEXT_PLAIN;
1733 - buffer_flush(w->response.data);
1734 - generate_config(w->response.data, 0);
1735 - }
1736 - else if(hash == hash_data && strcmp(tok, WEB_PATH_DATA) == 0) { // "data"
1737 - // the client is requesting rrd data -- OLD API
1738 - code = web_client_api_old_data_request(w, url, DATASOURCE_JSON);
1739 - }
1740 - else if(hash == hash_datasource && strcmp(tok, WEB_PATH_DATASOURCE) == 0) { // "datasource"
1741 - // the client is requesting google datasource -- OLD API
1742 - code = web_client_api_old_data_request(w, url, DATASOURCE_DATATABLE_JSONP);
1743 - }
1744 - else if(hash == hash_graph && strcmp(tok, WEB_PATH_GRAPH) == 0) { // "graph"
1745 - // the client is requesting an rrd graph -- OLD API
1746 -
1747 - // get the name of the data to show
1748 - tok = mystrsep(&url, "/?&");
1749 - if(tok && *tok) {
1750 - debug(D_WEB_CLIENT, "%llu: Searching for RRD data with name '%s'.", w->id, tok);
1751 -
1752 - // do we have such a data set?
1753 - RRDSET *st = rrdset_find_byname(tok);
1754 - if(!st) st = rrdset_find(tok);
1755 - if(!st) {
1756 - // we don't have it
1757 - // try to send a file with that name
1758 - buffer_flush(w->response.data);
1759 - code = mysendfile(w, tok);
1760 - }
1761 - else {
1762 - code = 200;
1763 - debug(D_WEB_CLIENT_ACCESS, "%llu: Sending %s.json of RRD_STATS...", w->id, st->name);
1764 - w->response.data->contenttype = CT_APPLICATION_JSON;
1765 - buffer_flush(w->response.data);
1766 - rrd_stats_graph_json(st, url, w->response.data);
1767 - }
1768 - }
1769 - else {
1770 - code = 400;
1771 - buffer_flush(w->response.data);
1772 - buffer_strcat(w->response.data, "Graph name?\r\n");
1773 - }
1774 - }
1775 - else if(hash == hash_list && strcmp(tok, "list") == 0) {
1776 - // OLD API
1777 - code = 200;
1778 -
1779 - debug(D_WEB_CLIENT_ACCESS, "%llu: Sending list of RRD_STATS...", w->id);
1780 -
1781 - buffer_flush(w->response.data);
1782 - RRDSET *st = localhost.rrdset_root;
1783 -
1784 - for ( ; st ; st = st->next )
1785 - buffer_sprintf(w->response.data, "%s\n", st->name);
1786 - }
1787 - else if(hash == hash_all_json && strcmp(tok, "all.json") == 0) {
1788 - // OLD API
1789 - code = 200;
1790 - debug(D_WEB_CLIENT_ACCESS, "%llu: Sending JSON list of all monitors of RRD_STATS...", w->id);
1791 -
1792 - w->response.data->contenttype = CT_APPLICATION_JSON;
1793 - buffer_flush(w->response.data);
1794 - rrd_stats_all_json(w->response.data);
1795 - }
1668 + hash_api = simple_hash("api");
1669 + hash_netdata_conf = simple_hash("netdata.conf");
1670 + hash_data = simple_hash(WEB_PATH_DATA);
1671 + hash_datasource = simple_hash(WEB_PATH_DATASOURCE);
1672 + hash_graph = simple_hash(WEB_PATH_GRAPH);
1673 + hash_list = simple_hash("list");
1674 + hash_all_json = simple_hash("all.json");
1675 + hash_exit = simple_hash("exit");
1676 + hash_debug = simple_hash("debug");
1677 + hash_mirror = simple_hash("mirror");
1678 + }
1679 +
1680 + int code = 500;
1681 + ssize_t bytes;
1682 +
1683 + int what_to_do = http_request_validate(w);
1684 +
1685 + // wait for more data
1686 + if(what_to_do < 0) {
1687 + if(w->response.data->len > TOO_BIG_REQUEST) {
1688 + strcpy(w->last_url, "too big request");
1689 +
1690 + debug(D_WEB_CLIENT_ACCESS, "%llu: Received request is too big (%zu bytes).", w->id, w->response.data->len);
1691 +
1692 + code = 400;
1693 + buffer_flush(w->response.data);
1694 + buffer_sprintf(w->response.data, "Received request is too big (%zu bytes).\r\n", w->response.data->len);
1695 + }
1696 + else {
1697 + // wait for more data
1698 + return;
1699 + }
1700 + }
1701 + else if(what_to_do > 0) {
1702 + // strcpy(w->last_url, "not a valid request");
1703 +
1704 + debug(D_WEB_CLIENT_ACCESS, "%llu: Cannot understand '%s'.", w->id, w->response.data->buffer);
1705 +
1706 + code = 500;
1707 + buffer_flush(w->response.data);
1708 + buffer_strcat(w->response.data, "I don't understand you...\r\n");
1709 + }
1710 + else { // what_to_do == 0
1711 + if(w->mode == WEB_CLIENT_MODE_OPTIONS) {
1712 + code = 200;
1713 + w->response.data->contenttype = CT_TEXT_PLAIN;
1714 + buffer_flush(w->response.data);
1715 + buffer_strcat(w->response.data, "OK");
1716 + }
1717 + else {
1718 + char *url = w->decoded_url;
1719 + char *tok = mystrsep(&url, "/?");
1720 + if(tok && *tok) {
1721 + uint32_t hash = simple_hash(tok);
1722 + debug(D_WEB_CLIENT, "%llu: Processing command '%s'.", w->id, tok);
1723 +
1724 + if(hash == hash_api && strcmp(tok, "api") == 0) {
1725 + // the client is requesting api access
1726 + code = web_client_api_request(w, url);
1727 + }
1728 + else if(hash == hash_netdata_conf && strcmp(tok, "netdata.conf") == 0) {
1729 + code = 200;
1730 + debug(D_WEB_CLIENT_ACCESS, "%llu: Sending netdata.conf ...", w->id);
1731 +
1732 + w->response.data->contenttype = CT_TEXT_PLAIN;
1733 + buffer_flush(w->response.data);
1734 + generate_config(w->response.data, 0);
1735 + }
1736 + else if(hash == hash_data && strcmp(tok, WEB_PATH_DATA) == 0) { // "data"
1737 + // the client is requesting rrd data -- OLD API
1738 + code = web_client_api_old_data_request(w, url, DATASOURCE_JSON);
1739 + }
1740 + else if(hash == hash_datasource && strcmp(tok, WEB_PATH_DATASOURCE) == 0) { // "datasource"
1741 + // the client is requesting google datasource -- OLD API
1742 + code = web_client_api_old_data_request(w, url, DATASOURCE_DATATABLE_JSONP);
1743 + }
1744 + else if(hash == hash_graph && strcmp(tok, WEB_PATH_GRAPH) == 0) { // "graph"
1745 + // the client is requesting an rrd graph -- OLD API
1746 +
1747 + // get the name of the data to show
1748 + tok = mystrsep(&url, "/?&");
1749 + if(tok && *tok) {
1750 + debug(D_WEB_CLIENT, "%llu: Searching for RRD data with name '%s'.", w->id, tok);
1751 +
1752 + // do we have such a data set?
1753 + RRDSET *st = rrdset_find_byname(tok);
1754 + if(!st) st = rrdset_find(tok);
1755 + if(!st) {
1756 + // we don't have it
1757 + // try to send a file with that name
1758 + buffer_flush(w->response.data);
1759 + code = mysendfile(w, tok);
1760 + }
1761 + else {
1762 + code = 200;
1763 + debug(D_WEB_CLIENT_ACCESS, "%llu: Sending %s.json of RRD_STATS...", w->id, st->name);
1764 + w->response.data->contenttype = CT_APPLICATION_JSON;
1765 + buffer_flush(w->response.data);
1766 + rrd_stats_graph_json(st, url, w->response.data);
1767 + }
1768 + }
1769 + else {
1770 + code = 400;
1771 + buffer_flush(w->response.data);
1772 + buffer_strcat(w->response.data, "Graph name?\r\n");
1773 + }
1774 + }
1775 + else if(hash == hash_list && strcmp(tok, "list") == 0) {
1776 + // OLD API
1777 + code = 200;
1778 +
1779 + debug(D_WEB_CLIENT_ACCESS, "%llu: Sending list of RRD_STATS...", w->id);
1780 +
1781 + buffer_flush(w->response.data);
1782 + RRDSET *st = localhost.rrdset_root;
1783 +
1784 + for ( ; st ; st = st->next )
1785 + buffer_sprintf(w->response.data, "%s\n", st->name);
1786 + }
1787 + else if(hash == hash_all_json && strcmp(tok, "all.json") == 0) {
1788 + // OLD API
1789 + code = 200;
1790 + debug(D_WEB_CLIENT_ACCESS, "%llu: Sending JSON list of all monitors of RRD_STATS...", w->id);
1791 +
1792 + w->response.data->contenttype = CT_APPLICATION_JSON;
1793 + buffer_flush(w->response.data);
1794 + rrd_stats_all_json(w->response.data);
1795 + }
1796 #ifdef NETDATA_INTERNAL_CHECKS
1797 - else if(hash == hash_exit && strcmp(tok, "exit") == 0) {
1798 - code = 200;
1799 - w->response.data->contenttype = CT_TEXT_PLAIN;
1800 - buffer_flush(w->response.data);
1801 -
1802 - if(!netdata_exit)
1803 - buffer_strcat(w->response.data, "ok, will do...");
1804 - else
1805 - buffer_strcat(w->response.data, "I am doing it already");
1806 -
1807 - error("web request to exit received.");
1808 - netdata_cleanup_and_exit(0);
1809 - netdata_exit = 1;
1810 - }
1811 - else if(hash == hash_debug && strcmp(tok, "debug") == 0) {
1812 - buffer_flush(w->response.data);
1813 -
1814 - // get the name of the data to show
1815 - tok = mystrsep(&url, "/?&");
1816 - if(tok && *tok) {
1817 - debug(D_WEB_CLIENT, "%llu: Searching for RRD data with name '%s'.", w->id, tok);
1818 -
1819 - // do we have such a data set?
1820 - RRDSET *st = rrdset_find_byname(tok);
1821 - if(!st) st = rrdset_find(tok);
1822 - if(!st) {
1823 - code = 404;
1824 - buffer_sprintf(w->response.data, "Chart %s is not found.\r\n", tok);
1825 - debug(D_WEB_CLIENT_ACCESS, "%llu: %s is not found.", w->id, tok);
1826 - }
1827 - else {
1828 - code = 200;
1829 - debug_flags |= D_RRD_STATS;
1830 - st->debug = !st->debug;
1831 - buffer_sprintf(w->response.data, "Chart %s has now debug %s.\r\n", tok, st->debug?"enabled":"disabled");
1832 - debug(D_WEB_CLIENT_ACCESS, "%llu: debug for %s is %s.", w->id, tok, st->debug?"enabled":"disabled");
1833 - }
1834 - }
1835 - else {
1836 - code = 500;
1837 - buffer_flush(w->response.data);
1838 - buffer_strcat(w->response.data, "debug which chart?\r\n");
1839 - }
1840 - }
1841 - else if(hash == hash_mirror && strcmp(tok, "mirror") == 0) {
1842 - code = 200;
1843 -
1844 - debug(D_WEB_CLIENT_ACCESS, "%llu: Mirroring...", w->id);
1845 -
1846 - // replace the zero bytes with spaces
1847 - buffer_char_replace(w->response.data, '\0', ' ');
1848 -
1849 - // just leave the buffer as is
1850 - // it will be copied back to the client
1851 - }
1852 -#endif /* NETDATA_INTERNAL_CHECKS */
1853 - else {
1854 - char filename[FILENAME_MAX+1];
1855 - url = filename;
1856 - strncpyz(filename, w->last_url, FILENAME_MAX);
1857 - tok = mystrsep(&url, "?");
1858 - buffer_flush(w->response.data);
1859 - code = mysendfile(w, (tok && *tok)?tok:"/");
1860 - }
1861 - }
1862 - else {
1863 - char filename[FILENAME_MAX+1];
1864 - url = filename;
1865 - strncpyz(filename, w->last_url, FILENAME_MAX);
1866 - tok = mystrsep(&url, "?");
1867 - buffer_flush(w->response.data);
1868 - code = mysendfile(w, (tok && *tok)?tok:"/");
1869 - }
1870 - }
1871 - }
1872 -
1873 - gettimeofday(&w->tv_ready, NULL);
1874 - w->response.data->date = time(NULL);
1875 - w->response.sent = 0;
1876 - w->response.code = code;
1877 -
1878 - // prepare the HTTP response header
1879 - debug(D_WEB_CLIENT, "%llu: Generating HTTP header with response %d.", w->id, code);
1880 -
1881 - const char *content_type_string = web_content_type_to_string(w->response.data->contenttype);
1882 - const char *code_msg = web_response_code_to_string(code);
1883 -
1884 - char date[32];
1885 - struct tm tmbuf, *tm = gmtime_r(&w->response.data->date, &tmbuf);
1886 - strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %Z", tm);
1887 -
1888 - buffer_sprintf(w->response.header_output,
1889 - "HTTP/1.1 %d %s\r\n"
1890 - "Connection: %s\r\n"
1891 - "Server: NetData Embedded HTTP Server\r\n"
1892 - "Access-Control-Allow-Origin: %s\r\n"
1893 - "Access-Control-Allow-Credentials: true\r\n"
1894 - "Content-Type: %s\r\n"
1895 - "Date: %s\r\n"
1896 - , code, code_msg
1897 - , w->keepalive?"keep-alive":"close"
1898 - , w->origin
1899 - , content_type_string
1900 - , date
1901 - );
1902 -
1903 - if(w->cookie1[0] || w->cookie2[0]) {
1904 - if(w->cookie1[0]) {
1905 - buffer_sprintf(w->response.header_output,
1906 - "Set-Cookie: %s\r\n",
1907 - w->cookie1);
1908 - }
1909 -
1910 - if(w->cookie2[0]) {
1911 - buffer_sprintf(w->response.header_output,
1912 - "Set-Cookie: %s\r\n",
1913 - w->cookie2);
1914 - }
1915 -
1916 - if(web_donotrack_comply)
1917 - buffer_sprintf(w->response.header_output,
1918 - "Tk: T;cookies\r\n");
1919 - }
1920 - else {
1921 - if(web_donotrack_comply) {
1922 - if(w->tracking_required)
1923 - buffer_sprintf(w->response.header_output,
1924 - "Tk: T;cookies\r\n");
1925 - else
1926 - buffer_sprintf(w->response.header_output,
1927 - "Tk: N\r\n");
1928 - }
1929 - }
1930 -
1931 - if(w->mode == WEB_CLIENT_MODE_OPTIONS) {
1932 - buffer_strcat(w->response.header_output,
1933 - "Access-Control-Allow-Methods: GET, OPTIONS\r\n"
1934 - "Access-Control-Allow-Headers: accept, x-requested-with, origin, content-type, cookie\r\n"
1935 - "Access-Control-Max-Age: 1209600\r\n" // 86400 * 14
1936 - );
1937 - }
1938 -
1939 - if(buffer_strlen(w->response.header))
1940 - buffer_strcat(w->response.header_output, buffer_tostring(w->response.header));
1941 -
1942 - if(w->mode == WEB_CLIENT_MODE_NORMAL && (w->response.data->options & WB_CONTENT_NO_CACHEABLE)) {
1943 - buffer_sprintf(w->response.header_output,
1944 - "Expires: %s\r\n"
1945 - "Cache-Control: no-cache\r\n"
1946 - , date);
1947 - }
1948 - else if(w->mode != WEB_CLIENT_MODE_OPTIONS) {
1949 - char edate[32];
1950 - time_t et = w->response.data->date + (86400 * 14);
1951 - struct tm etmbuf, *etm = gmtime_r(&et, &etmbuf);
1952 - strftime(edate, sizeof(edate), "%a, %d %b %Y %H:%M:%S %Z", etm);
1953 -
1954 - buffer_sprintf(w->response.header_output,
1955 - "Expires: %s\r\n"
1956 - "Cache-Control: public\r\n"
1957 - , edate);
1958 - }
1959 -
1960 - // if we know the content length, put it
1961 - if(!w->response.zoutput && (w->response.data->len || w->response.rlen))
1962 - buffer_sprintf(w->response.header_output,
1963 - "Content-Length: %zu\r\n"
1964 - , w->response.data->len? w->response.data->len: w->response.rlen
1965 - );
1966 - else if(!w->response.zoutput)
1967 - w->keepalive = 0; // content-length is required for keep-alive
1968 -
1969 - if(w->response.zoutput) {
1970 - buffer_strcat(w->response.header_output,
1971 - "Content-Encoding: gzip\r\n"
1972 - "Transfer-Encoding: chunked\r\n"
1973 - );
1974 - }
1975 -
1976 - buffer_strcat(w->response.header_output, "\r\n");
1977 -
1978 - // sent the HTTP header
1979 - debug(D_WEB_DATA, "%llu: Sending response HTTP header of size %zu: '%s'"
1980 - , w->id
1981 - , buffer_strlen(w->response.header_output)
1982 - , buffer_tostring(w->response.header_output)
1983 - );
1984 -
1985 - web_client_crock_socket(w);
1986 -
1987 - bytes = send(w->ofd, buffer_tostring(w->response.header_output), buffer_strlen(w->response.header_output), 0);
1988 - if(bytes != (ssize_t) buffer_strlen(w->response.header_output)) {
1989 - if(bytes > 0)
1990 - w->stats_sent_bytes += bytes;
1991 -
1992 - debug(D_WEB_CLIENT, "%llu: HTTP Header failed to be sent (I sent %zu bytes but the system sent %zd bytes). Closing web client."
1993 - , w->id
1994 - , buffer_strlen(w->response.header_output)
1995 - , bytes);
1996 -
1997 - WEB_CLIENT_IS_DEAD(w);
1998 - return;
1999 - }
2000 - else
2001 - w->stats_sent_bytes += bytes;
2002 -
2003 - // enable sending immediately if we have data
2004 - if(w->response.data->len) w->wait_send = 1;
2005 - else w->wait_send = 0;
2006 -
2007 - // pretty logging
2008 - switch(w->mode) {
2009 - case WEB_CLIENT_MODE_OPTIONS:
2010 - debug(D_WEB_CLIENT, "%llu: Done preparing the OPTIONS response. Sending data (%zu bytes) to client.", w->id, w->response.data->len);
2011 - break;
2012 -
2013 - case WEB_CLIENT_MODE_NORMAL:
2014 - debug(D_WEB_CLIENT, "%llu: Done preparing the response. Sending data (%zu bytes) to client.", w->id, w->response.data->len);
2015 - break;
2016 -
2017 - case WEB_CLIENT_MODE_FILECOPY:
2018 - if(w->response.rlen) {
2019 - debug(D_WEB_CLIENT, "%llu: Done preparing the response. Will be sending data file of %zu bytes to client.", w->id, w->response.rlen);
2020 - w->wait_receive = 1;
2021 -
2022 - /*
2023 - // utilize the kernel sendfile() for copying the file to the socket.
2024 - // this block of code can be commented, without anything missing.
2025 - // when it is commented, the program will copy the data using async I/O.
2026 - {
2027 - long len = sendfile(w->ofd, w->ifd, NULL, w->response.data->rbytes);
2028 - if(len != w->response.data->rbytes)
2029 - error("%llu: sendfile() should copy %ld bytes, but copied %ld. Falling back to manual copy.", w->id, w->response.data->rbytes, len);
2030 - else
2031 - web_client_reset(w);
2032 - }
2033 - */
2034 - }
2035 - else
2036 - debug(D_WEB_CLIENT, "%llu: Done preparing the response. Will be sending an unknown amount of bytes to client.", w->id);
2037 - break;
2038 -
2039 - default:
2040 - fatal("%llu: Unknown client mode %d.", w->id, w->mode);
2041 - break;
2042 - }
1797 + else if(hash == hash_exit && strcmp(tok, "exit") == 0) {
1798 + code = 200;
1799 + w->response.data->contenttype = CT_TEXT_PLAIN;
1800 + buffer_flush(w->response.data);
1801 +
1802 + if(!netdata_exit)
1803 + buffer_strcat(w->response.data, "ok, will do...");
1804 + else
1805 + buffer_strcat(w->response.data, "I am doing it already");
1806 +
1807 + error("web request to exit received.");
1808 + netdata_cleanup_and_exit(0);
1809 + netdata_exit = 1;
1810 + }
1811 + else if(hash == hash_debug && strcmp(tok, "debug") == 0) {
1812 + buffer_flush(w->response.data);
1813 +
1814 + // get the name of the data to show
1815 + tok = mystrsep(&url, "/?&");
1816 + if(tok && *tok) {
1817 + debug(D_WEB_CLIENT, "%llu: Searching for RRD data with name '%s'.", w->id, tok);
1818 +
1819 + // do we have such a data set?
1820 + RRDSET *st = rrdset_find_byname(tok);
1821 + if(!st) st = rrdset_find(tok);
1822 + if(!st) {
1823 + code = 404;
1824 + buffer_sprintf(w->response.data, "Chart %s is not found.\r\n", tok);
1825 + debug(D_WEB_CLIENT_ACCESS, "%llu: %s is not found.", w->id, tok);
1826 + }
1827 + else {
1828 + code = 200;
1829 + debug_flags |= D_RRD_STATS;
1830 + st->debug = !st->debug;
1831 + buffer_sprintf(w->response.data, "Chart %s has now debug %s.\r\n", tok, st->debug?"enabled":"disabled");
1832 + debug(D_WEB_CLIENT_ACCESS, "%llu: debug for %s is %s.", w->id, tok, st->debug?"enabled":"disabled");
1833 + }
1834 + }
1835 + else {
1836 + code = 500;
1837 + buffer_flush(w->response.data);
1838 + buffer_strcat(w->response.data, "debug which chart?\r\n");
1839 + }
1840 + }
1841 + else if(hash == hash_mirror && strcmp(tok, "mirror") == 0) {
1842 + code = 200;
1843 +
1844 + debug(D_WEB_CLIENT_ACCESS, "%llu: Mirroring...", w->id);
1845 +
1846 + // replace the zero bytes with spaces
1847 + buffer_char_replace(w->response.data, '\0', ' ');
1848 +
1849 + // just leave the buffer as is
1850 + // it will be copied back to the client
1851 + }
1852 +#endif /* NETDATA_INTERNAL_CHECKS */
1853 + else {
1854 + char filename[FILENAME_MAX+1];
1855 + url = filename;
1856 + strncpyz(filename, w->last_url, FILENAME_MAX);
1857 + tok = mystrsep(&url, "?");
1858 + buffer_flush(w->response.data);
1859 + code = mysendfile(w, (tok && *tok)?tok:"/");
1860 + }
1861 + }
1862 + else {
1863 + char filename[FILENAME_MAX+1];
1864 + url = filename;
1865 + strncpyz(filename, w->last_url, FILENAME_MAX);
1866 + tok = mystrsep(&url, "?");
1867 + buffer_flush(w->response.data);
1868 + code = mysendfile(w, (tok && *tok)?tok:"/");
1869 + }
1870 + }
1871 + }
1872 +
1873 + gettimeofday(&w->tv_ready, NULL);
1874 + w->response.data->date = time(NULL);
1875 + w->response.sent = 0;
1876 + w->response.code = code;
1877 +
1878 + // prepare the HTTP response header
1879 + debug(D_WEB_CLIENT, "%llu: Generating HTTP header with response %d.", w->id, code);
1880 +
1881 + const char *content_type_string = web_content_type_to_string(w->response.data->contenttype);
1882 + const char *code_msg = web_response_code_to_string(code);
1883 +
1884 + char date[32];
1885 + struct tm tmbuf, *tm = gmtime_r(&w->response.data->date, &tmbuf);
1886 + strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %Z", tm);
1887 +
1888 + buffer_sprintf(w->response.header_output,
1889 + "HTTP/1.1 %d %s\r\n"
1890 + "Connection: %s\r\n"
1891 + "Server: NetData Embedded HTTP Server\r\n"
1892 + "Access-Control-Allow-Origin: %s\r\n"
1893 + "Access-Control-Allow-Credentials: true\r\n"
1894 + "Content-Type: %s\r\n"
1895 + "Date: %s\r\n"
1896 + , code, code_msg
1897 + , w->keepalive?"keep-alive":"close"
1898 + , w->origin
1899 + , content_type_string
1900 + , date
1901 + );
1902 +
1903 + if(w->cookie1[0] || w->cookie2[0]) {
1904 + if(w->cookie1[0]) {
1905 + buffer_sprintf(w->response.header_output,
1906 + "Set-Cookie: %s\r\n",
1907 + w->cookie1);
1908 + }
1909 +
1910 + if(w->cookie2[0]) {
1911 + buffer_sprintf(w->response.header_output,
1912 + "Set-Cookie: %s\r\n",
1913 + w->cookie2);
1914 + }
1915 +
1916 + if(web_donotrack_comply)
1917 + buffer_sprintf(w->response.header_output,
1918 + "Tk: T;cookies\r\n");
1919 + }
1920 + else {
1921 + if(web_donotrack_comply) {
1922 + if(w->tracking_required)
1923 + buffer_sprintf(w->response.header_output,
1924 + "Tk: T;cookies\r\n");
1925 + else
1926 + buffer_sprintf(w->response.header_output,
1927 + "Tk: N\r\n");
1928 + }
1929 + }
1930 +
1931 + if(w->mode == WEB_CLIENT_MODE_OPTIONS) {
1932 + buffer_strcat(w->response.header_output,
1933 + "Access-Control-Allow-Methods: GET, OPTIONS\r\n"
1934 + "Access-Control-Allow-Headers: accept, x-requested-with, origin, content-type, cookie\r\n"
1935 + "Access-Control-Max-Age: 1209600\r\n" // 86400 * 14
1936 + );
1937 + }
1938 +
1939 + if(buffer_strlen(w->response.header))
1940 + buffer_strcat(w->response.header_output, buffer_tostring(w->response.header));
1941 +
1942 + if(w->mode == WEB_CLIENT_MODE_NORMAL && (w->response.data->options & WB_CONTENT_NO_CACHEABLE)) {
1943 + buffer_sprintf(w->response.header_output,
1944 + "Expires: %s\r\n"
1945 + "Cache-Control: no-cache\r\n"
1946 + , date);
1947 + }
1948 + else if(w->mode != WEB_CLIENT_MODE_OPTIONS) {
1949 + char edate[32];
1950 + time_t et = w->response.data->date + (86400 * 14);
1951 + struct tm etmbuf, *etm = gmtime_r(&et, &etmbuf);
1952 + strftime(edate, sizeof(edate), "%a, %d %b %Y %H:%M:%S %Z", etm);
1953 +
1954 + buffer_sprintf(w->response.header_output,
1955 + "Expires: %s\r\n"
1956 + "Cache-Control: public\r\n"
1957 + , edate);
1958 + }
1959 +
1960 + // if we know the content length, put it
1961 + if(!w->response.zoutput && (w->response.data->len || w->response.rlen))
1962 + buffer_sprintf(w->response.header_output,
1963 + "Content-Length: %zu\r\n"
1964 + , w->response.data->len? w->response.data->len: w->response.rlen
1965 + );
1966 + else if(!w->response.zoutput)
1967 + w->keepalive = 0; // content-length is required for keep-alive
1968 +
1969 + if(w->response.zoutput) {
1970 + buffer_strcat(w->response.header_output,
1971 + "Content-Encoding: gzip\r\n"
1972 + "Transfer-Encoding: chunked\r\n"
1973 + );
1974 + }
1975 +
1976 + buffer_strcat(w->response.header_output, "\r\n");
1977 +
1978 + // sent the HTTP header
1979 + debug(D_WEB_DATA, "%llu: Sending response HTTP header of size %zu: '%s'"
1980 + , w->id
1981 + , buffer_strlen(w->response.header_output)
1982 + , buffer_tostring(w->response.header_output)
1983 + );
1984 +
1985 + web_client_crock_socket(w);
1986 +
1987 + bytes = send(w->ofd, buffer_tostring(w->response.header_output), buffer_strlen(w->response.header_output), 0);
1988 + if(bytes != (ssize_t) buffer_strlen(w->response.header_output)) {
1989 + if(bytes > 0)
1990 + w->stats_sent_bytes += bytes;
1991 +
1992 + debug(D_WEB_CLIENT, "%llu: HTTP Header failed to be sent (I sent %zu bytes but the system sent %zd bytes). Closing web client."
1993 + , w->id
1994 + , buffer_strlen(w->response.header_output)
1995 + , bytes);
1996 +
1997 + WEB_CLIENT_IS_DEAD(w);
1998 + return;
1999 + }
2000 + else
2001 + w->stats_sent_bytes += bytes;
2002 +
2003 + // enable sending immediately if we have data
2004 + if(w->response.data->len) w->wait_send = 1;
2005 + else w->wait_send = 0;
2006 +
2007 + // pretty logging
2008 + switch(w->mode) {
2009 + case WEB_CLIENT_MODE_OPTIONS:
2010 + debug(D_WEB_CLIENT, "%llu: Done preparing the OPTIONS response. Sending data (%zu bytes) to client.", w->id, w->response.data->len);
2011 + break;
2012 +
2013 + case WEB_CLIENT_MODE_NORMAL:
2014 + debug(D_WEB_CLIENT, "%llu: Done preparing the response. Sending data (%zu bytes) to client.", w->id, w->response.data->len);
2015 + break;
2016 +
2017 + case WEB_CLIENT_MODE_FILECOPY:
2018 + if(w->response.rlen) {
2019 + debug(D_WEB_CLIENT, "%llu: Done preparing the response. Will be sending data file of %zu bytes to client.", w->id, w->response.rlen);
2020 + w->wait_receive = 1;
2021 +
2022 + /*
2023 + // utilize the kernel sendfile() for copying the file to the socket.
2024 + // this block of code can be commented, without anything missing.
2025 + // when it is commented, the program will copy the data using async I/O.
2026 + {
2027 + long len = sendfile(w->ofd, w->ifd, NULL, w->response.data->rbytes);
2028 + if(len != w->response.data->rbytes)
2029 + error("%llu: sendfile() should copy %ld bytes, but copied %ld. Falling back to manual copy.", w->id, w->response.data->rbytes, len);
2030 + else
2031 + web_client_reset(w);
2032 + }
2033 + */
2034 + }
2035 + else
2036 + debug(D_WEB_CLIENT, "%llu: Done preparing the response. Will be sending an unknown amount of bytes to client.", w->id);
2037 + break;
2038 +
2039 + default:
2040 + fatal("%llu: Unknown client mode %d.", w->id, w->mode);
2041 + break;
2042 + }
2043 }
2044
2045 ssize_t web_client_send_chunk_header(struct web_client *w, size_t len)
2046 {
2047 - debug(D_DEFLATE, "%llu: OPEN CHUNK of %zu bytes (hex: %zx).", w->id, len, len);
2048 - char buf[24];
2049 - sprintf(buf, "%zX\r\n", len);
2050 -
2051 - ssize_t bytes = send(w->ofd, buf, strlen(buf), 0);
2052 - if(bytes > 0) {
2053 - debug(D_DEFLATE, "%llu: Sent chunk header %zd bytes.", w->id, bytes);
2054 - w->stats_sent_bytes += bytes;
2055 - }
2056 -
2057 - else if(bytes == 0) {
2058 - debug(D_WEB_CLIENT, "%llu: Did not send chunk header to the client.", w->id);
2059 - WEB_CLIENT_IS_DEAD(w);
2060 - }
2061 - else {
2062 - debug(D_WEB_CLIENT, "%llu: Failed to send chunk header to client.", w->id);
2063 - WEB_CLIENT_IS_DEAD(w);
2064 - }
2065 -
2066 - return bytes;
2047 + debug(D_DEFLATE, "%llu: OPEN CHUNK of %zu bytes (hex: %zx).", w->id, len, len);
2048 + char buf[24];
2049 + sprintf(buf, "%zX\r\n", len);
2050 +
2051 + ssize_t bytes = send(w->ofd, buf, strlen(buf), 0);
2052 + if(bytes > 0) {
2053 + debug(D_DEFLATE, "%llu: Sent chunk header %zd bytes.", w->id, bytes);
2054 + w->stats_sent_bytes += bytes;
2055 + }
2056 +
2057 + else if(bytes == 0) {
2058 + debug(D_WEB_CLIENT, "%llu: Did not send chunk header to the client.", w->id);
2059 + WEB_CLIENT_IS_DEAD(w);
2060 + }
2061 + else {
2062 + debug(D_WEB_CLIENT, "%llu: Failed to send chunk header to client.", w->id);
2063 + WEB_CLIENT_IS_DEAD(w);
2064 + }
2065 +
2066 + return bytes;
2067 }
2068
2069 ssize_t web_client_send_chunk_close(struct web_client *w)
2070 {
2071 - //debug(D_DEFLATE, "%llu: CLOSE CHUNK.", w->id);
2072 -
2073 - ssize_t bytes = send(w->ofd, "\r\n", 2, 0);
2074 - if(bytes > 0) {
2075 - debug(D_DEFLATE, "%llu: Sent chunk suffix %zd bytes.", w->id, bytes);
2076 - w->stats_sent_bytes += bytes;
2077 - }
2078 -
2079 - else if(bytes == 0) {
2080 - debug(D_WEB_CLIENT, "%llu: Did not send chunk suffix to the client.", w->id);
2081 - WEB_CLIENT_IS_DEAD(w);
2082 - }
2083 - else {
2084 - debug(D_WEB_CLIENT, "%llu: Failed to send chunk suffix to client.", w->id);
2085 - WEB_CLIENT_IS_DEAD(w);
2086 - }
2087 -
2088 - return bytes;
2071 + //debug(D_DEFLATE, "%llu: CLOSE CHUNK.", w->id);
2072 +
2073 + ssize_t bytes = send(w->ofd, "\r\n", 2, 0);
2074 + if(bytes > 0) {
2075 + debug(D_DEFLATE, "%llu: Sent chunk suffix %zd bytes.", w->id, bytes);
2076 + w->stats_sent_bytes += bytes;
2077 + }
2078 +
2079 + else if(bytes == 0) {
2080 + debug(D_WEB_CLIENT, "%llu: Did not send chunk suffix to the client.", w->id);
2081 + WEB_CLIENT_IS_DEAD(w);
2082 + }
2083 + else {
2084 + debug(D_WEB_CLIENT, "%llu: Failed to send chunk suffix to client.", w->id);
2085 + WEB_CLIENT_IS_DEAD(w);
2086 + }
2087 +
2088 + return bytes;
2089 }
2090
2091 ssize_t web_client_send_chunk_finalize(struct web_client *w)
2092 {
2093 - //debug(D_DEFLATE, "%llu: FINALIZE CHUNK.", w->id);
2094 -
2095 - ssize_t bytes = send(w->ofd, "\r\n0\r\n\r\n", 7, 0);
2096 - if(bytes > 0) {
2097 - debug(D_DEFLATE, "%llu: Sent chunk suffix %zd bytes.", w->id, bytes);
2098 - w->stats_sent_bytes += bytes;
2099 - }
2100 -
2101 - else if(bytes == 0) {
2102 - debug(D_WEB_CLIENT, "%llu: Did not send chunk finalize suffix to the client.", w->id);
2103 - WEB_CLIENT_IS_DEAD(w);
2104 - }
2105 - else {
2106 - debug(D_WEB_CLIENT, "%llu: Failed to send chunk finalize suffix to client.", w->id);
2107 - WEB_CLIENT_IS_DEAD(w);
2108 - }
2109 -
2110 - return bytes;
2093 + //debug(D_DEFLATE, "%llu: FINALIZE CHUNK.", w->id);
2094 +
2095 + ssize_t bytes = send(w->ofd, "\r\n0\r\n\r\n", 7, 0);
2096 + if(bytes > 0) {
2097 + debug(D_DEFLATE, "%llu: Sent chunk suffix %zd bytes.", w->id, bytes);
2098 + w->stats_sent_bytes += bytes;
2099 + }
2100 +
2101 + else if(bytes == 0) {
2102 + debug(D_WEB_CLIENT, "%llu: Did not send chunk finalize suffix to the client.", w->id);
2103 + WEB_CLIENT_IS_DEAD(w);
2104 + }
2105 + else {
2106 + debug(D_WEB_CLIENT, "%llu: Failed to send chunk finalize suffix to client.", w->id);
2107 + WEB_CLIENT_IS_DEAD(w);
2108 + }
2109 +
2110 + return bytes;
2111 }
2112
2113 #ifdef NETDATA_WITH_ZLIB
2114 ssize_t web_client_send_deflate(struct web_client *w)
2115 {
2116 - ssize_t len = 0, t = 0;
2117 -
2118 - // when using compression,
2119 - // w->response.sent is the amount of bytes passed through compression
2120 -
2121 - debug(D_DEFLATE, "%llu: web_client_send_deflate(): w->response.data->len = %zu, w->response.sent = %zu, w->response.zhave = %zu, w->response.zsent = %zu, w->response.zstream.avail_in = %u, w->response.zstream.avail_out = %u, w->response.zstream.total_in = %lu, w->response.zstream.total_out = %lu.",
2122 - w->id, w->response.data->len, w->response.sent, w->response.zhave, w->response.zsent, w->response.zstream.avail_in, w->response.zstream.avail_out, w->response.zstream.total_in, w->response.zstream.total_out);
2123 -
2124 - if(w->response.data->len - w->response.sent == 0 && w->response.zstream.avail_in == 0 && w->response.zhave == w->response.zsent && w->response.zstream.avail_out != 0) {
2125 - // there is nothing to send
2126 -
2127 - debug(D_WEB_CLIENT, "%llu: Out of output data.", w->id);
2128 -
2129 - // finalize the chunk
2130 - if(w->response.sent != 0) {
2131 - t = web_client_send_chunk_finalize(w);
2132 - if(t < 0) return t;
2133 - }
2134 -
2135 - if(w->mode == WEB_CLIENT_MODE_FILECOPY && w->wait_receive && w->response.rlen && w->response.rlen > w->response.data->len) {
2136 - // we have to wait, more data will come
2137 - debug(D_WEB_CLIENT, "%llu: Waiting for more data to become available.", w->id);
2138 - w->wait_send = 0;
2139 - return t;
2140 - }
2141 -
2142 - if(unlikely(!w->keepalive)) {
2143 - debug(D_WEB_CLIENT, "%llu: Closing (keep-alive is not enabled). %zu bytes sent.", w->id, w->response.sent);
2144 - WEB_CLIENT_IS_DEAD(w);
2145 - return t;
2146 - }
2147 -
2148 - // reset the client
2149 - web_client_reset(w);
2150 - debug(D_WEB_CLIENT, "%llu: Done sending all data on socket.", w->id);
2151 - return t;
2152 - }
2153 -
2154 - if(w->response.zhave == w->response.zsent) {
2155 - // compress more input data
2156 -
2157 - // close the previous open chunk
2158 - if(w->response.sent != 0) {
2159 - t = web_client_send_chunk_close(w);
2160 - if(t < 0) return t;
2161 - }
2162 -
2163 - debug(D_DEFLATE, "%llu: Compressing %zu new bytes starting from %zu (and %u left behind).", w->id, (w->response.data->len - w->response.sent), w->response.sent, w->response.zstream.avail_in);
2164 -
2165 - // give the compressor all the data not passed through the compressor yet
2166 - if(w->response.data->len > w->response.sent) {
2167 - w->response.zstream.next_in = (Bytef *)&w->response.data->buffer[w->response.sent - w->response.zstream.avail_in];
2168 - w->response.zstream.avail_in += (uInt) (w->response.data->len - w->response.sent);
2169 - }
2170 -
2171 - // reset the compressor output buffer
2172 - w->response.zstream.next_out = w->response.zbuffer;
2173 - w->response.zstream.avail_out = ZLIB_CHUNK;
2174 -
2175 - // ask for FINISH if we have all the input
2176 - int flush = Z_SYNC_FLUSH;
2177 - if(w->mode == WEB_CLIENT_MODE_NORMAL
2178 - || (w->mode == WEB_CLIENT_MODE_FILECOPY && !w->wait_receive && w->response.data->len == w->response.rlen)) {
2179 - flush = Z_FINISH;
2180 - debug(D_DEFLATE, "%llu: Requesting Z_FINISH, if possible.", w->id);
2181 - }
2182 - else {
2183 - debug(D_DEFLATE, "%llu: Requesting Z_SYNC_FLUSH.", w->id);
2184 - }
2185 -
2186 - // compress
2187 - if(deflate(&w->response.zstream, flush) == Z_STREAM_ERROR) {
2188 - error("%llu: Compression failed. Closing down client.", w->id);
2189 - web_client_reset(w);
2190 - return(-1);
2191 - }
2192 -
2193 - w->response.zhave = ZLIB_CHUNK - w->response.zstream.avail_out;
2194 - w->response.zsent = 0;
2195 -
2196 - // keep track of the bytes passed through the compressor
2197 - w->response.sent = w->response.data->len;
2198 -
2199 - debug(D_DEFLATE, "%llu: Compression produced %zu bytes.", w->id, w->response.zhave);
2200 -
2201 - // open a new chunk
2202 - ssize_t t2 = web_client_send_chunk_header(w, w->response.zhave);
2203 - if(t2 < 0) return t2;
2204 - t += t2;
2205 - }
2206 -
2207 - debug(D_WEB_CLIENT, "%llu: Sending %zu bytes of data (+%zd of chunk header).", w->id, w->response.zhave - w->response.zsent, t);
2208 -
2209 - len = send(w->ofd, &w->response.zbuffer[w->response.zsent], (size_t) (w->response.zhave - w->response.zsent), MSG_DONTWAIT);
2210 - if(len > 0) {
2211 - w->stats_sent_bytes += len;
2212 - w->response.zsent += len;
2213 - len += t;
2214 - debug(D_WEB_CLIENT, "%llu: Sent %zd bytes.", w->id, len);
2215 - }
2216 - else if(len == 0) {
2217 - debug(D_WEB_CLIENT, "%llu: Did not send any bytes to the client (zhave = %zu, zsent = %zu, need to send = %zu).",
2218 - w->id, w->response.zhave, w->response.zsent, w->response.zhave - w->response.zsent);
2219 -
2220 - WEB_CLIENT_IS_DEAD(w);
2221 - }
2222 - else {
2223 - debug(D_WEB_CLIENT, "%llu: Failed to send data to client.", w->id);
2224 - WEB_CLIENT_IS_DEAD(w);
2225 - }
2226 -
2227 - return(len);
2116 + ssize_t len = 0, t = 0;
2117 +
2118 + // when using compression,
2119 + // w->response.sent is the amount of bytes passed through compression
2120 +
2121 + debug(D_DEFLATE, "%llu: web_client_send_deflate(): w->response.data->len = %zu, w->response.sent = %zu, w->response.zhave = %zu, w->response.zsent = %zu, w->response.zstream.avail_in = %u, w->response.zstream.avail_out = %u, w->response.zstream.total_in = %lu, w->response.zstream.total_out = %lu.",
2122 + w->id, w->response.data->len, w->response.sent, w->response.zhave, w->response.zsent, w->response.zstream.avail_in, w->response.zstream.avail_out, w->response.zstream.total_in, w->response.zstream.total_out);
2123 +
2124 + if(w->response.data->len - w->response.sent == 0 && w->response.zstream.avail_in == 0 && w->response.zhave == w->response.zsent && w->response.zstream.avail_out != 0) {
2125 + // there is nothing to send
2126 +
2127 + debug(D_WEB_CLIENT, "%llu: Out of output data.", w->id);
2128 +
2129 + // finalize the chunk
2130 + if(w->response.sent != 0) {
2131 + t = web_client_send_chunk_finalize(w);
2132 + if(t < 0) return t;
2133 + }
2134 +
2135 + if(w->mode == WEB_CLIENT_MODE_FILECOPY && w->wait_receive && w->response.rlen && w->response.rlen > w->response.data->len) {
2136 + // we have to wait, more data will come
2137 + debug(D_WEB_CLIENT, "%llu: Waiting for more data to become available.", w->id);
2138 + w->wait_send = 0;
2139 + return t;
2140 + }
2141 +
2142 + if(unlikely(!w->keepalive)) {
2143 + debug(D_WEB_CLIENT, "%llu: Closing (keep-alive is not enabled). %zu bytes sent.", w->id, w->response.sent);
2144 + WEB_CLIENT_IS_DEAD(w);
2145 + return t;
2146 + }
2147 +
2148 + // reset the client
2149 + web_client_reset(w);
2150 + debug(D_WEB_CLIENT, "%llu: Done sending all data on socket.", w->id);
2151 + return t;
2152 + }
2153 +
2154 + if(w->response.zhave == w->response.zsent) {
2155 + // compress more input data
2156 +
2157 + // close the previous open chunk
2158 + if(w->response.sent != 0) {
2159 + t = web_client_send_chunk_close(w);
2160 + if(t < 0) return t;
2161 + }
2162 +
2163 + debug(D_DEFLATE, "%llu: Compressing %zu new bytes starting from %zu (and %u left behind).", w->id, (w->response.data->len - w->response.sent), w->response.sent, w->response.zstream.avail_in);
2164 +
2165 + // give the compressor all the data not passed through the compressor yet
2166 + if(w->response.data->len > w->response.sent) {
2167 + w->response.zstream.next_in = (Bytef *)&w->response.data->buffer[w->response.sent - w->response.zstream.avail_in];
2168 + w->response.zstream.avail_in += (uInt) (w->response.data->len - w->response.sent);
2169 + }
2170 +
2171 + // reset the compressor output buffer
2172 + w->response.zstream.next_out = w->response.zbuffer;
2173 + w->response.zstream.avail_out = ZLIB_CHUNK;
2174 +
2175 + // ask for FINISH if we have all the input
2176 + int flush = Z_SYNC_FLUSH;
2177 + if(w->mode == WEB_CLIENT_MODE_NORMAL
2178 + || (w->mode == WEB_CLIENT_MODE_FILECOPY && !w->wait_receive && w->response.data->len == w->response.rlen)) {
2179 + flush = Z_FINISH;
2180 + debug(D_DEFLATE, "%llu: Requesting Z_FINISH, if possible.", w->id);
2181 + }
2182 + else {
2183 + debug(D_DEFLATE, "%llu: Requesting Z_SYNC_FLUSH.", w->id);
2184 + }
2185 +
2186 + // compress
2187 + if(deflate(&w->response.zstream, flush) == Z_STREAM_ERROR) {
2188 + error("%llu: Compression failed. Closing down client.", w->id);
2189 + web_client_reset(w);
2190 + return(-1);
2191 + }
2192 +
2193 + w->response.zhave = ZLIB_CHUNK - w->response.zstream.avail_out;
2194 + w->response.zsent = 0;
2195 +
2196 + // keep track of the bytes passed through the compressor
2197 + w->response.sent = w->response.data->len;
2198 +
2199 + debug(D_DEFLATE, "%llu: Compression produced %zu bytes.", w->id, w->response.zhave);
2200 +
2201 + // open a new chunk
2202 + ssize_t t2 = web_client_send_chunk_header(w, w->response.zhave);
2203 + if(t2 < 0) return t2;
2204 + t += t2;
2205 + }
2206 +
2207 + debug(D_WEB_CLIENT, "%llu: Sending %zu bytes of data (+%zd of chunk header).", w->id, w->response.zhave - w->response.zsent, t);
2208 +
2209 + len = send(w->ofd, &w->response.zbuffer[w->response.zsent], (size_t) (w->response.zhave - w->response.zsent), MSG_DONTWAIT);
2210 + if(len > 0) {
2211 + w->stats_sent_bytes += len;
2212 + w->response.zsent += len;
2213 + len += t;
2214 + debug(D_WEB_CLIENT, "%llu: Sent %zd bytes.", w->id, len);
2215 + }
2216 + else if(len == 0) {
2217 + debug(D_WEB_CLIENT, "%llu: Did not send any bytes to the client (zhave = %zu, zsent = %zu, need to send = %zu).",
2218 + w->id, w->response.zhave, w->response.zsent, w->response.zhave - w->response.zsent);
2219 +
2220 + WEB_CLIENT_IS_DEAD(w);
2221 + }
2222 + else {
2223 + debug(D_WEB_CLIENT, "%llu: Failed to send data to client.", w->id);
2224 + WEB_CLIENT_IS_DEAD(w);
2225 + }
2226 +
2227 + return(len);
2228 }
2229 #endif // NETDATA_WITH_ZLIB
2230
2231 ssize_t web_client_send(struct web_client *w) {
2232 #ifdef NETDATA_WITH_ZLIB
2233 - if(likely(w->response.zoutput)) return web_client_send_deflate(w);
2233 + if(likely(w->response.zoutput)) return web_client_send_deflate(w);
2234 #endif // NETDATA_WITH_ZLIB
2235
2236 - ssize_t bytes;
2237 -
2238 - if(unlikely(w->response.data->len - w->response.sent == 0)) {
2239 - // there is nothing to send
2240 -
2241 - debug(D_WEB_CLIENT, "%llu: Out of output data.", w->id);
2242 -
2243 - // there can be two cases for this
2244 - // A. we have done everything
2245 - // B. we temporarily have nothing to send, waiting for the buffer to be filled by ifd
2246 -
2247 - if(w->mode == WEB_CLIENT_MODE_FILECOPY && w->wait_receive && w->response.rlen && w->response.rlen > w->response.data->len) {
2248 - // we have to wait, more data will come
2249 - debug(D_WEB_CLIENT, "%llu: Waiting for more data to become available.", w->id);
2250 - w->wait_send = 0;
2251 - return 0;
2252 - }
2253 -
2254 - if(unlikely(!w->keepalive)) {
2255 - debug(D_WEB_CLIENT, "%llu: Closing (keep-alive is not enabled). %zu bytes sent.", w->id, w->response.sent);
2256 - WEB_CLIENT_IS_DEAD(w);
2257 - return 0;
2258 - }
2259 -
2260 - web_client_reset(w);
2261 - debug(D_WEB_CLIENT, "%llu: Done sending all data on socket. Waiting for next request on the same socket.", w->id);
2262 - return 0;
2263 - }
2264 -
2265 - bytes = send(w->ofd, &w->response.data->buffer[w->response.sent], w->response.data->len - w->response.sent, MSG_DONTWAIT);
2266 - if(likely(bytes > 0)) {
2267 - w->stats_sent_bytes += bytes;
2268 - w->response.sent += bytes;
2269 - debug(D_WEB_CLIENT, "%llu: Sent %zd bytes.", w->id, bytes);
2270 - }
2271 - else if(likely(bytes == 0)) {
2272 - debug(D_WEB_CLIENT, "%llu: Did not send any bytes to the client.", w->id);
2273 - WEB_CLIENT_IS_DEAD(w);
2274 - }
2275 - else {
2276 - debug(D_WEB_CLIENT, "%llu: Failed to send data to client.", w->id);
2277 - WEB_CLIENT_IS_DEAD(w);
2278 - }
2279 -
2280 - return(bytes);
2236 + ssize_t bytes;
2237 +
2238 + if(unlikely(w->response.data->len - w->response.sent == 0)) {
2239 + // there is nothing to send
2240 +
2241 + debug(D_WEB_CLIENT, "%llu: Out of output data.", w->id);
2242 +
2243 + // there can be two cases for this
2244 + // A. we have done everything
2245 + // B. we temporarily have nothing to send, waiting for the buffer to be filled by ifd
2246 +
2247 + if(w->mode == WEB_CLIENT_MODE_FILECOPY && w->wait_receive && w->response.rlen && w->response.rlen > w->response.data->len) {
2248 + // we have to wait, more data will come
2249 + debug(D_WEB_CLIENT, "%llu: Waiting for more data to become available.", w->id);
2250 + w->wait_send = 0;
2251 + return 0;
2252 + }
2253 +
2254 + if(unlikely(!w->keepalive)) {
2255 + debug(D_WEB_CLIENT, "%llu: Closing (keep-alive is not enabled). %zu bytes sent.", w->id, w->response.sent);
2256 + WEB_CLIENT_IS_DEAD(w);
2257 + return 0;
2258 + }
2259 +
2260 + web_client_reset(w);
2261 + debug(D_WEB_CLIENT, "%llu: Done sending all data on socket. Waiting for next request on the same socket.", w->id);
2262 + return 0;
2263 + }
2264 +
2265 + bytes = send(w->ofd, &w->response.data->buffer[w->response.sent], w->response.data->len - w->response.sent, MSG_DONTWAIT);
2266 + if(likely(bytes > 0)) {
2267 + w->stats_sent_bytes += bytes;
2268 + w->response.sent += bytes;
2269 + debug(D_WEB_CLIENT, "%llu: Sent %zd bytes.", w->id, bytes);
2270 + }
2271 + else if(likely(bytes == 0)) {
2272 + debug(D_WEB_CLIENT, "%llu: Did not send any bytes to the client.", w->id);
2273 + WEB_CLIENT_IS_DEAD(w);
2274 + }
2275 + else {
2276 + debug(D_WEB_CLIENT, "%llu: Failed to send data to client.", w->id);
2277 + WEB_CLIENT_IS_DEAD(w);
2278 + }
2279 +
2280 + return(bytes);
2281 }
2282
2283 ssize_t web_client_receive(struct web_client *w)
2284 {
2285 - // do we have any space for more data?
2286 - buffer_need_bytes(w->response.data, WEB_REQUEST_LENGTH);
2287 -
2288 - ssize_t left = w->response.data->size - w->response.data->len;
2289 - ssize_t bytes;
2290 -
2291 - if(unlikely(w->mode == WEB_CLIENT_MODE_FILECOPY))
2292 - bytes = read(w->ifd, &w->response.data->buffer[w->response.data->len], (size_t) (left - 1));
2293 - else
2294 - bytes = recv(w->ifd, &w->response.data->buffer[w->response.data->len], (size_t) (left - 1), MSG_DONTWAIT);
2295 -
2296 - if(likely(bytes > 0)) {
2297 - if(w->mode != WEB_CLIENT_MODE_FILECOPY)
2298 - w->stats_received_bytes += bytes;
2299 -
2300 - size_t old = w->response.data->len;
2301 - w->response.data->len += bytes;
2302 - w->response.data->buffer[w->response.data->len] = '\0';
2303 -
2304 - debug(D_WEB_CLIENT, "%llu: Received %zd bytes.", w->id, bytes);
2305 - debug(D_WEB_DATA, "%llu: Received data: '%s'.", w->id, &w->response.data->buffer[old]);
2306 -
2307 - if(w->mode == WEB_CLIENT_MODE_FILECOPY) {
2308 - w->wait_send = 1;
2309 -
2310 - if(w->response.rlen && w->response.data->len >= w->response.rlen)
2311 - w->wait_receive = 0;
2312 - }
2313 - }
2314 - else if(likely(bytes == 0)) {
2315 - debug(D_WEB_CLIENT, "%llu: Out of input data.", w->id);
2316 -
2317 - // if we cannot read, it means we have an error on input.
2318 - // if however, we are copying a file from ifd to ofd, we should not return an error.
2319 - // in this case, the error should be generated when the file has been sent to the client.
2320 -
2321 - if(w->mode == WEB_CLIENT_MODE_FILECOPY) {
2322 - // we are copying data from ifd to ofd
2323 - // let it finish copying...
2324 - w->wait_receive = 0;
2325 -
2326 - debug(D_WEB_CLIENT, "%llu: Read the whole file.", w->id);
2327 - if(w->ifd != w->ofd) close(w->ifd);
2328 - w->ifd = w->ofd;
2329 - }
2330 - else {
2331 - debug(D_WEB_CLIENT, "%llu: failed to receive data.", w->id);
2332 - WEB_CLIENT_IS_DEAD(w);
2333 - }
2334 - }
2335 - else {
2336 - debug(D_WEB_CLIENT, "%llu: receive data failed.", w->id);
2337 - WEB_CLIENT_IS_DEAD(w);
2338 - }
2339 -
2340 - return(bytes);
2285 + // do we have any space for more data?
2286 + buffer_need_bytes(w->response.data, WEB_REQUEST_LENGTH);
2287 +
2288 + ssize_t left = w->response.data->size - w->response.data->len;
2289 + ssize_t bytes;
2290 +
2291 + if(unlikely(w->mode == WEB_CLIENT_MODE_FILECOPY))
2292 + bytes = read(w->ifd, &w->response.data->buffer[w->response.data->len], (size_t) (left - 1));
2293 + else
2294 + bytes = recv(w->ifd, &w->response.data->buffer[w->response.data->len], (size_t) (left - 1), MSG_DONTWAIT);
2295 +
2296 + if(likely(bytes > 0)) {
2297 + if(w->mode != WEB_CLIENT_MODE_FILECOPY)
2298 + w->stats_received_bytes += bytes;
2299 +
2300 + size_t old = w->response.data->len;
2301 + w->response.data->len += bytes;
2302 + w->response.data->buffer[w->response.data->len] = '\0';
2303 +
2304 + debug(D_WEB_CLIENT, "%llu: Received %zd bytes.", w->id, bytes);
2305 + debug(D_WEB_DATA, "%llu: Received data: '%s'.", w->id, &w->response.data->buffer[old]);
2306 +
2307 + if(w->mode == WEB_CLIENT_MODE_FILECOPY) {
2308 + w->wait_send = 1;
2309 +
2310 + if(w->response.rlen && w->response.data->len >= w->response.rlen)
2311 + w->wait_receive = 0;
2312 + }
2313 + }
2314 + else if(likely(bytes == 0)) {
2315 + debug(D_WEB_CLIENT, "%llu: Out of input data.", w->id);
2316 +
2317 + // if we cannot read, it means we have an error on input.
2318 + // if however, we are copying a file from ifd to ofd, we should not return an error.
2319 + // in this case, the error should be generated when the file has been sent to the client.
2320 +
2321 + if(w->mode == WEB_CLIENT_MODE_FILECOPY) {
2322 + // we are copying data from ifd to ofd
2323 + // let it finish copying...
2324 + w->wait_receive = 0;
2325 +
2326 + debug(D_WEB_CLIENT, "%llu: Read the whole file.", w->id);
2327 + if(w->ifd != w->ofd) close(w->ifd);
2328 + w->ifd = w->ofd;
2329 + }
2330 + else {
2331 + debug(D_WEB_CLIENT, "%llu: failed to receive data.", w->id);
2332 + WEB_CLIENT_IS_DEAD(w);
2333 + }
2334 + }
2335 + else {
2336 + debug(D_WEB_CLIENT, "%llu: receive data failed.", w->id);
2337 + WEB_CLIENT_IS_DEAD(w);
2338 + }
2339 +
2340 + return(bytes);
2341 }
2342
2343
@@ -2351,131 +2351,131 @@ ssize_t web_client_receive(struct web_client *w)
2351
2352 void *web_client_main(void *ptr)
2353 {
2354 - if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
2355 - error("Cannot set pthread cancel type to DEFERRED.");
2356 -
2357 - if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
2358 - error("Cannot set pthread cancel state to ENABLE.");
2359 -
2360 - struct web_client *w = ptr;
2361 - struct pollfd fds[2], *ifd, *ofd;
2362 - int retval, fdmax = 0, timeout;
2363 -
2364 - log_access("%llu: %s port %s connected on thread task id %d", w->id, w->client_ip, w->client_port, gettid());
2365 -
2366 - for(;;) {
2367 - if(unlikely(w->dead)) {
2368 - debug(D_WEB_CLIENT, "%llu: client is dead.", w->id);
2369 - break;
2370 - }
2371 - else if(unlikely(!w->wait_receive && !w->wait_send)) {
2372 - debug(D_WEB_CLIENT, "%llu: client is not set for neither receiving nor sending data.", w->id);
2373 - break;
2374 - }
2375 -
2376 - if(unlikely(w->ifd < 0 || w->ofd < 0)) {
2377 - error("%llu: invalid file descriptor, ifd = %d, ofd = %d (required 0 <= fd", w->id, w->ifd, w->ofd);
2378 - break;
2379 - }
2380 -
2381 - if(w->ifd == w->ofd) {
2382 - fds[0].fd = w->ifd;
2383 - fds[0].events = 0;
2384 - fds[0].revents = 0;
2385 -
2386 - if(w->wait_receive) fds[0].events |= POLLIN;
2387 - if(w->wait_send) fds[0].events |= POLLOUT;
2388 -
2389 - fds[1].fd = -1;
2390 - fds[1].events = 0;
2391 - fds[1].revents = 0;
2392 -
2393 - ifd = ofd = &fds[0];
2394 -
2395 - fdmax = 1;
2396 - }
2397 - else {
2398 - fds[0].fd = w->ifd;
2399 - fds[0].events = 0;
2400 - fds[0].revents = 0;
2401 - if(w->wait_receive) fds[0].events |= POLLIN;
2402 - ifd = &fds[0];
2403 -
2404 - fds[1].fd = w->ofd;
2405 - fds[1].events = 0;
2406 - fds[1].revents = 0;
2407 - if(w->wait_send) fds[1].events |= POLLOUT;
2408 - ofd = &fds[1];
2409 -
2410 - fdmax = 2;
2411 - }
2412 -
2413 - debug(D_WEB_CLIENT, "%llu: Waiting socket async I/O for %s %s", w->id, w->wait_receive?"INPUT":"", w->wait_send?"OUTPUT":"");
2414 - errno = 0;
2415 - timeout = web_client_timeout * 1000;
2416 - retval = poll(fds, fdmax, timeout);
2417 -
2418 - if(unlikely(retval == -1)) {
2419 - if(errno == EAGAIN || errno == EINTR) {
2420 - debug(D_WEB_CLIENT, "%llu: EAGAIN received.", w->id);
2421 - continue;
2422 - }
2423 -
2424 - debug(D_WEB_CLIENT, "%llu: LISTENER: poll() failed (input fd = %d, output fd = %d). Closing client.", w->id, w->ifd, w->ofd);
2425 - break;
2426 - }
2427 - else if(unlikely(!retval)) {
2428 - debug(D_WEB_CLIENT, "%llu: Timeout while waiting socket async I/O for %s %s", w->id, w->wait_receive?"INPUT":"", w->wait_send?"OUTPUT":"");
2429 - break;
2430 - }
2431 -
2432 - int used = 0;
2433 - if(w->wait_send && ofd->revents & POLLOUT) {
2434 - used++;
2435 - if(web_client_send(w) < 0) {
2436 - debug(D_WEB_CLIENT, "%llu: Cannot send data to client. Closing client.", w->id);
2437 - break;
2438 - }
2439 - }
2440 -
2441 - if(w->wait_receive && (ifd->revents & POLLIN || ifd->revents & POLLPRI)) {
2442 - used++;
2443 - if(web_client_receive(w) < 0) {
2444 - debug(D_WEB_CLIENT, "%llu: Cannot receive data from client. Closing client.", w->id);
2445 - break;
2446 - }
2447 -
2448 - if(w->mode == WEB_CLIENT_MODE_NORMAL) {
2449 - debug(D_WEB_CLIENT, "%llu: Attempting to process received data.", w->id);
2450 - web_client_process(w);
2451 - }
2452 - }
2453 -
2454 - if(unlikely(!used)) {
2455 - debug(D_WEB_CLIENT_ACCESS, "%llu: Received error on socket.", w->id);
2456 - break;
2457 - }
2458 - }
2459 -
2460 - web_client_reset(w);
2461 -
2462 - log_access("%llu: %s port %s disconnected from thread task id %d", w->id, w->client_ip, w->client_port, gettid());
2463 - debug(D_WEB_CLIENT, "%llu: done...", w->id);
2464 -
2465 - // close the sockets/files now
2466 - // to free file descriptors
2467 - if(w->ifd == w->ofd) {
2468 - if(w->ifd != -1) close(w->ifd);
2469 - }
2470 - else {
2471 - if(w->ifd != -1) close(w->ifd);
2472 - if(w->ofd != -1) close(w->ofd);
2473 - }
2474 - w->ifd = -1;
2475 - w->ofd = -1;
2476 -
2477 - w->obsolete = 1;
2478 -
2479 - pthread_exit(NULL);
2480 - return NULL;
2354 + if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
2355 + error("Cannot set pthread cancel type to DEFERRED.");
2356 +
2357 + if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
2358 + error("Cannot set pthread cancel state to ENABLE.");
2359 +
2360 + struct web_client *w = ptr;
2361 + struct pollfd fds[2], *ifd, *ofd;
2362 + int retval, fdmax = 0, timeout;
2363 +
2364 + log_access("%llu: %s port %s connected on thread task id %d", w->id, w->client_ip, w->client_port, gettid());
2365 +
2366 + for(;;) {
2367 + if(unlikely(w->dead)) {
2368 + debug(D_WEB_CLIENT, "%llu: client is dead.", w->id);
2369 + break;
2370 + }
2371 + else if(unlikely(!w->wait_receive && !w->wait_send)) {
2372 + debug(D_WEB_CLIENT, "%llu: client is not set for neither receiving nor sending data.", w->id);
2373 + break;
2374 + }
2375 +
2376 + if(unlikely(w->ifd < 0 || w->ofd < 0)) {
2377 + error("%llu: invalid file descriptor, ifd = %d, ofd = %d (required 0 <= fd", w->id, w->ifd, w->ofd);
2378 + break;
2379 + }
2380 +
2381 + if(w->ifd == w->ofd) {
2382 + fds[0].fd = w->ifd;
2383 + fds[0].events = 0;
2384 + fds[0].revents = 0;
2385 +
2386 + if(w->wait_receive) fds[0].events |= POLLIN;
2387 + if(w->wait_send) fds[0].events |= POLLOUT;
2388 +
2389 + fds[1].fd = -1;
2390 + fds[1].events = 0;
2391 + fds[1].revents = 0;
2392 +
2393 + ifd = ofd = &fds[0];
2394 +
2395 + fdmax = 1;
2396 + }
2397 + else {
2398 + fds[0].fd = w->ifd;
2399 + fds[0].events = 0;
2400 + fds[0].revents = 0;
2401 + if(w->wait_receive) fds[0].events |= POLLIN;
2402 + ifd = &fds[0];
2403 +
2404 + fds[1].fd = w->ofd;
2405 + fds[1].events = 0;
2406 + fds[1].revents = 0;
2407 + if(w->wait_send) fds[1].events |= POLLOUT;
2408 + ofd = &fds[1];
2409 +
2410 + fdmax = 2;
2411 + }
2412 +
2413 + debug(D_WEB_CLIENT, "%llu: Waiting socket async I/O for %s %s", w->id, w->wait_receive?"INPUT":"", w->wait_send?"OUTPUT":"");
2414 + errno = 0;
2415 + timeout = web_client_timeout * 1000;
2416 + retval = poll(fds, fdmax, timeout);
2417 +
2418 + if(unlikely(retval == -1)) {
2419 + if(errno == EAGAIN || errno == EINTR) {
2420 + debug(D_WEB_CLIENT, "%llu: EAGAIN received.", w->id);
2421 + continue;
2422 + }
2423 +
2424 + debug(D_WEB_CLIENT, "%llu: LISTENER: poll() failed (input fd = %d, output fd = %d). Closing client.", w->id, w->ifd, w->ofd);
2425 + break;
2426 + }
2427 + else if(unlikely(!retval)) {
2428 + debug(D_WEB_CLIENT, "%llu: Timeout while waiting socket async I/O for %s %s", w->id, w->wait_receive?"INPUT":"", w->wait_send?"OUTPUT":"");
2429 + break;
2430 + }
2431 +
2432 + int used = 0;
2433 + if(w->wait_send && ofd->revents & POLLOUT) {
2434 + used++;
2435 + if(web_client_send(w) < 0) {
2436 + debug(D_WEB_CLIENT, "%llu: Cannot send data to client. Closing client.", w->id);
2437 + break;
2438 + }
2439 + }
2440 +
2441 + if(w->wait_receive && (ifd->revents & POLLIN || ifd->revents & POLLPRI)) {
2442 + used++;
2443 + if(web_client_receive(w) < 0) {
2444 + debug(D_WEB_CLIENT, "%llu: Cannot receive data from client. Closing client.", w->id);
2445 + break;
2446 + }
2447 +
2448 + if(w->mode == WEB_CLIENT_MODE_NORMAL) {
2449 + debug(D_WEB_CLIENT, "%llu: Attempting to process received data.", w->id);
2450 + web_client_process(w);
2451 + }
2452 + }
2453 +
2454 + if(unlikely(!used)) {
2455 + debug(D_WEB_CLIENT_ACCESS, "%llu: Received error on socket.", w->id);
2456 + break;
2457 + }
2458 + }
2459 +
2460 + web_client_reset(w);
2461 +
2462 + log_access("%llu: %s port %s disconnected from thread task id %d", w->id, w->client_ip, w->client_port, gettid());
2463 + debug(D_WEB_CLIENT, "%llu: done...", w->id);
2464 +
2465 + // close the sockets/files now
2466 + // to free file descriptors
2467 + if(w->ifd == w->ofd) {
2468 + if(w->ifd != -1) close(w->ifd);
2469 + }
2470 + else {
2471 + if(w->ifd != -1) close(w->ifd);
2472 + if(w->ofd != -1) close(w->ofd);
2473 + }
2474 + w->ifd = -1;
2475 + w->ofd = -1;
2476 +
2477 + w->obsolete = 1;
2478 +
2479 + pthread_exit(NULL);
2480 + return NULL;
2481 }
src/web_client.h
+45 -45
@@ -8,83 +8,83 @@ extern int web_client_timeout;
8 extern int web_enable_gzip, web_gzip_level, web_gzip_strategy, web_donotrack_comply;
9 #endif /* NETDATA_WITH_ZLIB */
10
11 -#define WEB_CLIENT_MODE_NORMAL 0
12 -#define WEB_CLIENT_MODE_FILECOPY 1
13 -#define WEB_CLIENT_MODE_OPTIONS 2
11 +#define WEB_CLIENT_MODE_NORMAL 0
12 +#define WEB_CLIENT_MODE_FILECOPY 1
13 +#define WEB_CLIENT_MODE_OPTIONS 2
14
15 #define URL_MAX 8192
16 -#define ZLIB_CHUNK 16384
16 +#define ZLIB_CHUNK 16384
17 #define HTTP_RESPONSE_HEADER_SIZE 4096
18 #define COOKIE_MAX 1024
19 #define ORIGIN_MAX 1024
20
21 struct response {
22 - BUFFER *header; // our response header
23 - BUFFER *header_output; // internal use
24 - BUFFER *data; // our response data buffer
22 + BUFFER *header; // our response header
23 + BUFFER *header_output; // internal use
24 + BUFFER *data; // our response data buffer
25
26 - int code; // the HTTP response code
26 + int code; // the HTTP response code
27
28 - size_t rlen; // if non-zero, the excepted size of ifd (input of firecopy)
29 - size_t sent; // current data length sent to output
28 + size_t rlen; // if non-zero, the excepted size of ifd (input of firecopy)
29 + size_t sent; // current data length sent to output
30
31 - int zoutput; // if set to 1, web_client_send() will send compressed data
31 + int zoutput; // if set to 1, web_client_send() will send compressed data
32 #ifdef NETDATA_WITH_ZLIB
33 - z_stream zstream; // zlib stream for sending compressed output to client
34 - Bytef zbuffer[ZLIB_CHUNK]; // temporary buffer for storing compressed output
35 - size_t zsent; // the compressed bytes we have sent to the client
36 - size_t zhave; // the compressed bytes that we have received from zlib
37 - int zinitialized:1;
33 + z_stream zstream; // zlib stream for sending compressed output to client
34 + Bytef zbuffer[ZLIB_CHUNK]; // temporary buffer for storing compressed output
35 + size_t zsent; // the compressed bytes we have sent to the client
36 + size_t zhave; // the compressed bytes that we have received from zlib
37 + int zinitialized:1;
38 #endif /* NETDATA_WITH_ZLIB */
39
40 };
41
42 struct web_client {
43 - unsigned long long id;
43 + unsigned long long id;
44
45 - uint8_t obsolete:1; // if set to 1, the listener will remove this client
46 - // after setting this to 1, you should not touch
47 - // this web_client
45 + uint8_t obsolete:1; // if set to 1, the listener will remove this client
46 + // after setting this to 1, you should not touch
47 + // this web_client
48
49 - uint8_t dead:1; // if set to 1, this client is dead
49 + uint8_t dead:1; // if set to 1, this client is dead
50
51 - uint8_t keepalive:1; // if set to 1, the web client will be re-used
51 + uint8_t keepalive:1; // if set to 1, the web client will be re-used
52
53 - uint8_t mode:3; // the operational mode of the client
53 + uint8_t mode:3; // the operational mode of the client
54
55 - uint8_t wait_receive:1; // 1 = we are waiting more input data
56 - uint8_t wait_send:1; // 1 = we have data to send to the client
55 + uint8_t wait_receive:1; // 1 = we are waiting more input data
56 + uint8_t wait_send:1; // 1 = we have data to send to the client
57
58 - uint8_t donottrack:1; // 1 = we should not set cookies on this client
59 - uint8_t tracking_required:1; // 1 = if the request requires cookies
58 + uint8_t donottrack:1; // 1 = we should not set cookies on this client
59 + uint8_t tracking_required:1; // 1 = if the request requires cookies
60
61 - int tcp_cork; // 1 = we have a cork on the socket
61 + int tcp_cork; // 1 = we have a cork on the socket
62
63 - int ifd;
64 - int ofd;
63 + int ifd;
64 + int ofd;
65
66 - char client_ip[NI_MAXHOST+1];
67 - char client_port[NI_MAXSERV+1];
66 + char client_ip[NI_MAXHOST+1];
67 + char client_port[NI_MAXSERV+1];
68
69 - char decoded_url[URL_MAX + 1]; // we decode the URL in this buffer
70 - char last_url[URL_MAX+1]; // we keep a copy of the decoded URL here
69 + char decoded_url[URL_MAX + 1]; // we decode the URL in this buffer
70 + char last_url[URL_MAX+1]; // we keep a copy of the decoded URL here
71
72 - struct timeval tv_in, tv_ready;
72 + struct timeval tv_in, tv_ready;
73
74 - char cookie1[COOKIE_MAX+1];
75 - char cookie2[COOKIE_MAX+1];
76 - char origin[ORIGIN_MAX+1];
74 + char cookie1[COOKIE_MAX+1];
75 + char cookie2[COOKIE_MAX+1];
76 + char origin[ORIGIN_MAX+1];
77
78 - struct sockaddr_storage clientaddr;
79 - struct response response;
78 + struct sockaddr_storage clientaddr;
79 + struct response response;
80
81 - size_t stats_received_bytes;
82 - size_t stats_sent_bytes;
81 + size_t stats_received_bytes;
82 + size_t stats_sent_bytes;
83
84 - pthread_t thread; // the thread servicing this client
84 + pthread_t thread; // the thread servicing this client
85
86 - struct web_client *prev;
87 - struct web_client *next;
86 + struct web_client *prev;
87 + struct web_client *next;
88 };
89
90 #define WEB_CLIENT_IS_DEAD(w) (w)->dead=1
src/web_server.c
+303 -303
@@ -10,75 +10,75 @@ int web_server_mode = WEB_SERVER_MODE_MULTI_THREADED;
10 #ifdef NETDATA_INTERNAL_CHECKS
11 static void log_allocations(void)
12 {
13 - static int mem = 0;
13 + static int mem = 0;
14
15 - struct mallinfo mi;
15 + struct mallinfo mi;
16
17 - mi = mallinfo();
18 - if(mi.uordblks > mem) {
19 - int clients = 0;
20 - struct web_client *w;
21 - for(w = web_clients; w ; w = w->next) clients++;
17 + mi = mallinfo();
18 + if(mi.uordblks > mem) {
19 + int clients = 0;
20 + struct web_client *w;
21 + for(w = web_clients; w ; w = w->next) clients++;
22
23 - info("Allocated memory increased from %d to %d (increased by %d bytes). There are %d web clients connected.", mem, mi.uordblks, mi.uordblks - mem, clients);
24 - mem = mi.uordblks;
25 - }
23 + info("Allocated memory increased from %d to %d (increased by %d bytes). There are %d web clients connected.", mem, mi.uordblks, mi.uordblks - mem, clients);
24 + mem = mi.uordblks;
25 + }
26 }
27 #endif
28
29 #ifndef HAVE_ACCEPT4
30 int accept4(int sock, struct sockaddr *addr, socklen_t *addrlen, int flags) {
31 - int fd = accept(sock, addr, addrlen);
32 - int newflags = 0;
33 -
34 - if (fd < 0) return fd;
35 -
36 - if (flags & SOCK_NONBLOCK) {
37 - newflags |= O_NONBLOCK;
38 - flags &= ~SOCK_NONBLOCK;
39 - }
40 -
41 - if (flags & SOCK_CLOEXEC) {
42 - newflags |= O_CLOEXEC;
43 - flags &= ~SOCK_CLOEXEC;
44 - }
45 -
46 - if (flags) {
47 - errno = -EINVAL;
48 - return -1;
49 - }
50 -
51 - if (fcntl(fd, F_SETFL, newflags) < 0) {
52 - int saved_errno = errno;
53 - close(fd);
54 - errno = saved_errno;
55 - return -1;
56 - }
57 -
58 - return fd;
31 + int fd = accept(sock, addr, addrlen);
32 + int newflags = 0;
33 +
34 + if (fd < 0) return fd;
35 +
36 + if (flags & SOCK_NONBLOCK) {
37 + newflags |= O_NONBLOCK;
38 + flags &= ~SOCK_NONBLOCK;
39 + }
40 +
41 + if (flags & SOCK_CLOEXEC) {
42 + newflags |= O_CLOEXEC;
43 + flags &= ~SOCK_CLOEXEC;
44 + }
45 +
46 + if (flags) {
47 + errno = -EINVAL;
48 + return -1;
49 + }
50 +
51 + if (fcntl(fd, F_SETFL, newflags) < 0) {
52 + int saved_errno = errno;
53 + close(fd);
54 + errno = saved_errno;
55 + return -1;
56 + }
57 +
58 + return fd;
59 }
60 #endif
61
62 int create_listen_socket4(const char *ip, int port, int listen_backlog) {
63 - int sock;
64 - int sockopt = 1;
63 + int sock;
64 + int sockopt = 1;
65
66 - debug(D_LISTENER, "IPv4 creating new listening socket on ip '%s' port %d", ip, port);
66 + debug(D_LISTENER, "IPv4 creating new listening socket on ip '%s' port %d", ip, port);
67
68 - sock = socket(AF_INET, SOCK_STREAM, 0);
69 - if(sock < 0) {
70 - error("IPv4 socket() on ip '%s' port %d failed.", ip, port);
71 - return -1;
72 - }
68 + sock = socket(AF_INET, SOCK_STREAM, 0);
69 + if(sock < 0) {
70 + error("IPv4 socket() on ip '%s' port %d failed.", ip, port);
71 + return -1;
72 + }
73
74 - /* avoid "address already in use" */
75 - if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*)&sockopt, sizeof(sockopt)) != 0)
76 - error("Cannot set SO_REUSEADDR on ip '%s' port's %d.", ip, port);
74 + /* avoid "address already in use" */
75 + if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*)&sockopt, sizeof(sockopt)) != 0)
76 + error("Cannot set SO_REUSEADDR on ip '%s' port's %d.", ip, port);
77
78 - struct sockaddr_in name;
79 - memset(&name, 0, sizeof(struct sockaddr_in));
80 - name.sin_family = AF_INET;
81 - name.sin_port = htons (port);
78 + struct sockaddr_in name;
79 + memset(&name, 0, sizeof(struct sockaddr_in));
80 + name.sin_family = AF_INET;
81 + name.sin_port = htons (port);
82
83 int ret = inet_pton(AF_INET, ip, (void *)&name.sin_addr.s_addr);
84 if(ret != 1) {
@@ -87,34 +87,34 @@ int create_listen_socket4(const char *ip, int port, int listen_backlog) {
87 return -1;
88 }
89
90 - if(bind (sock, (struct sockaddr *) &name, sizeof (name)) < 0) {
91 - close(sock);
92 - error("IPv4 bind() on ip '%s' port %d failed.", ip, port);
93 - return -1;
94 - }
90 + if(bind (sock, (struct sockaddr *) &name, sizeof (name)) < 0) {
91 + close(sock);
92 + error("IPv4 bind() on ip '%s' port %d failed.", ip, port);
93 + return -1;
94 + }
95
96 - if(listen(sock, listen_backlog) < 0) {
97 - close(sock);
98 - fatal("IPv4 listen() on ip '%s' port %d failed.", ip, port);
99 - return -1;
100 - }
96 + if(listen(sock, listen_backlog) < 0) {
97 + close(sock);
98 + fatal("IPv4 listen() on ip '%s' port %d failed.", ip, port);
99 + return -1;
100 + }
101
102 - debug(D_LISTENER, "Listening on IPv4 ip '%s' port %d", ip, port);
103 - return sock;
102 + debug(D_LISTENER, "Listening on IPv4 ip '%s' port %d", ip, port);
103 + return sock;
104 }
105
106 int create_listen_socket6(const char *ip, int port, int listen_backlog) {
107 - int sock = -1;
108 - int sockopt = 1;
107 + int sock = -1;
108 + int sockopt = 1;
109 int ipv6only = 1;
110
111 - debug(D_LISTENER, "IPv6 creating new listening socket on ip '%s' port %d", ip, port);
111 + debug(D_LISTENER, "IPv6 creating new listening socket on ip '%s' port %d", ip, port);
112
113 - sock = socket(AF_INET6, SOCK_STREAM, 0);
114 - if (sock < 0) {
115 - error("IPv6 socket() on ip '%s' port %d failed.", ip, port);
116 - return -1;
117 - }
113 + sock = socket(AF_INET6, SOCK_STREAM, 0);
114 + if (sock < 0) {
115 + error("IPv6 socket() on ip '%s' port %d failed.", ip, port);
116 + return -1;
117 + }
118
119 /* avoid "address already in use" */
120 if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*)&sockopt, sizeof(sockopt)) != 0)
@@ -125,9 +125,9 @@ int create_listen_socket6(const char *ip, int port, int listen_backlog) {
125 error("Cannot set IPV6_V6ONLY on ip '%s' port's %d.", ip, port);
126
127 struct sockaddr_in6 name;
128 - memset(&name, 0, sizeof(struct sockaddr_in6));
129 - name.sin6_family = AF_INET6;
130 - name.sin6_port = htons ((uint16_t) port);
128 + memset(&name, 0, sizeof(struct sockaddr_in6));
129 + name.sin6_family = AF_INET6;
130 + name.sin6_port = htons ((uint16_t) port);
131
132 int ret = inet_pton(AF_INET6, ip, (void *)&name.sin6_addr.s6_addr);
133 if(ret != 1) {
@@ -136,22 +136,22 @@ int create_listen_socket6(const char *ip, int port, int listen_backlog) {
136 return -1;
137 }
138
139 - name.sin6_scope_id = 0;
139 + name.sin6_scope_id = 0;
140
141 - if (bind (sock, (struct sockaddr *) &name, sizeof (name)) < 0) {
142 - close(sock);
143 - error("IPv6 bind() on ip '%s' port %d failed.", ip, port);
144 - return -1;
145 - }
141 + if (bind (sock, (struct sockaddr *) &name, sizeof (name)) < 0) {
142 + close(sock);
143 + error("IPv6 bind() on ip '%s' port %d failed.", ip, port);
144 + return -1;
145 + }
146
147 - if (listen(sock, listen_backlog) < 0) {
148 - close(sock);
149 - error("IPv6 listen() on ip '%s' port %d failed.", ip, port);
150 - return -1;
151 - }
147 + if (listen(sock, listen_backlog) < 0) {
148 + close(sock);
149 + error("IPv6 listen() on ip '%s' port %d failed.", ip, port);
150 + return -1;
151 + }
152
153 - debug(D_LISTENER, "Listening on IPv6 ip '%s' port %d", ip, port);
154 - return sock;
153 + debug(D_LISTENER, "Listening on IPv6 ip '%s' port %d", ip, port);
154 + return sock;
155 }
156
157 static inline int add_listen_socket(int fd, const char *ip, int port) {
@@ -275,13 +275,13 @@ static inline int bind_to_one(const char *definition, int default_port, int list
275 }
276 }
277
278 - freeaddrinfo(result);
278 + freeaddrinfo(result);
279
280 return added;
281 }
282
283 int create_listen_sockets(void) {
284 - listen_backlog = (int) config_get_number("global", "http port listen backlog", LISTEN_BACKLOG);
284 + listen_backlog = (int) config_get_number("global", "http port listen backlog", LISTEN_BACKLOG);
285
286 if(config_exists("global", "bind socket to IP") && !config_exists("global", "bind to"))
287 config_rename("global", "bind socket to IP", "bind to");
@@ -290,11 +290,11 @@ int create_listen_sockets(void) {
290 config_rename("global", "port", "default port");
291
292 listen_port = (int) config_get_number("global", "default port", LISTEN_PORT);
293 - if(listen_port < 1 || listen_port > 65535) {
294 - error("Invalid listen port %d given. Defaulting to %d.", listen_port, LISTEN_PORT);
293 + if(listen_port < 1 || listen_port > 65535) {
294 + error("Invalid listen port %d given. Defaulting to %d.", listen_port, LISTEN_PORT);
295 listen_port = (int) config_set_number("global", "default port", LISTEN_PORT);
296 - }
297 - debug(D_OPTIONS, "Default listen port set to %d.", listen_port);
296 + }
297 + debug(D_OPTIONS, "Default listen port set to %d.", listen_port);
298
299 char *s = config_get("global", "bind to", "*");
300 while(*s) {
@@ -319,27 +319,27 @@ int create_listen_sockets(void) {
319 if(!listen_fds_count)
320 fatal("Cannot listen on any socket. Exiting...");
321
322 - return (int)listen_fds_count;
322 + return (int)listen_fds_count;
323 }
324
325 // --------------------------------------------------------------------------------------
326 // the main socket listener
327
328 static inline void cleanup_web_clients(void) {
329 - struct web_client *w;
330 -
331 - for (w = web_clients; w;) {
332 - if (w->obsolete) {
333 - debug(D_WEB_CLIENT, "%llu: Removing client.", w->id);
334 - // pthread_cancel(w->thread);
335 - // pthread_join(w->thread, NULL);
336 - w = web_client_free(w);
329 + struct web_client *w;
330 +
331 + for (w = web_clients; w;) {
332 + if (w->obsolete) {
333 + debug(D_WEB_CLIENT, "%llu: Removing client.", w->id);
334 + // pthread_cancel(w->thread);
335 + // pthread_join(w->thread, NULL);
336 + w = web_client_free(w);
337 #ifdef NETDATA_INTERNAL_CHECKS
338 - log_allocations();
338 + log_allocations();
339 #endif
340 - }
341 - else w = w->next;
342 - }
340 + }
341 + else w = w->next;
342 + }
343 }
344
345 // 1. it accepts new incoming requests on our port
@@ -350,252 +350,252 @@ static inline void cleanup_web_clients(void) {
350 #define CLEANUP_EVERY_EVENTS 100
351
352 void *socket_listen_main_multi_threaded(void *ptr) {
353 - (void)ptr;
353 + (void)ptr;
354
355 - web_server_mode = WEB_SERVER_MODE_MULTI_THREADED;
356 - info("Multi-threaded WEB SERVER thread created with task id %d", gettid());
355 + web_server_mode = WEB_SERVER_MODE_MULTI_THREADED;
356 + info("Multi-threaded WEB SERVER thread created with task id %d", gettid());
357
358 - struct web_client *w;
359 - int retval, counter = 0;
358 + struct web_client *w;
359 + int retval, counter = 0;
360
361 - if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
362 - error("Cannot set pthread cancel type to DEFERRED.");
361 + if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
362 + error("Cannot set pthread cancel type to DEFERRED.");
363
364 - if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
365 - error("Cannot set pthread cancel state to ENABLE.");
364 + if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
365 + error("Cannot set pthread cancel state to ENABLE.");
366
367 - if(!listen_fds_count)
368 - fatal("LISTENER: No sockets to listen to.");
367 + if(!listen_fds_count)
368 + fatal("LISTENER: No sockets to listen to.");
369
370 - struct pollfd *fds = callocz(sizeof(struct pollfd), listen_fds_count);
370 + struct pollfd *fds = callocz(sizeof(struct pollfd), listen_fds_count);
371
372 - size_t i;
373 - for(i = 0; i < listen_fds_count ;i++) {
374 - fds[i].fd = listen_fds[i];
375 - fds[i].events = POLLIN;
376 - fds[i].revents = 0;
372 + size_t i;
373 + for(i = 0; i < listen_fds_count ;i++) {
374 + fds[i].fd = listen_fds[i];
375 + fds[i].events = POLLIN;
376 + fds[i].revents = 0;
377
378 info("Listening on '%s'", (listen_fds_names[i])?listen_fds_names[i]:"UNKNOWN");
379 }
380
381 - int timeout = 10 * 1000;
382 -
383 - for(;;) {
384 - // debug(D_WEB_CLIENT, "LISTENER: Waiting...");
385 - retval = poll(fds, listen_fds_count, timeout);
386 -
387 - if(unlikely(retval == -1)) {
388 - error("LISTENER: poll() failed.");
389 - continue;
390 - }
391 - else if(unlikely(!retval)) {
392 - debug(D_WEB_CLIENT, "LISTENER: select() timeout.");
393 - counter = 0;
394 - cleanup_web_clients();
395 - continue;
396 - }
397 -
398 - for(i = 0 ; i < listen_fds_count ; i++) {
399 - short int revents = fds[i].revents;
400 -
401 - // check for new incoming connections
402 - if(revents & POLLIN || revents & POLLPRI) {
403 - fds[i].revents = 0;
404 -
405 - w = web_client_create(fds[i].fd);
406 - if(unlikely(!w)) {
407 - // no need for error log - web_client_create already logged the error
408 - continue;
409 - }
410 -
411 - if(pthread_create(&w->thread, NULL, web_client_main, w) != 0) {
412 - error("%llu: failed to create new thread for web client.", w->id);
413 - w->obsolete = 1;
414 - }
415 - else if(pthread_detach(w->thread) != 0) {
416 - error("%llu: Cannot request detach of newly created web client thread.", w->id);
417 - w->obsolete = 1;
418 - }
419 - }
420 - }
421 -
422 - // cleanup unused clients
423 - counter++;
424 - if(counter >= CLEANUP_EVERY_EVENTS) {
425 - counter = 0;
426 - cleanup_web_clients();
427 - }
428 - }
429 -
430 - debug(D_WEB_CLIENT, "LISTENER: exit!");
381 + int timeout = 10 * 1000;
382 +
383 + for(;;) {
384 + // debug(D_WEB_CLIENT, "LISTENER: Waiting...");
385 + retval = poll(fds, listen_fds_count, timeout);
386 +
387 + if(unlikely(retval == -1)) {
388 + error("LISTENER: poll() failed.");
389 + continue;
390 + }
391 + else if(unlikely(!retval)) {
392 + debug(D_WEB_CLIENT, "LISTENER: select() timeout.");
393 + counter = 0;
394 + cleanup_web_clients();
395 + continue;
396 + }
397 +
398 + for(i = 0 ; i < listen_fds_count ; i++) {
399 + short int revents = fds[i].revents;
400 +
401 + // check for new incoming connections
402 + if(revents & POLLIN || revents & POLLPRI) {
403 + fds[i].revents = 0;
404 +
405 + w = web_client_create(fds[i].fd);
406 + if(unlikely(!w)) {
407 + // no need for error log - web_client_create already logged the error
408 + continue;
409 + }
410 +
411 + if(pthread_create(&w->thread, NULL, web_client_main, w) != 0) {
412 + error("%llu: failed to create new thread for web client.", w->id);
413 + w->obsolete = 1;
414 + }
415 + else if(pthread_detach(w->thread) != 0) {
416 + error("%llu: Cannot request detach of newly created web client thread.", w->id);
417 + w->obsolete = 1;
418 + }
419 + }
420 + }
421 +
422 + // cleanup unused clients
423 + counter++;
424 + if(counter >= CLEANUP_EVERY_EVENTS) {
425 + counter = 0;
426 + cleanup_web_clients();
427 + }
428 + }
429 +
430 + debug(D_WEB_CLIENT, "LISTENER: exit!");
431 close_listen_sockets();
432
433 - return NULL;
433 + return NULL;
434 }
435
436 struct web_client *single_threaded_clients[FD_SETSIZE];
437
438 static inline int single_threaded_link_client(struct web_client *w, fd_set *ifds, fd_set *ofds, fd_set *efds, int *max) {
439 - if(unlikely(w->obsolete || w->dead || (!w->wait_receive && !w->wait_send)))
440 - return 1;
439 + if(unlikely(w->obsolete || w->dead || (!w->wait_receive && !w->wait_send)))
440 + return 1;
441
442 - if(unlikely(w->ifd < 0 || w->ifd >= FD_SETSIZE || w->ofd < 0 || w->ofd >= FD_SETSIZE)) {
443 - error("%llu: invalid file descriptor, ifd = %d, ofd = %d (required 0 <= fd < FD_SETSIZE (%d)", w->id, w->ifd, w->ofd, FD_SETSIZE);
444 - return 1;
445 - }
442 + if(unlikely(w->ifd < 0 || w->ifd >= FD_SETSIZE || w->ofd < 0 || w->ofd >= FD_SETSIZE)) {
443 + error("%llu: invalid file descriptor, ifd = %d, ofd = %d (required 0 <= fd < FD_SETSIZE (%d)", w->id, w->ifd, w->ofd, FD_SETSIZE);
444 + return 1;
445 + }
446
447 - FD_SET(w->ifd, efds);
448 - if(unlikely(*max < w->ifd)) *max = w->ifd;
447 + FD_SET(w->ifd, efds);
448 + if(unlikely(*max < w->ifd)) *max = w->ifd;
449
450 - if(unlikely(w->ifd != w->ofd)) {
451 - if(*max < w->ofd) *max = w->ofd;
452 - FD_SET(w->ofd, efds);
453 - }
450 + if(unlikely(w->ifd != w->ofd)) {
451 + if(*max < w->ofd) *max = w->ofd;
452 + FD_SET(w->ofd, efds);
453 + }
454
455 - if(w->wait_receive) FD_SET(w->ifd, ifds);
456 - if(w->wait_send) FD_SET(w->ofd, ofds);
455 + if(w->wait_receive) FD_SET(w->ifd, ifds);
456 + if(w->wait_send) FD_SET(w->ofd, ofds);
457
458 - single_threaded_clients[w->ifd] = w;
459 - single_threaded_clients[w->ofd] = w;
458 + single_threaded_clients[w->ifd] = w;
459 + single_threaded_clients[w->ofd] = w;
460
461 - return 0;
461 + return 0;
462 }
463
464 static inline int single_threaded_unlink_client(struct web_client *w, fd_set *ifds, fd_set *ofds, fd_set *efds) {
465 - FD_CLR(w->ifd, efds);
466 - if(unlikely(w->ifd != w->ofd)) FD_CLR(w->ofd, efds);
465 + FD_CLR(w->ifd, efds);
466 + if(unlikely(w->ifd != w->ofd)) FD_CLR(w->ofd, efds);
467
468 - if(w->wait_receive) FD_CLR(w->ifd, ifds);
469 - if(w->wait_send) FD_CLR(w->ofd, ofds);
468 + if(w->wait_receive) FD_CLR(w->ifd, ifds);
469 + if(w->wait_send) FD_CLR(w->ofd, ofds);
470
471 - single_threaded_clients[w->ifd] = NULL;
472 - single_threaded_clients[w->ofd] = NULL;
471 + single_threaded_clients[w->ifd] = NULL;
472 + single_threaded_clients[w->ofd] = NULL;
473
474 - if(unlikely(w->obsolete || w->dead || (!w->wait_receive && !w->wait_send)))
475 - return 1;
474 + if(unlikely(w->obsolete || w->dead || (!w->wait_receive && !w->wait_send)))
475 + return 1;
476
477 - return 0;
477 + return 0;
478 }
479
480 void *socket_listen_main_single_threaded(void *ptr) {
481 - (void)ptr;
481 + (void)ptr;
482
483 - web_server_mode = WEB_SERVER_MODE_SINGLE_THREADED;
483 + web_server_mode = WEB_SERVER_MODE_SINGLE_THREADED;
484
485 - info("Single-threaded WEB SERVER thread created with task id %d", gettid());
485 + info("Single-threaded WEB SERVER thread created with task id %d", gettid());
486
487 - struct web_client *w;
488 - int retval;
487 + struct web_client *w;
488 + int retval;
489
490 - if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
491 - error("Cannot set pthread cancel type to DEFERRED.");
490 + if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
491 + error("Cannot set pthread cancel type to DEFERRED.");
492
493 - if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
494 - error("Cannot set pthread cancel state to ENABLE.");
493 + if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
494 + error("Cannot set pthread cancel state to ENABLE.");
495
496 - if(!listen_fds_count)
497 - fatal("LISTENER: no listen sockets available.");
496 + if(!listen_fds_count)
497 + fatal("LISTENER: no listen sockets available.");
498
499 size_t i;
500 for(i = 0; i < FD_SETSIZE ; i++)
501 - single_threaded_clients[i] = NULL;
501 + single_threaded_clients[i] = NULL;
502
503 - fd_set ifds, ofds, efds, rifds, rofds, refds;
504 - FD_ZERO (&ifds);
505 - FD_ZERO (&ofds);
506 - FD_ZERO (&efds);
507 - int fdmax = 0;
503 + fd_set ifds, ofds, efds, rifds, rofds, refds;
504 + FD_ZERO (&ifds);
505 + FD_ZERO (&ofds);
506 + FD_ZERO (&efds);
507 + int fdmax = 0;
508
509 - for(i = 0; i < listen_fds_count ; i++) {
510 - if (listen_fds[i] < 0 || listen_fds[i] >= FD_SETSIZE)
511 - fatal("LISTENER: Listen socket %d is not ready, or invalid.", listen_fds[i]);
509 + for(i = 0; i < listen_fds_count ; i++) {
510 + if (listen_fds[i] < 0 || listen_fds[i] >= FD_SETSIZE)
511 + fatal("LISTENER: Listen socket %d is not ready, or invalid.", listen_fds[i]);
512
513 info("Listening on '%s'", (listen_fds_names[i])?listen_fds_names[i]:"UNKNOWN");
514
515 - FD_SET(listen_fds[i], &ifds);
516 - FD_SET(listen_fds[i], &efds);
517 - if(fdmax < listen_fds[i])
515 + FD_SET(listen_fds[i], &ifds);
516 + FD_SET(listen_fds[i], &efds);
517 + if(fdmax < listen_fds[i])
518 fdmax = listen_fds[i];
519 - }
520 -
521 - for(;;) {
522 - debug(D_WEB_CLIENT_ACCESS, "LISTENER: single threaded web server waiting (fdmax = %d)...", fdmax);
523 -
524 - struct timeval tv = { .tv_sec = 1, .tv_usec = 0 };
525 - rifds = ifds;
526 - rofds = ofds;
527 - refds = efds;
528 - retval = select(fdmax+1, &rifds, &rofds, &refds, &tv);
529 -
530 - if(unlikely(retval == -1)) {
531 - error("LISTENER: select() failed.");
532 - continue;
533 - }
534 - else if(likely(retval)) {
535 - debug(D_WEB_CLIENT_ACCESS, "LISTENER: got something.");
536 -
537 - for(i = 0; i < listen_fds_count ; i++) {
538 - if (FD_ISSET(listen_fds[i], &rifds)) {
539 - debug(D_WEB_CLIENT_ACCESS, "LISTENER: new connection.");
540 - w = web_client_create(listen_fds[i]);
541 - if (single_threaded_link_client(w, &ifds, &ofds, &ifds, &fdmax) != 0) {
542 - web_client_free(w);
543 - }
544 - }
545 - }
546 -
547 - for(i = 0 ; i <= (size_t)fdmax ; i++) {
548 - if(likely(!FD_ISSET(i, &rifds) && !FD_ISSET(i, &rofds) && !FD_ISSET(i, &refds)))
549 - continue;
550 -
551 - w = single_threaded_clients[i];
552 - if(unlikely(!w))
553 - continue;
554 -
555 - if(unlikely(single_threaded_unlink_client(w, &ifds, &ofds, &efds) != 0)) {
556 - web_client_free(w);
557 - continue;
558 - }
559 -
560 - if (unlikely(FD_ISSET(w->ifd, &refds) || FD_ISSET(w->ofd, &refds))) {
561 - web_client_free(w);
562 - continue;
563 - }
564 -
565 - if (unlikely(w->wait_receive && FD_ISSET(w->ifd, &rifds))) {
566 - if (unlikely(web_client_receive(w) < 0)) {
567 - web_client_free(w);
568 - continue;
569 - }
570 -
571 - if (w->mode != WEB_CLIENT_MODE_FILECOPY) {
572 - debug(D_WEB_CLIENT, "%llu: Processing received data.", w->id);
573 - web_client_process(w);
574 - }
575 - }
576 -
577 - if (unlikely(w->wait_send && FD_ISSET(w->ofd, &rofds))) {
578 - if (unlikely(web_client_send(w) < 0)) {
579 - debug(D_WEB_CLIENT, "%llu: Cannot send data to client. Closing client.", w->id);
580 - web_client_free(w);
581 - continue;
582 - }
583 - }
584 -
585 - if(unlikely(single_threaded_link_client(w, &ifds, &ofds, &efds, &fdmax) != 0)) {
586 - web_client_free(w);
587 - }
588 - }
589 - }
590 - else {
591 - debug(D_WEB_CLIENT_ACCESS, "LISTENER: single threaded web server timeout.");
519 + }
520 +
521 + for(;;) {
522 + debug(D_WEB_CLIENT_ACCESS, "LISTENER: single threaded web server waiting (fdmax = %d)...", fdmax);
523 +
524 + struct timeval tv = { .tv_sec = 1, .tv_usec = 0 };
525 + rifds = ifds;
526 + rofds = ofds;
527 + refds = efds;
528 + retval = select(fdmax+1, &rifds, &rofds, &refds, &tv);
529 +
530 + if(unlikely(retval == -1)) {
531 + error("LISTENER: select() failed.");
532 + continue;
533 + }
534 + else if(likely(retval)) {
535 + debug(D_WEB_CLIENT_ACCESS, "LISTENER: got something.");
536 +
537 + for(i = 0; i < listen_fds_count ; i++) {
538 + if (FD_ISSET(listen_fds[i], &rifds)) {
539 + debug(D_WEB_CLIENT_ACCESS, "LISTENER: new connection.");
540 + w = web_client_create(listen_fds[i]);
541 + if (single_threaded_link_client(w, &ifds, &ofds, &ifds, &fdmax) != 0) {
542 + web_client_free(w);
543 + }
544 + }
545 + }
546 +
547 + for(i = 0 ; i <= (size_t)fdmax ; i++) {
548 + if(likely(!FD_ISSET(i, &rifds) && !FD_ISSET(i, &rofds) && !FD_ISSET(i, &refds)))
549 + continue;
550 +
551 + w = single_threaded_clients[i];
552 + if(unlikely(!w))
553 + continue;
554 +
555 + if(unlikely(single_threaded_unlink_client(w, &ifds, &ofds, &efds) != 0)) {
556 + web_client_free(w);
557 + continue;
558 + }
559 +
560 + if (unlikely(FD_ISSET(w->ifd, &refds) || FD_ISSET(w->ofd, &refds))) {
561 + web_client_free(w);
562 + continue;
563 + }
564 +
565 + if (unlikely(w->wait_receive && FD_ISSET(w->ifd, &rifds))) {
566 + if (unlikely(web_client_receive(w) < 0)) {
567 + web_client_free(w);
568 + continue;
569 + }
570 +
571 + if (w->mode != WEB_CLIENT_MODE_FILECOPY) {
572 + debug(D_WEB_CLIENT, "%llu: Processing received data.", w->id);
573 + web_client_process(w);
574 + }
575 + }
576 +
577 + if (unlikely(w->wait_send && FD_ISSET(w->ofd, &rofds))) {
578 + if (unlikely(web_client_send(w) < 0)) {
579 + debug(D_WEB_CLIENT, "%llu: Cannot send data to client. Closing client.", w->id);
580 + web_client_free(w);
581 + continue;
582 + }
583 + }
584 +
585 + if(unlikely(single_threaded_link_client(w, &ifds, &ofds, &efds, &fdmax) != 0)) {
586 + web_client_free(w);
587 + }
588 + }
589 + }
590 + else {
591 + debug(D_WEB_CLIENT_ACCESS, "LISTENER: single threaded web server timeout.");
592 #ifdef NETDATA_INTERNAL_CHECKS
593 - log_allocations();
593 + log_allocations();
594 #endif
595 - }
596 - }
595 + }
596 + }
597
598 - debug(D_WEB_CLIENT, "LISTENER: exit!");
598 + debug(D_WEB_CLIENT, "LISTENER: exit!");
599 close_listen_sockets();
600 - return NULL;
600 + return NULL;
601 }
src/web_server.h
+4 -4
@@ -1,10 +1,10 @@
1 #ifndef NETDATA_WEB_SERVER_H
2 #define NETDATA_WEB_SERVER_H 1
3
4 -#define WEB_PATH_FILE "file"
5 -#define WEB_PATH_DATA "data"
6 -#define WEB_PATH_DATASOURCE "datasource"
7 -#define WEB_PATH_GRAPH "graph"
4 +#define WEB_PATH_FILE "file"
5 +#define WEB_PATH_DATA "data"
6 +#define WEB_PATH_DATASOURCE "datasource"
7 +#define WEB_PATH_GRAPH "graph"
8
9 #define LISTEN_PORT 19999
10 #define LISTEN_BACKLOG 100