warden
warden copied to clipboard
Improve debugging support - decision evaluation tracing
I saw a relevant blog post today: https://publicobject.com/2022/05/01/eventlisteners-are-good/
Here are the key snippets
[W]e created an abstract class with functions for each of our would-be log statements:
abstract class EventListener { open fun callStart(call: Call) {} open fun callEnd(call: Call) {} open fun callFailed(call: Call, ioe: IOException) {} open fun dnsStart(call: Call, domainName: String) {} open fun dnsEnd(call: Call, domainName: String, list: List<InetAddress>) {} ... }
...
EventListener
RecipeIf you wanna do an event listener in your library or app, here’s what I’ve done:
- Create an abstract class
EventListener
. I prefer an abstract class over an interface here ’cause I want to introduce new functions in library upgrades without breaking compatibility.- Create a value
EventListener.NONE
that is the no-opEventListener
. This makes a nice default.- Create a pair of functions for important long-running operations. For example, OkHttp has
dnsStart()
anddnsEnd()
. Include relevant data as arguments! In OkHttp we were a bit too conservative in what we passed to these functions; given a do-over I would have added more information.- Create functions for stuff that can fail, like
callFailed()
. In OkHttp we don’t always call the end callback if the operation fails.- Create functions for other interesting things that happen in your library! In OkHttp we have events like
cacheHit()
andcacheMiss()
, and metrics systems can use this to create line charts showing cache effectiveness.
Ya, a bit visitor patterny. Nice clean decoupled approach. But in my head I was imagining the output to be a nicely nested tree structure of the policy evaluations - event listener might not be able to produce something like that... will have to think about it. start and end events help, or have to pass some sort of depth parameter around.
Going to start work on this one soon though - very important for ease of use I think