SRE tools
SRE math without hand-waving: how SLI, SLO and SLA differ, what each availability target costs in real minutes, and how burn rate turns an SLO into a paging threshold.
3 tools
SLI, SLO and SLA are three different numbers
An SLI is a measurement: good events over valid events — requests answered in
under 300 ms with a non-5xx status, over all requests that reached the load
balancer. An SLO is a target for that ratio across a window, like 99.9% over
30 rolling days. An SLA is a contract attaching money to a usually looser
target. Conflating them is how a team pages someone at 03:00 over a number nobody
agreed to defend.
The hard part is the SLI definition, not the percentage. Two teams claiming 99.9%
can mean different things depending on whether 429 counts as an error, whether
health checks sit in the denominator, and whether measurement happens at the CDN
edge or inside the service. Fix numerator and denominator before arguing about
nines.
The SLO then yields the one number that changes behaviour: the error budget,
100% − SLO. At 99.9% over 30 days you may fail 0.1% of requests, or be fully
down for 43.2 minutes. It is currency — releases and migrations spend it, a fresh
window replenishes it, and a month ending at 100% usually means you shipped too
slowly.
Availability targets in real minutes
Nines are unintuitive; minutes are not. Each additional nine divides allowed downtime by ten.
| Availability | Per year (365 d) | Per 30-day month | Per week | Per day |
|---|---|---|---|---|
99% | 3 d 15.6 h | 7.2 h | 1.68 h | 14.4 min |
99.5% | 1 d 19.8 h | 3.6 h | 50.4 min | 7.2 min |
99.9% | 8.76 h | 43.2 min | 10.1 min | 1.44 min |
99.95% | 4.38 h | 21.6 min | 5.04 min | 43.2 s |
99.99% | 52.6 min | 4.32 min | 60.5 s | 8.64 s |
99.999% | 5.26 min | 25.9 s | 6.05 s | 0.86 s |
Up to 99.9%, a human can notice, diagnose and fix inside the budget. At 99.99% the monthly allowance is 4.32 minutes — a claim about automated failover, not about on-call.
Burn rate: from SLO to alert threshold
Burn rate is the observed error rate divided by the rate the SLO permits. The
identity that matters is budget consumed = burn rate × (window ÷ SLO period): it
turns a short observation into a claim about the whole month.
| Burn rate | Error rate at 99.9% SLO | Fresh 30-day budget gone in | Typical response |
|---|---|---|---|
1× | 0.1% | 30 days | no alert |
6× | 0.6% | 5 days | page (6 h window, 5% burned) |
14.4× | 1.44% | 50 h | page (1 h window, 2% burned) |
100× | 10% | 7.2 h | page now |
1000× | 100%, hard down | 43.2 min | incident |
Pair each fast threshold with a shorter confirmation window (5 min at 14.4×,
30 min at 6×) so the alert clears when the incident does. Slow burns belong in a
ticket, not a page.
Which tool answers which question
Reach for the SLA Uptime Calculator when you hold a percentage
and need the time equivalent: it turns any value from 0 to 100 into allowed
downtime per year, 30-day month, week and day, presets 90% to 99.999%. It is
the contract-review tool.
Use the Error Budget Calculator once the number must drive engineering decisions. Give it an SLO, a window in days and expected traffic; it returns the budget as a percentage, as allowed downtime, and as a count of requests that may fail — 1,000 out of a million at 99.9% over 30 days, the figure that survives partial degradation where a downtime number does not.
First, settle which responses are “bad”. The
HTTP Status Code Reference is a code → meaning lookup — name,
class and a one-line description per code, filterable by number or keyword — so
400 (“could not understand the request”) versus 422 (“well-formed but
semantically invalid”) settles on the spot. It marks 307 and 308 as
preserving the method, but says nothing about what 301 does to a POST:
clients may rewrite it to GET and drop the body, which is why a permanently
moved POST endpoint needs 308. To see what a live endpoint returns, the
HTTP Headers Checker fetches from api.sitekits.dev and
reports final status, redirect hops, response time and every header; the body is never retrieved, and private or localhost targets are
refused by its SSRF guard. Need a body, auth headers or a POST? The
REST API Tester fires from your browser straight to the
target, so its CORS policy applies. More in the HTTP hub, whose
redirect matrix compares 301, 302, 303, 307 and 308 side by side.
For latency evidence, open a DevTools export in the
HAR File Viewer: method, status, type, size and time per request,
4xx/5xx highlighted. Sanitize it with the
HAR File Sanitizer before attaching it to a ticket —
authorization, cookie, x-api-key, token-like parameters and all bodies become
[REDACTED].
Schedules, windows and clocks
Cron is where reliability work quietly breaks. The
Crontab Expression Editor parses a five-field expression and
lists the next eight fire times in your browser’s local timezone. Read the table as
two things at once: the field ranges every cron shares, and the narrower grammar
this editor actually parses — integers combined with *, lists, ranges and steps,
and nothing else.
| Field | Range | Forms the editor accepts | Valid elsewhere, rejected here |
|---|---|---|---|
| minute | 0–59 | *, 5,20, 0-30, */15 | — |
| hour | 0–23 | same | — |
| day-of-month | 1–31 | same | L, W (Quartz, AWS) |
| month | 1–12 | same | JAN–DEC names (Vixie, cronie) |
| day-of-week | 0–6 (0 = Sun) | same | 7 for Sunday and SUN–SAT (Vixie, cronie); 5#3 (Quartz) |
Everything in that last column fails with one message —
Invalid cron expression (expected 5 fields) — even when five fields are present,
so 0 3 * * 7 looks like a counting mistake when it is really a vocabulary one.
Write Sunday as 0. Line-level macros (@daily, @reboot) and six-field seconds
dialects are refused the same way, and so are reversed ranges — write 22-2 as
22-23,0-2. One form fails quietly instead — 5/15 is read as the single value
5, where Kubernetes-style parsers expand it to 5-59/15, so spell the range out.
Three things the table cannot show. On day combination the editor applies the
POSIX either-match rule — with day-of-month and day-of-week both restricted,
0 0 1 * 1 means the 1st and every Monday — but it decides restricted by
text, counting any day field that starts with * as unrestricted. A step slips
through that test: */3 in day-of-month reads as unrestricted, so 0 0 */3 * 1
is ANDed and fires only on Mondays landing on the 1st, 4th, 7th and so on.
Spell those days as 1-31/3 to get the either-match rule back. Steps divide the
field, not the clock — */7 on minutes runs :00 through :56, then restarts with a
4-minute gap. And the preview uses your browser’s timezone while the host clock is
usually UTC.
Incident timelines need the same rigour: the Unix Time Converter reads values below 1e12 as seconds and larger ones as milliseconds, and the Timezone Converter pins one instant across 12 IANA zones with the correct DST offset before you announce a maintenance window. More of the on-call kit: tools for SREs.
Common mistakes
The month in the contract is not the month in the calculator
The calculator uses a fixed 30-day month and 365-day year. Per calendar month, a 99.9% SLO permits 40.32 minutes in a 28-day February and 44.64 in July — 10% swing on identical wording.
Availability multiplies down the dependency chain
Three hard dependencies at 99.9% each, in series, give 0.999³ = 99.70%: about
2.16 hours of monthly downtime, not 43.2 minutes. Without redundancy you cannot
promise more than the product of the critical path.
Time-based and request-based budgets are not interchangeable
The allowed-downtime figure assumes a 100% error rate while down. A degradation
failing 5% of requests burns a 99.9% request budget at 50× while barely moving
an uptime clock driven by synthetic probes.
Your probe interval is the floor of your resolution
A 60-second synthetic check cannot see a 20-second outage, and each missed probe records roughly a minute — already 23% of a 99.99% monthly budget. Above three nines, measure from request logs, not polling.