升级CXF至3.1、Log4j2后Spring Java应用异常日志无法输出至文件及SMTP
Spring Java应用升级CXF(从2.x到3.1)和Log4j(从1.x到2.x)后,日志功能出现异常:RollingFile Appender和SMTP Appender不再记录异常信息。使用maven-jetty插件运行时,异常能正常打印到控制台,但其他日志都能正常输出,只有异常日志无法被这两个Appender记录。
此前使用的outFaultInterceptors已按团队建议移除,替换为providers中的ExceptionMapper,相关配置如下:
applicationcontext.xml
<bean id="logInbound" class="org.apache.cxf.interceptor.LoggingInInterceptor"/> <bean id="logOutbound" class="org.apache.cxf.interceptor.LoggingOutInterceptor"/> <jaxrs:server id="serviceResource" address="/rest"> <jaxrs:serviceBeans> <ref bean="endpoint1"/> <ref bean="endpoint2"/> </jaxrs:serviceBeans> <!-- this is removed after migrating to new cxf 3 infavor of exception mappers <jaxrs:outFaultInterceptors> <ref bean="cxfRestFaultInterceptor"/> </jaxrs:outFaultInterceptors> --> <jaxrs:inInterceptors> <ref bean="logInbound"/> </jaxrs:inInterceptors> <jaxrs:outInterceptors> <ref bean="logOutbound"/> </jaxrs:outInterceptors> <jaxrs:providers> <bean id="businessExceptionMapper" class="com.commons.interceptors.BusinessExceptionMapper"> <property name="exceptionMessageSource" ref="exceptionMessageSource"/> <property name="exceptionCodeSource" ref="exceptionCodeSource"/> </bean> <bean id="globalExceptionMapper" class="com.common.interceptors.GlobalExceptionMapper"> <property name="messageSource" ref="messageSource"/> </bean> <bean id="applicationExceptionMapper" class="com.common.interceptors.ApplicationExceptionMapper"> <property name="messageSource" ref="messageSource"/> </bean> <ref bean='jacksonProvider'/> </jaxrs:providers> </jaxrs:server>
log4j2.xml
<Configuration> <Appenders> <RollingFile name="fileout" fileName="../logs/web.log" filePattern="../logs/web.%i.log" ignoreExceptions="false" append="true"> <PatternLayout> <Pattern>[%d{DATE}] - %X{hostName} - [%-5p][%c{1},%t] - %m%n</Pattern> </PatternLayout> <Policies> <SizeBasedTriggeringPolicy size="2MB"/> </Policies> <DefaultRolloverStrategy max="10"/> </RollingFile> <SMTP name="mail" from="from_email" to="to_email" subject="APIWebError" smtpHost="smtp_host"> <HtmlLayout/> </SMTP> </Appenders> <Loggers> <Root level="error"> <AppenderRef ref="fileout"/> <AppenderRef ref="mail"/> </Root> </Loggers> </Configuration>
说明:outFaultInterceptors此前被使用,现已移除,替换为providers中的ExceptionMapper,此为团队推荐方案。
1. 补全ExceptionMapper的日志输出逻辑
替换outFaultInterceptors后,原拦截器负责的异常日志输出逻辑丢失,需要在三个ExceptionMapper的实现类中主动添加日志记录:
在BusinessExceptionMapper、GlobalExceptionMapper、ApplicationExceptionMapper的toResponse方法中,加入Log4j2日志代码,注意必须传入异常对象以输出堆栈信息:
private static final Logger logger = LogManager.getLogger(GlobalExceptionMapper.class); @Override public Response toResponse(Throwable exception) { // 记录包含堆栈的异常日志 logger.error("系统处理异常", exception); // 原有构建响应的逻辑 return Response.status(Response.Status.INTERNAL_SERVER_ERROR) .entity("服务内部错误") .build(); }
2. 修改Log4j2的PatternLayout配置
当前Pattern仅输出日志消息,未包含异常堆栈,需添加%ex参数:
<Pattern>[%d{DATE}] - %X{hostName} - [%-5p][%c{1},%t] - %m%ex%n</Pattern>
3. 优化SMTP Appender配置
确保SMTP Appender能捕获完整异常信息,可明确配置布局和级别过滤:
<SMTP name="mail" from="from_email" to="to_email" subject="APIWebError" smtpHost="smtp_host"> <HtmlLayout locationInfo="true"> <Pattern>%d{ISO8601} %-5p [%t] %c{1} - %m%ex</Pattern> </HtmlLayout> </SMTP>
4. 确认CXF拦截器行为
CXF的LoggingOutInterceptor仅处理正常响应日志,异常响应在使用ExceptionMapper后不会被它处理,必须依赖ExceptionMapper内部的日志逻辑输出异常。
内容的提问来源于stack exchange,提问作者Diablo

