GM
EN/ES
Back to projects

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.

Role: Architecture, backend, client and dashboard Duration: Own project, evolving 2026

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.

From call site to viewer Business code writes against the standard abstraction; the target is resolved by configuration. Service ILOGGER<T> Abstraction NO COUPLING Buffer ASYNCHRONOUS Targets NETWORK · REMOTE · CONSOLE Viewer DASHBOARD Consumers do not know where their logs go. That is why the pattern can be carried to another application.
From call site to viewer

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

Chose Expose the framework's standard logging abstraction and resolve the backend by configuration
Instead of Exposing the chosen logging library's client directly
Because Consumers write against an interface they already know. The backend can change without touching a single line of consumer code.
Chose Wrap the network target in an asynchronous buffer
Instead of Writing to the socket synchronously from the call site
Because A log line must never make the interface wait. Dropping messages under pressure beats blocking the application.
Chose A separate contracts project shared by API, client and dashboard
Instead of Defining the models at each end
Because The record format is the system's point of agreement. Keeping it in one place turns a change into a compile error rather than a production one.
Chose Transport over a connectionless protocol, compatible with existing viewers
Instead of A custom protocol with delivery acknowledgement
Because For a diagnostics channel, compatibility with tools that already exist was worth more than delivery guarantees.

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.