logback4

logback4,第1张

logback4

文章目录
  • 一 What's MDC
    • 1.1 本质
    • 1.2 例子
  • 二 Automating access to the MDC
    • 2.1 案例一
    • 2.2 切线程
    • 2.3 MDCInsertingServletFilter
  • 三 参考

MDC (Mapped Diagnostic Context)

一 What’s MDC

在分布式系统中,多线程处理多个客户端司空见惯.有个做法是每个客户端对应一个Logger,但这种做法会产生大量Logger而且管理起来也不便.另有一种做法是将日志的上下文信息放到MDC里.

MDC 是slf4j的定义,而不是 Logback的, 但Logback-classic依赖了 slf4j,所以Logback中也能使用slf4j.

但是 slf4j中的MDC 只是个 代理, Logback中真正的MDC实现是LogbackMDCAdapter.

这是MDC的核心方法, 其实也是些增删改查的方法.

public class MDC {
  //Put a context value as identified by key
  //into the current thread's context map.
  public static void put(String key, String val);

  //Get the context identified by the key parameter.
  public static String get(String key);

  //Remove the context identified by the key parameter.
  public static void remove(String key);

  //Clear all entries in the MDC.
  public static void clear();
}
1.1 本质

MDC本质上就是个 ThreadLocal.
从LogbackMDCAdapter的代码中我们可以看出来 , 这个类的核心数据结构是 :

final ThreadLocal> copyonThreadLocal = new ThreadLocal>();

1.2 例子

下面三块反映了如何使用MDC.
1 java代码

public class SimpleMDC {
  static public void main(String[] args) throws Exception {
    // You can put values in the MDC at any time. Before anything else
    // we put the first name
    MDC.put("first", "Dorothy");
    Logger logger = LoggerFactory.getLogger(SimpleMDC.class);
    // We now put the last name
    MDC.put("last", "Parker");
    // The most beautiful two words in the English language according
    // to Dorothy Parker:
    logger.info("Check enclosed.");
    logger.debug("The most beautiful two words in English.");
    MDC.put("first", "Richard");
    MDC.put("last", "Nixon");
    logger.info("I am not a crook.");
    logger.info("Attributed to the former US president. 17 Nov 1973.");
  }
}

2 配置

 
  
    %X{first} %X{last} - %m%n
   

3 结果

Dorothy Parker - Check enclosed.
Dorothy Parker - The most beautiful two words in English.
Richard Nixon - I am not a crook.
二 Automating access to the MDC

在处理多客户端的时候,MDC很有用. 通过MDC在线程中传递数据, 也通过MDC将数据透传给 appender . 虽然没有MDC 我们在logger.xxx()时 多打印出自己想要的信息也是可以,但是:其一没有封装, 其二通过方法人肉传参其实很繁琐.

2.1 案例一

有一个web应用, 我们希望在日志中记录客户端的ip host user等信息,一个简便的方法是在 servlet Filter 中实现,比如:

public class UserServletFilter implements Filter {
  private final String USER_KEY = "username";
  public void destroy() {
  }
  public void doFilter(ServletRequest request, ServletResponse response,
    FilterChain chain) throws IOException, ServletException {
    boolean successfulRegistration = false;
    HttpServletRequest req = (HttpServletRequest) request;    
    Principal principal = req.getUserPrincipal();
    // Please note that we could have also used a cookie to 
    // retrieve the user name
    if (principal != null) {
      String username = principal.getName();
      successfulRegistration = registerUsername(username);
    } 
    try {
      chain.doFilter(request, response);
    } finally {
      if (successfulRegistration) {
        MDC.remove(USER_KEY);
      }
    }
  }
  public void init(FilterConfig arg0) throws ServletException {
  }
  private boolean registerUsername(String username) {
    if (username != null && username.trim().length() > 0) {
      MDC.put(USER_KEY, username);
      return true;
    }
    return false;
  }
}

然后我们将这个Filter 注册到servlet 容器中(通过web.xml)

2.2 切线程

正由于MDC的本质是ThreadLocal,在多线程环境中使用时需要特别注意.
如果涉及到线程切换, 我们可以在 当前线程中 MDC.getCopyOfContextMap(), 然后在另一个线程中 第一句就执行 MDC.setCopyOfContextMap(). 本质上这把 ThreadLocal的内容跨线程传递了.

2.3 MDCInsertingServletFilter

MDCInsertingServletFilter是一个Logback内置的记录HTTP信息的Filter, 我们只要:
1 在web.xml中配置:


  MDCInsertingServletFilter
  
    ch.qos.logback.classic.helpers.MDCInsertingServletFilter
  


  MDCInsertingServletFilter
  /*

2 在 appender 配置
%X{req.remoteHost} %X{req.requestURI}%n%d - %m%n

这里的 req.remoteHost就是一个MDC key (内置)

1 ,2 两步完成即可使用该Filter .

三 参考
  • 参考文献

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5683379.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存