sitekits.dev
sre

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

§01 FIELD GUIDE

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.

AvailabilityPer year (365 d)Per 30-day monthPer weekPer day
99%3 d 15.6 h7.2 h1.68 h14.4 min
99.5%1 d 19.8 h3.6 h50.4 min7.2 min
99.9%8.76 h43.2 min10.1 min1.44 min
99.95%4.38 h21.6 min5.04 min43.2 s
99.99%52.6 min4.32 min60.5 s8.64 s
99.999%5.26 min25.9 s6.05 s0.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 rateError rate at 99.9% SLOFresh 30-day budget gone inTypical response
0.1%30 daysno alert
0.6%5 dayspage (6 h window, 5% burned)
14.4×1.44%50 hpage (1 h window, 2% burned)
100×10%7.2 hpage now
1000×100%, hard down43.2 minincident

Pair each fast threshold with a shorter confirmation window (5 min at 14.4×, 30 min at ) 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.

FieldRangeForms the editor acceptsValid elsewhere, rejected here
minute0–59*, 5,20, 0-30, */15
hour0–23same
day-of-month1–31sameL, W (Quartz, AWS)
month1–12sameJANDEC names (Vixie, cronie)
day-of-week0–6 (0 = Sun)same7 for Sunday and SUNSAT (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.

FAQ
How much downtime does 99.9% uptime actually allow?
8.76 hours per year, 43.2 minutes per 30-day month, 10.1 minutes per week, or 1.44 minutes per day. If your contract measures per calendar month, the same 99.9% target moves with month length: 40.32 minutes in a 28-day February and 44.64 minutes in a 31-day month. Check the SLA's measurement clause before you compare numbers.
What is error budget burn rate, and when should it page someone?
Burn rate is your observed error rate divided by the rate the SLO permits, so a 99.9% SLO seeing 1.44% errors is burning at 14.4×. Budget consumed equals burn rate × (alert window ÷ SLO window), which is why 14.4× sustained for 1 hour spends 2% of a 30-day budget and deserves a page, while 1× sustained for 3 days spends 10% and deserves a ticket. Pairing each threshold with a shorter confirmation window (5 minutes at 14.4×, 30 minutes at 6×) stops the alert flapping after recovery.
Should my internal SLO be the same as the SLA I sell?
No — keep the SLO tighter than the SLA, because the gap is your operating margin. An internal 99.9% SLO behind a 99.5% contractual SLA leaves about 2.9 hours of monthly slack between missing your own target (43.2 min) and owing service credits (3.6 h). If the two are equal, the first breach is an engineering signal and a billing event at the same moment.
Why does my cron job fire at the wrong time?
Three usual causes. The host clock is UTC while you reasoned in local time, so 0 3 * * * on a UTC server fires at 12:00 in Asia/Tokyo. Daylight saving makes an 02:30 local job run twice or not at all on transition days. And POSIX cron ORs day-of-month with day-of-week when both fields are restricted, so 0 0 1 * 1 runs on the 1st of the month and on every Monday — not only on Mondays that fall on the 1st.
How often does a synthetic check need to run to measure a 99.99% SLO?
More often than is practical, which is the real answer: at 99.99% the entire 30-day budget is 4.32 minutes, so a 60-second probe cannot see a 20-second outage at all, and a single missed probe records roughly a minute — 23% of the month gone on one data point. Probe interval is a floor on measurement resolution, so above three nines measure the SLI from request logs (good events over valid events) and keep synthetics for coarse reachability and third-party checks. At 99.9%, where the budget is 43.2 minutes, a 60-second probe is proportionate.