The EventLogger class provides a simple mechanism for logging events that occur in an application. While the EventLogger is useful as a way of initiating events that should be processed by an audit Logging system, by itself it does not implement any of the features an audit logging system would require such as guaranteed delivery.
EventLogger类提供了一种用于记录应用程序中发生的日志事件的简单机制。
尽管EventLogger作为一种启动事件的有效方法,(这种启动方法)应该被审核日志记录系统处理。但EventLogger本身并未实现审核日志记录系统所需的任何功能,例如保证交付。
The recommended way of using the EventLogger in a typical web application is to populate the ThreadContext Map with data that is related to the entire lifespan of the request such as the user’s id, the user’s IP address, the product name, etc. This can easily be done in a servlet filter where the ThreadContext Map can also be cleared at the end of the request. When an event that needs to be recorded occurs a StructuredDataMessage should be created and populated. Then call EventLogger.logEvent(msg) where msg is a reference to the StructuredDataMessage.
在典型的Web应用程序中,使用EventLogger的推荐方法是,
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.
* 在每次请求都填充MDC的过滤器示例
* 什么是MDC在文末会提到
*/
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest)servletRequest;
HttpServletResponse response = (HttpServletResponse)servletResponse;
//在ThreadContext中填充相关数据,这边是IP地址
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. 这里假设有一些js在用户页面上用来创建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() {
}
}
Sample class that uses EventLogger. 使用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对象。
StructuredDataMessage msg = new StructuredDataMessage(confirm, null, "transfer");
msg.put("toAccount", toAccount);
msg.put("fromAccount", fromAccount);
msg.put("amount", amount);
//最后调用EventLogger的logEvent方法来记录日志。
EventLogger.logEvent(msg);
return confirm;
}
}
The EventLogger class uses a Logger named “EventLogger”. EventLogger uses a logging level of OFF as the default to indicate that it cannot be filtered. These events can be formatted for printing using the StructuredDataLayout.
EventLogger使用OFF作为默认的日志级别来表示它不能被过滤。
这些日志事件可以使用StructuredDataLayout 格式化之后打印。
“Mapped Diagnostic Context”映射诊断上下文(简称MDC)是一种用于区分来自不同来源的交错日志输出的工具。
log4j official API of Class MDC
官方文档这样解释:
The MDC class is similar to the NDC class except that it is based on a map instead of a stack. It provides mapped diagnostic contexts. A Mapped Diagnostic Context, or MDC in short, is an instrument for distinguishing interleaved log output from different sources. Log output is typically interleaved when a server handles multiple clients near-simultaneously.
它类似于NDC,只不过NDC是基于栈,而MDC是基于map的。
MDC是一个用来区分不同来源的交错的日志输出的工具。当一个服务器几乎同时处理多个客户端时,日志输出通常是交错的。
The MDC is managed on a per thread basis. A child thread automatically inherits a copy of the mapped diagnostic context of its parent. MDC基于每个线程进行管理。一个子线程自动继承一份来自它父类的MDC拷贝。