02 June 2010

watch your code do actual work - in runtime

Short version: Use AOP to log your method invocations. Store method input parameters and result object, serialized to XML. Put it all into context with a Graphviz file generated as a side-effect.

Visual beats plain old text for a lot of purposes. So why not generate something visual from your running code, showing you what's happening using boxes and arrows. I've had tons of fun (and not too much sleep) lately digging into this using Graphviz.

The value of this is to track that the flow is as expected, and if you need to you can investigate the input and output data going into your ex. repositories or "logical services". The limitation of this is that all needs to run within the same VM and thread.

Here is what the proof of concept app produced from a dummy java stack in a unit test.

The text on the arrows are clickable links and gives the user this if clicking the "0.Arguments":

Okok, the arguments and results are just boring serialized XML data. They could probably be graphs too, but I haven't come around to that and that isn't really what I'm after.

I also made a simple Servlet, which lists all generated graphs and makes you able to click and view any of these.

the code
The rest of this blog will be slightly in-depth and describing the knots and bolts of this.

The main idea is to accumulate a graphviz dot -file a cross a call-stack. At the points you want as opposed to everything (using reflection and looking at your entire call stack).

Aspect point cuts (Spring and AspectJ) is perfect for the job. I use ThreadLocal to keep a graph context/handler and simply append to it every time the aspect is invoked. The context saves a file and is released when the call-stack is done.

The Servlet in the proof of concept code is just a nice-to-have and requires graphviz to be installed on the "server". It invokes the 'dot' executable and pushes the output svg (or pdf / png / whatever you want) to the user.

You probably don't want this logging done all the time, due to performance and extensive logging to your temp. So I've stuck a check for an environment variable in the aspect - so you can enable and disable when you need this.

That's it really. You can check out the proof of concept from github and run the tests to see the graph-files get generated. Use the code as you please. Check out the README and please comment if you see any weaknesses or have any opinions.