Monitoring, uptime and log management
Health endpoints, uptime checks and alerting, log aggregation and retention, error tracking, and the difference between uptime and correctness.
Health endpoints
// two endpoints with different jobs
app.get("/healthz", (req, res) => res.status(200).send("ok")); // liveness: is the process alive
app.get("/readyz", async (req, res) => { // readiness: can it serve?
const checks = await Promise.allSettled([
db.query("select 1"),
cache.ping(),
queue.ping()
]);
const failed = checks.filter((c) => c.status === "rejected").map((c) => String(c.reason));
if (failed.length) return res.status(503).json({ ok: false, failed });
return res.json({ ok: true });
});| Endpoint | Answers | On failure |
|---|---|---|
| Liveness | Is this process running and not deadlocked | Restart the container |
| Readiness | Can this instance serve a request now | Remove it from the load balancer, do not restart |
| Startup | Has initialisation finished | Wait before probing liveness |
| Deep health | Are dependencies healthy | Use for alerting, not for removing instances |
| Ping | Is the socket accepting connections | Almost never useful on its own |
- Never point a liveness probe at an endpoint that checks the database. A brief database blip would restart every instance at once, turning a degradation into an outage.
- A readiness check should be fast and cheap. It runs every few seconds on every instance.
- Keep the health endpoint out of the public route if it exposes dependency names, or return a minimal body.
Uptime checks and alerting
- Check from outside the provider's network. A monitor inside the same platform shares its fate and will report green during an edge failure.
- Check the user journey, not just the homepage: a login, a search, one write that is rolled back. A homepage that returns 200 while checkout is broken is not uptime.
- Alert on symptoms users feel - error rate, latency percentiles, failed checkouts - not on every CPU spike.
- Set thresholds that a single blip cannot cross. An alert that fires for 30 seconds of noise gets muted within a week.
- Route alerts to a person, with a runbook link in the alert body. An alert with no owner is decoration.
- Review the alert list monthly and delete the ones nobody acts on.
Alerting sketch
page error rate above 1 percent for 5 minutes
p95 latency above 2 s for 10 minutes
readiness failing on more than half the instances
certificate expiring in less than 14 days
backup job failed
queue depth growing for 15 minutes
ticket disk above 80 percent
a single failed deploy
elevated 404 rate on a key route
dashboard request rate, error rate, latency, saturation - and nothing else# an external check you can run from anywhere
curl -fsS -o /dev/null -w "%{http_code} %{time_total}s\n" https://example.com/readyz
# and one that exercises a real path
curl -fsS -o /dev/null -w "%{http_code} %{time_total}s\n" \
"https://example.com/api/search?q=test"Logs and error tracking
// structured logs: one JSON object per line, with the fields you will search on
logger.info({
event: "order.created",
orderId: order.id,
customerId: order.customerId,
amount: order.total,
durationMs: Date.now() - started
});
// never log secrets, tokens or full personal data
logger.info({ event: "auth.login", userId: user.id, ip: req.ip }); // not the password, not the token| Concern | Practice | Why |
|---|---|---|
| Format | Structured, one line per event | Searchable and parseable |
| Correlation | A request id on every line | Rebuilds one user's journey |
| Levels | Debug in dev, info or warn in production | Cost and signal-to-noise |
| Retention | Short for debug, longer for audit | Storage is billed |
| Redaction | Strip tokens, cookies, card data | Compliance and safety |
| Error tracking | A separate tool with grouping and stack traces | Logs are not a good error UI |
| Sampling | Sample high-volume success paths | Cost control without losing failures |
Metrics answer "how much" cheaply and over time; logs answer "what exactly happened" expensively; traces answer "where did the time go" across services. Sending everything to logs and nothing to metrics is the most common and most expensive mistake.
⚠️
A green uptime check is not a working service. If checkout has failed for every user for an hour while the homepage returns 200, your monitoring is measuring the wrong thing. Add one synthetic transaction that a real user would recognise.
FAQ
How long should logs be kept?
Long enough to investigate anything you would need to investigate. Thirty days is a common default for application logs; security and audit logs usually need longer, and some regulations specify a period.
Should I alert on every error?
No. Alert on rates and on user-visible impact. A single failed request in an hour is normal; a spike or a sustained failure is not.
Related
Databases, object storage and backups Scaling: load balancing, autoscaling and stateless design
Last refreshed 2026-09-18.