Live Demo: Incident Déjà Vu
When something breaks, the first useful question is whether it has happened before, and what fixed it last time. In this demo the invented web shop from the Logs demo carries on for two more hours. Its file already holds the day before: every kind of log line counted a minute at a time, and six incidents the on-call team wrote down. Every ten seconds the page asks the file what stands out right now and which of those incidents it looks like.
Simulated logs, real code. The shop and its log lines follow a fixed script, incidents included. The log reducer and the Engine are the real Go program built for WebAssembly, and the comparison is plain SQL kept in the same SQLite file.
How to Run It
- Press Play. Two hours pass in about a minute and a half, slowing down as each incident begins.
- Watch Right now. A kind of incident the file knows is named within seconds, with what fixed it last time. A kind it has never seen is flagged as new.
- Start one of your own. Pick a kind and press Start it now. Write a new one down, start it again, and the file recognizes it.
- Review the results. The two hours finish, and every count in the file is checked against a recount of the lines.
On a wide screen the demo can use the whole window: open it full screen.
The Controls
| Control | What it does |
|---|---|
| Play, Pause, Resume | Starts the two hours, pauses them and carries on. An uninterrupted run takes about a minute and a half |
| Stop | Ends the run and goes back to 12:00, with the file as it was at the end of yesterday |
| Review the results | Finishes the two hours at full speed, then checks every count |
| Start an incident | Starts an incident of the chosen kind at once: one of the five kinds in the file, or one of two it has never seen |
| Write it down | Appears when something stands out that nothing in the file looks like. Its first two minutes are saved as its fingerprint |
| Policy, The comparison, Compiled SQL | The policy, the SQL that compares incidents, and what the policy compiles to |
| Run | Runs your SQL against the file while the run is paused or finished |
The Shop’s Day Before
The file the demo starts from covers 24 hours of the shop, from 29 September 2026 at 12:00 to 30 September at 12:00 UTC: 2,133,322 log lines, 25 kinds of line. The same code that runs in the page made it, and making it again from the same lines gives the same bytes. Two deploys that log extra debug lines and a newsletter that brings more visitors are in there too, and none of them are incidents.
| # | Began (UTC) | What the on-call team wrote down | What fixed it |
|---|---|---|---|
| 1 | 29 Sep, 14:10 | Card payments failing: northpay outage | Moved card payments to quickcard until northpay recovered |
| 2 | 29 Sep, 17:40 | Login attack from a botnet | Turned on the per-IP sign-in limit and blocked the attacking network |
| 3 | 29 Sep, 21:05 | Search shard 3 lost its replica | Restarted search-2; shard 3 rebuilt in six minutes |
| 4 | 30 Sep, 02:30 | Checkout database pool exhausted | Stopped a runaway report query and raised the pool from 20 to 40 connections |
| 5 | 30 Sep, 06:15 | Recommendations cache down | Restarted cache-2 and cut the recommendations timeout to 150 ms |
| 6 | 30 Sep, 09:50 | Card payments failing: quickcard outage | Moved card payments to northpay until quickcard recovered |
Today’s Two Hours
From 12:00 to 14:00 UTC on 30 September, five incidents happen on schedule:
- 12:18. Card payments start failing at northpay, for eight minutes.
- 12:52. The checkout database runs out of connections, for seven minutes.
- 13:14. The certificate on an image server expires, and product images start failing. The file has never seen this kind. At 13:22 the on-call team writes it down.
- 13:34. A login attack, for five minutes.
- 13:48. The certificate on a second image server expires.
How the File Tells
The policy counts every kind of log line by service and level, a minute at a time for a week and an hour at a time for 90 days, and keeps every line whole for ten minutes:
stream lines from logs {
key service text
key level text
key template integer
raw keep 10m
rollup 1m keep 7d
rollup 1h keep 90d
}
The comparison is plain SQL beside the policy’s tables, in the same file:
- What stands out. A kind of line stands out when its rate over the last minute or two is at least three times its usual minute, higher or lower, and at least six lines a minute away. Usual is the median minute of the hour before, so an earlier incident in that hour doesn’t move it. A kind of line going quiet must stay quiet over one minute more, since quiet takes longer to be sure of. DEBUG lines are left out.
- The fingerprint. Each kind of line that stands out gets a score, the logarithm of how far it moved. A new error from nothing scores high. A line that went quiet scores below zero.
- Writing it down. Saving an incident saves the fingerprint of its first two minutes beside it, with the newest raw line of each kind in it while the raw lines are still kept. A trigger does it on the insert. The saved fingerprint outlives the week the minute counts are kept.
- The comparison. The view
deja_vucompares the fingerprint of now with every saved one by the cosine of their scores. At 0.7 or more, now looks like that incident. At 0.4 or more, it is partly like it. - Two that look the same. The northpay and quickcard outages leave the same kinds of line, so their fingerprints match equally well. The page then compares the words those lines hide, in the newest raw line against the example saved with each incident.
provider=northpaydecides.
Things to Try
- Let the two hours finish untouched. The run ends with all five incidents right. The three kinds from the day before were named 8 to 10 seconds after they began. The new kind was flagged as new after 5 seconds and, once written down, its return was named 10 seconds in. Nothing stood out outside an incident in 721 checks, and all 1,661 counts by minute and hour equal a recount of the lines.
- Watch 12:18. Within seconds Right now says it looks like #1, with what fixed it, and that the raw lines tell it from #6:
provider=northpay. - Start the order queue incident. The file has never seen it, so the page offers to write it down. Write down what it was and what fixed it, wait for it to pass, then start it again.
- Start two at once. Overlapping incidents mix their fingerprints. See what the file makes of it.
- Ask the file.
SELECT * FROM deja_vuwhile something stands out, or Every fingerprint in the file.
What the Numbers Mean
- Stood out after: seconds from an incident’s first line to the first check where something stood out. A check runs every ten seconds, after the Engine writes the file, so this is at most ten seconds late.
- Similarity: the cosine of two fingerprints. 1 means the same kinds of line moved in the same proportions, and 0 means they share none.
- A check takes: the time to read what stands out and the closest incidents from the file, both SQL views. On our test machine, 4 to 5 ms on average in Chromium, at most 35 ms.
- Counts checked: the lines a minute and an hour for each service and level, from the file, against a recount of the lines by separate code that never reads it.
Measured Beyond the Script
The same code runs headless in Node (tools/run-demo6.mjs), which is how these were measured:
| What | Result |
|---|---|
| The day before, checked every minute | 1,379 minutes checked. Something stood out in 47, all during the six incidents, and each incident at the first check after it began |
| 20 more days, other seeds, incidents at random times | Known kinds named right 80 times out of 80, 12 seconds after they began at the median and 50 at most. New kinds flagged as new 20 times out of 20. None named wrong. No false alarms |
| The native Engine | precomputing put --lines took the same 2,375,957 lines and wrote the same file: 45,366 rows, 328,955 values, 0 differences |
If It Does Not Start
The demo works in any current Chrome, Edge, Firefox or Safari, on a computer or a phone, with JavaScript switched on. It downloads SQLite (1.5 MB, 577 KB compressed) and the reducer with the Engine (5.0 MB, 1.3 MB compressed) from this site, then the file of the day before (3.7 MB, 0.73 MB compressed). If the demo says it could not start, try another browser, or allow scripts on this page if an extension blocks them.
What Is Real Here
Real:
- The log reducer, the template miner and the Engine: the same Go code as
precomputing put --lines, compiled to WebAssembly. - The comparison: views and a trigger in plain SQL, in the same SQLite file as the counts.
- The day before: made from its 24 hours of lines by the same code, and the same bytes when made again.
- The checks: separate code recounts the lines and never reads the file.
Simulated:
- The shop, its incidents and what the on-call team wrote down.
- Time: two hours pass in about a minute and a half.
The incident déjà vu case study follows the two hours.