@Configuration public class YuncaiRequestLoggingFilter { private static final int MAX_PAYLOAD_LENGTH = 10000; @Autowired private CustomServletContextRequestLoggingFilter customServletContextRequestLoggingFilter; @Bean public ServletContextRequestLoggingFilter requestLoggingFilter() { ServletContextRequestLoggingFilter loggingFilter = customServletContextRequestLoggingFilter; loggingFilter.setIncludeClientInfo(true); loggingFilter.setIncludeQueryString(true); loggingFilter.setIncludePayload(true); loggingFilter.setIncludeHeaders(true); loggingFilter.setMaxPayloadLength(MAX_PAYLOAD_LENGTH); return loggingFilter; } }
@Slf4j @Component public class CustomServletContextRequestLoggingFilter extends ServletContextRequestLoggingFilter { @Autowired private EmailLogService emailLogService; private void sendLogEmail(String exceptionMessage, String requestMessage) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append("Timestamp: ").append(System.currentTimeMillis()).append("\n").append("Time: ") .append(LocalDateTime.now().toString()).append("\n").append("Thread Id: ") .append(Thread.currentThread().getId()).append("\n").append("Thread Name: ") .append(Thread.currentThread().getName()).append("\n").append("Request: \n").append(requestMessage) .append("\n").append("Exception: \n").append(exceptionMessage).append("\n"); emailLogService.sendMail(stringBuilder.toString()); } @Override protected void afterRequest(HttpServletRequest request, String message) { super.afterRequest(request, message); if (ExceptionContext.getExceptionMessage() != null) { try { // ExceptionMessage exceptionMessage = new ExceptionMessage(); // //TODO 异常消息发送 // exceptionSendComponent.sendExceptionMessage(exceptionMessage); sendLogEmail(ExceptionContext.getExceptionMessage(), message); ExceptionContext.destroy(); } catch (Exception e) { log.error("error", e); } } } }
2018-04-26 15:14:57.952 INFO 1464 --- [http-nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : After request [uri=/scan?code=111111111&uid=111111111&userId=1&payType=0;client=0:0:0:0:0:0:0:1;headers={host=[localhost:8080], connection=[keep-alive], accept=[*/*], user-agent=[Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36], privatetenantcode=[zyd], referer=[http://localhost:8080/swagger-ui.html], accept-encoding=[gzip, deflate, br], accept-language=[zh-CN,zh;q=0.9,en;q=0.8]}]
AbstractRequestLoggingFilter类定义了两个方法beforeRequest和afterRequest分别用于设定过滤前后执行的操作,它有三个子类,分别是CommonsRequestLoggingFilter、ServletContextRequestLoggingFilter和Log4jNestedDiagnosticContextFilter,这三个子类分别实现了各自的beforeRequest和afterRequest。其中,CommonsRequestLoggingFilter在过滤前后分别打印出一段debug的信息;ServletContextRequestLoggingFilter在过滤前后分别向日志文件中写入一段日志信息,日志文件可由log4j.properties等指定;Log4jNestedDiagnosticContextFilter则将日志信息存储到NDC中,NDC采用了一个类似栈的机制来push和pot上下文信息,每一个线程都独立地储存上下文信息,比如说一个servlet就可以针对 每一个request创建对应的NDC,储存客户端地址等信息。