Axiu Blog
输出机制。除此之外,作者(们)还写了SLF4j、logback等一系列的log组件,不过log4j应该是持续时间最久,用户基数也比较大的一支。 关于log4j的介绍,可以看 [LOG4J官网](https://logging.apache.org/log4j/1.2/)。有使用方法等详细信息。但是有时候除了log,还希望输出一些附加信息,虽然可以在每个打印
log是程序员的好朋友,合理的使用log系统,可以方便记录发生的bug、异常,尤其在debug无能的时候,log发挥至关重要的作用。Log4j是Apache的一个开源项目,是一个功能强大的日志组件。可以使用配置文件,即可在程序中使用它的日志输出机制。除此之外,作者(们)还写了SLF4j、logback等一系列的log组件,不过log4j应该是持续时间最久,用户基数也比较大的一支。 关于log4j
log是程序员的好朋友,合理的使用log系统,可以方便记录发生的bug、异常,尤其在debug无能的时候,log发挥至关重要的作用。Log4j是Apache的一个开源项目,是一个功能强大的日志组件。可以使用配置文件,即可在程序中使用它的日志输出机制。除此之外,作者(们)还写了SLF4j、logback等一系列的log组件,不过log4j应该是持续时间最久,用户基数也比较大的一支。 关于log4j
使用MDC在log4j里记录用户信息
Max

log是程序员的好朋友,合理的使用log系统,可以方便记录发生的bug、异常,尤其在debug无能的时候,log发挥至关重要的作用。Log4j是Apache的一个开源项目,是一个功能强大的日志组件。可以使用配置文件,即可在程序中使用它的日志输出机制。除此之外,作者(们)还写了SLF4j、logback等一系列的log组件,不过log4j应该是持续时间最久,用户基数也比较大的一支。

关于log4j的介绍,可以看 LOG4J官网。有使用方法等详细信息。但是有时候除了log,还希望输出一些附加信息,虽然可以在每个打印log的地方都插入这些信息,但显然是很不方便的,尤其对于一些固定来源的信息,不如给个上层调用来的方便。这就是此文要讨论的内容。

NDC vs MDC

NDC和MDC可以记录程序中上下文相关的信息,经常被用于输出log。NDC(Nested Diagnostic Context)即嵌套上下文诊断,MDC(Mapped Diagnostic Context)即映射的上下文诊断,二者的区别从表面上来看就是存储方式不一样。

更进一步的,NDC使用了栈的思想来存取信息,即把相关信息压入(push)/弹出(pop),这就是达到嵌套效果的原因:入A入B出B出A,或者,入A出A入B出B这样。在适当的时候push一堆进去,然后log4j在打印的时候就会从NDC里取值,这样,就很容易把当前NDC的内容给关联进去。通过这种机制,打log的时候就不用关注上下文或者NDC的信息,完全由系统去做。
NDC需要程序去控制合适push/pop适当的信息,并有可能操作不当(没有定期执行NDC.remove)造成内存泄漏。

MDC的机制和NDC类似,不过是采用了键值对应的思想来存取信息。

哪个更合适?

当需要打印的内容有嵌套关系的时候,用NDC;当键值就够用的时候,MDC。

将当前用户信息加入log

目前的Spring项目中某些操作希望简单输出具体用户信息到log里,所以就用了MDC处理这个。

目前使用了shiro来进行用户权限管理,SecurityUtils.getSubject().getPrincipal()是用来获取当前用户的。此处可以改成其他内容。

public class UserToMdcFilter implements Filter{ @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { MDC.put("user", (SecurityUtils.getSubject().getPrincipal() != null) ? SecurityUtils.getSubject().getPrincipal() : ""); try { chain.doFilter(request, response); } finally { MDC.remove("user"); } }

@Override
public void init(FilterConfig filterConfig) throws ServletException {
}

@Override
public void destroy() {
}

}

在spring的xml文件里声明一个bean,指向上面创建的类,方便注入。

在web.xml里声明一个filter,用它过滤所有request。

log4jMDCUserFilter
    org.springframework.web.filter.DelegatingFilterProxy


log4jMDCUserFilter
    /\*

最后记得在logj.properties里加入user,格式为%X{user}(user为上面放到MDC里的key)

例如:

log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH\:mm\:ss} [%c{1}:%L]-[%p] %X{user} - %m%n

输出效果:

2016-03-24 16:44:49 [DispatcherServlet:997]-[DEBUG] axiu - Successfully completed request

Comments