Recently I have switched from the log4j logging framework to the logback framework. logback seems to have evolved into something better than log4j. It has cool features like the ability of logging into context specific logging files almost out-of-the-box (Using a sifting appender). However the application has to provide the context (usually as MDC variables) which is kind of boring task to do.

So, I have implemented a fairly generic servlet that is able to provide almost any servlet request information for an active HTTP request. This servlet accepts a set of SpEL expressions (SpEL will be available with Spring 3.0) which are parsed and evaluated. Finally it produces the evaluation results as MDC variables through the org.slf4j.MDC api (So I guess that might be usable for log4j as well).

1
2
3
4
5
6
7
8
<filter>
  <filter-name>slf4jmdc</filter-name>
  <filter-class>at...SpringExpressionSlf4jMdcRequestFilter</filter-class>
  <init-param>
      <param-name>mdcKeyExpression</param-name>
      <param-value>contextPath=${request.contextPath};username=${request.userPrincipal?.name}</param-value>
  </init-param>
</filter>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
  StandardEvaluationContext context = new StandardEvaluationContext(new RootObject(request));
  ExpressionParser parser = new SpelExpressionParser();

  String[] mdc = StringUtils.delimitedListToStringArray(mdcKeyExpression, ";");
  Properties expressions = StringUtils.splitArrayElementsIntoProperties(mdc, "=");

  Enumeration<?> keyNames = expressions.propertyNames();
  while (keyNames.hasMoreElements()) {
      String key = keyNames.nextElement().toString();
      try {
          Expression exp = parser.parseExpression(expressions.getProperty(key), new TemplateParserContext());
          Object value = exp.getValue(context);
          if (value != null) {
              MDC.put(key, value.toString());
          }
      } catch (ParseException e) {
          LOGGER.error("Parsing expression", e);
      }
  }

  try {
      filterChain.doFilter(request, response);
  } finally {
      while (keyNames.hasMoreElements()) {
          MDC.remove(keyNames.nextElement().toString());
      }
  }
}

This servlet can be used about anywhere MDC variables are needed!

Comments