20.8. Monitoring
Table of Contents
Why Monitoring Matters
Monitoring is how you see what your backend is doing in real time. Logs tell you what happened. Monitoring tells you how things are going right now, and whether you need to act.
Some problems you can only catch by monitoring:
- Traffic spikes that overload your database
- Memory leaks that slowly grow until the process crashes
- Slow endpoints that hurt user experience but do not fail
- External services (payment, email, etc.) going slow or down
Without monitoring you often only learn about problems when users complain.
Important: Monitoring is about continuous measurement of system health and performance, not about debugging single requests. Use logs for details, use monitoring for trends and alerts.
In this chapter we focus on the concepts of monitoring. Specific tools like Prometheus and Grafana are covered in their own chapters.
Key Concepts in Monitoring
Metrics vs Logs vs Traces
You already saw logging earlier. Monitoring mainly works with metrics and sometimes traces.
- Logs
- Text, event based
- Example:
"User 123 created order 456" - Good for: debugging a specific error, understanding exact flows
- Metrics
- Numbers, aggregated over time
- Example:
requests_per_second = 124,error_rate = 0.8% - Good for: dashboards, alerts, trends, capacity planning
- Traces (covered more under Observability)
- Show how a single request moves through multiple services
- Example: user request → API → database → email service
Monitoring focuses mostly on metrics.
Types of Metrics
You will see the same few metric types again and again.
1. Counters
A counter only goes up, never down, except when the process restarts.
Examples:
- Total HTTP requests:
http_requests_total - Total errors:
http_errors_total - Total sent emails:
emails_sent_total
Example in pseudo code (Python style):
http_requests_total += 1
if response.status_code >= 500:
http_errors_total += 1You do not reset counters manually. Monitoring systems calculate rates from them, like requests per second.
2. Gauges
A gauge can go up and down.
Examples:
- Current CPU usage:
cpu_usage_percent - Current memory usage:
memory_used_bytes - Open DB connections:
db_connections_open - Queue length:
jobs_waiting_in_queue
Example:
db_connections_open = get_current_connection_count()3. Histograms / Summaries
These measure distributions, such as:
- Request duration
- Response sizes
- DB query times
They let you answer:
- How many requests finished in under 100 ms?
- What is the 95th percentile latency?
Example labels:
http_request_duration_seconds_bucket{
path="/api/orders",
method="GET",
le="0.1"
} 1234
This says: 1234 GET /api/orders requests finished in ≤ 0.1 seconds.
Rule of thumb:
Use counters for counts, gauges for "current values", and histograms for latencies and sizes. Do not store every value as a log if you only need aggregated behavior, use metrics.
What You Should Monitor
You cannot monitor everything. Start with the most important signals.
The “Four Golden Signals”
A very common model is the four golden signals of monitoring:
| Signal | Question it answers | Examples |
|---|---|---|
| Latency | How fast are requests? | Request duration, DB query time |
| Traffic | How much work is the system doing? | Requests per second, messages per second |
| Errors | How often do things fail? | Error rate, failed jobs, 5xx responses |
| Saturation | How “full” is the system? | CPU, memory, queue length, DB connections |
These give a high level picture of system health.
Latency
You care about:
- Overall average latency (not very useful alone)
- Percentiles like p95 or p99
Example:
- p50 (median) = 40 ms
- p95 = 450 ms
- p99 = 2 seconds
This tells you some users have a bad experience, even if the average looks fine.
Traffic
Examples:
- HTTP requests per second
- Tasks enqueued per minute
- Emails sent per minute
Use traffic metrics to:
- Spot sudden spikes
- See the effect of marketing campaigns
- Plan capacity
Errors
Important metrics:
- HTTP 5xx rate, e.g.
% of responses with status_code >= 500 - Failed background jobs
- Failed database transactions
- Failed external API calls
Often you define an error budget, for example:
Example error budget:
Up to 0.1% of all requests may fail in a month. If you exceed that, you must spend time on reliability before adding new features.
Saturation
Saturation shows how close you are to the limits:
- CPU usage, e.g. 80%
- Memory usage, e.g. 90% of RAM used
- DB connection pool usage, e.g. 95% connections in use
- Queue length growing over time
If saturation is always high, you may need more instances or optimization.
Application-Level Monitoring
System metrics like CPU and RAM are useful. But you also need application metrics that reflect your business and logic.
Technical Application Metrics
Common examples:
| Metric | Description |
|---|---|
http_requests_total | Total HTTP requests |
http_requests_in_flight | Requests currently being processed |
http_request_duration_seconds | Request duration histogram |
db_queries_total | Total DB queries |
db_query_duration_seconds | DB query time histogram |
jobs_queued_total | Jobs pushed to background queue |
jobs_failed_total | Failed jobs |
Add labels to metrics, for example:
method(GET, POST, etc.)endpoint(/api/orders,/api/users/{id})status_code(200, 400, 500)
Example in pseudo code:
increment("http_requests_total", labels={
"method": request.method,
"endpoint": "/api/orders",
"status_code": response.status_code,
})Do not create labels with unbounded values such as user IDs, email addresses, or random strings. That will explode your metric storage.
Important rule:
Metric label values should come from small, fixed sets like HTTP methods or a limited set of endpoints.
Never put user IDs, request IDs, or arbitrary strings in labels.
Business Metrics
Business metrics describe what the application achieves, not just how it runs.
Examples:
orders_created_totalpayments_failed_totalactive_users_gaugecart_abandon_rateemails_verification_sent_total
These help answer:
- Did a bug reduce the number of orders per hour?
- Is payment success rate dropping after a deployment?
- Are many users failing to log in?
Business metrics are often more important than purely technical ones, because they show real user impact.
Infrastructure Monitoring
Monitoring should not stop at your application. You also monitor the environment it runs in.
Host and Container Metrics
Examples:
| Metric | Description |
|---|---|
cpu_usage_percent | CPU usage per host or container |
memory_used_bytes | RAM usage |
disk_used_percent | Disk usage |
network_rx_bytes_total | Received bytes over network |
network_tx_bytes_total | Sent bytes over network |
With containers and orchestration (for example Docker, Kubernetes), you also monitor:
- Container restarts
- Container CPU and memory limits
- Pod status (Running, CrashLoopBackOff, etc.)
Dependency and External Service Monitoring
Dependencies often fail:
- Database
- Cache (Redis)
- Message queue
- Payment provider
- Email provider
- Third party APIs
For each important dependency, measure:
- Availability: Can you connect?
- Latency: How long do calls take?
- Error rate: How many calls fail?
Example:
external_api_requests_total{service="payments", status="success"} 1532
external_api_requests_total{service="payments", status="error"} 27When external services become slow, your own system may become slow too. Monitoring helps you detect this quickly.
Health Checks and Probes
Monitoring tools and load balancers often call health endpoints to check if your application is alive and ready.
Liveness vs Readiness
Two useful concepts:
- Liveness probe
- Answers: "Should this process be restarted?"
- Example: returns 200 OK if main loop is running
- If it fails, something is very wrong and restart is needed
- Readiness probe
- Answers: "Can this instance receive traffic?"
- Example: checks database connection, migration status, etc.
- If it fails, the load balancer should stop sending requests to this instance, but not necessarily restart it
Typical FastAPI style example:
@app.get("/health/live")
def liveness():
# If code runs, return OK
return {"status": "ok"}
@app.get("/health/ready")
def readiness():
if not db_is_connected():
raise HTTPException(status_code=503, detail="DB not ready")
return {"status": "ready"}Monitoring systems can watch these endpoints and alert if they fail.
Rule:
Expose simple, fast health endpoints.
Liveness should only check if the process is alive.
Readiness should check if dependencies are usable.
Dashboards
Dashboards present metrics in a way humans can understand quickly.
What to Put on a Dashboard
You usually create multiple dashboards:
- Overview dashboard
- Requests per second
- Error rate
- p95 latency
- CPU, memory, database connections
- API performance dashboard
- Latency per endpoint
- Error rate per endpoint
- Successful vs failed calls to external services
- Background jobs dashboard
- Jobs queued vs processed
- Failed jobs per worker
- Job processing latency
- Business dashboard
- Orders per minute
- Payment success rate
- Signups per hour
The main rule: keep them simple enough to understand in a stressful situation.
Example Dashboard Layout
| Row | Graphs |
|---|---|
| 1 | Requests per second, Error rate |
| 2 | p95 latency overall, p95 latency by main endpoints |
| 3 | CPU and memory, DB connections and query duration |
| 4 | Queue length, failed jobs per minute |
Alerting
Monitoring is useless if nobody reacts. Alerting notifies you when metrics cross dangerous thresholds.
Alert Rules
Typical alert rules:
- High error rate
- Condition:
5xx_error_rate > 2% for 5 minutes - Meaning: Many users see server errors
- High latency
- Condition:
p95_latency > 1s for 10 minutes - Meaning: Most users experience slow responses
- Resource saturation
- Condition:
cpu_usage_percent > 90% for 15 minutes - Condition:
db_connections_in_use > 95% - Unavailable health check
- Condition:
/health/readyfailing for 3 checks in a row
Example rule in plain language:
If http_5xx_error_rate is above 5% for 10 minutes, send a critical alert to the on-call channel.
Alert Channels
Common channels:
- Chat tools (Slack, Teams, etc.)
- Pager tools (PagerDuty, Opsgenie, etc.)
- SMS or phone call for critical alerts
You want:
- Low noise: Do not alert for everything. Too many alerts and people ignore them.
- High value: Every alert should mean "someone must look now".
Alert Priorities
Usually you define levels:
| Level | Example | Action |
|---|---|---|
| Info | New version deployed | No immediate action |
| Warning | Latency slightly higher than normal | Investigate during working hours |
| Critical | High error rate affecting many users | Immediate action, wake up on-call engineer |
Monitoring in Different Environments
You usually have at least:
- Development
- Staging / testing
- Production
Monitoring is most important in production, but other environments are useful too.
Production
- Full monitoring and alerting
- SLOs (service level objectives) and error budgets
- Dashboards for on-call and product teams
Staging / Testing
- Lighter monitoring
- Used to test end to end flows
- Check new deployments before going to production
Example:
- After deployment to staging, monitor error rate and latency for a while.
- If metrics look bad, fix before deploying to production.
Local Development
You normally do not need full monitoring locally, but you might:
- Expose a few metrics
- Try the metrics endpoint manually
- Verify that health checks work
Common Monitoring Pitfalls
Too Many Metrics
It is easy to instrument everything. That can create problems:
- High storage costs
- Slow dashboards
- Hard to find important metrics
Guidelines:
- Start with the four golden signals and a small set of business metrics.
- Remove unused metrics from dashboards.
- Think before adding labels.
Missing Context
If you only see "error rate high", that is not enough.
Combine metrics with:
- Logs for details about errors
- Traces for which step is slow or failing
- Deployment information (version, time of last deployment)
Example: after a deployment at 12:05, latency jumps at 12:07. This gives you a strong hint that the deployment caused the issue.
No Clear Ownership
If everyone owns monitoring, sometimes nobody does. Decide:
- Who maintains alert rules
- Who is on call
- Who keeps dashboards up to date
How Monitoring Fits With Logging and Observability
Monitoring is one part of a bigger picture often called observability.
A simple mental model:
| Layer | Purpose |
|---|---|
| Logging | Understand specific events and errors |
| Monitoring | Watch system health and performance over time |
| Tracing | Follow a single request through the system |
You will often:
- Receive an alert from monitoring.
- Look at dashboards to confirm there is a problem.
- Check logs or traces to find the exact cause.
Monitoring connects high level symptoms (error rate up, latency up) to detailed investigation (logs, traces).
Summary
- Monitoring is about continuous measurement of system health and performance, mainly using metrics.
- Focus on the four golden signals: latency, traffic, errors, saturation.
- Use counters, gauges, and histograms for different kinds of data.
- Monitor both technical metrics and business metrics.
- Add clear health checks for liveness and readiness.
- Build dashboards that are easy to read during incidents.
- Configure alerts for meaningful, user impacting problems, not everything.
- Combine monitoring with logs and traces for full understanding.
Next chapters will show concrete tools like Prometheus and Grafana, and how to implement monitoring for your backend.
Views: 7
KAHIBARO