packages/super-sync-server/scripts/MONITORING-README.md
Comprehensive suite of tools for monitoring and analyzing SuperSync server storage, operations, and user patterns.
# Run all monitoring checks
npm run monitor:all
# Run quick health check (skip deep analysis)
npm run monitor:all:quick
# Save full report to file
npm run monitor:all:save
# Focus on specific user
npm run monitor:all -- --user 29
monitor.ts)General server health and user storage tracking.
# System vitals (CPU, memory, disk, DB)
npm run monitor:dev -- stats
# Top 20 users by storage
npm run monitor:dev -- usage
# View usage history/trends
npm run monitor:dev -- usage-history --tail 20
# Active user counts and recent activity
npm run monitor:dev -- active-users
npm run monitor:dev -- active-users --threshold 5 --limit 50
# Recent operations analysis
npm run monitor:dev -- ops --tail 100
npm run monitor:dev -- ops --user 29
# View server logs
npm run monitor:dev -- logs --tail 200
npm run monitor:dev -- logs --search "error"
npm run monitor:dev -- logs --error
analyze-storage.ts)Deep-dive analysis for investigating storage anomalies and patterns.
# Analyze operation size distribution
npm run analyze-storage -- operation-sizes
npm run analyze-storage -- operation-sizes --user 29
# Temporal patterns (bursts, daily/hourly trends)
npm run analyze-storage -- operation-timeline
npm run analyze-storage -- operation-timeline --user 29
# Breakdown by operation/entity types
npm run analyze-storage -- operation-types
npm run analyze-storage -- operation-types --user 29
# Find largest operations
npm run analyze-storage -- large-ops --limit 50
# Detect rapid-fire/sync loops (>5 ops/second by default)
npm run analyze-storage -- rapid-fire --threshold 10
# Analyze snapshot patterns
npm run analyze-storage -- snapshot-analysis
# Complete deep-dive for one user
npm run analyze-storage -- user-deep-dive --user 27
# Export operations to JSON for external analysis
npm run analyze-storage -- export-ops --user 29 --limit 1000
# Compare two users
npm run analyze-storage -- compare-users 27 29
run-all-monitoring.ts)Runs all monitoring and analysis tools in sequence.
# Run everything
npm run monitor:all
# Quick mode (skip deep analysis)
npm run monitor:all:quick
# Save to timestamped file in monitoring-reports/
npm run monitor:all:save
# Focus on specific user
npm run monitor:all -- --user 29 --save
npm run monitor:all:quick
Review:
User has unusually high storage (e.g., User #29 with 28k operations):
# Step 1: Get complete picture
npm run analyze-storage -- user-deep-dive --user 29
# Step 2: Check for rapid-fire patterns
npm run analyze-storage -- rapid-fire --threshold 3
# Step 3: Export for detailed analysis
npm run analyze-storage -- export-ops --user 29 --limit 5000
User has unusually large operations (e.g., User #27 with 54KB avg):
# Step 1: Find largest operations
npm run analyze-storage -- large-ops --limit 20
# Step 2: Analyze that user's patterns
npm run analyze-storage -- user-deep-dive --user 27
# Step 3: Compare with "normal" user
npm run analyze-storage -- compare-users 27 29
Suspect a sync loop or rapid-fire operations:
# Step 1: Detect rapid-fire (lower threshold)
npm run analyze-storage -- rapid-fire --threshold 3
# Step 2: Timeline analysis for affected user
npm run analyze-storage -- operation-timeline --user 29
# Step 3: Check operation types
npm run analyze-storage -- operation-types --user 29
Generate comprehensive monthly storage report:
# Generate and save full report
npm run monitor:all:save
# Review trends
npm run monitor:dev -- usage-history --tail 30
logs/usage-history.jsonl - Appended by monitor.ts usageanalysis-output/ - JSON exports from export-opsmonitoring-reports/ - Timestamped reports from monitor:all --savePossible causes:
Investigate: user-deep-dive, operation-timeline, rapid-fire
Possible causes:
Investigate: large-ops, operation-types, compare with normal users
Possible causes:
Investigate: rapid-fire, operation-timeline, per-device breakdown in user-deep-dive
Possible causes:
Investigate: snapshot-analysis, correlation with op count
The reports above are things you go and read. health-alert.sh is the only thing
that comes and finds you, and it is the piece that has to be installed — it
is not started by deploy.sh and nothing else runs it:
(crontab -l 2>/dev/null; echo "*/5 * * * * [email protected] /path/to/super-sync-server/scripts/health-alert.sh") | crontab -
deploy.sh reports at the end of every deploy whether this exact cron exists,
whether it is still completing, and whether the last attempted email failed. It
cannot prove delivery while the system is healthy because no email is sent then.
If it says the cron is missing, nothing is watching the server.
| # | Check | Fires when |
|---|---|---|
| 0–3 | Docker daemon, container state/health, OOM kills, restart counts | a container is down, unhealthy, OOM-killed, or crash-looping |
| 4 | /health endpoint | HTTP != 200 |
| 5 | Disk usage | > 85% |
| 6 | Long-running queries | any query active > MAX_QUERY_SECONDS (default 120) |
| 7 | Pool saturation | connections in use ≥ POOL_WARN_PCT% (default 75) of connection_limit |
| 8 | Invalid operations indexes | a non-building index is not valid/ready/live |
Checks 0–5 detect the outage once containers or /health fail. Checks 6–8 inspect
the database through the app container and catch the precursor while the server
can still answer. This also works when POSTGRES_SERVICE= selects an external
database. A failed/malformed probe and a missing connection_limit are themselves
alertable problems, so the new checks cannot silently become inert.
Check 7 is deliberately a ratio against connection_limit, not a fixed
number: measured steady state sits the same order of magnitude below the
pathological-query ceiling (pool size ÷ worst-case query duration), so the
absolute margin is thin and a fixed threshold would not survive a pool resize.
Check 8 matters more than it looks. An interrupted CREATE INDEX CONCURRENTLY
leaves an index that is unusable for reads but still maintained on every
insert. If operations_entity_ids_gin were the invalid one, the conflict
lookup would silently degrade to a sequential scan on every upload, permanently,
and nothing else in the codebase would report it.
The known migrator is excluded from the long-query check. Indexes currently
listed in pg_stat_progress_create_index, and invalid indexes carrying the
exact DDL lock held by an active migrator, are excluded from check 8. The latter
also covers DROP INDEX CONCURRENTLY, which has no progress-view entry, without
hiding unrelated invalid indexes. Each migration run has a unique database
application id; its finite database/client timeouts and targeted backend cleanup
bound interrupted DDL without generating incident/recovery noise.
Repeat alerts for the same problem are suppressed by a content hash, so counts and durations are normalised out — you get one mail per distinct problem, plus a recovery mail when it clears.
You can set up cron jobs for regular monitoring:
# Daily health check at 2 AM
0 2 * * * cd /path/to/super-sync-server && npm run monitor:all:quick >> logs/daily-check.log 2>&1
# Weekly full report every Sunday at 3 AM
0 3 * * 0 cd /path/to/super-sync-server && npm run monitor:all:save
# Hourly rapid-fire detection
0 * * * * cd /path/to/super-sync-server && npm run analyze-storage -- rapid-fire >> logs/rapid-fire.log 2>&1
monitor:all:quick first, then drill down with specific commands--save or redirect output to filescompare-users to understand what's "normal" vs anomalousexport-ops to get raw data for custom analysisusage-history checks reveal growth patternsnpm install -g tsxnpx tsx scripts/analyze-storage.ts ...--limit valuesNODE_OPTIONS=--max-old-space-size=4096 npm run ...To add new analysis commands:
scripts/analyze-storage.tsmain() switchgetMonitoringCommands() in run-all-monitoring.ts if it should run in full suiteQuestions or issues? File an issue or check the main SuperSync documentation.