Logs and monitoring
Backend logs
One logging configuration, built by EMAW_BACKEND/logging_utils.py, applies everywhere. Handlers are on the root logger only.
| Output | What | Where |
|---|---|---|
| stdout | everything (always on) | `docker compose logs -f django |
app.log | general application log | log_data volume → /app/logs/ in the containers |
error.log | warnings and errors | same |
security.log | events written through EMAW.security_log.audit() (logins, verification, staff actions) | same |
| access line per request | method, path, status, duration, request id (from RequestLoggingMiddleware) | app.log / stdout; gunicorn's own access log is disabled |
Files rotate via concurrent-log-handler (multiprocess-safe). Variables: LOG_DIR (default logs/, /app/logs in Docker), DJANGO_LOG_LEVEL, LOG_TO_FILE (0 for stdout only), LOG_JSON (structured lines), TRUST_CF_CONNECTING_IP (real client IP behind the tunnel).
docker compose exec django tail -n 200 /app/logs/error.log
docker compose exec django grep <request-id> /app/logs/app.log
What is never logged
Emails, tokens, verification codes, passwords and request bodies. The formatter redacts JWTs, emails and Stripe keys as a backstop. Log user ids. Use %s lazy formatting.
Following one request
Every response carries X-Request-ID. The Admin CRM shows it on error toasts; ask the staff member for it, then grep the backend logs. Celery propagates the id into task logs, so an order's webhook, CRM link, email and Deposco submission share it.
Frontend and mobile
- Cloudflare Pages / Workers: deployment logs in the Cloudflare dashboard; the CRM Worker has live logs under Workers →
emaw-admin→ Logs. - The CRM's ESLint forbids
console.logbecause bodies can contain personal data; errors go to toasts with the request id. - Mobile:
adb logcat, Xcode console; the axios instance logs requests in development only. Crash reporting comes from the store consoles (Google Play vitals, App Store Connect crashes). No crash SDK is installed.
External dashboards
| Service | Shows |
|---|---|
| Stripe Dashboard → Developers → Webhooks | failed deliveries to the webhook; retry from there |
| Azure Communication Services → Email → Insights | campaign delivery, bounces |
| Cloudflare → Zero Trust → Tunnels | whether a connector is up for dev.emaw-app.com / app.emaw-app.com (and how many: two means someone has the dev tunnel) |
| Cloudflare → Workers & Pages → project → Deployments | last deploy, build logs |
| Azure Portal → VM → Metrics | CPU, disk; the dev DB VM's disk is worth watching |
| Expo → project → Updates / Builds | what mobile users are running |
What does not exist yet
- No uptime check on
app.emaw-app.comor the frontends. - No alerting on
error.logor Celery failures. - No centralised log shipping; logs stay on the VMs.
- No crash reporting SDK in the mobile app.
These are candidates for the known gaps list and the modernization roadmap's "monitoring, alerts and incident response" item.