114 lines
3.3 KiB
Bash
Executable File
114 lines
3.3 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
set -euo pipefail
|
|
export LC_ALL=C
|
|
|
|
# May be overridden by Telegraf's environment or with a positional argument.
|
|
FSPATH="${1:-${FSPATH:-/mnt}}"
|
|
UUID="${BCACHEFS_UUID:-3d3a0763-4dfe-41e6-93c1-8c791ec98176}"
|
|
|
|
# Convert the rounded, binary human-readable values printed by bcachefs to
|
|
# bytes. The result is exact for the displayed value; bcachefs does not expose
|
|
# the additional precision that it rounded away (for example, in "4.73T").
|
|
human_to_bytes()
|
|
{
|
|
local value="$1"
|
|
local whole fraction unit multiplier scale bytes
|
|
|
|
if [[ ! $value =~ ^([0-9]+)([.]([0-9]+))?([KMGTPEkmgtpe]?)(i?[Bb])?$ ]]; then
|
|
return 1
|
|
fi
|
|
|
|
whole="${BASH_REMATCH[1]}"
|
|
fraction="${BASH_REMATCH[3]}"
|
|
unit="${BASH_REMATCH[4]^^}"
|
|
|
|
case "$unit" in
|
|
"") multiplier=1 ;;
|
|
K) multiplier=$((1024)) ;;
|
|
M) multiplier=$((1024 ** 2)) ;;
|
|
G) multiplier=$((1024 ** 3)) ;;
|
|
T) multiplier=$((1024 ** 4)) ;;
|
|
P) multiplier=$((1024 ** 5)) ;;
|
|
E) multiplier=$((1024 ** 6)) ;;
|
|
*) return 1 ;;
|
|
esac
|
|
|
|
bytes=$((10#$whole * multiplier))
|
|
if [[ -n $fraction ]]; then
|
|
scale=$((10 ** ${#fraction}))
|
|
# Round to the nearest byte instead of dropping the fractional byte.
|
|
bytes=$((bytes + (10#$fraction * multiplier + scale / 2) / scale))
|
|
fi
|
|
|
|
printf '%s\n' "$bytes"
|
|
}
|
|
|
|
escape_tag()
|
|
{
|
|
local value="$1"
|
|
value="${value//\\/\\\\}"
|
|
value="${value//,/\\,}"
|
|
value="${value// /\\ }"
|
|
value="${value//=/\\=}"
|
|
printf '%s' "$value"
|
|
}
|
|
|
|
declare -A data_bytes=()
|
|
declare -A metadata_bytes=()
|
|
types=(replicas checksum erasure_code compression target high_priority pending stripes)
|
|
scan_pending=""
|
|
rows=0
|
|
|
|
# Capture everything before printing a metric: on command or parser failure,
|
|
# Telegraf gets no partial point that could look like a valid zero reading.
|
|
if ! status="$(bcachefs reconcile status "$FSPATH")"; then
|
|
echo "bcachefs reconcile status failed for $FSPATH" >&2
|
|
exit 1
|
|
fi
|
|
|
|
while IFS= read -r line; do
|
|
if [[ $line =~ ^Scan[[:space:]]pending:[[:space:]]*([0-9]+)[[:space:]]*$ ]]; then
|
|
scan_pending="${BASH_REMATCH[1]}"
|
|
elif [[ $line =~ ^[[:space:]]*([[:alnum:]_]+):[[:space:]]+([^[:space:]]+)[[:space:]]+([^[:space:]]+)[[:space:]]*$ ]]; then
|
|
type="${BASH_REMATCH[1]}"
|
|
raw_data="${BASH_REMATCH[2]}"
|
|
raw_metadata="${BASH_REMATCH[3]}"
|
|
|
|
if ! data_bytes["$type"]="$(human_to_bytes "$raw_data")" ||
|
|
! metadata_bytes["$type"]="$(human_to_bytes "$raw_metadata")"; then
|
|
echo "Unable to parse reconcile values for $type: $raw_data $raw_metadata" >&2
|
|
exit 1
|
|
fi
|
|
((rows += 1))
|
|
fi
|
|
done <<< "$status"
|
|
|
|
if ((rows == 0)); then
|
|
echo "No reconcile values found for $FSPATH" >&2
|
|
exit 1
|
|
fi
|
|
|
|
printf 'bcachefs_reconcile,fspath=%s,uuid=%s ' \
|
|
"$(escape_tag "$FSPATH")" "$(escape_tag "$UUID")"
|
|
|
|
first=1
|
|
if [[ -n $scan_pending ]]; then
|
|
printf 'scan_pending=%s' "$scan_pending"
|
|
first=0
|
|
fi
|
|
|
|
for type in "${types[@]}"; do
|
|
# Current bcachefs versions print all types, including zero-valued ones.
|
|
# Skipping a missing type is safer than inventing a zero on format changes.
|
|
[[ -v data_bytes["$type"] ]] || continue
|
|
|
|
((first)) || printf ','
|
|
printf '%s_data=%s,%s_metadata=%s' \
|
|
"$type" "${data_bytes[$type]}" \
|
|
"$type" "${metadata_bytes[$type]}"
|
|
first=0
|
|
done
|
|
|
|
printf '\n'
|