Files
box/bin/chrome-error-scan.sh
T

100 lines
3.2 KiB
Bash
Raw Normal View History

#!/bin/bash
# chrome-error-scan.sh - scan per-profile chrome logs for concerning patterns.
# Self-contained: scans, compares against watermark, reports only NEW matches.
#
# Usage: chrome-error-scan.sh [--json] [--no-advance]
# Default output: "profile:new_count" lines for profiles with new matches,
# or "OK: no new errors" if clean.
# --json: output JSON {"profile": {"total": N, "new": M}, ...}
# --no-advance: report against the watermark WITHOUT advancing it.
# Peek-only read for high-frequency pollers (e.g. the web
# surface via `box-ctl chrome-errors --no-advance`). Runs
# without the flag keep the classic advance-on-read semantics.
#
# Watermark: /home/super/Projects/NetVM/chrome-error-watermark.json
# Patterns: FATAL, crash, segfault, out of memory (case-insensitive)
LOGDIR="/home/super/Projects/NetVM"
WATERMARK="$LOGDIR/chrome-error-watermark.json"
AS_JSON=0
NO_ADVANCE=0
for arg in "$@"; do
case "$arg" in
--json) AS_JSON=1 ;;
--no-advance) NO_ADVANCE=1 ;;
*) echo "chrome-error-scan.sh: unknown argument: $arg" >&2; exit 2 ;;
esac
done
# Gather current counts per profile (grep -c prints 0 with exit 1 on no match;
# the || true masks the exit code while preserving the "0" on stdout)
get_count() {
local f="$LOGDIR/chromebox-$1.log"
if [ -f "$f" ]; then
grep -ciE "FATAL|crash|segfault|out of memory" "$f" 2>/dev/null || true
else
echo 0
fi
}
MUSE_C=$(get_count muse)
PIP_C=$(get_count pip)
N646_C=$(get_count 646)
OPM_C=$(get_count opm)
python3 - "$WATERMARK" "$MUSE_C" "$PIP_C" "$N646_C" "$OPM_C" "$AS_JSON" "$NO_ADVANCE" <<'PYEOF'
import json, sys, os
watermark_path = sys.argv[1]
current = {
"muse": int(sys.argv[2]),
"pip": int(sys.argv[3]),
"646": int(sys.argv[4]),
"opm": int(sys.argv[5]),
}
as_json = len(sys.argv) > 6 and sys.argv[6] == "1"
no_advance = len(sys.argv) > 7 and sys.argv[7] == "1"
# Load watermark (tolerate missing/corrupt file -> treat as all-zero)
watermark = {}
if os.path.exists(watermark_path):
try:
with open(watermark_path) as f:
data = json.load(f)
watermark = data.get("counts", data) if isinstance(data, dict) else {}
except (ValueError, IOError, OSError):
watermark = {}
new_counts = {}
for prof in ("muse", "pip", "646", "opm"):
old = watermark.get(prof, 0)
try:
old = int(old)
except (TypeError, ValueError):
old = 0
delta = current[prof] - old
new_counts[prof] = max(delta, 0)
if as_json:
out = {p: {"total": current[p], "new": new_counts[p]} for p in current}
print(json.dumps(out))
else:
any_new = False
for prof in ("muse", "pip", "646", "opm"):
if new_counts[prof] > 0:
print("%s:%d" % (prof, new_counts[prof]))
any_new = True
if not any_new:
print("OK: no new errors")
# Update watermark atomically (skipped in --no-advance peek mode: the
# caller gets a read-only view and the CLI's advance-on-read semantics are
# left untouched).
if not no_advance:
tmp = watermark_path + ".tmp"
with open(tmp, "w") as f:
json.dump({"counts": current}, f, indent=2)
os.replace(tmp, watermark_path)
PYEOF