Module

Error monitoring for a server that reports hundreds of thousands of errors

Collected without an agent, grouped by signature, and rated so you know what comes first.

A live production server produces errors continuously. Most of them repeat, some are not yours at all, and in a list they all look the same. The question is not "how many errors were there" but "what do I fix today".

Collected without touching the customer's code

Errors are pulled from the system's own feed every five minutes, with a cursor to continue from. Connected error trackers (Sentry, Rollbar, Bugsnag, Application Insights) are polled once an hour. There is no agent to install and no library to add to the code: what the system already reports is what gets collected.

Orders of magnitude from one live project, as an example of scale and not as a promise: 348,628 events collected over two months.

One signature, one group

The same error repeats thousands of times and is not thousands of problems. Every event gets a signature made of three parts (module, function and a normalised message), and events sharing a signature fall into one group with a counter.

Orders of magnitude: 348,628 events compressed into 902 groups. The largest of them counted 1,425,190 occurrences, a number that on its own would drown any list.

Not every error is your bug

Every group is sorted into three kinds: a real error, an external service (SMS, mail) and noise: bots, scanners, probes for addresses that do not exist. The sorting is explicit rules rather than a guess, and the default is "real": what we failed to recognise is not hidden.

Orders of magnitude: 881 real, 19 noise, 2 external.

A rating that says what comes first

Each group gets a severity from how many times it occurred in the last seven days: a hundred or more is critical, fifteen or more high, five or more medium, fewer is low. Noise stays low always; an external service is capped at medium; a group that came back after being closed moves up a step while it keeps occurring. A group that goes quiet drops on its own: its occurrences leave the window, and the recalculation runs every night.

A "growth trend" term is deliberately absent: the accumulated history is not deep enough, and a measure that cannot be computed honestly would look like a measurement.

Orders of magnitude as of 24 October 2026: 1,136 low, 11 medium, 8 high, 1 critical. That is how it is supposed to look: what burns is a handful, not a hundred.

One letter for a new group, a separate letter for a returning one

A new group produces one letter. If a closed group comes back, a different letter goes out, one that says so in words rather than with a badge: "appeared" and "came back" call for different things, and an identical subject line would teach you to read neither.

The error text passes through identifier masking both in the letter and on screen. An error message carries whatever the user typed: a national id in a query parameter, a phone from a form, and a letter that has gone out cannot be recalled.

Where in the code it came from

The class where the error fell is extracted from the call stack. This does not always work: a stack does not arrive with every error, and it does not always contain a frame of our own.

Orders of magnitude, deliberately not rounded to something pretty: 399 groups out of 902 with a recognised class.

Areas, so you can ask "what is broken in payments"

Groups can be given an area label (payments, registration, the admin panel), and then the question stops being "which error is the most frequent" and becomes "what is wrong in this part of the system". Eight such labels exist at present.

The first run does not bury you in everything that ever happened

When a feed that has been running for years is connected, everything in it is "new" as far as we are concerned, and without a rule of its own the first run would send hundreds of letters at once, all of which would be deleted unread.

So groups that existed before the connection are marked as known silently, and a narrow window is left for what genuinely appeared just now. On the live project that avoided 849 unnecessary letters, and the one group that really was born in that hour got written about.

A task opens from here

A task is opened from a group in one action, and the task remembers which error it came from. There is also a solution field and a mechanism that looks for similar groups already solved.

And plainly: on the live project exactly one such task has been opened, and a solution is recorded for zero groups out of 902. The mechanism exists; the material in it does not yet.

What the customer sees

Not the error list. The error screens belong to the provider. The customer sees a health tile: either all is well or how many areas currently have errors, and when the last check ran. Below it is a short list of the month's incidents: which area, when it started, when it ended. No stack traces, no severity and no technical names. Everything else reaches them as whatever became a task or a report.

Frequently asked questions

Which sources are errors collected from?
From Sentry, Rollbar, Bugsnag and Application Insights, from failed runs in GitHub Actions and GitLab CI, and also from the system's own error feed, without installing an agent or adding a library to the code. Collection continues from the point where it stopped. All sources flow into one stream, where errors are grouped by signature, sorted and rated by severity.
Will connecting an old system flood us with letters?
No. Groups that existed before the connection are marked as known silently, and only a narrow window is left for what genuinely appeared at that time. After that, one letter goes out for each new group, and a different letter, which says so in words, when a closed group comes back. The error text is masked for identifiers both in the letter and on screen.
How is the severity of an error group decided?
By three factors: how many times the group occurred in the last seven days, its kind, and a return after being closed. A hundred occurrences or more is critical, fifteen or more high, five or more medium. Noise, such as bots and scanners, always stays low. An error from an external service, such as SMS or mail, never rises above medium. A group that came back moves up a step while it keeps occurring, and a group that goes quiet drops on its own, because the recalculation runs every night. The sorting runs on explicit rules, and when nothing matches, the default is "real".
Does the client see the error list?
No. The error screens belong to the provider only. What reaches the client is what became work: a task opened from an error group, which remembers the group it came from, and the hours logged on it in the monthly report. That way the client sees what is being handled and how long it took, without receiving a raw list of thousands of events, some of them noise and some not related to them at all.

Want to see this on your own data? You can start with a trial, no card required.

Start a free trial