echo >&2 "Cleaning a possibly old compilation ..."
make clean || exit 1
- echo >&2 "Compiling netdata ..."
- make || exit 1
fi
+echo >&2 "Compiling netdata ..."
+make || exit 1
+
if [ -z "${netdata}" -o src/netdata -nt "${netdata}" ]
then
echo >&2 "Installing netdata ..."
netdata=$(which netdata)
-base="`dirname "$0"`"
-
-if [ ! -d "${base}" ]
-then
- echo >&2 "Cannot find my home directory '${base}'."
- exit 1
-fi
-cd "${base}" || exit 1
-
# -----------------------------------------------------------------------------
# load options from the configuration file
if [ -s "/etc/netdata/netdata.conf" ]
then
- line="$( grep "^[[:space:]]*${key}[[:space:]]*=[[:space:]]*" "conf.d/netdata.conf" | head -n 1 )"
+ line="$( grep "^[[:space:]]*${key}[[:space:]]*=[[:space:]]*" "/etc/netdata/netdata.conf" | head -n 1 )"
[ ! -z "${line}" ] && value="$( echo "${line}" | cut -d '=' -f 2 | sed -e "s/^[[:space:]]\+//g" -e "s/[[:space:]]\+$//g" )"
fi
NETDATA_PORT="$( config_option "port" ${defport} )"
# directories
-NETDATA_CACHE_DIR="$( config_option "database directory" "/var/cache/netdata" )"
+NETDATA_CACHE_DIR="$( config_option "cache directory" "/var/cache/netdata" )"
NETDATA_WEB_DIR="$( config_option "web files directory" "/usr/share/netdata/web" )"
-NETDATA_LOG_DIR="log"
-NETDATA_CONF_DIR="conf.d"
+NETDATA_LOG_DIR="$( config_option "log directory" "/var/log/netdata" )"
+NETDATA_CONF_DIR="$( config_option "config directory" "/etc/netdata" )"
# -----------------------------------------------------------------------------
do
if [ ! -d "${x}" ]
then
- mkdir "${x}" || exit 1
+ echo >&2 "Creating directory '${x}'"
+ mkdir -p "${x}" || exit 1
fi
chown -R "${NETDATA_USER}" "${x}" || echo >&2 "WARNING: Cannot change the ownership of the files in directory ${x} to ${NETDATA_USER}..."
chmod 0775 "${x}" "${x}" || echo >&2 "WARNING: Cannot change the permissions of the directory ${x} to 0755..."
# -----------------------------------------------------------------------------
# run netdata
-# avoid extended stat(/etc/localtime)
-# http://stackoverflow.com/questions/4554271/how-to-avoid-excessive-stat-etc-localtime-calls-in-strftime-on-linux
-export TZ=":/etc/localtime"
-
echo >&2 "Starting netdata..."
netdata "${@}"
#!/bin/bash
+PROGRAM_FILE="$0"
+PROGRAM_NAME="charts.d"
+echo >&2 "$PROGRAM_NAME: started from '$PROGRAM_FILE' with options: $*"
+
+if [ $(( ${BASH_VERSINFO[0]} )) -lt 4 ]
+then
+ echo >&2
+ echo >&2 "$PROGRAM_NAME: ERROR"
+ echo >&2 "BASH version 4 or later is required."
+ echo >&2 "You are running version: ${BASH_VERSION}"
+ echo >&2 "Please upgrade."
+ echo >&2
+ exit 1
+fi
+
+# check a few commands
+require_cmd() {
+ which "$1" >/dev/null
+ if [ $? -ne 0 ]
+ then
+ echo >&2 "$PROGRAM_NAME: ERROR: Command '$1' is not found in the system path."
+ return 1
+ fi
+ return 0
+}
+
+require_cmd date || exit 1
+require_cmd sed || exit 1
+require_cmd basename || exit 1
+require_cmd dirname || exit 1
+require_cmd cat || exit 1
+require_cmd grep || exit 1
+require_cmd mktemp || exit 1
+
# -----------------------------------------------------------------------------
# insternal defaults
+# netdata exposes a few environment variables for us
pause_method="sleep" # use either "suspend" or "sleep"
# DO NOT USE SUSPEND - LINUX WILL SUSPEND NETDATA TOO
# THE WHOLE PROCESS GROUP - NOT JUST THE SHELL
-pluginsd="plugins.d"
-confd="conf.d"
-chartsd="charts.d"
+pluginsd="${NETDATA_PLUGINS_DIR}"
+[ -z "$pluginsd" ] && pluginsd="$( dirname $PROGRAM_FILE )"
+
+confd="${NETDATA_CONFIG_DIR-/etc/netdata}"
+chartsd="$pluginsd/../charts.d"
myconfig="$confd/charts.d.conf"
-minimum_update_frequency=1
-update_every=1 # this is overwritten by the command line
+
+minimum_update_frequency="${NETDATA_UPDATE_EVERY-1}"
+update_every=${minimum_update_frequency} # this will be overwritten by the command line
# work around for non BASH shells
charts_create="_create"
continue
fi
- if [ -f "$1" ]
- then
- debug=1
- chart_only="$( basename "$1" | sed "s/\.chart\.sh$//g" )"
- shift
- continue
- fi
-
# number check
n="$1"
- x=$((n + 1 - 1))
+ x=$(( n ))
if [ "$x" = "$n" ]
then
- update_every=$x
shift
+ update_every=$x
continue
fi
. "$myconfig"
if [ $? -ne 0 ]
then
- echo >&2 "charts.d: cannot load $myconfig"
+ echo >&2 "$PROGRAM_NAME: cannot load $myconfig"
echo "DISABLE"
exit 1
fi
# check the charts.d directory
if [ ! -d "$chartsd" ]
then
- echo >&2 "charts.d: cannot find charts directory '$chartsd'"
+ echo >&2 "$PROGRAM_NAME: cannot find charts directory '$chartsd'"
echo "DISABLE"
fi
loopsleepms() {
sleep $1
}
+
+now_ms=
+current_time_ms() {
+ now_ms="$(date +'%s')000"
+}
+
# if found and included, this file overwrites loopsleepms()
-# with a high resolution timer function for precise looping.
-. "$( dirname $0 )/loopsleepms.sh.inc"
+# and current_time_ms() with a high resolution timer function
+# for precise looping.
+. "$pluginsd/loopsleepms.sh.inc"
# -----------------------------------------------------------------------------
all_charts() {
cd "$chartsd"
+ [ $? -ne 0 ] && echo >&2 "$PROGRAM_NAME: Cannot cd to $chartsd" && return 1
+
ls *.chart.sh | sed "s/\.chart\.sh$//g"
}
eval "enabled=\$$chart"
if [ "$enabled" = "yes" ]
then
+ [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: '$chart' is enabled."
local charts="$charts $chart"
else
- echo >&2 "charts.d: chart '$chart' is NOT enabled. Add a line with $chart=yes in $myconfig to enable it."
+ echo >&2 "$PROGRAM_NAME: '$chart' is NOT enabled. Add a line with $chart=yes in $myconfig to enable it."
fi
done
local check="$( cat "$chartsd/$chart.chart.sh" | sed "s/^ \+//g" | grep "^$chart$charts_check()" )"
if [ -z "$check" ]
then
- echo >&2 "charts.d: chart '$chart' does not seem to have a $chart$charts_check() function. Disabling it."
+ echo >&2 "$PROGRAM_NAME: chart '$chart' does not seem to have a $chart$charts_check() function. Disabling it."
continue
fi
local create="$( cat "$chartsd/$chart.chart.sh" | sed "s/^ \+//g" | grep "^$chart$charts_create()" )"
if [ -z "$create" ]
then
- echo >&2 "charts.d: chart '$chart' does not seem to have a $chart$charts_create() function. Disabling it."
+ echo >&2 "$PROGRAM_NAME: chart '$chart' does not seem to have a $chart$charts_create() function. Disabling it."
continue
fi
local update="$( cat "$chartsd/$chart.chart.sh" | sed "s/^ \+//g" | grep "^$chart$charts_update()" )"
if [ -z "$update" ]
then
- echo >&2 "charts.d: chart '$chart' does not seem to have a $chart$charts_update() function. Disabling it."
+ echo >&2 "$PROGRAM_NAME: chart '$chart' does not seem to have a $chart$charts_update() function. Disabling it."
continue
fi
# check its config
- if [ -f "$confd/$chart.conf" ]
- then
- if [ ! -z "$( cat "$confd/$chart.conf" | sed "s/^ \+//g" | grep -v "^$" | grep -v "^#" | grep -v "^$chart$charts_undescore" )" ]
- then
- echo >&2 "charts.d: chart's $chart config $confd/$chart.conf should only have lines starting with $chart$charts_undescore . Disabling it."
- continue
- fi
- fi
+ #if [ -f "$confd/$chart.conf" ]
+ #then
+ # if [ ! -z "$( cat "$confd/$chart.conf" | sed "s/^ \+//g" | grep -v "^$" | grep -v "^#" | grep -v "^$chart$charts_undescore" )" ]
+ # then
+ # echo >&2 "$PROGRAM_NAME: chart's $chart config $confd/$chart.conf should only have lines starting with $chart$charts_undescore . Disabling it."
+ # continue
+ # fi
+ #fi
"$pluginsd/charts.d.dryrun-helper.sh" "$chart" "$chartsd/$chart.chart.sh" "$confd/$chart.conf" >/dev/null
if [ $? -ne 0 ]
then
- echo >&2 "charts.d: chart's $chart did not pass the dry run check. This means it uses global variables not starting with $chart. Disabling it."
+ 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."
continue
fi
done
echo $charts2
+ [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: enabled charts: $charts2"
}
active_charts=
for chart in $( all_enabled_charts )
do
+ [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: loading chart: '$chartsd/$chart.chart.sh'"
. "$chartsd/$chart.chart.sh"
if [ -f "$confd/$chart.conf" ]
then
+ [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: loading chart options: '$confd/$chart.conf'"
. "$confd/$chart.conf"
fi
$chart$charts_check
if [ $? -eq 0 ]
then
+ [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: '$chart' activated"
active_charts="$active_charts $chart"
else
- echo >&2 "charts.d: chart '$chart' check() function reports failure."
+ echo >&2 "$PROGRAM_NAME: chart '$chart' check() function reports failure."
fi
done
+[ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: activated charts: $active_charts"
# -----------------------------------------------------------------------------
test $debug -eq 1 && debug_time=tellwork
# if we only need a specific chart, remove all the others
-if [ ! -z "$chart_only" ]
+if [ ! -z "${chart_only}" ]
then
+ [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: requested to run only for: '${chart_only}'"
check_charts=
for chart in $active_charts
do
done
active_charts="$check_charts"
fi
+[ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: activated charts: $active_charts"
# stop if we just need a pre-check
if [ $check -eq 1 ]
then
- echo "CHECK RESULT"
- echo "Will run the charts: $active_charts"
+ echo >&2 "CHECK RESULT"
+ echo >&2 "Will run the charts: $active_charts"
exit 0
fi
TMP_DIR=
chartsd_cleanup() {
+ cd /tmp
if [ ! -z "$TMP_DIR" -a -d "$TMP_DIR" ]
then
- echo >&2 "charts.d: cleaning up temporary directory $TMP_DIR ..."
+ [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: cleaning up temporary directory $TMP_DIR ..."
rm -rf "$TMP_DIR"
fi
exit 0
TMP_DIR="$( mktemp -d /tmp/.netdata-charts.d-XXXXXXXXXX )"
fi
+cd "$TMP_DIR" || exit 1
+
# -----------------------------------------------------------------------------
# library functions
run_charts=
for chart in $active_charts
do
+ [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: Calling '$chart$charts_create()'..."
$chart$charts_create
if [ $? -eq 0 ]
then
run_charts="$run_charts $chart"
+ [ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: '$chart' has initialized."
else
- echo >&2 "charts.d: chart '$chart' create() function reports failure."
+ echo >&2 "$PROGRAM_NAME: chart '$chart' function '$chart$charts_create()' reports failure."
fi
done
+[ $debug -eq 1 ] && echo >&2 "$PROGRAM_NAME: run_charts='$run_charts'"
# -----------------------------------------------------------------------------
# update dimensions
+declare -A charts_last_update=() charts_min_dt=()
global_update() {
- local exit_after=$((3600 / update_every))
+ local exit_after=$((3600 / update_every)) \
+ c=0 dt \
+ chart now_charts=() next_charts=($run_charts)
# return the current time in ms in $now_ms
current_time_ms
- local chart=
- for chart in $now_charts
+ for chart in $run_charts
do
- eval "local last_update_$chart=\$((now_ms - ($chart$suffix_update_every * 1000) ))"
+ eval "charts_min_dt[$chart]=\$$chart$suffix_update_every"
+ test -z "${charts_min_dt[$chart]}" && charts_min_dt[$charts]=$update_every
+ charts_last_update[$chart]=$((now_ms - (charts_min_dt[$chart] * 1000) ))
done
# the main loop
- local c=0
while [ 1 ]
do
- local c=$((c + 1))
- local now_charts="$run_charts"
- local run_charts=
+ c=$((c + 1))
+ now_charts=("${next_charts[@]}")
+ next_charts=()
- local chart=
- for chart in $now_charts
+ for chart in "${now_charts[@]}"
do
# return the current time in ms in $now_ms
current_time_ms
- eval "local chart_min_dt=\$$chart$suffix_update_every"
- test -z "$chart_min_dt" && local chart_min_dt=$update_every
- local chart_min_dt=$((chart_min_dt * 1000000))
-
- eval "local last=\$last_update_$chart"
- test -z "$last" && local last=$((now_ms - (chart_min_dt / 1000) ))
-
- local dt=$(( (now_ms - last) * 1000 ))
- if [ $dt -ge $chart_min_dt ]
+ dt=$(( (now_ms - charts_last_update[$chart]) * 1000 ))
+ if [ $dt -ge $(( charts_min_dt[$chart] * 1000000 )) ]
then
- eval "last_update_$chart=$now_ms"
+ charts_last_update[$chart]=$now_ms
# the first call should not give a duration
# so that netdata calibrates to current time
- test $c -eq 1 && local dt=
+ test $c -eq 1 && dt=
$chart$charts_update $dt
if [ $? -eq 0 ]
then
- run_charts="$run_charts $chart"
+ next_charts+=($chart)
else
- echo >&2 "charts.d: chart '$chart' update() function reports failure. Disabling it."
+ echo >&2 "$PROGRAM_NAME: chart '$chart' update() function reports failure. Disabling it."
fi
else
- run_charts="$run_charts $chart"
+ next_charts+=($chart)
fi
done
if [ "$pause_method" = "suspend" ]
then
echo "STOPPING_WAKE_ME_UP_PLEASE"
- suspend || ( echo >&2 "suspend returned error $?, falling back to sleep."; loopsleepms $debug_time $update_every )
+ suspend || ( echo >&2 "$PROGRAM_NAME: suspend returned error $?, falling back to sleep."; loopsleepms $debug_time $update_every )
else
# wait the time you are required to
loopsleepms $debug_time $update_every
+#!/bin/bash
+
# this function is used to sleep a fraction of a second
# it calculates the difference between every time is called
# and tries to align the sleep time to give you exactly the
# loop you need.
-LOOPSLEEPMS_HIGHRES=2
+LOOPSLEEP_DATE="$(which date)"
+if [ -z "$LOOPSLEEP_DATE" ]
+ then
+ echo >&2 "$0: ERROR: Cannot find the command 'date' in the system path."
+ exit 1
+fi
+
LOOPSLEEPMS_LASTRUN=0
LOOPSLEEPMS_LASTSLEEP=0
LOOPSLEEPMS_LASTWORK=0
-check_high_res() {
- LOOPSLEEPMS_HIGHRES=1
- test `date +%N` = "%N" && LOOPSLEEPMS_HIGHRES=0
-}
+LOOPSLEEPMS_HIGHRES=1
+test "$($LOOPSLEEP_DATE +%N)" = "%N" && LOOPSLEEPMS_HIGHRES=0
now_ms=
current_time_ms() {
- # check if high resolution timer is supported
- test $LOOPSLEEPMS_HIGHRES -eq 2 && check_high_res
-
# if high resolution is not supported
# just sleep the time requested, in seconds
if [ $LOOPSLEEPMS_HIGHRES -eq 0 ]
then
- local s="`date +'%s'`"
- local m="000"
+ now_ms="$($LOOPSLEEP_DATE +'%s')000"
else
- local d="`date +'%s.%N'`"
- local s="`echo $d | cut -d '.' -f 1`"
- local m="`echo $d | cut -d '.' -f 2 | cut -b 1-3`"
+ now_ms="$(( $( $LOOPSLEEP_DATE +'%s * 1000 + %-N / 1000000' ) ))"
fi
- now_ms="$s$m"
}
loopsleepms() {
- tellwork=0
- if [ "$1" = "tellwork" ]
+ local tellwork=0 t="$1" s m now mstosleep
+
+ if [ "$t" = "tellwork" ]
then
- local tellwork=1
+ tellwork=1
shift
+ t="$1"
fi
- # the time in seconds to wait, as the first argument
- local t=$1
-
- # check if high resolution timer is supported
- test $LOOPSLEEPMS_HIGHRES -eq 2 && check_high_res
+ # $t = the time in seconds to wait
# if high resolution is not supported
# just sleep the time requested, in seconds
return
fi
- # get the current time
- local d="`date +'%s.%N'`"
- local s="`echo $d | cut -d '.' -f 1`"
- local m="`echo $d | cut -d '.' -f 2 | cut -b 1-3`"
- local now="$s$m" # milliseconds since epoch (1-1-1970)
+ # get the current time, in ms
+ # milliseconds since epoch (1-1-1970)
+ now="$(( $( $LOOPSLEEP_DATE +'%s * 1000 + %-N / 1000000' ) ))"
# calculate required sleep in ms
t=$((t * 1000))
test $tellwork -eq 1 && echo >&2 " >>> PERFORMANCE >>> WORK TOOK $LOOPSLEEPMS_LASTWORK ms ( $((LOOPSLEEPMS_LASTWORK * 100 / 1000)).$((LOOPSLEEPMS_LASTWORK % 10))% cpu )"
# calculate ms to sleep
- local mstosleep=$((t - LOOPSLEEPMS_LASTWORK))
+ mstosleep=$((t - LOOPSLEEPMS_LASTWORK))
# echo "# mstosleep is $mstosleep ms"
# if we are too slow, sleep some time
test $mstosleep -lt $((t / 2)) && mstosleep=$((t / 2))
- local s=$((mstosleep / 1000))
- local m=$((mstosleep - (s * 1000)))
+ s=$((mstosleep / 1000))
+ m=$((mstosleep - (s * 1000)))
# echo "# sleeping $s.$m"
# echo
if(!config_loaded) load_config(NULL, 0);
+ // prepare configuration environment variables for the plugins
+ setenv("NETDATA_CONFIG_DIR" , config_get("global", "config directory" , CONFIG_DIR) , 1);
+ setenv("NETDATA_PLUGINS_DIR", config_get("global", "plugins directory" , PLUGINS_DIR), 1);
+ setenv("NETDATA_WEB_DIR" , config_get("global", "web files directory", WEB_DIR) , 1);
+ setenv("NETDATA_CACHE_DIR" , config_get("global", "cache directory" , CACHE_DIR) , 1);
+ setenv("NETDATA_LOG_DIR" , config_get("global", "log directory" , LOG_DIR) , 1);
+
+ // avoid extended to stat(/etc/localtime)
+ // http://stackoverflow.com/questions/4554271/how-to-avoid-excessive-stat-etc-localtime-calls-in-strftime-on-linux
+ setenv("TZ", ":/etc/localtime", 0);
+
+ // cd to /tmp to avoid any plugins writing files at random places
+ if(chdir("/tmp")) fprintf(stderr, "netdata: ERROR: Cannot cd to /tmp: %s", strerror(errno));
+
char *input_log_file = NULL;
char *output_log_file = NULL;
char *error_log_file = NULL;
sprintf(buffer, "0x%08llx", 0ULL);
char *flags = config_get("global", "debug flags", buffer);
+ setenv("NETDATA_DEBUG_FLAGS", flags, 1);
+
debug_flags = strtoull(flags, NULL, 0);
debug(D_OPTIONS, "Debug flags set to '0x%8llx'.", debug_flags);
// --------------------------------------------------------------------
global_host_prefix = config_get("global", "host access prefix", "");
+ setenv("NETDATA_HOST_PREFIX", global_host_prefix, 1);
// --------------------------------------------------------------------
}
else debug(D_OPTIONS, "update timer set to %d.", rrd_update_every);
+ // let the plugins know the min update_every
+ {
+ char buffer[50];
+ snprintf(buffer, 50, "%d", rrd_update_every);
+ setenv("NETDATA_UPDATE_EVERY", buffer, 1);
+ }
+
// --------------------------------------------------------------------
for (i = 0; static_threads[i].name != NULL ; i++) {
char *ret = NULL;
static char *cache_dir = NULL;
- if(!cache_dir) cache_dir = config_get("global", "database directory", CACHE_DIR);
+ if(!cache_dir) cache_dir = config_get("global", "cache directory", CACHE_DIR);
char b[FILENAME_MAX + 1];
char n[FILENAME_MAX + 1];
rrdset_strncpy_name(b, id, FILENAME_MAX);
snprintf(n, FILENAME_MAX, "%s/%s", cache_dir, b);
- ret = config_get(id, "database directory", n);
+ ret = config_get(id, "cache directory", n);
if(rrd_memory_mode == RRD_MEMORY_MODE_MAP || rrd_memory_mode == RRD_MEMORY_MODE_SAVE) {
int r = mkdir(ret, 0775);
// if the new is smaller than the old (an overflow, or reset), set the old equal to the new
// to reset the calculation (it will give zero as the calculation for this second)
if(unlikely(rd->last_collected_value > rd->collected_value)) {
- info("%s.%s: Detect RESET or OVERFLOW. Last collected value = " COLLECTED_NUMBER_FORMAT ", current = " COLLECTED_NUMBER_FORMAT
+ debug(D_RRD_STATS, "%s.%s: Detect RESET or OVERFLOW. Last collected value = " COLLECTED_NUMBER_FORMAT ", current = " COLLECTED_NUMBER_FORMAT
, st->name, rd->name
, rd->last_collected_value
, rd->collected_value);