Tuesday, August 05, 2008

Postcompilation instrumentation and performance monitoring

Part 2 of my article series on Java run-time monitoring was published today. Last week I reviewed methods of instrumenting java classes at the source level. While not ideal in light of the ubiquity of AOP techniques to inject instrumentation at runtime, if you have or want to do it, take a page from Log4J's book and make sure that the instrumentation is externally configurable (i.e. you don't need to re-compile to tweak it). Here's a quick list of features you might look for in your Log4J instrumentation analog:
  • Verbosity: Yep, just like Log4J (and many other logging packages) the Level of loggers can be modified at runtime through JMX or simply by placing a watch on the XML configuration file.
  • Thresholds: Automatically trace incidents when measurements exceed externally defined thresholds.
  • Ranges: Automatically trace counts of measurements that fall into a value window as part of an externally defined and named range. (useful for SLAs where an operation's elapsed time might be classified as GOOD, WARN or CIRITCAL.)
  • Rollups: Maintain aggregated performance statistics all the way up a hierarchical tree.
So in this week's article, I review methods of instrumentation that can be used in the post-compilation phase, or more simply, without futzing with the source code.

  • Interceptors: J2EE and a bunch of other [not just] Java frameworks support the ability to inject interceptors into the application without ever touching the source code of your code application classes.
  • Class Wrapping: Implement instrumentation in a class wrapper and then wrap your target class. You get the same functionality and instrumentation to boot.
  • Byte Code Instrumentation: Inject instrumentation byte code directly into your already compiled classes. This can be done statically (i.e. you end up with the original jar and and instrumented jar) or it can be done dynamically at runtime when the classes are classloaded.
An additional approach which I did not really address in the article is the concept of class swapping. For example, if you wanted to know some low down performance and byte volume details of a network service, you could create a new class called com.myco.instrumentation.InstrumentedSocket which extends java.net.Socket and adds in some basic instrumentation like counting byte transfer rates. At class load time, you could swap out the implementation of all instances of java.net.Socket with your instrumented version.

Hopefully the article is useful to you.


No comments: