Observability
Vercel's built-in logs capture console.* output and unhandled exceptions; on top of that we emit structured JSON through a small logger wrapper.
What's available now
- Structured logger at
src/lib/log.ts—log.info,log.warn,log.error,logError(event, err, context?). All wrapconsole.*and write{level, event, ts, ...context}JSON so Vercel log search can filter byevent. - Per-request correlation via
X-Request-Id— generated inwithApiAuth(src/lib/api/request-id.ts) and echoed back on every/api/v1/*response. /api/health— Postgres + Upstash probes. Used by external uptime monitors;logError("health.check_failed", ...)fires only on failure so polling doesn't spam the log.- Vercel Function Logs — stdout / stderr.
- Upstash Analytics — rate-limit call counts (enabled on
@upstash/ratelimit). - Stripe Dashboard — subscription and webhook events.
- AWS CloudWatch — SES + SNS call-level metrics.
- Webhook delivery log —
webhook_deliveriestable rows; inspection UI on/overview/webhooks. - Audit log —
audit_logstable; dashboard at/overview/settings/audit.
What the logger covers today
| Surface | Event prefix | Notes |
|---|---|---|
| Cron: scheduled sends | cron.scheduled.* |
usage_increment and fanout failures, plus cron.scheduled.run summary |
| Cron: webhook retry | cron.retry_webhooks.run |
processed + due counts |
| Cron: idempotency cleanup | cron.cleanup_idempotency.run |
delete count |
| Cron: overage report | cron.overage.* |
run summary; per-org Stripe create failures |
| Webhook: SES | webhook.ses.* |
signature failures, fan-out failures, processed summary |
| Webhook: SNS SMS | webhook.sns_sms.* |
signature failures, fan-out failures, processed summary |
| Webhook: inbound email | webhook.inbound_email.* |
signature failures, fan-out failures, processed summary |
| Template test send | template.test_send* |
success + failure paths |
| Stripe webhook | stripe.webhook.* |
handler-level failures |
Webhook fan-out now runs inside after(() => ...) from next/server, so the handler returns a 200 before provider callbacks happen and errors surface via the logger only.
Still missing
- No Sentry / OTEL / APM.
- No latency histograms beyond Vercel defaults.
- No
webhook_deliveriesfailure surface beyond the dashboard view.
Quick wins next
- Sentry —
@sentry/nextjspicks up both server and client errors with one install + config. - Vercel OTEL — export traces to Honeycomb / Datadog / Jaeger.
- Weekly audit log email to owners summarizing notable actions.