1
0
mirror of git://f0xx.org/android_cast synced 2026-07-29 08:57:44 +03:00
Files
android_cast/examples/network/wan-snapshot.sh
Anton Afanasyeu ce4e2e89f3 sync infra
2026-06-10 22:34:59 +02:00

204 lines
5.8 KiB
Bash
Executable File

#!/bin/sh
#
# Log WAN vs LAN ping quality on the Debian edge router.
# Use to compare "rocketship" evenings vs slow periods (ISP/upstream vs local).
#
# Topology (see docs/INFRA.md):
# world -> 134.17.26.161 (router 10.7.6.228) -> 10.7.0.10 (FE) -> 10.7.0.0/8 (BE, …)
#
# Install on router:
# sudo cp wan-snapshot.sh /usr/local/bin/wan-snapshot.sh
# sudo chmod +x /usr/local/bin/wan-snapshot.sh
# sudo mkdir -p /var/log
#
# Cron (every 15 minutes):
# */15 * * * * root /usr/local/bin/wan-snapshot.sh
#
# Env overrides:
# WAN_SNAPSHOT_LOG=/var/log/wan-quality.log
# WAN_PING_TARGET=1.1.1.1
# FE_PING_TARGET=10.7.0.10
# BE_PING_TARGET=10.7.16.128 (set to "none" to skip)
# PING_COUNT=10
# PING_DEADLINE_S=15
#
set -eu
WAN_SNAPSHOT_LOG="${WAN_SNAPSHOT_LOG:-/var/log/wan-quality.log}"
WAN_PING_TARGET="${WAN_PING_TARGET:-1.1.1.1}"
FE_PING_TARGET="${FE_PING_TARGET:-10.7.0.10}"
BE_PING_TARGET="${BE_PING_TARGET-10.7.16.128}"
PING_COUNT="${PING_COUNT:-10}"
PING_DEADLINE_S="${PING_DEADLINE_S:-15}"
usage() {
sed -n '2,22p' "$0"
printf '\nCommands:\n'
printf ' (default) append one snapshot line to the log\n'
printf ' --report summarize today vs yesterday averages\n'
printf ' --tail [N] print last N log lines (default 24)\n'
printf ' --help this text\n'
}
need_ping() {
command -v ping >/dev/null 2>&1 || {
echo "wan-snapshot: missing ping" >&2
exit 1
}
}
# ping_summary HOST -> prints: loss_pct avg_ms (or loss_pct=-1 avg_ms=-1 on total failure)
ping_summary() {
_host="$1"
_out=""
_out="$(ping -c "$PING_COUNT" -w "$PING_DEADLINE_S" "$_host" 2>/dev/null)" || true
if [ -z "$_out" ]; then
printf '%s %s' "-1" "-1"
return 0
fi
_loss="$(printf '%s\n' "$_out" | awk '/packet loss/ {
for (i = 1; i <= NF; i++) if ($i ~ /%$/) { gsub(/%/, "", $i); print $i; exit }
}')"
_avg="$(printf '%s\n' "$_out" | awk -F'[=/ ]' '/min\/avg\/max/ { print $8; exit }')"
[ -n "$_loss" ] || _loss="-1"
[ -n "$_avg" ] || _avg="-1"
printf '%s %s' "$_loss" "$_avg"
}
snapshot_once() {
need_ping
_ts="$(date -Iseconds 2>/dev/null || date '+%Y-%m-%dT%H:%M:%S%z')"
_wan="$(ping_summary "$WAN_PING_TARGET")"
_wan_loss="${_wan%% *}"
_wan_avg="${_wan#* }"
_fe="$(ping_summary "$FE_PING_TARGET")"
_fe_loss="${_fe%% *}"
_fe_avg="${_fe#* }"
_line="ts=$_ts wan=$WAN_PING_TARGET wan_loss=${_wan_loss}% wan_avg_ms=${_wan_avg} fe=$FE_PING_TARGET fe_loss=${_fe_loss}% fe_avg_ms=${_fe_avg}"
if [ -n "$BE_PING_TARGET" ] && [ "$BE_PING_TARGET" != "none" ]; then
_be="$(ping_summary "$BE_PING_TARGET")"
_be_loss="${_be%% *}"
_be_avg="${_be#* }"
_line="$_line be=$BE_PING_TARGET be_loss=${_be_loss}% be_avg_ms=${_be_avg}"
fi
_dir="$(dirname "$WAN_SNAPSHOT_LOG")"
[ -d "$_dir" ] || mkdir -p "$_dir" 2>/dev/null || true
printf '%s\n' "$_line" >> "$WAN_SNAPSHOT_LOG"
printf '%s\n' "$_line"
}
# Average wan_avg_ms / fe_avg_ms for lines matching DATE prefix (YYYY-MM-DD).
day_avg() {
_log="$1"
_date="$2"
_field="$3"
[ -r "$_log" ] || return 0
awk -v d="$_date" -v f="$_field" '
$0 ~ "^ts=" d {
for (i = 1; i <= NF; i++) {
if ($i ~ "^" f "=") {
split($i, a, "=")
v = a[2]
gsub(/%/, "", v)
if (v + 0 == v && v >= 0) { n++; s += v }
}
}
}
END {
if (n > 0) printf "%.2f", s / n
else print "n/a"
}
' "$_log"
}
day_max_loss() {
_log="$1"
_date="$2"
_field="$3"
[ -r "$_log" ] || return 0
awk -v d="$_date" -v f="$_field" '
$0 ~ "^ts=" d {
for (i = 1; i <= NF; i++) {
if ($i ~ "^" f "=") {
split($i, a, "=")
v = a[2]
gsub(/%/, "", v)
if (v + 0 == v && v >= 0 && v > max) max = v
}
}
}
END {
if (max == "") print "n/a"
else printf "%.0f", max
}
' "$_log"
}
report() {
_log="$WAN_SNAPSHOT_LOG"
_today="$(date '+%Y-%m-%d')"
_yesterday="$(date -d 'yesterday' '+%Y-%m-%d' 2>/dev/null || date -v-1d '+%Y-%m-%d' 2>/dev/null || echo '')"
if [ ! -r "$_log" ]; then
echo "wan-snapshot: no log at $_log (run default command first)" >&2
exit 1
fi
_samples_today="$(grep -c "^ts=$_today" "$_log" 2>/dev/null || echo 0)"
printf 'log=%s\n' "$_log"
printf 'today=%s samples=%s\n' "$_today" "$_samples_today"
printf ' wan_avg_ms=%s wan_max_loss%%=%s\n' \
"$(day_avg "$_log" "$_today" "wan_avg_ms")" \
"$(day_max_loss "$_log" "$_today" "wan_loss")"
printf ' fe_avg_ms=%s fe_max_loss%%=%s\n' \
"$(day_avg "$_log" "$_today" "fe_avg_ms")" \
"$(day_max_loss "$_log" "$_today" "fe_loss")"
if [ -n "$_yesterday" ] && grep -q "^ts=$_yesterday" "$_log" 2>/dev/null; then
_samples_y="$(grep -c "^ts=$_yesterday" "$_log" 2>/dev/null || echo 0)"
printf 'yesterday=%s samples=%s\n' "$_yesterday" "$_samples_y"
printf ' wan_avg_ms=%s wan_max_loss%%=%s\n' \
"$(day_avg "$_log" "$_yesterday" "wan_avg_ms")" \
"$(day_max_loss "$_log" "$_yesterday" "wan_loss")"
printf ' fe_avg_ms=%s fe_max_loss%%=%s\n' \
"$(day_avg "$_log" "$_yesterday" "fe_avg_ms")" \
"$(day_max_loss "$_log" "$_yesterday" "fe_loss")"
fi
printf '\nInterpretation:\n'
printf ' wan bad + fe good -> likely ISP/upstream (world -> 134.17.26.161)\n'
printf ' wan + fe bad -> router or LAN (10.7.6.228 -> 10.7.0.10)\n'
printf ' wan + fe good, apps slow -> DNAT/nginx above ping path\n'
}
tail_log() {
_n="${1:-24}"
[ -r "$WAN_SNAPSHOT_LOG" ] || {
echo "wan-snapshot: no log at $WAN_SNAPSHOT_LOG" >&2
exit 1
}
tail -n "$_n" "$WAN_SNAPSHOT_LOG"
}
case "${1:-}" in
-h|--help|help)
usage
;;
--report|report)
report
;;
--tail|tail)
tail_log "${2:-24}"
;;
"")
snapshot_once
;;
*)
echo "wan-snapshot: unknown command: $1 (try --help)" >&2
exit 1
;;
esac