1
0
Fork 0
mirror of https://github.com/munin-monitoring/contrib.git synced 2025-07-22 02:51:03 +00:00
Munin-Contrib/plugins/lxc/lxc-multigraph
2019-08-12 02:36:01 +02:00

389 lines
9.4 KiB
Bash
Executable file

#!/bin/bash
# -*- sh -*-
: << =cut
=head1 NAME
lxc-multigraph - Plugin to monitor LXC containers (v2.0)
=head1 CONFIGURATION
[lxc-multigraph]
user root
# The memory usage of containers are by default drawn as stacked area
# charts. Alternatively a non-stacked graph with lines can be configured.
# Default: true
#env.ram_display_stacked true
# lxc container path, default below
#env.lxcpath /var/lib/lxc
# exclude the following containers
# (default none excluded)
#env.exclude container1 container2
# path where tasks sysfs files are stored,
# set this if the various attempts in the
# code don't work
# (default none)
#env.cgrouppath /sys/fs/cgroup/cpuacct/lxc/
=head1 INTERPRETATION
This plugin needs root privilege.
This plugin has been tested with lxc 3 and
lx2 (on Debian buster and Debian jessie,
respectively).
For the network graphs to work, you need
to have in every container's config file
a line defining the virtual network interface
path (else lxc will use a random name at
each container's start); see the lxc_netdev()
function below.
If using lxc 2, make sure you do not have cruft
in your container config files, you can test
it with:
lxc-cgroup -o /dev/stdout -l INFO -n 104 cpuacct.usage
-- with 104 a valid lxc instance), if you
get a warning, fix the config file.
For the logins graph, the "users" command is required in each
container.
Tested on Debian buster and Debian jessie.
The double __ for values is for compatibility
with the previous implementation.
=head1 AUTHOR
vajtsz vajtsz@gmail.com
mitty mitty@mitty.jp
alphanet schaefer@alphanet.ch (many changes and multigraph)
See https://framagit.org/alphanet/various-stuff
(plugins/lcx)
=head1 LICENSE
2-clause BSD License
or GPLv3 license or later, at your option
=head1 MAGIC MARKERS
#%# family=auto
#%# capabilities=autoconf
=cut
. "$MUNIN_LIBDIR/plugins/plugin.sh"
lxcpath=${lxcpath:-/var/lib/lxc}
# containers to be ignored
exclude=${exclude:-}
ram_display_stacked=${ram_display_stacked:-true}
# try to guess the location, if empty
cgrouppath=${cgrouppath:-}
# --- FUNCTIONS
function active_guests {
local excludes="$1"
local guest_name
for guest_name in $(lxc-ls)
do
# handle optional exclude list in $1
if ! echo "$excludes" | grep -qwF "$guest_name"; then
if lxc-info -n "$guest_name" --state 2>/dev/null | grep -qw RUNNING; then
echo "$guest_name"
fi
fi
done
}
function lxc_cgroup {
# lxc3 (lxc < 3: may output some warnings if there is cruft in your config dir)
lxc-cgroup -o /dev/stdout -l INFO $* | sed 's/^.*lxc_cgroup.c:main:[0-9][0-9]* - //'
}
function lxc_netdev {
local guest_name="$1"
if [ -f "$lxcpath/$guest_name/config" ]; then
# lxc 3 vs < 3
(grep -EF '^lxc.net.0.veth.pair' "$lxcpath/$guest_name/config" 2>/dev/null \
|| grep -EF '^lxc.network.veth.pair' "$lxcpath/$guest_name/config"
) | awk '{print $NF;}'
fi
}
# find proper sysfs and count it
# Debian 6.0: /sys/fs/cgroup/<container>/tasks
# Ubuntu 12.04 with fstab: /sys/fs/cgroup/lxc/<container>/tasks
# Ubuntu 12.04 with cgroup-lite: /sys/fs/cgroup/cpuacct/lxc/<container>/tasks
# Ubuntu 12.04 with cgroup-bin: /sys/fs/cgroup/cpuacct/sysdefault/lxc/<container>/tasks
# Ubuntu 14.04 /sys/fs/cgroup/systemd/lxc/<container>/tasks
# and with cgmanager on jessie
lxc_count_processes () {
local guest_name="$1"
local SYSFS
[ -z "$guest_name" ] && return 0
if [ -n "$cgrouppath" ]; then
SYSFS="$cgrouppath/$guest_name/tasks"
if [ -e "$SYSFS" ]; then
wc -l <"$SYSFS"
return
fi
fi
for SYSFS in \
"/sys/fs/cgroup/$guest_name/tasks" \
"/sys/fs/cgroup/lxc/$guest_name/tasks" \
"/sys/fs/cgroup/systemd/lxc/$guest_name/tasks" \
"/sys/fs/cgroup/cpuacct/lxc/$guest_name/tasks" \
"/sys/fs/cgroup/cpuacct/sysdefault/lxc/$guest_name/tasks"
do
if [ -e "$SYSFS" ]; then
wc -l <"$SYSFS"
return
fi
done
if [ -e /usr/bin/cgm ]; then
cgm getvalue cpu "lxc/$guest_name" tasks 2>/dev/null | wc -l
else
lxc_cgroup -n "$guest_name" tasks | wc -l
fi
}
# --- BASIC DEFINES
active_guests=$(active_guests $exclude)
# --- AUTOCONF
if [ "$1" = "autoconf" ]; then
if [ ! -r /proc/net/dev ]; then
echo "no (/proc/net/dev cannot be read)"
elif [ ! -e "$lxcpath" ]; then
echo "no ($lxcpath is not present)"
else
echo yes
fi
exit 0
fi
# --- CONFIG OUTPUT
if [ "$1" = "config" ]; then
cat <<EOF
multigraph lxc_cpu
graph_title CPU Usage
graph_args -l 0 --base 1000
graph_vlabel USER_HZ
graph_category lxc
EOF
for n in $active_guests
do
for i in user system
do
cat <<EOF
$(clean_fieldname "cpu_${i}__${n}").label $n: $(echo "${i:0:1}" | tr "[:lower:]" "[:upper:]")${i:1}
$(clean_fieldname "cpu_${i}__${n}").type DERIVE
$(clean_fieldname "cpu_${i}__${n}").min 0
EOF
done
done
cat <<EOF
multigraph lxc_cpu_time
graph_title CPU time
graph_args -l 0 --base 1000
graph_vlabel nanosec
graph_category lxc
EOF
for n in $active_guests
do
cat <<EOF
$(clean_fieldname "cpu_time__${n}").label $n: CPU time
$(clean_fieldname "cpu_time__${n}").type DERIVE
$(clean_fieldname "cpu_time__${n}").min 0
EOF
done
cat <<EOF
multigraph lxc_logins
graph_title Logins
graph_category lxc
EOF
for n in $active_guests
do
cat <<EOF
$(clean_fieldname "logins__${n}").label $n: logins
$(clean_fieldname "logins__${n}").type GAUGE
EOF
done
cat <<EOF
multigraph lxc_net
graph_title Network traffic
graph_args --base 1000
graph_vlabel bits in (-) / out (+) per \${graph_period}
graph_category lxc
graph_info This graph shows the traffic of active LXC containers.
EOF
for n in $active_guests
do
device=$(lxc_netdev "$n")
if [ -z "$device" ]; then
continue
fi
cat <<EOF
$(clean_fieldname "net__${n}_down").label $n
$(clean_fieldname "net__${n}_down").type DERIVE
$(clean_fieldname "net__${n}_down").graph no
$(clean_fieldname "net__${n}_down").cdef $(clean_fieldname "net__${n}_down"),8,*
$(clean_fieldname "net__${n}_down").min 0
$(clean_fieldname "net__${n}_up").label $n
$(clean_fieldname "net__${n}_up").type DERIVE
$(clean_fieldname "net__${n}_up").negative $(clean_fieldname "net__${n}_down")
$(clean_fieldname "net__${n}_up").cdef $(clean_fieldname "net__${n}_up"),8,*
$(clean_fieldname "net__${n}_up").min 0
EOF
if [ -r "/sys/class/net/$device/speed" ]; then
megabit_per_second=$(cat "/sys/class/net/$device/speed")
bps=$((megabit_per_second * 1000 * 1000))
cat <<EOF
$(clean_fieldname "net__${n}_down").max $bps
$(clean_fieldname "net__${n}_up").max $bps
EOF
fi
done
cat <<EOF
multigraph lxc_proc
graph_title Processes
graph_args -l 0 --base 1000
graph_vlabel Number of processes
graph_category lxc
EOF
for n in $active_guests
do
cat <<EOF
$(clean_fieldname "lxc_proc__${n}").label $n: processes
$(clean_fieldname "lxc_proc__${n}").type GAUGE
$(clean_fieldname "lxc_proc__${n}").min 0
EOF
done
cat <<EOF
multigraph lxc_ram
graph_title Memory
graph_args -l 0 --base 1024
graph_vlabel byte
graph_category lxc
EOF
for n in $active_guests
do
if [ "$ram_display_stacked" != "true" ]; then
draw_style="LINE1"
else
draw_style="AREASTACK"
fi
cat <<EOF
$(clean_fieldname "mem_usage__${n}").label ${n}: Mem usage
$(clean_fieldname "mem_usage__${n}").type GAUGE
$(clean_fieldname "mem_usage__${n}").draw $draw_style
$(clean_fieldname "mem_cache__${n}").label ${n}: Cache
$(clean_fieldname "mem_cache__${n}").type GAUGE
$(clean_fieldname "mem_active__${n}").label ${n}: Active
$(clean_fieldname "mem_active__${n}").type GAUGE
$(clean_fieldname "mem_inactive__${n}").label ${n}: Inactive
$(clean_fieldname "mem_inactive__${n}").type GAUGE
EOF
done
exit 0
fi
# --- DATA OUTPUT
echo "multigraph lxc_cpu"
for n in $active_guests
do
for i in user system
do
echo "$(clean_fieldname "cpu_${i}__${n}").value $(lxc_cgroup -n "$n" cpuacct.stat | grep "$i" | awk '{ print $2; }')"
done
done
echo "multigraph lxc_cpu_time"
for n in $active_guests
do
echo "$(clean_fieldname "cpu_time__${n}").value $(lxc_cgroup -n "$n" cpuacct.usage)"
done
echo "multigraph lxc_logins"
for n in $active_guests
do
echo "$(clean_fieldname "logins__${n}").value $(lxc-attach -n "$n" users | wc -w)"
done
echo "multigraph lxc_net"
for n in $active_guests
do
device=$(lxc_netdev "$n")
if [ -z "$device" ]; then
value_up="U"
value_down="U"
else
value_up=$(grep -E "^ *${device}:" /proc/net/dev | awk '{print $10;}')
value_down=$(grep -E "^ *${device}:" /proc/net/dev | awk '{print $2;}')
fi
cat <<EOF
$(clean_fieldname "net__${n}_up").value $value_up
$(clean_fieldname "net__${n}_down").value $value_down
EOF
done
echo "multigraph lxc_proc"
for n in $active_guests
do
echo "$(clean_fieldname "lxc_proc__${n}").value $(lxc_count_processes "$n")"
done
echo "multigraph lxc_ram"
for n in $active_guests
do
cat <<EOF
$(clean_fieldname "mem_usage__${n}").value $(lxc_cgroup -n "$n" memory.usage_in_bytes)
$(clean_fieldname "mem_cache__${n}").value $(lxc_cgroup -n "$n" memory.stat | grep total_cache | awk '{print $2;}')
$(clean_fieldname "mem_active__${n}").value $(lxc_cgroup -n "$n" memory.stat | grep total_active_anon | awk '{print $2;}')
$(clean_fieldname "mem_inactive__${n}").value $(lxc_cgroup -n "$n" memory.stat | grep total_inactive_anon | awk '{print $2;}')
EOF
done