From a3ae40e9234efd7385c27d7beac648842c942fbc Mon Sep 17 00:00:00 2001 From: Valentin Lab Date: Tue, 8 Oct 2024 18:38:56 +0200 Subject: [PATCH] new: [vps] add ``disk-2`` stats target with full disk usage breakdown --- bin/vps | 186 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 184 insertions(+), 2 deletions(-) diff --git a/bin/vps b/bin/vps index 3980945..b00c625 100755 --- a/bin/vps +++ b/bin/vps @@ -2205,7 +2205,7 @@ cmdline.spec::cmd:stats:run() { return 1 esac - local resources=(c.{memory,network} load_avg disk) + local resources=(c.{memory,network} load_avg disk-2) if [ -n "${opt_resource}" ]; then resources=(${opt_resource//,/ }) fi @@ -2222,7 +2222,7 @@ cmdline.spec::cmd:stats:run() { not_found_msg=${not_found_msg%, } err "Unsupported resource(s) provided: ${not_found_msg}" echo " resource must be one-of:" >&2 - declare -F | egrep -- '-fx? stats:[a-zA-Z0-9_.]+$' | cut -f 3- -d " " | cut -f 2- -d ":" | prefix " - " >&2 + declare -F | egrep -- '-fx? stats:[a-zA-Z0-9_.-]+$' | cut -f 3- -d " " | cut -f 2- -d ":" | prefix " - " >&2 return 1 fi @@ -2378,6 +2378,188 @@ stats:disk() { } +stats:disk-2() { + local format="$1" + local out + out=$(disk:usage:stats) + printf "%s\n" "$out" | rrd:update "disk-2" "size|2:size:GAUGE:U:U" || { + return 1 + } + case "${format:-p}" in + raw|r) + printf "%s\n" "$out" + ;; + pretty|p) + awk:require 4.1.4 || return 1 + echo "${WHITE}host:${NORMAL}" + echo " ${WHITE}general:${NORMAL}" + { + echo "ident" "size____" + printf "%s\n" "$out" | grep ^host/ | sed -r 's%^host/%%g' | + egrep "^(used|available) " | + cut -f 1,3 -d " " | + numfmt --field 2-4 --to=iec-i --from-unit=1024 --format=%8.1fB | + sed -r 's/(\.[0-9])([A-Z]?i?B)/\1:\2/g' + } | col:normalize:size -+ | + sed -r ' + s/(\.[0-9]):([A-Z]?iB)/\1 \2/g; + s/(\.[0-9]):([KMGTPE])/\1 \2/g; + s/ ([0-9]+)\.0:B/\1 B/g; + s/ ([0-9]+)\.0:/\1 /g; + ' | + header:make | + prefix " " + echo " ${WHITE}usage:${NORMAL}" + { + echo "ident" "size____" + printf "%s\n" "$out" | grep ^host/ | sed -r 's%^host/%%g' | + egrep -v "^(used|available) " | + sort -rn -k 3 | + cut -f 1,3 -d " " | + numfmt --field 2-4 --to=iec-i --from-unit=1024 --format=%8.1fB | + sed -r 's/(\.[0-9])([A-Z]?i?B)/\1:\2/g' + } | col:normalize:size -+ | + sed -r ' + s/(\.[0-9]):([A-Z]?iB)/\1 \2/g; + s/(\.[0-9]):([KMGTPE])/\1 \2/g; + s/ ([0-9]+)\.0:B/\1 B/g; + s/ ([0-9]+)\.0:/\1 /g; + ' | + header:make | + prefix " " + echo "${WHITE}data:${NORMAL}" + { + echo "folder" "size____" + printf "%s\n" "$out" | grep ^data/ | sed -r 's%^data/%%g' | + sort -rn -k 3 | + cut -f 1,3 -d " " | + numfmt --field 2 --to=iec-i --from-unit=1024 --format=%8.1fB | + sed -r 's/(\.[0-9])([A-Z]?i?B)/\1:\2/g' + } | col:normalize:size -+ | + sed -r ' + s/(\.[0-9]):([A-Z]?iB)/\1 \2/g; + s/(\.[0-9]):([KMGTPE])/\1 \2/g; + s/ ([0-9]+)\.0:B/\1 B/g; + s/ ([0-9]+)\.0:/\1 /g; +' | + header:make | + prefix " " + + echo "${WHITE}docker:${NORMAL}" + { + echo "ident" "size____" + printf "%s\n" "$out" | grep ^docker/ | sed -r 's%^docker/%%g' | + egrep -v "^[a-z0-9_]+_r " | + sort -rn -k 3 | + cut -f 1,3 -d " " | + numfmt --field 2-4 --to=iec-i --from-unit=1024 --format=%8.1fB | + sed -r 's/(\.[0-9])([A-Z]?i?B)/\1:\2/g' + } | col:normalize:size -+ | + sed -r ' + s/(\.[0-9]):([A-Z]?iB)/\1 \2/g; + s/(\.[0-9]):([KMGTPE])/\1 \2/g; + s/ ([0-9]+)\.0:B/\1 B/g; + s/ ([0-9]+)\.0:/\1 /g; + ' | + header:make | + prefix " " + + ;; + esac +} + + +disk:total() { + local disk_used_size + disk_used_size=$(df --output=used,size "/") || return 1 + disk_used_size=${disk_used_size##*$'\n'} + disk_used_size=${disk_used_size// / } + printf "%s" "$disk_used_size" +} + +disk:usage:stats() { + local disk_used_size + + data_sum=0 + while read-0 size_name; do + name=${size_name#*$'\t'} + [ -d "$name" ] || continue + size=${size_name%%$'\t'*} + name=${name##*/} + data_sum=$((data_sum + size)) + printf "%s %s %s\n" "data/${name##*/}" "$(date +%s)" "$size" + done < <(du -s0 /srv/datastore/data/*) + + docker_sum=0 + if ! out=$(du -s /var/lib/docker/containers/*/*-json.log); then + err "Failed to get disk usage of docker container logs." + return 1 + fi + total_usage_logs=$(printf "%s" "$out" | awk '{s+=$1} END {print s}') + docker_sum=$((docker_sum + total_usage_logs)) + printf "%s %s %s\n" "docker/logs" "$(date +%s)" "$total_usage_logs" + + if ! out=$(docker system df --format '{{.Type}}\t{{.Size}}\t{{.Reclaimable}}'); then + err "Failed to get disk usage of docker system." + return 1 + fi + date=$(date +%s) + while read-0 ident size reclaimable; do + docker_sum=$((docker_sum + size)) + printf "%s %s %s\n" "docker/$ident" "$date" "$size" + printf "%s %s %s\n" "docker/${ident}_r" "$date" "$reclaimable" + done < <( + printf "%s" "$out" | + sed -r 's/^(.*)\t([0-9.]+)([kMGT]?B)\t([0-9.]+)([kMGT]?B).*$/\1\t\2\t\3\t\4\t\5/g' | + awk -F'\t' ' + # Function to convert sizes to kilobytes + function convert_to_kb(value, unit) { + if (unit == "B") { + return value / 1024; + } else if (unit == "kB") { + return value; + } else if (unit == "MB") { + return value * 1024; + } else if (unit == "GB") { + return value * 1024 * 1024; + } else if (unit == "TB") { + return value * 1024 * 1024 * 1024; + } + return 0; + } + + { + size_value = $2; + size_unit = $3; + reclaimable_value = $4; + reclaimable_unit = $5; + type = $1; + + # Convert type to lowercase and replace spaces with underscores + type=tolower(type); + gsub(/ /, "_", type); + + # Convert size and reclaimable to kilobytes + size_kb = convert_to_kb(size_value, size_unit); + reclaimable_kb = convert_to_kb(reclaimable_value, reclaimable_unit); + + printf "%s\0%d\0%d\0", type, size_kb, reclaimable_kb; + }' + ) + + used_size=$(disk:total) + used=${used_size%% *} + available=${used_size##* } + date=$(date +%s) + printf "%s %s %s\n" "host/used" "$date" "${used}" + printf "%s %s %s\n" "host/available" "$date" "${available}" + printf "%s %s %s\n" "host/docker" "$date" "$docker_sum" + printf "%s %s %s\n" "host/data" "$date" "$data_sum" + printf "%s %s %s\n" "host/other" "$date" "$((used - docker_sum - data_sum))" + + +} + host:sys:load_avg() { local uptime uptime="$(uptime)"