日志和业务联系在一块的时侯怎么办? 比如,记下登录用户ID,串起前后日志;不同的业务模块记录在不同的日志文件里。SLF4J 解决这两件事很容易。

记录上下文相关信息可以用MDC,MDC 的用法非常简单。首先在logback.xml 里面用%X{your_key} 标记需要记录上下文信息。然后在代码中用MDC 记录your_key 的值。举例:

T.java:
MDC.put("your_key", "your_value");
logger.info("Hello World");

logback.xml
<layout class="ch.qos.logback.classic.PatternLayout">
   <pattern>%d{yyyy-MM-dd HH:mm:ss} %X{your_key} %msg%n</pattern>
</layout>

output:
   2012-12-17 23:20:45 your_value Hello World

区分不同的模块的日志,可以在getLogger() 的时侯根据logger 的名字拿到不同的logger-> appender 。不过这条路略微有点土。用SLF4J 的marker 可以相对优雅的解决这个问题。可惜,目前只有logback 才支持。

如果把所有的日志混在一起记录,只是用关键字做区分,很简单,之需要在代码中声明marker,然后在logback 中配置就可以了。举例:

T.java:
MDC.put("your_key", "your_value");
logger.info("Hello World");

logback.xml
<layout class="ch.qos.logback.classic.PatternLayout">
   <pattern>%d{yyyy-MM-dd HH:mm:ss} %X{your_key} %msg%n</pattern>
</layout>

output:
   2012-12-17 23:20:45 your_value Hello World

如果把不同模块的日志要放到不同的文件里面,还需要配合Filter 才能做到,有一点点编码的工作,继承AbstractMatcherFilter 做一个简单的匹配过滤就可以了。举例:

public class MarkerFilter extends AbstractMatcherFilter<ILoggingEvent> {
    private Marker markerToMatch = null;
    @Override
    public void start() {
        if (null != this.markerToMatch)
            super.start();
         else
        	addError("!!! no marker yet !!!");
    }
    @Override
    public FilterReply decide(ILoggingEvent event) {
    	Marker marker = event.getMarker();
        if (!isStarted())
            return FilterReply.NEUTRAL;
        if (null == marker)
            return onMismatch;
        if (markerToMatch.contains(marker))
            return onMatch;
        return onMismatch;
    }
    public void setMarker(String markerStr) {
        if(null != markerStr)
            markerToMatch = MarkerFactory.getMarker(markerStr);
    }
}

然后在logback.xml 对应的appender里做下配置:

<filter class="your.pkg.MarkerFilter">
    <marker>TEST_MARKER</marker>
    <onMatch>ACCEPT</onMatch>
    <onMismatch>DENY</onMismatch>
</filter>

这样通过TEST_MARKER 标记的appender 就能互相独立开了。比较麻烦的是如果模块很多,那么必须都要有相应的marker 做对应。

前面不分日志文件简单标记的情况,在做日志分析的时侯,前面可能需要做个预处理,以区分不同业务模块。而后面的方法,不需要预处理就已经业务模块对应日志文件,但是对应的配置起来比较麻烦。见仁见智。

References:
http://www.slf4j.org/
http://www.slf4j.org/faq.html
http://www.slf4j.org/extensions.html
http://logback.qos.ch/
http://logback.qos.ch/recipes/
http://logback.qos.ch/manual/filters.html

 

2 Responses to SLF4J MDC and Marker

  1. Ken says:

    I’ve learned a lot from your blog. I am headhunter focused on IT industry. Could I have your contact information?
    QQ:1805807540
    Email;zai_feng@139.com

  2. Ken says:

    朱先生,你好!我是IT猎头顾问提供年薪20-100万职位。希望有机会与你合作。求联系方式。
    我的联系方式:55280432@qq.com

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>