• Home
  • Events
  • About
  • @Log – Groovy’s New and Extensible Logging Conveniences

    The latest version 1.8 snapshot of Groovy includes a cool new logging feature called @Log. The key of @Log and the other logging annotations is that the parameters sent to logging methods are not evaluated unless that specific log level is enabled. For instance, you can call Logger.debug with a long running closure as a parameter, and if the debug log level is not enabled then the parameter is never evaluated.

    The goal is to transform logging code that looks like this:

    Into something simpler but with the same effect:

    Currently, we support the latest versions of Apache Commons Logging, java.util.Logging, Log4j, Logback, and Slf4j frameworks. However, the system is open and extensible and you can add your own logging framework in as you wish.

    Let’s start with a fully functioning java.util.Logging example:

    When you use the @Log annotation on a class, the class will be injected with a private static field of type Logger, which you can use for logging. You can invoke methods on this log field just like any other field in your class. It really is a log field and Java can see the field as well, it is injected at compile time.

    Here is the fun part. Unless the log level is enabled, then the parameters are not evaluated. For instance, this code does not normally throw a divide by zero exception:

    However, as soon as your logging level is tuned to “fine” then you will get that nice exception at runtime. Cool huh? No more “ifLevelEnabled” calls littering your logic.

    How do I change the log field name?

    If you want to name your logging something different then just pass the name as a parameter like so:

    This can be handy if you already have a field called “log” in your class. Of course, if there is a naming conflict then you will get a compile error when compiling the Groovy source. All of this is part of the compiler and not runtime magic.

    Which Logging Frameworks are Supported?

    There are four annotations to choose from, @Log is not the only one. Which annotation you use depends on which logging framework you intend to deploy. The logging framework does not need to be present during compile time in order to use this feature.

    • @Log – Adds a java.util.Logger to your class.
    • @Log4j – Adds a log4j Logger to your class.
    • @Slf4j – Adds an SLF4J logger to your class. Also note, the Logback framework uses slf4j internally, so use this annotation for Logback as well.
    • @Commons – Adds an Apache Commons Logger to your class.

    How is Logger Instantiated?

    For the most part, the Logger objects are instantiated by passing the name of the current class in as a parameter to the standard static factory method. If you simply must have a different name then you can change it but it isn’t as simple as an annotation parameter. You’ll have to write your own annotation based AST transformation, which is described next.

    Does this work with my own custom Log class?

    Yes! You can use the same mechanism that the Groovy code base uses. It is quite easy and there are four examples already. The java.util.Logging @Log Source Code makes the best example. Here is what a new Groovy logging annotation might look like for your company’s Log class:

    This is a standard Groovy declaration for a Local AST Transformation. You want to use “org.codehaus.groovy.transform.LogASTTransformation” as the transformation class because it contains all the logic to call you back and weave in the new field. Then you need to specify a LoggingStrategy, which you need to write yourself. In this example I called it “MyLoggingStrategy”. It just needs to be a public class with a default constructor implementing LoggingStrategy. This is a 3 method interface:

    In addLoggerFieldToClass you need to construct your new FieldNode and add it to the ClassNode. This is invoked during the compile of a class annotated with @MyLog. In isLoggingMethod you need to determine if a methodName is one that you can wrap with an isEnabled check. This is invoked during the compile every time a method is invoked on your field from the source code. Lastly, you need to write the logic of wrapping and delaying evaluation of the log method in “wrapLoggingMethodCall”. The source code is your best guide for implementing these three methods. This interface and callbacks is exactly how the Groovy annotations work internally, and the source is there to be read and followed as an example.

    Happy Logging Everyone!

    Canoo Engineering AG is ready to help with your next Groovy project. We can coach your team, kick start your Groovy and Grails project, deliver your entire product, or anything in between. For more info contact info@canoo.com. We’d love to hear from you.

    Share and Enjoy: These icons link to social bookmarking sites where readers can share and discover new web pages.
    • email
    • Print
    • Twitter
    • LinkedIn
    • XING
    • Facebook
    • Google Bookmarks

    1 Comment »

    1. Maxim Gubin said,

      September 21, 2010 @ 22:40

      This sounds pretty awesome!!! I love what AST can achieve!

    RSS feed for comments on this post · TrackBack URI

    Leave a Comment

    Time limit is exhausted. Please reload the CAPTCHA.