mirror of
https://github.com/netdata/netdata.git
synced 2025-04-14 09:38:34 +00:00
315 lines
7.7 KiB
Bash
Executable file
315 lines
7.7 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
|
|
# netdata
|
|
# real-time performance and health monitoring, done right!
|
|
# (C) 2017 Costa Tsaousis <costa@tsaousis.gr>
|
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
#
|
|
# This script is a helper to allow netdata collect tc data.
|
|
# tc output parsing has been implemented in C, inside netdata
|
|
# This script allows setting names to dimensions.
|
|
|
|
export PATH="${PATH}:/sbin:/usr/sbin:/usr/local/sbin"
|
|
export LC_ALL=C
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# logging functions
|
|
|
|
PROGRAM_FILE="$0"
|
|
PROGRAM_NAME="$(basename $0)"
|
|
PROGRAM_NAME="${PROGRAM_NAME/.plugin}"
|
|
|
|
logdate() {
|
|
date "+%Y-%m-%d %H:%M:%S"
|
|
}
|
|
|
|
log() {
|
|
local status="${1}"
|
|
shift
|
|
|
|
echo >&2 "$(logdate): ${PROGRAM_NAME}: ${status}: ${*}"
|
|
|
|
}
|
|
|
|
warning() {
|
|
log WARNING "${@}"
|
|
}
|
|
|
|
error() {
|
|
log ERROR "${@}"
|
|
}
|
|
|
|
info() {
|
|
log INFO "${@}"
|
|
}
|
|
|
|
fatal() {
|
|
log FATAL "${@}"
|
|
exit 1
|
|
}
|
|
|
|
debug=0
|
|
debug() {
|
|
[ $debug -eq 1 ] && log DEBUG "${@}"
|
|
}
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# find /var/run/fireqos
|
|
|
|
# the default
|
|
fireqos_run_dir="/var/run/fireqos"
|
|
|
|
function realdir {
|
|
local r="$1"
|
|
local t=$(readlink "$r")
|
|
|
|
while [ "$t" ]
|
|
do
|
|
r=$(cd $(dirname "$r") && cd $(dirname "$t") && pwd -P)/$(basename "$t")
|
|
t=$(readlink "$r")
|
|
done
|
|
|
|
dirname "$r"
|
|
}
|
|
|
|
if [ ! -d "${fireqos_run_dir}" ]
|
|
then
|
|
|
|
# the fireqos executable - we will use it to find its config
|
|
fireqos="$(which fireqos 2>/dev/null || command -v fireqos 2>/dev/null)"
|
|
|
|
if [ ! -z "${fireqos}" ]
|
|
then
|
|
|
|
fireqos_exec_dir="$(realdir ${fireqos})"
|
|
|
|
if [ ! -z "${fireqos_exec_dir}" -a "${fireqos_exec_dir}" != "." -a -f "${fireqos_exec_dir}/install.config" ]
|
|
then
|
|
|
|
LOCALSTATEDIR=
|
|
source "${fireqos_exec_dir}/install.config"
|
|
|
|
if [ -d "${LOCALSTATEDIR}/run/fireqos" ]
|
|
then
|
|
fireqos_run_dir="${LOCALSTATEDIR}/run/fireqos"
|
|
else
|
|
warning "FireQoS is installed as '${fireqos}', its installation config at '${fireqos_exec_dir}/install.config' specifies local state data at '${LOCALSTATEDIR}/run/fireqos', but this directory is not found or is not readable (check the permissions of its parents)."
|
|
fi
|
|
else
|
|
warning "Although FireQoS is installed on this system as '${fireqos}', I cannot find/read its installation configuration at '${fireqos_exec_dir}/install.config'."
|
|
fi
|
|
else
|
|
warning "FireQoS is not installed on this system. Use FireQoS to apply traffic QoS and expose the class names to netdata. Check https://github.com/netdata/netdata/wiki/You-should-install-QoS-on-all-your-servers"
|
|
fi
|
|
fi
|
|
|
|
# -----------------------------------------------------------------------------
|
|
|
|
[ -z "${NETDATA_PLUGINS_DIR}" ] && NETDATA_PLUGINS_DIR="$(dirname "${0}")"
|
|
[ -z "${NETDATA_USER_CONFIG_DIR}" ] && NETDATA_USER_CONFIG_DIR="@configdir_POST@"
|
|
[ -z "${NETDATA_STOCK_CONFIG_DIR}" ] && NETDATA_STOCK_CONFIG_DIR="@libconfigdir_POST@"
|
|
|
|
plugins_dir="${NETDATA_PLUGINS_DIR}"
|
|
tc="$(which tc 2>/dev/null || command -v tc 2>/dev/null)"
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# user configuration
|
|
|
|
# time in seconds to refresh QoS class/qdisc names
|
|
qos_get_class_names_every=120
|
|
|
|
# time in seconds to exit - netdata will restart the script
|
|
qos_exit_every=3600
|
|
|
|
# what to use? classes or qdiscs?
|
|
tc_show="qdisc" # can also be "class"
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# check if we have a valid number for interval
|
|
|
|
t=${1}
|
|
update_every=$((t))
|
|
[ $((update_every)) -lt 1 ] && update_every=${NETDATA_UPDATE_EVERY}
|
|
[ $((update_every)) -lt 1 ] && update_every=1
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# allow the user to override our defaults
|
|
|
|
for CONFIG in "${NETDATA_STOCK_CONFIG_DIR}/tc-qos-helper.conf" "${NETDATA_USER_CONFIG_DIR}/tc-qos-helper.conf"
|
|
do
|
|
if [ -f "${CONFIG}" ]
|
|
then
|
|
info "Loading config file '${CONFIG}'..."
|
|
source "${CONFIG}"
|
|
[ $? -ne 0 ] && error "Failed to load config file '${CONFIG}'."
|
|
else
|
|
warning "Cannot find file '${CONFIG}'."
|
|
fi
|
|
done
|
|
|
|
case "${tc_show}" in
|
|
qdisc|class)
|
|
;;
|
|
|
|
*)
|
|
error "tc_show variable can be either 'qdisc' or 'class' but is set to '${tc_show}'. Assuming it is 'qdisc'."
|
|
tc_show="qdisc"
|
|
;;
|
|
esac
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# default sleep function
|
|
|
|
LOOPSLEEPMS_LASTWORK=0
|
|
loopsleepms() {
|
|
sleep $1
|
|
}
|
|
|
|
# if found and included, this file overwrites loopsleepms()
|
|
# with a high resolution timer function for precise looping.
|
|
. "${plugins_dir}/loopsleepms.sh.inc"
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# final checks we can run
|
|
|
|
if [ -z "${tc}" -o ! -x "${tc}" ]
|
|
then
|
|
fatal "cannot find command 'tc' in this system."
|
|
fi
|
|
|
|
tc_devices=
|
|
fix_names=
|
|
|
|
# -----------------------------------------------------------------------------
|
|
|
|
setclassname() {
|
|
if [ "${tc_show}" = "qdisc" ]
|
|
then
|
|
echo "SETCLASSNAME $4 $2"
|
|
else
|
|
echo "SETCLASSNAME $3 $2"
|
|
fi
|
|
}
|
|
|
|
show_tc_cls() {
|
|
[ "${tc_show}" = "qdisc" ] && return 1
|
|
|
|
local x="${1}"
|
|
|
|
if [ -f /etc/iproute2/tc_cls ]
|
|
then
|
|
local classid name rest
|
|
while read classid name rest
|
|
do
|
|
[ -z "${classid}" -o -z "${name}" -o "${classid}" = "#" -o "${name}" = "#" -o "${classid:0:1}" = "#" -o "${name:0:1}" = "#" ] && continue
|
|
setclassname "" "${name}" "${classid}"
|
|
done </etc/iproute2/tc_cls
|
|
return 0
|
|
fi
|
|
return 1
|
|
}
|
|
|
|
show_fireqos_names() {
|
|
local x="${1}" name n interface_dev interface_classes interface_classes_monitor
|
|
|
|
if [ -f "${fireqos_run_dir}/ifaces/${x}" ]
|
|
then
|
|
name="$(<"${fireqos_run_dir}/ifaces/${x}")"
|
|
echo "SETDEVICENAME ${name}"
|
|
|
|
interface_dev=
|
|
interface_classes=
|
|
interface_classes_monitor=
|
|
source "${fireqos_run_dir}/${name}.conf"
|
|
for n in ${interface_classes_monitor}
|
|
do
|
|
setclassname ${n//|/ }
|
|
done
|
|
[ ! -z "${interface_dev}" ] && echo "SETDEVICEGROUP ${interface_dev}"
|
|
|
|
return 0
|
|
fi
|
|
|
|
return 1
|
|
}
|
|
|
|
show_tc() {
|
|
local x="${1}"
|
|
|
|
echo "BEGIN ${x}"
|
|
|
|
# netdata can parse the output of tc
|
|
${tc} -s ${tc_show} show dev ${x}
|
|
|
|
# check FireQOS names for classes
|
|
if [ ! -z "${fix_names}" ]
|
|
then
|
|
show_fireqos_names "${x}" || show_tc_cls "${x}"
|
|
fi
|
|
|
|
echo "END ${x}"
|
|
}
|
|
|
|
find_tc_devices() {
|
|
local count=0 devs= dev rest l
|
|
|
|
# find all the devices in the system
|
|
# without forking
|
|
while IFS=":| " read dev rest
|
|
do
|
|
count=$((count + 1))
|
|
[ ${count} -le 2 ] && continue
|
|
devs="${devs} ${dev}"
|
|
done </proc/net/dev
|
|
|
|
# from all the devices find the ones
|
|
# that have QoS defined
|
|
# unfortunately, one fork per device cannot be avoided
|
|
tc_devices=
|
|
for dev in ${devs}
|
|
do
|
|
l="$(${tc} class show dev ${dev} 2>/dev/null)"
|
|
[ ! -z "${l}" ] && tc_devices="${tc_devices} ${dev}"
|
|
done
|
|
}
|
|
|
|
# update devices and class names
|
|
# once every 2 minutes
|
|
names_every=$((qos_get_class_names_every / update_every))
|
|
|
|
# exit this script every hour
|
|
# it will be restarted automatically
|
|
exit_after=$((qos_exit_every / update_every))
|
|
|
|
c=0
|
|
gc=0
|
|
while [ 1 ]
|
|
do
|
|
fix_names=
|
|
c=$((c + 1))
|
|
gc=$((gc + 1))
|
|
|
|
if [ ${c} -le 1 -o ${c} -ge ${names_every} ]
|
|
then
|
|
c=1
|
|
fix_names="YES"
|
|
find_tc_devices
|
|
fi
|
|
|
|
for d in ${tc_devices}
|
|
do
|
|
show_tc ${d}
|
|
done
|
|
|
|
echo "WORKTIME ${LOOPSLEEPMS_LASTWORK}"
|
|
|
|
loopsleepms ${update_every}
|
|
|
|
[ ${gc} -gt ${exit_after} ] && exit 0
|
|
done
|