Skip to content

Monitoring & health

An honest account: monitoring is thin. This page covers what exists, then the gaps — because the gaps are the operationally interesting part.

What exists

MechanismCovers
deploy.gcp.sh statusPM2 process table + all four ports bound
deploy.gcp.sh logs <app> <n>PM2 logs
Deploy health checkPort bound + last 12 log lines, exits non-zero on failure
PM2 autorestart + max_memory_restart: 1GProcess-level recovery
Request loggerEvery request: timestamp, method, URL, forwarded IP, origin
SENTRY_DSNError reporting, if configured
ENABLE_MONITORING, LOG_TARGET, LOG_TARGETSFlags whose wiring should be verified before relying on them
TELEGRAM_ALERTS_CHAT_IDAn alert channel exists
models/networkStatusModel.jsPer-chain health records
models/monitoredTransactionModel.jsTransactions under watch
GET /api/debug-statsUnauthenticated, registered before all middleware

Health checks you can run now

bash
cd bz-backend

./scripts/deploy.gcp.sh status              # processes + ports

# read-only chain and contract checks
node scripts/checkRelayerDeployed.js        # relayer presence per chain
node scripts/check-contract-owner.js        # owner / signer verification
node scripts/check-contract-state.js        # fee config, pause state
node scripts/checkDeployerBalance.js        # EXECUTOR GAS — check this often
node scripts/fetchAllChainBalances.js
node scripts/blazai-analytics.js            # chat usage figures

HTTP checks:

bash
# is the API alive and can it quote?
curl 'https://api.blazpay.com/api/defi/quotes?fromChainId=42161&toChainId=42161&fromToken=0x…&toToken=0x…&amount=1&type=swap'

# accumulated fees across all chains, bypassing cache
curl 'https://api.blazpay.com/api/defi/fees/summary?force=1'

Executor gas

This is the single most important thing to watch

PRIVATE_KEY_EXECUTOR (0x5935745431D1385ae1a9CE2644fb5f5d1f140459) pays gas for every CSIP buy, every auto-claim and every Autopilot trade.

When it empties, both automation products stop silently. No error surfaces, no alert fires, and users simply see their scheduled buys stop happening.

Arbitrum consumption is roughly 0.00002 ETH per batch.

bash
node scripts/checkDeployerBalance.js

There is no automated top-up and no threshold alert. Until there is, this belongs on a human checklist.

Silent provider failure

The biggest observability gap in the platform

AggregatorFactory.getQuotes wraps every aggregator in a try/catch so one failing API cannot kill an SSE stream. That resilience is correct — but it means a permanently broken provider disappears with no signal. The user sees fewer routes and worse prices; nothing alerts.

Three providers are already commented out for exactly this reason (nitro, icecream_swap, kima), and each was discovered by someone noticing, not by monitoring.

The cheap fix: count per-provider quote successes and failures per hour, and alert when a previously-healthy provider drops to zero. Nothing like this exists today.

Manual check — quote a common pair and count the routes:

bash
curl -N 'https://api.blazpay.com/api/defi/quotes?…' | grep -c '^data:'

Compare against the 21 registered providers. A sudden drop from ~12 routes to ~4 on a liquid pair is the symptom.

What each failure looks like

FailureSymptomDetected by
Backend downEverything 502sPort check, user reports
bz-agent downChat returns errors; trading unaffectedstatus, user reports
MongoDB unreachableEverything failsLogs
Redis unreachableQuotes cannot be built (5-min cache gone), Socket.io adapter off, Autopilot dip_buy stops firingLogs, gradually
One aggregator downFewer routes, worse pricesNothing
All aggregators downNo routes at allUser reports
Executor out of gasAutomation stopsNothing
Autopilot routers not allow-listedNo agent ever tradesNothing — see below
Policy hash mismatchThat agent silently skippedautopilotEventModel
Orderly downPerpetuals unusableUser reports
Zerion downEmpty portfolios, wallet cards failUser reports
Etherscan downAuditor, token safety, approvals, wallet card failUser reports
Extraction provider downAudit and token safety fail; all extraction nodes fail → chat brokenUser reports
Conversation provider partially configuredAnswers quietly get worseNothing
Netlify build failureFrontend staleNetlify notification
IndexNow 403New pages not submitted to BingPlugin log

