Expert · Deploying and running the app · topic 27 of 34 · 30 min
Monitoring, logs and alerts
Explanation
Why monitor?
Most users do not report problems. They see an error, close the tab and do not come back. Monitoring means machines watch the app all the time and tell a person when something is wrong, often before many users notice.
A health endpoint
A health endpoint is a small route, such as GET /api/health, that says whether the app can do its job. It checks the parts it depends on, mainly the database, and returns 200 when all is well or 503 (Service Unavailable) when something is broken.
app.get('/api/health', async (req, res) => {
const checks = {};
try {
await db.query('SELECT 1'); // a tiny query: can we reach the database?
checks.database = 'ok';
} catch (err) {
checks.database = 'fail';
}
const healthy = Object.values(checks).every((v) => v === 'ok');
res.set('Cache-Control', 'no-store');
res.status(healthy ? 200 : 503).json({ status: healthy ? 'ok' : 'error', checks });
});An uptime monitor is an outside service, such as UptimeRobot or Better Stack, that calls your health URL every minute or few minutes from several places. If it fails, it alerts you by email, SMS or a phone app. Many platforms can also use the health path to restart an unhealthy instance. Free plans exist, but their limits change; check the official pages.
Logs that help, without leaking
A log is a line your app writes for each event. Structured logs are written as JSON with fixed field names, one line per event, so a log tool can search and count them ("all requests with status 500 in the last hour"). For Express, a fast JSON logger such as pino is common. Add a request id to every line, so you can follow one request through all its log lines.
{"level":"info","time":"2026-10-19T08:15:02.120Z","requestId":"9f1c2a","method":"POST","path":"/api/notes","status":201,"durationMs":48,"userId":17}Errors and the key numbers
Error tracking tools such as Sentry catch crashes in the browser and on the server, group the same error together, and show the stack trace (the list of function calls that led to it), the release and how many users were hit. You fix the biggest group first.
| Number | What it means | A sensible goal for the Notes app |
|---|---|---|
| Error rate | Percent of requests that end with a server error (status 500 to 599) | Below 1% |
| p95 latency | 95% of requests are faster than this; the slowest 5% are slower | Below 500 ms for GET /api/notes |
| Uptime | Percent of time the health check passed | 99.9%, which still allows about 43 minutes down in a 30-day month |
Why p95 and not the average? An average hides the slow requests. If 19 requests take 50 ms and one takes 5 seconds, the average is about 300 ms and looks fine, but one user in twenty waited 5 seconds. The p95 shows that pain.
Alerts, backups and incidents
- An alert must reach a person who can act: a phone notification or SMS to whoever is on duty, not only an email folder nobody opens.
- Alert on what users feel: the site is down, or the error rate is above 2% for 5 minutes. Too many small alerts teach people to ignore all of them.
- Backups: managed PostgreSQL usually has automatic backups and point-in-time recovery (restoring the database to how it was at a chosen minute). Check how many days your plan keeps.
- Test the restore: once a month, restore a backup into a new, separate database and check the notes are there. Note how long it took.
- Acknowledge the alert and tell the team you are on it.
- Look at what changed: the last deploy, config, traffic, the provider's status page.
- Stop the harm first: roll back, restart or switch the feature off.
- Tell users in plain words (a status page or a banner) if they are affected.
- Fix the cause, then write a short, blameless note: what happened, why, and what will stop it happening again.
Watch the lesson
Monitoring, logs and alerts · 1/7
Our Notes app is live. Now we must know it is healthy before users complain.
Prefer a video by a teacher? Find free videos on “monitoring logging alerting web app health check sentry uptime tutorial” on YouTube ↗
In real life: A UPI-based fee payment site at the month end
A coaching centre collects monthly fees through a site with UPI payments. On the 1st, the uptime monitor still showed green, but the error tracker showed a new error group: payment confirmations failing for some users. The p95 latency of the confirm route had jumped from 300 ms to 6 seconds, and the logs (with request ids, but no payment details) showed timeouts to the database. The on-duty developer rolled back the morning release, which had added a slow query. Later they added an alert on error rate, not only on uptime, and an index for the query.
Practice (0/3 done)
Write healthResponse(checks). checks is an object like { database: true, storage: false }. Return { status, body } where body is { status, checks }: each check becomes "ok" (true) or "fail" (anything else), keeping the same keys in the same order. If every check is true, status is 200 and body.status is "ok"; otherwise status is 503 and body.status is "error".
Write p95(latencies) that returns the 95th percentile of an array of response times in milliseconds, using the nearest-rank method: sort a COPY of the numbers from smallest to largest, then return the value at position Math.ceil(n * 95 / 100) - 1, where n is the count. Return null for an empty array. Do not change the input array.
Write errorRate(requests). Each request is an object like { path, status }. Return the percent of requests whose status is from 500 to 599, rounded to 1 decimal place (use Math.round(x * 10) / 10). Client errors such as 400, 401 and 404 do not count. Return 0 for an empty list.
Quick quiz
Read more (free)
Pass the quiz (60% or more) or mark this topic as done when you are ready.
Your progress is saved on this device only.