Skip to content

Expert · Deploying and running the app · topic 27 of 34 · 30 min

Monitoring, logs and alerts

Explanation

Once the app is live, you need to know it is working before users tell you it is not. A health endpoint, an uptime monitor, clean logs and error tracking show what is happening; a few key numbers and alerts tell a person when to act. Backups that you have actually restored, and a simple incident routine, protect the users' notes when something goes wrong.

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.

Think of it like this: In a hospital ward, a monitor beside each bed shows heart rate, blood pressure and oxygen. The nurse does not stare at it all night; it beeps when a number crosses a safe limit. The patient's file records what happened and when, so the doctor can understand it later. Your app needs the same: numbers, an alarm and a written record (the logs).

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.

javascript
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 });
});
The health route of the Notes API. No login needed, no secrets in the answer.

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.

json
{"level":"info","time":"2026-10-19T08:15:02.120Z","requestId":"9f1c2a","method":"POST","path":"/api/notes","status":201,"durationMs":48,"userId":17}
One structured log line: what happened, how long it took and for which user id, with no private content.
Careful: Never log passwords, session cookies, tokens, API keys, full phone numbers or the text of users' notes. Logs are copied to many tools and kept for a long time, and people with log access are not supposed to read users' private data. Log ids, and mask anything personal you truly need (r***@example.com).

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.

NumberWhat it meansA sensible goal for the Notes app
Error ratePercent of requests that end with a server error (status 500 to 599)Below 1%
p95 latency95% of requests are faster than this; the slowest 5% are slowerBelow 500 ms for GET /api/notes
UptimePercent of time the health check passed99.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.
  1. Acknowledge the alert and tell the team you are on it.
  2. Look at what changed: the last deploy, config, traffic, the provider's status page.
  3. Stop the harm first: roll back, restart or switch the feature off.
  4. Tell users in plain words (a status page or a banner) if they are affected.
  5. Fix the cause, then write a short, blameless note: what happened, why, and what will stop it happening again.
Tip: Keep the health check fast and cheap, and do not put version numbers, hostnames or error details in its answer. Attackers read public health pages too.

Watch the lesson

Monitoring, logs and alerts · 1/7

Know before users tell you

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)

Task 1 · Code · Javascript

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".

Task 2 · Code · Javascript

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.

Task 3 · Code · Javascript

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

Question 1

1.The database is down. What should GET /api/health return?

Question 2

2.Which log line is safe to write?

Question 3

3.19 requests take 50 ms and one takes 5000 ms. Which number shows the slow request best?

Question 4

4.When can you trust a database backup?

Question 5

5.In an incident, what comes before finding the root cause?

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.

← Previous: CI/CD: shipping every change safely