25 1月 2010

利用MDC簡化取得特定對象Log資料的方法

這是半反省文。

以往要想取得某一使用者操作過程所產生的Log,由於我會將User放在ThreadLocal中,所以想到的做法就是在LogPattern中加入一個{},並每次自ThreadLocal中取出,例如下列這樣
logger.info("user{} does something.", ThreadLocalHolder.getUserName);
logger.info("user{} create role{}.", ThreadLocalHolder.getUserName, role);
這樣可以很方便的用grep取回這User相關的Log而濾掉非必要的Log.

但是log4j跟logback都有一個Class叫MDC(Mapped Diagnostic Context),可以更簡單地達到這個功能。只要在取得User的那個Filter或是Intercepter,放入MDC中,並在離開時移除即可。

例如使用Filter

public void doFilter(ServletRequest request, ServletResponse response,
    FilterChain chain) throws IOException, ServletException {
    HttpSession session = (HttpServletRequest) request.getSession();
    User user = (User) session.get("User");
    if (null != user) {
        ThreadLocalHolder.putUser(user);
        MDC.put("username", user.getName());
    }
    try {
      chain.doFilter(request, response);
    } finally {
      if (null != user) {
        MDC.remove("username");
      }
    }
  }



皆下來LogPattern只要利用%X{username}就可以帶出user name了。

為什麼是半反省文?因為這樣做就代表綁定了Log的做法,還是有些缺點的。

沒有留言: