Learning objectives
By the end of this module, you should be able to:
- Use `rate()` correctly with counters.
- Preserve useful dimensions with `sum by(...)`.
- Explain why aggregation order can hide a localized problem.
Rates make counters operational
Cumulative counters become useful for current traffic and error behavior when converted to rates over a window. Choose a window appropriate to scrape interval and operational sensitivity.
Aggregate after preserving the dimension you need
A single global average can hide one slow route, region or instance. Group by the dimension that matches the question before broad aggregation.
Ratios need aligned numerator and denominator
An error ratio compares error request rate with total request rate over the same population and time window. Mismatched labels or filters can produce misleading ratios.
Worked example
See the investigation idea in practice.
PromQL investigation patterns
rate(http_requests_total[5m])
sum by (route) (rate(http_requests_total[5m]))
sum(rate(http_requests_total{status=~"5.."}[5m])) / sum(rate(http_requests_total[5m]))
- Read the evidence before deciding what it means.
- Prefer a hypothesis that explains multiple independent signals.
Core lab · account-free
Lab 04 — Query reasoning without a server
Goal: Evaluate grouping and ratio logic against a small request-rate dataset.
Before you start
- No cloud account required.
- Core lab uses bash/Python 3 and local files only.
STEP 1Create route rates
cat > /tmp/rates.csv <<'EOF'
route,total,error,p95_ms
/,100,1,120
/search,80,2,180
/checkout,20,7,2200
EOF
STEP 2Calculate error ratios
python3 - <<'PY'
import csv
for r in csv.DictReader(open('/tmp/rates.csv')):
print(r['route'], round(100*float(r['error'])/float(r['total']),1),'%')
PY
STEP 3Compare aggregation
Explain why a global error ratio is less diagnostic than grouping by route in this incident.
Verify
- Checkout is identified as the worst route by both error ratio and p95 latency.
- You explain which grouping dimension preserves the signal.
Expected outcome
- A query plan that answers a specific operational question without aggregating away the problem.
Diagnose / troubleshoot
- If `rate()` appears negative after hand-calculation, remember counters can reset; Prometheus `rate()` handles resets.
- If a ratio is impossible (>1), inspect label alignment and numerator/denominator filters.
Real-world connectionGood PromQL is question-driven: query only after stating what you are trying to distinguish.
Optional real-tool lab
Optional tool lab — run PromQL
Execute basic PromQL against the local Prometheus API.
Resources created
- Local containers/files only; no cloud resources.
Cost / risk
- Expected cloud cost: none. Local CPU, memory and disk usage only.
Prerequisites
- Docker Engine with Compose plugin for the optional shared stack.
- Core course completion does not require Docker or external credentials.
TOOL 1cd labs/observability-stack
TOOL 2docker compose up -d
TOOL 3curl -Gs 'http://127.0.0.1:9090/api/v1/query' --data-urlencode 'query=up'
TOOL 4curl -Gs 'http://127.0.0.1:9090/api/v1/query' --data-urlencode 'query=rate(prometheus_http_requests_total[5m])'
Verify
- The API returns successful query results.
- `up` has a value for the self-scrape target.
Cleanup
- Run `docker compose down -v` from `labs/observability-stack`.
Warnings
- Optional only: not required by the account-free validator.
- The bundled local stack is for training, not a production observability architecture.
Avoid these traps
Common mistakes
- Using `rate()` on a gauge.
- Aggregating all routes before looking for a localized failure.
- Comparing numerator and denominator from different populations.
Knowledge check
Can you reason from the signal?
Three concept checks plus one scenario check. Open each answer only after deciding first.
1Why use `rate()` with a counter?
To estimate per-second change over a time window while accounting for counter resets.
2What does `sum by (route)` preserve?
A separate aggregate for each route label value.
3Why can a global average mislead?
Healthy high-volume dimensions can mask a failing low-volume dimension.
4Scenario: global latency looks acceptable but checkout is slow. What helps?
Group or filter by route before global aggregation so the failing dimension remains visible.