3

Caught up in a weird requirement. I need to attach unique error id to log4j message and return that message id back to interface.So, I though lets create a spring service, like this

public class LoggingService {

   protected static Logger logger = LoggerFactory.getLogger(LoggingService.class);



   public String debug(String debug_msg)
   {
       String uniqueMsgId = generateUniqueId();
       logger.debug(concatIdWithMsg(uniqueMsgId, debug_msg));
       return uniqueMsgId;
   }

  }

and autowired this to wherever i need it.

 public class LoginLogoutController {

    @Autowired
    LoggingService logger;

    @RequestMapping(value = "/login", method = RequestMethod.GET)
    public String getLoginPage()
    {
       logger.debug("Login page requested");
    }
    }

Although it worked fine, but the source class in logger msg is LoggingService which is obvious. What i want is to pass the class in which LoggingService is autowired so that the logger message shows the original source of problem. I tried somehow to change the service but got no further idea how to pass source class

 public class LoggingService<T> {

       protected static Logger logger = null;

       Class<T> sourceClass;

       public void construct(Class<T> sourceClass)
       {
           this.sourceClass = sourceClass;
           logger = LoggerFactory.getLogger(sourceClass);
       }

       public String debug(String debug_msg)
       {
           String uniqueMsgId = generateUniqueId();
           logger.debug(concatIdWithMsg(uniqueMsgId, debug_msg));
           return null;
       }
    }
ntstha
  • 1,187
  • 4
  • 23
  • 41

2 Answers2

3

I used this mechanism to inject a logger.

Create this annotation..

/**
* Indicates InjectLogger of appropriate type to
* be supplied at runtime to the annotated field.
*
* The injected logger is an appropriate implementation
* of org.slf4j.Logger.
*/
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

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

@Retention(RUNTIME)
@Target(FIELD)
@Documented
public @interface InjectLogger {
}

Now lets define a class that actually does the job of injecting the logger implementation.

/**
 * Auto injects the underlying implementation of logger into the bean with field
 * having annotation <code>InjectLogger</code>.
 * 
 */
import java.lang.reflect.Field;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.util.ReflectionUtils;

import static org.springframework.util.ReflectionUtils.FieldCallback;

public class LoggerInjector implements BeanPostProcessor {

 public Object postProcessAfterInitialization(Object bean, String beanName)
   throws BeansException {
  return bean;
 }

 public Object postProcessBeforeInitialization(final Object bean,
   String beanName) throws BeansException {
  ReflectionUtils.doWithFields(bean.getClass(), new FieldCallback() {
   public void doWith(Field field) throws IllegalArgumentException,
     IllegalAccessException {
    // make the field accessible if defined private
    ReflectionUtils.makeAccessible(field);
    if (field.getAnnotation(InjectLogger.class) != null) {
     Logger log = LoggerFactory.getLogger(bean.getClass());
     field.set(bean, log);
    }
   }
  });
  return bean;
 }
}

Using it is even simpler. Just add the Logger annotation created above to the Log field in the required class.

import org.slf4j.Logger;

public class Demo {

 @InjectLogger
 private Logger log;

 public void doSomething() {
  log.info("message");
  log.error("Lets see how the error message looks...");
 }
}
Xstian
  • 8,184
  • 10
  • 42
  • 72
  • But i need to generate unique message id with each message or error and add it with the logger message, that's why i am creating the service. But, I didn't understand why you need to do this if you can simple declare your logger in your demo class? – ntstha Sep 08 '14 at 10:52
  • In this way, you could inject a bean that you want, with a custom behaviour, only with an annotation. – Xstian Sep 08 '14 at 14:01
1

Why dont you use Spring AOP. AOP provides you much accessibility and features, and you can exploit its interesting features later also, when your application becomes heavy. Spring AOP

H S Raju
  • 380
  • 3
  • 12
  • Logging is one of the prime use of Spring AOP(Aspect Oriented Programming). You can specify, what needs to be logged while entering or exiting a method. [Logging using AOP](http://www.tutorialspoint.com/spring/aspectj_based_aop_appoach.htm). You can also check [spring logging](http://www.tutorialspoint.com/spring/logging_with_log4j.htm) – H S Raju Sep 08 '14 at 05:28
  • @Raju The problem is that he needs to log the message and return the log message id. I'm not sure how AOP will be help him in this case. – Ricardo Veguilla Sep 08 '14 at 15:30