20.6. Metrics
Table of Contents
Why Metrics Matter
Metrics are numeric measurements that describe how your backend behaves over time. They tell you:
- Is the application healthy?
- How fast are requests?
- How many errors happen?
- How much CPU, memory, or database capacity you use?
Logs tell you what happened, for specific events. Metrics tell you how often and how much, in an aggregated way that you can chart and alert on.
Key idea: Metrics are numbers over time that you can aggregate, visualize, and alert on. They are essential for understanding performance, reliability, and capacity.
You will later connect these ideas to tools like Prometheus and Grafana, but here we focus on understanding what to measure and how to think about metrics.
Types of Metrics
There are three big families you should know: infrastructure metrics, application metrics, and business metrics.
Infrastructure Metrics
These come from servers, containers, and databases.
Examples:
| Area | Example Metric | Description |
|---|---|---|
| CPU | cpu_usage_percent | How busy the CPU is |
| Memory | memory_used_bytes | RAM currently used |
| Disk | disk_used_percent | Used disk as a percentage of total |
| Network | network_bytes_in_total | Bytes received over the network |
| OS Processes | process_count | Number of processes/threads |
| Database | db_active_connections | Open DB connections from your app |
You usually get these from the OS, container runtime, cloud provider, or database.
Application Metrics
These come from your backend code. You add these manually through your application.
Typical examples:
| Category | Example Metric |
|---|---|
| Requests | http_requests_total |
| Errors | http_requests_errors_total |
| Latency | http_request_duration_seconds |
| Background jobs | jobs_processed_total |
| Caching | cache_hits_total, cache_miss_total |
| External calls | external_api_duration_seconds |
You will often expose these through an endpoint like /metrics for tools to scrape.
Business Metrics
These describe what users and the business are doing, not just the technical system.
Examples for an e‑commerce backend:
| Metric | Meaning |
|---|---|
orders_created_total | Number of orders created |
payments_failed_total | Number of payment failures |
active_users | Currently logged-in users |
cart_abandon_rate | Percentage of carts never checked out |
Business metrics help you connect technical issues to business impact.
Core Backend Metrics: RED and USE
Two widely used frameworks help you remember the important metrics.
RED: Requests, Errors, Duration
The RED method is for services that handle requests (APIs, web backends).
- Requests: how many requests per second
- Errors: how many failed requests
- Duration: how long requests take
Examples:
http_requests_totalhttp_requests_errors_total(4xx and 5xx)http_request_duration_seconds(recorded for each request)
You usually break these down by:
- HTTP method:
GET,POST,PUT, etc. - Path or endpoint:
/users,/orders/{id} - Status code: 200, 404, 500
USE: Utilization, Saturation, Errors
The USE method is for resources like CPU, memory, disk, and databases.
- Utilization: how busy the resource is
- Saturation: how overloaded it is
- Errors: how many hardware or resource errors occur
Examples:
| Resource | Utilization | Saturation | Errors |
|---|---|---|---|
| CPU | cpu_usage_percent | run_queue_length | cpu_errors_total (rare) |
| Disk | disk_usage_percent | disk_io_queue_length | disk_errors_total |
| DB | db_active_connections vs max | db_query_queue_length | db_connection_errors_total |
Use RED to see if your service is “slow or failing”. Use USE to see “which resource is the bottleneck”.
Metric Types: Counter, Gauge, Histogram, Summary
Monitoring tools categorize metrics into a few types. Understanding them helps you choose the right one.
Counters
A counter is a number that only goes up (or resets to zero).
Examples:
http_requests_totalhttp_requests_errors_totaljobs_processed_totalorders_created_total
Use counters for “how many times something happened”.
You often compute rates from counters, for example:
- Requests per second
- Errors per minute
If you have a counter http_requests_total, the rate over time window $\Delta t$ is:
$$\text{requests\_per\_second} = \frac{\Delta\text{http\_requests\_total}}{\Delta t}$$
Rule: Use counters for values that only increase (requests, errors, jobs). Calculate rates from counters instead of incrementing “per second” values yourself.
Gauges
A gauge goes up and down.
Examples:
memory_used_bytesdb_active_connectionsqueue_lengthactive_usersin_progress_requests
Use gauges for “current state right now”.
Histograms
A histogram samples observations into buckets. It is used to measure distributions like latencies.
Example: http_request_duration_seconds with buckets
- 0.01s
- 0.05s
- 0.1s
- 0.5s
- 1s
- 5s
The system counts how many requests fall into each bucket. From this you can compute:
- Median latency (p50)
- 95th percentile latency (p95)
- 99th percentile latency (p99)
Summaries
A summary is similar to a histogram but often precomputes quantiles directly on the application side. In practice:
- Histograms are usually preferred with systems like Prometheus.
- Summaries can be useful but are less flexible at query time.
For this course, focus on histograms and counters.
Useful Metrics for a Typical Backend
Here is a practical set of metrics to aim for when you build a backend API.
HTTP Request Metrics
You can define these for every endpoint:
| Metric name | Type | Description |
|---|---|---|
http_requests_total | Counter | Total number of HTTP requests |
http_requests_errors_total | Counter | Total 4xx and 5xx responses |
http_request_duration_seconds | Histogram | Request handling time |
http_in_progress_requests | Gauge | Requests currently being processed |
request_body_size_bytes | Histogram | Size of incoming request bodies |
response_body_size_bytes | Histogram | Size of responses |
You should label these by:
methodlikeGET,POSTpathlike/users/{id}normalized to avoid unique IDsstatus_codelike200,404,500
Example label set:
http_requests_total{method="GET", path="/users", status_code="200"}
Database Metrics
Important database metrics:
| Metric | Type | Meaning |
|---|---|---|
db_active_connections | Gauge | Current connections from your app |
db_connection_errors_total | Counter | Failed connection attempts |
db_query_duration_seconds | Histogram | Time each query takes |
db_deadlocks_total | Counter | Number of detected deadlocks |
db_rows_read_total | Counter | Rows read by queries |
db_rows_written_total | Counter | Rows inserted or updated |
Later, in the PostgreSQL and performance sections, you will see how to collect DB metrics in more detail.
Background Job Metrics
For background workers:
| Metric | Type | Meaning |
|---|---|---|
jobs_enqueued_total | Counter | Jobs added to the queue |
jobs_started_total | Counter | Jobs started |
jobs_completed_total | Counter | Jobs finished successfully |
jobs_failed_total | Counter | Jobs that ended with an error |
job_duration_seconds | Histogram | Time taken per job |
job_queue_length | Gauge | Number of pending jobs |
Cache Metrics
For Redis or in‑memory caches:
| Metric | Type | Meaning |
|---|---|---|
cache_hits_total | Counter | Number of cache hits |
cache_misses_total | Counter | Number of cache misses |
cache_evictions_total | Counter | Items removed due to memory limits |
cache_size | Gauge | Items currently stored |
You can compute the cache hit ratio:
$$
\text{hit\_ratio} = \frac{\text{cache\_hits\_total}}{\text{cache\_hits\_total} + \text{cache\_misses\_total}}
$$
Important: A higher cache hit ratio usually means better performance and less load on your database.
Latency Metrics and Percentiles
Average latency is often misleading. Averages hide “tail latency” where a small percentage of requests are very slow.
For example:
- 90 requests take 50 ms
- 10 requests take 5 seconds
The average is:
$$
\text{avg} = \frac{90 \cdot 0.05 + 10 \cdot 5}{100} = 0.545 \text{ seconds}
$$
But:
- 90% of users see 0.05 s.
- 10% of users see 5 s.
So you need percentiles:
- p50 (median) 50% of requests are faster than this.
- p95 95% are faster than this.
- p99 99% are faster than this.
Typical SLOs use p95 or p99 latency.
Example SLO:
- “95 percent of
GET /ordersrequests must complete in under 300 ms.”
When you define histograms for latencies, you can compute these percentiles with your monitoring tools.
From Metrics to Alerts and SLOs
Metrics are not useful if nobody looks at them. You use them to define:
- Dashboards for visual inspection.
- Alerts when something is wrong.
- SLOs (Service Level Objectives) about uptime and performance.
Simple Alert Examples
Using the RED and USE metrics:
- Error rate is high
http_requests_errors_total / http_requests_total > 0.05for 5 minutes.- Latency is high
- p95 of
http_request_duration_seconds> 1 second for 10 minutes. - Database is overloaded
db_active_connectionsclose to max for 10 minutes.- Queue is stuck
job_queue_lengthgrowing for 15 minutes whilejobs_completed_totalis flat.
You will learn more about alerting in monitoring and production chapters, but keep these patterns in mind as you design metrics.
How to Instrument a Backend (Conceptually)
The exact code depends on your language and monitoring stack, but the steps are similar.
1. Choose a Metrics Library
For Python backends, popular choices include:
prometheus_clientfor Prometheus style metrics.- Built‑in integrations in frameworks or ASGI servers.
2. Define Metrics
You typically define metrics as globals near your app startup:
from prometheus_client import Counter, Histogram
REQUEST_COUNT = Counter(
"http_requests_total",
"Total HTTP requests",
["method", "path", "status_code"],
)
REQUEST_LATENCY = Histogram(
"http_request_duration_seconds",
"HTTP request latency",
["method", "path", "status_code"],
buckets=[0.01, 0.05, 0.1, 0.3, 1.0, 3.0]
)
Note: Do not overdo labels. Stick to a small set like method, path, status_code.
3. Instrument Requests (e.g., via Middleware)
Use middleware to measure every request:
import time
from starlette.middleware.base import BaseHTTPMiddleware
class MetricsMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request, call_next):
start = time.perf_counter()
response = await call_next(request)
latency = time.perf_counter() - start
method = request.method
path = request.url.path
status_code = str(response.status_code)
REQUEST_COUNT.labels(method=method, path=path, status_code=status_code).inc()
REQUEST_LATENCY.labels(method=method, path=path, status_code=status_code).observe(latency)
return response
Later, you expose a /metrics endpoint that returns all metrics in a format that your monitoring system understands.
You will go deeper into specific tools in the Prometheus and Grafana sections, but this pattern is common across stacks.
Good Practices for Metrics Design
Start Simple
Begin with a small set:
http_requests_totalhttp_requests_errors_totalhttp_request_duration_secondsdb_active_connectionsjobs_processed_totalif you have workers
You can add more when you see a clear need.
Be Careful With Labels
Each unique set of labels creates a new time series. Too many labels can cause high memory usage.
Avoid:
- Labels with user IDs
- Labels with request IDs
- Labels with timestamps
- Labels with high‑cardinality values like full URLs with IDs
Prefer:
- Normalized paths like
/users/{id}instead of/users/123 - Small enums like
status="success" | "failure"
Use Consistent Naming
You do not have to copy these exactly, but consistency helps:
- Use
_totalsuffix for counters, for example,http_requests_total. - Use
_secondsfor duration metrics, for example,http_request_duration_seconds. - Use
_bytesfor size metrics, for example,response_size_bytes. - Use
_ratioor_percentwhen applicable, for example,cache_hit_ratio.
Rule: A metric name should be clear, consistent, and unit‑aware. Include the unit in the name, such as _seconds or _bytes.
Align Metrics With Requirements
Think about questions you want to answer:
- “Is the API slow for users?”
- “Is the database near capacity?”
- “Are background jobs keeping up?”
- “Is caching effective?”
Choose metrics that let you answer those questions quickly, without digging through logs.
Summary
In this chapter you learned:
- Metrics are numeric measurements over time, essential for performance, reliability, and capacity.
- You can group metrics into infrastructure, application, and business metrics.
- RED focuses on requests, errors, and duration, while USE focuses on utilization, saturation, and errors.
- Metric types are counters, gauges, histograms, and summaries, with counters and histograms being most important.
- Latency percentiles like p95 and p99 are more meaningful than simple averages.
- You use metrics to build dashboards, define alerts, and support SLOs.
- Basic instrumentation involves defining metrics, measuring in middleware, and exposing them via an endpoint.
Later chapters on Prometheus, Grafana, and observability will show how to collect, store, visualize, and alert on these metrics in a production backend.
Views: 5
KAHIBARO