Log4j 2 API

事件日志记录

EventLogger 类提供了一种简单的机制来记录应用程序中发生的事件。虽然 EventLogger 作为一种启动应由审计日志记录系统处理的事件的方式很有用,但它本身并没有实现审计日志记录系统所需的任何功能,例如保证交付。

在典型的 Web 应用程序中使用 EventLogger 的推荐方法是在 ThreadContext Map 中填充与请求整个生命周期相关的数据,例如用户的 ID、用户的 IP 地址、产品名称等。这可以在 servlet 过滤器中轻松完成,在 servlet 过滤器中,ThreadContext Map 也可以在请求结束时清除。当需要记录的事件发生时,应该创建一个 StructuredDataMessage 并填充它。然后调用 EventLogger.logEvent(msg),其中 msg 是对 StructuredDataMessage 的引用。

import org.apache.logging.log4j.ThreadContext;
import org.apache.commons.lang.time.DateUtils;

import javax.servlet.Filter;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.FilterChain;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.TimeZone;

public class RequestFilter implements Filter {
    private FilterConfig filterConfig;
    private static String TZ_NAME = "timezoneOffset";

    public void init(FilterConfig filterConfig) throws ServletException {
        this.filterConfig = filterConfig;
    }

    /**
     * Sample filter that populates the MDC on every request.
     */
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
            throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest)servletRequest;
        HttpServletResponse response = (HttpServletResponse)servletResponse;
        ThreadContext.put("ipAddress", request.getRemoteAddr());
        HttpSession session = request.getSession(false);
        TimeZone timeZone = null;
        if (session != null) {
            // Something should set this after authentication completes
            String loginId = (String)session.getAttribute("LoginId");
            if (loginId != null) {
                ThreadContext.put("loginId", loginId);
            }
            // This assumes there is some javascript on the user's page to create the cookie.
            if (session.getAttribute(TZ_NAME) == null) {
                if (request.getCookies() != null) {
                    for (Cookie cookie : request.getCookies()) {
                        if (TZ_NAME.equals(cookie.getName())) {
                            int tzOffsetMinutes = Integer.parseInt(cookie.getValue());
                            timeZone = TimeZone.getTimeZone("GMT");
                            timeZone.setRawOffset((int)(tzOffsetMinutes * DateUtils.MILLIS_PER_MINUTE));
                            request.getSession().setAttribute(TZ_NAME, tzOffsetMinutes);
                            cookie.setMaxAge(0);
                            response.addCookie(cookie);
                        }
                    }
                }
            }
        }
        ThreadContext.put("hostname", servletRequest.getServerName());
        ThreadContext.put("productName", filterConfig.getInitParameter("ProductName"));
        ThreadContext.put("locale", servletRequest.getLocale().getDisplayName());
        if (timeZone == null) {
            timeZone = TimeZone.getDefault();
        }
        ThreadContext.put("timezone", timeZone.getDisplayName());
        filterChain.doFilter(servletRequest, servletResponse);
        ThreadContext.clear();
    }

    public void destroy() {
    }
}

使用 EventLogger 的示例类。

import org.apache.logging.log4j.StructuredDataMessage;
import org.apache.logging.log4j.EventLogger;

import java.util.Date;
import java.util.UUID;

public class MyApp {

    public String doFundsTransfer(Account toAccount, Account fromAccount, long amount) {
        toAccount.deposit(amount);
        fromAccount.withdraw(amount);
        String confirm = UUID.randomUUID().toString();
        StructuredDataMessage msg = new StructuredDataMessage(confirm, null, "transfer");
        msg.put("toAccount", toAccount);
        msg.put("fromAccount", fromAccount);
        msg.put("amount", amount);
        EventLogger.logEvent(msg);
        return confirm;
    }
}

EventLogger 类使用名为“EventLogger”的记录器。EventLogger 使用 OFF 作为默认日志级别,表示它不能被过滤。这些事件可以使用 StructuredDataLayout 格式化以进行打印。