Log4J: Strategies for creating Logger instances

后端 未结 10 576
不思量自难忘°
不思量自难忘° 2020-11-30 21:22

I decided to use Log4J logging framework for a new Java project. I am wondering what strategy should I use for creating/managing Logger instances and why?

相关标签:
10条回答
  • 2020-11-30 21:35

    As has been said by others, I would create a Logger per class:

    private final static Logger LOGGER = Logger.getLogger(Foo.class);
    

    or

    private final Logger logger = Logger.getLogger(this.getClass());
    

    However, I have found it useful in the past to have other information in the logger. For instance, if you have a web site, you could include the user ID in every log message. That way,, you can trace everything a user is doing (very useful for debugging problems etc).

    The easiest way to do this is to use an MDC, but you can use a Logger created for each instance of the class with the name including the user ID.

    Another advantage of using an MDC is if you use SL4J, you can change the settings depending upon the values in your MDC. So if you wish to log all activity for a particular user at DEBUG level, and leave all of the other users at ERROR, you can. You can also redirect different output to different places depending upon your MDC.

    Some useful links:

    http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/MDC.html

    http://www.slf4j.org/api/index.html?org/slf4j/MDC.html

    0 讨论(0)
  • 2020-11-30 21:37

    Typically, you'd have loggers setup per class because that's a nice logical component. Threads are already part of the log messages (if your filter displays them) so slicing loggers that way is probably redundant.

    Regarding application or layer based loggers, the problem is that you have to find a place to stick that Logger object. Not a really big deal. The bigger issue is that some classes may be used at multiple levels of from multiple applications... it could be difficult to get your logger right. Or at least tricky.

    ...and the last thing you want is bad assumptions in your logging setup.

    If you care about applications and layers and have easy separation points, the NDC is the way to go. The code can be a little excessive sometimes but I don't know how many times I've been saved by an accurate context stack showing me that Foo.bar() was called from application X in layer Y.

    0 讨论(0)
  • 2020-11-30 21:38
    • Create one logger per class.
    • If you have dependencies that require Commons Logging (quite likely) use slf4j's bridge for Commons Logging. Instantiate your loggers (per class) using the Commons Logging interface: private static final Log log = LogFactory.getLog(MyClass.class);
    • Manifest this pattern in your IDE using shortcuts. I use IDEA's live templates for this purpose.
    • Provide contextual information to threads using an NDC (thread local stack of strings) or an MDC (thread local map of String → ?).

    Examples for templates:

    private static final Log log = LogFactory.getLog($class$.class); // live template 'log'
    
    if (log.isDebugEnabled())
        log.debug(String.format("$string$", $vars$)); // live template 'ld', 'lw', 'le' ...
    
    0 讨论(0)
  • 2020-11-30 21:39

    I'm certain this isn't a best practice, but I've sacked some startup time on applications before to save lines of code. Specifically, when pasting in:

    Logger logger = Logger.getLogger(MyClass.class);
    

    ...developers often forget to change "MyClass" to the current class name, and several loggers always wind up pointing at the wrong place. This Is Bad.

    I've occasionally written:

    static Logger logger = LogUtil.getInstance(); 
    

    And:

    class LogUtil {
       public Logger getInstance() {
          String callingClassName = 
             Thread.currentThread().getStackTrace()[2].getClass().getCanonicalName();
          return Logger.getLogger(callingClassName);
       }
    }
    

    The "2" in that code might be wrong, but the gist is there; take a performance hit to (on class load, as a static variable) find the class name, so that a developer doesn't really have a way to mistype this or introduce any error.

    I'm generally not thrilled with losing performance to prevent developer error at runtime, but if it happens as a singleton, once? Often sounds like a good trade to me.

    0 讨论(0)
  • 2020-11-30 21:42

    Another Option : You can try AspectJ crosscutting on logging. Check here : Simplify Your Logging. (If you don't want to use AOP, you can look slf4j)

    //Without AOP
    
        Class A{
           methodx(){
            logger.info("INFO");
           }
        }
    
        Class B{
           methody(){
            logger.info("INFO");
           }
        }
    
    //With AOP
    
        Class A{
           methodx(){
             ......
           }
        }
    
        Class B{
           methody(){
             ......
           }
        }
    
        Class LoggingInterceptor{
    
           //Catched defined method before process
           public void before(...xyz){
             logger.info("INFO" + ...xyz);
           }
    
           //Catched defined method after processed          
           public void after(...xyz){
             logger.info("INFO" + ...xyz);
           }
           .....
    
        }
    

    P.S : AOP will be better, it is DRY(Don't Repeat Yourself) way.

    0 讨论(0)
  • 2020-11-30 21:47

    the best and easiest method to create custom loggers, notlinked to any classname is:

    // create logger
    Logger customLogger = Logger.getLogger("myCustomLogName");
    
    // create log file, where messages will be sent, 
    // you can also use console appender
    FileAppender fileAppender = new FileAppender(new PatternLayout(), 
                                                 "/home/user/some.log");
    
    // sometimes you can call this if you reuse this logger 
    // to avoid useless traces
    customLogger.removeAllAppenders();
    
    // tell to logger where to write
    customLogger.addAppender(fileAppender);
    
     // send message (of type :: info, you can use also error, warn, etc)
    customLogger.info("Hello! message from custom logger");
    

    now, if you need another logger in same class, no problem :) just create new one

    // create logger
    Logger otherCustomLogger = Logger.getLogger("myOtherCustomLogName");
    

    now see the code above and create new fileappender so your output will be sent in other file

    This is usefull for (at least) 2 situations

    • when you want separate error from info and warns

    • when you manage multiple processes and you need output from each process

    ps. have questions ? feel free to ask! :)

    0 讨论(0)
提交回复
热议问题