Build the mental model
Monitoring answers urgent questions: is the app running, is it slow, are errors increasing, is memory or CPU near a limit.
| Pillar | Question it answers |
|---|---|
| Logs | What happened? A discrete record of one event. |
| Metrics | How much, how often? Numbers over time. |
| Traces | Where did the time go? A request's path across services. |
Structured logging writes each log as a JSON object with consistent fields, making logs searchable and aggregable at scale instead of a wall of text.
Never log secrets
Never write a full password, API key, or auth token into a log line — for example "apiKey: sk_live_abc123..." in a log statement. Logs are searched, copied, and kept far more casually than a database.
Health checks should return a simple status, not internal details. Error tracking and uptime monitoring use the same signals to answer different, equally necessary questions.
- Metrics
- Numeric measurements over time, like requests per second or error rate, used to answer 'how much, how often'.
- Traces
- The recorded path and timing of one request as it moves across multiple services.
- Observability
- The broader ability to answer questions about a running system, including ones not anticipated in advance, using logs, metrics, and traces together.
THREE PILLARS OF OBSERVABILITY
------------------------------
THREE PILLARS OF OBSERVABILITY
---------------------------------
[ LOGS ] [ METRICS ] [ TRACES ]
what happened how much/often where time went
| | |
+--------+--------+--------+--------+
|
v
"is the system healthy?"
|
+---------+---------+
v v v
health check error uptime
endpoint tracking monitoringConnect it to a real scenario
A structured log entry is an object with consistent fields, turned into JSON — the shape a log aggregator expects.
Before printing, every field name is checked against secret-shaped keys (password, apiKey, token, secret) and redacted if matched.
Redaction should be automatic, not remembered
A log line is a place secrets go to leak. Redaction applied automatically beats relying on every developer remembering it correctly under deadline pressure.
Never log secrets
A full API key, password, or auth token in a log line is a leak the moment anyone can read that log — and logs are read far more casually than a database.
Try the working example
function createLogEntry({ level, requestId, message, fields = {} }) {
const SECRET_KEYS = ["password", "apikey", "api_key", "token", "secret"];
const safeFields = {};
for (const [key, value] of Object.entries(fields)) {
safeFields[key] = SECRET_KEYS.includes(key.toLowerCase())
? "[REDACTED]"
: value;
}
return JSON.stringify({
level,
requestId,
message,
fields: safeFields,
timestamp: "2026-09-04T00:00:00.000Z",
});
}
console.log(createLogEntry({
level: "info",
requestId: "req-1",
message: "user login succeeded",
fields: { userId: "u-42", apiKey: "sk_live_abc123" },
}));
console.log(createLogEntry({
level: "error",
requestId: "req-2",
message: "payment failed",
fields: { orderId: "o-99", password: "hunter2" },
}));{"level":"info","requestId":"req-1","message":"user login succeeded","fields":{"userId":"u-42","apiKey":"[REDACTED]"},"timestamp":"2026-09-04T00:00:00.000Z"}
{"level":"error","requestId":"req-2","message":"payment failed","fields":{"orderId":"o-99","password":"[REDACTED]"},"timestamp":"2026-09-04T00:00:00.000Z"}5-minute try-it
Add 'creditCardNumber' and 'ssn' to SECRET_KEYS, then log an entry containing both alongside a normal field like orderId. Confirm both sensitive fields come out redacted while orderId does not.
One important caution
Logging a full request or user object without filtering, accidentally including a password or token field that rode along inside it.
Treating error tracking and uptime monitoring as the same thing — a healthy uptime check can still hide a spike in application errors.
MDN — HTTP response status codes (health check status) — Cloud & Deployment