基于4.1.7.RELEASE
Filter处理request log的基类,提供了在filterChain.doFilter调用前后的回调函数,其实现类有CommonsRequestLoggingFilter,Log4jNestedDiagnosticContextFilter,ServletContextRequestLoggingFilter。
其核心代码为doFilterInternal方法:
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
boolean isFirstRequest = !isAsyncDispatch(request);
HttpServletRequest requestToUse = request;
if (isIncludePayload() && isFirstRequest && !(request instanceof ContentCachingRequestWrapper)) {
requestToUse = new ContentCachingRequestWrapper(request);
}
boolean shouldLog = shouldLog(requestToUse);
if (shouldLog && isFirstRequest) {
beforeRequest(requestToUse, getBeforeMessage(requestToUse));
}
try {
filterChain.doFilter(requestToUse, response);
}
finally {
if (shouldLog && !isAsyncStarted(requestToUse)) {
afterRequest(requestToUse, getAfterMessage(requestToUse));
}
}
}
在调用filterChain.doFilter方法前后分别调用beforeRequest和afterRequest,而这两个方法具体实现由子类决定,根据功能不同来决定记录日志的方法,
在beforeRequest中和afterRequest中分别调用了 getBeforeMessage,getAfterMessage,这两个方法代码如下
private String getBeforeMessage(HttpServletRequest request) {
return createMessage(request, this.beforeMessagePrefix, this.beforeMessageSuffix);
}
private String getAfterMessage(HttpServletRequest request) {
return createMessage(request, this.afterMessagePrefix, this.afterMessageSuffix);
}
最终都会进入到createMessage中去,只是前缀后缀不同,
before的Msg格式是: Before request [ Msg ]
after的Msg格式是 : After request [ Msg ]
这里的Msg具体内容则由createMessage决定
protected String createMessage(HttpServletRequest request, String prefix, String suffix) {
StringBuilder msg = new StringBuilder();
msg.append(prefix);
msg.append("uri=").append(request.getRequestURI());
if (isIncludeQueryString()) {
msg.append('?').append(request.getQueryString());
}
if (isIncludeClientInfo()) {
String client = request.getRemoteAddr();
if (StringUtils.hasLength(client)) {
msg.append(";client=").append(client);
}
HttpSession session = request.getSession(false);
if (session != null) {
msg.append(";session=").append(session.getId());
}
String user = request.getRemoteUser();
if (user != null) {
msg.append(";user=").append(user);
}
}
if (isIncludePayload() && request instanceof ContentCachingRequestWrapper) {
ContentCachingRequestWrapper wrapper = (ContentCachingRequestWrapper) request;
byte[] buf = wrapper.getContentAsByteArray();
if (buf.length > 0) {
int length = Math.min(buf.length, getMaxPayloadLength());
String payload;
try {
payload = new String(buf, 0, length, wrapper.getCharacterEncoding());
}
catch (UnsupportedEncodingException e) {
payload = "[unknown]";
}
msg.append(";payload=").append(payload);
}
}
msg.append(suffix);
return msg.toString();
}
根据具体的参数设置的不同,其表现出不同的形式,msg的最基本格式为
Before/After request [ uri=xxx ]
设置includeQueryString=true:
Before/After request [ uri=xxx?a=xx&b=xxx ]
设置includeClientInfo=true:
Before/After request [ uri=xxx?a=xxx&b=xxx;client=xxx;session=sessionId;user=xxx ]
设置includePayload=true:
先判断request的content的长度,如果超过设置maxPayload的长度,则按照maxPayload进行截取,如果出现异常,则payload=[unknown]
Before/After request [ uri=xxx?a=xxx&b=xxx;client=xxx;session=sessionId;user=xxx;payload=xxx/[unknown] ]
下面来看其子类对应的不同的实现
CommonsRequestLoggingFilter:
@Override
protected boolean shouldLog(HttpServletRequest request) {
return logger.isDebugEnabled();
}
@Override
protected void beforeRequest(HttpServletRequest request, String message) {
logger.debug(message);
}
@Override
protected void afterRequest(HttpServletRequest request, String message) {
logger.debug(message);
}
其主要是调用初始化时候设置的GenericFilterBean中的logger进行记录。
Log4jNestedDiagnosticContextFilter:
其采用了Log4j来进行日志记录。自定义变量
protected final Logger log4jLogger = Logger.getLogger(getClass());
ServletContextRequestLoggingFilter:
使用ServletContext来记录日志