пятница, 31 июля 2015 г.

J2EE. Logging in application

Logging is an cross-cutting concern in the application.

It is tedious to write every time

Logger log = LogManager.getLogger(getClass()); 

To speed up one can copy this string from one class to another.
Not very expressive way. Well, it is more code to read.
Nowadays we have annotations, we have EJB, we have CDI.

We can improve the logging code in two ways:
  1. implement the logging as a cross-cutting concern with a CDI interceptor
  2. if we need more logging it would be much simpler to inject logger


Let's implement the interceptor:

import javax.interceptor.AroundInvoke;
import javax.interceptor.Interceptor;
import javax.interceptor.InvocationContext;

import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

@Logable
@Interceptor
public class LoggingInterceptor {

 @AroundInvoke
 public Object log(InvocationContext ctx) throws Exception {
  Logger logger = LogManager.getLogger(ctx.getTarget().getClass()
    .getName());
  Object[] args = ctx.getParameters();
  logger.info("enter " + ctx.getMethod() + " : "
    + ReflectionToStringBuilder.toString(args));
  Object returnMe = ctx.proceed();
  logger.info("exit " + ctx.getMethod() + " returned "
    + ReflectionToStringBuilder.toString(returnMe));
  return returnMe;
 }
}

Let's implement the Logable annotation:


import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import javax.interceptor.InterceptorBinding;

@InterceptorBinding
@Retention(RUNTIME)
@Target({ TYPE, METHOD })
public @interface Logable {

}
Let's implement the injectable Logger:


import javax.enterprise.inject.Produces;
import javax.enterprise.inject.spi.InjectionPoint;

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

public class LogFactory {

 @Produces
 Logger createLogger(InjectionPoint injectionPoint) {
  String name = injectionPoint.getMember().getDeclaringClass().getName();
  return LogManager.getLogger(name);
 }
}

Here is how can we use the code:


@ApplicationScoped
@Logable
public class ConnectionFactory implements IConnectionFactory {

 @Inject
 private Logger log;
}

With just one annotation we have ease out life and typing boiler plate code of enter and exit from method.

Happy coding!

Комментариев нет:

Отправить комментарий