Three failures produce no signal at all

Executor gas, single-provider outage, and an unseeded Autopilot router allow-list. All three degrade a product to zero while every process reports healthy.

The conversation-tier silent downgrade

A partially configured environment quietly costs answer quality

getConversationLLM() needs all three of LLM_GOOGLE_PROJECT_ID, LLM_GOOGLE_CLIENT_EMAIL and LLM_GOOGLE_PRIVATE_KEY. With any one missing it falls back to the cheaper extraction model instead of the conversation tier. No error, no log line, just worse conversation.

Check all three together after any .env edit.

Reading the logs

bash
./scripts/deploy.gcp.sh logs bz-backend 500

On the VM: /home/bisht/.pm2/logs/bz-backend-{error,out}.log, merged, YYYY-MM-DD HH:mm:ss Z.

GrepFinds
cron-ablesStartup banner — crons started
cron job is disabledCRON=false
/defi/quotesQuote requests, with per-aggregator failures nearby
Route viaExecution-engine route rejections
Not swap calldataCalldata-guard hits
delivers no in-tx outputProbe rejections (solver providers)
error creating recordDCA creation failures
Not allowed by CORSAn origin missing from the allowlist
A wallet addressThat user's entire session
🔌 [Socket.io]Socket startup and adapter state

Log volume is high

Every request logs a line, and entryNode in bz-agent logs the classified intent on every chat message. Useful for debugging, noisy for storage. There is no log rotation policy documented beyond PM2's defaults.

Usage analytics

bash
node scripts/blazai-analytics.js

Produces the figures used in PROOF_POINTS — messages, sessions, unique wallets, non-fallback rate.

The non-fallback rate is not an accuracy measure

It counts messages that reached a real intent rather than the fallback path. A message classified as the wrong intent counts as a success. The headline "99.9%+ accuracy" should be read with that in mind, and re-verified before any public claim.

Frontend analytics: GA4 via src/utils/analytics.ts, a no-op unless VITE_GA_MEASUREMENT_ID is set. It also detects AI referrers (chatgpt, perplexity, gemini, copilot, claude, grok, meta-ai) and fires ai_referral once per session — the only measurement of AEO/GEO performance.

Revenue monitoring

bash
curl 'https://api.blazpay.com/api/defi/fees/summary?force=1'

Walks the relayer deployment record, reads native and known-token balances per chain over RPC, prices via CoinGecko, returns a USD total. Cached five minutes.

Only tokens with a coingeckoId are counted

Long-tail and spam tokens never accumulate as relayer fees, and skipping them keeps the RPC fan-out inside the 8-second per-chain timeout on big-catalogue chains. So the number is a floor, not an exact total.

Autopilot and DCA earnings accrue inside their vaults (platformEarnings) and are not in this summary. Read them on-chain or sweep with withdrawEarnings.

A practical daily check

Until there is real monitoring, this is the substitute:

□ ./scripts/deploy.gcp.sh status                  — four ports bound
□ node scripts/checkDeployerBalance.js            — executor has gas
□ Quote a liquid pair; count the routes            — provider health
□ ./scripts/deploy.gcp.sh logs bz-backend 200     — no repeated errors
□ curl /defi/fees/summary?force=1                 — fees still accruing
□ Spot-check a CSIP position executed today
□ If Autopilot is live: an agent traded, or a documented reason it did not

What to build first

Ranked by outage-minutes prevented per hour of work:

  1. Executor gas alert. A balance threshold with a Telegram message. TELEGRAM_ALERTS_CHAT_ID already exists.
  2. Per-provider quote success rate. Count and alert on a healthy provider dropping to zero. Closes the largest blind spot.
  3. Cron heartbeat. Write a lastRunAt per job and alert when one goes stale. A dead cron is currently invisible.
  4. Uptime check on /api plus a synthetic quote. Catches the "process is up but every request fails" case that the port check misses.
  5. Verify Sentry is actually wired. SENTRY_DSN is read; confirm errors arrive before trusting it.
  6. Autopilot router-allow-list assertion at startup. Log loudly when a configured chain has zero allow-listed routers.
  7. An intent-classification eval set. 50 labelled messages run on every prompt change — the only way to detect mis-classification.

Internal + developer documentation. Usage figures are point-in-time snapshots — re-verify before publishing them.