Diagnostics platform / Own product
Speed.Logging
Distributed logging platform with an API, a client, shared contracts and a dashboard, born from a real field-diagnostics problem.
The problem
Diagnosing an application running on a device in the field is hard: there is no debugger attached, the problem does not reproduce on the desktop, and local logs are only read after someone travels to the site. I needed to see what the application was doing while it was doing it, without installing anything new on the device.
Constraints
- Sending logs must never block the UI thread
- It must be switchable on and off without restarting the application
- Consumers of the library should not be coupled to a specific logging backend
- Unreliable local network — losing a record is acceptable, freezing the application is not
Decisions
Outcome
- Ingestion API, instrumentable client, shared contracts and a query dashboard
- Diagnostics enabled at runtime, without restarting the application
- Interchangeable targets — network, remote and console — driven by rules
- A documented pattern, reusable as a plugin in other applications
From a single problem to a platform
This started as a concrete need: understanding what an industrial Android application was doing while running at a customer site. The first version was a network target wired to the standard logging abstraction. It worked well enough to make me ask what was still missing.
What was missing was the other end: a service to receive, an explicit contract for what a record is, and an interface to read them. That is where the four components came from.
The decision the design rests on
Consumers write against the framework’s logging abstraction, not against the concrete library underneath. That indirection is why the same pattern can be carried to another application as a plugin: nothing in the business code knows where its logs go.
The network target is wrapped in an asynchronous buffer. It is a decision with an explicit cost — under pressure, messages are dropped — taken because the alternative, making the UI thread wait on a socket, is unacceptable in an application someone is using standing in front of a machine.
Why it belongs here
Because it shows the full cycle on a problem of my own: spotting the need, solving it narrowly, recognising the pattern was reusable, documenting it, and building the rest of the system around it.