Search code examples
javaaopaspectj

Using Eclipse AspectJ to Inject a Logger which Logs context/meta data of the code execute?


I am trying to define an aspect to inject a logger.

I am looking to create something like:

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public aspect LogInjector {

    private pointcut executionJoinPoints(): !within(LogInjector) && execution (* *.*(..));

    before(): executionJoinPoints(){
        // Get class name of the executed code
        clazz = ...
        final Logger logger = LogManager.getLogger(clazz);

        // Get method name of the executed code
        method = ...

        // Get params name, type and values triplet or values at least if the previous is not possible, of the executed code
        params = ...

        // Get call stack of the executed code
        stack = ...

        logger.trace("{}.{}({}) - {}", clazz.name(), method.name(), params, stack);
    }

    after(): executionJoinPoints(){
        // Get class name of the executed code
        clazz = ...
        final Logger logger = LogManager.getLogger(clazz);

        // Get method name of the executed code
        method = ...

        // Get return value or exception of the executed code
        result = ...

        logger.trace("{}.{} = {}", clazz.name(), method.name(), result);
    }
}

For this I want to retrieve execution metadata/context data:

  • exceptions
  • return values

How can get this metadata/context data?


Solution

  • In order to keep your aspect efficient, I recommend the following:

    • Limit your pointcut to the target packages and classes you really wish to debug. Don't log/trace the whole world. You could also use an abstract base aspect with an abstract pointcut and extend the aspect into a concrete sub-aspect with a concrete pointcut. The latter can even be provided via XML configuration if you use load time weaving.
    • Use an around() advice instead of a before() / after() pair. Then you only need to calculate some of the logged values once and use them both before and after the original method call done via proceed().
    • Simply log thisJoinPoint instead of piecing together bits contained therein by default. This will already give you the type of joinpoint, method signature including parameter types and return value.
    • Don't log parameter names, the information adds no real value. Furthermore, parameter names are subject to refactoring and are only present if your code is compiled with debug information. Keep it simple and only log the parameter values.
    • In the around() advice mentioned above you can enclose the proceed() call into try-catch-finally and conveniently handle and log any exceptions and stack traces and/or wrap checked exceptions into AspectJ's SoftException or a simple RuntimeException and re-throw them. Whatever is applicable to your situation.
    • Method call results are just the results of proceed(), which would you also be what you need to return from the around() advice. You can also return something else instead (but it must have the correct return type) or completely skip proceed() if for whatever reason you wish to skip target method execution.

    All of what I just said is written in the AspectJ manual or in any other AspectJ tutorial. You might want to read some of those next time before asking a general question like this one.