log4j.properties文件
#根设置,输出级别为DEBUG级别, 输出文件为 ERRORA,stdout,DEBUGA
log4j.rootLogger=DEBUG,ERRORA,stdout,DEBUGA
#过滤掉spring框架下的额外日志
#log4j.category.org.springframework = WARN
#输出到控制台
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %-5p %c{1}:%L - %m%n
#输出DEBUG信息到指定文件
log4j.appender.DEBUGA=org.apache.log4j.DailyRollingFileAppender
log4j.appender.DEBUGA.layout=org.apache.log4j.PatternLayout
log4j.appender.DEBUGA.layout.ConversionPattern=%d{yyyy-MM-dd-HH-mm} [%t] [%c] [%p] - %m%n
log4j.appender.DEBUGA.datePattern=yyyy-MM-dd'.log'
log4j.appender.DEBUGA.Threshold = DEBUG
log4j.appender.DEBUGA.append=true
log4j.appender.DEBUGA.File=d:/log/debug_log.log
log4j.appender.DEBUGA.filter.F1=org.apache.log4j.varia.LevelRangeFilter
log4j.appender.DEBUGA.filter.F1.LevelMin=DEBUG
log4j.appender.DEBUGA.filter.F1.LevelMax=INFO
#输出error到指定文件
log4j.appender.ERRORA=org.apache.log4j.DailyRollingFileAppender
log4j.appender.ERRORA.layout=org.apache.log4j.PatternLayout
log4j.appender.ERRORA.layout.ConversionPattern=%d{yyyy-MM-dd-HH-mm} [%t] [%c] [%p] - %m%n
log4j.appender.ERRORA.datePattern=yyyy-MM-dd'.log'
log4j.appender.ERRORA.Threshold = ERROR
log4j.appender.ERRORA.append=true
log4j.appender.ERRORA.File=d:/errorlog/error_log.log
#打印sql语句
log4j.logger.com.ibatis=DEBUG
log4j.logger.java.sql.ResultSet=INFO
log4j.logger.com.ibatis.common.jdbc.SimpleDataSource=DEBUG
log4j.logger.com.ibatis.common.jdbc.ScriptRunner=DEBUG
log4j.logger.com.ibatis.sqlmap.engine.impl.SqlMapClientDelegate=DEBUG
log4j.logger.java.sql.Connection=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG
为了对每个请求的进行日志输出,我们需要配置拦截器
<!-- 拦截器配置,拦截顺序:先执行后定义的,排在第一位的最后执行。--> <mvc:interceptors> <!-- API访问日志记录拦截器 --> <mvc:interceptor> <mvc:mapping path="/user/**" /> <bean class="com.utils.ApiLogInterceptor" /> </mvc:interceptor> <mvc:interceptor> <mvc:mapping path="/childs/**" /> <bean class="com.utils.ApiLogInterceptor" /> </mvc:interceptor> </mvc:interceptors>
开发自定义的拦截器,实现 HandlerInterceptor 接口
public class ApiLogInterceptor implements HandlerInterceptor { private static final Logger logger = org.apache.log4j.Logger.getLogger(ApiLogInterceptor.class); private static final ThreadLocal<Long> startTimeThreadLocal = new NamedThreadLocal<Long>("ThreadLocal StartTime"); @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { if (logger.isDebugEnabled()){ long beginTime = System.currentTimeMillis();//1、开始时间 startTimeThreadLocal.set(beginTime); //线程绑定变量(该数据只有当前请求的线程可见) logger.debug("开始计时: {"+new SimpleDateFormat("HH:mm:ss.SSS").format(beginTime)+"} URI: {"+request.getRequestURI()+"}"); } return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { if (modelAndView != null){ logger.info("ViewName: " + modelAndView.getViewName()); } } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { logger.debug("Header: " + request.getHeader("user-agent")); logger.debug("RequestURI: " + request.getRequestURI()); logger.debug("Method: " + request.getMethod()); logger.debug("ParameterMap: " + request.getParameterMap().toString()); // 打印JVM信息 if (logger.isDebugEnabled()){ long beginTime = startTimeThreadLocal.get();//得到线程绑定的局部变量(开始时间) long endTime = System.currentTimeMillis(); //2、结束时间 logger.debug("计时结束:{"+new SimpleDateFormat("HH:mm:ss.SSS").format(endTime)+"} 耗时:{"+DateUtils.formatDateTime(endTime - beginTime)+"} URI: {"+request.getRequestURI()+"} 最大内存: {"+(Runtime.getRuntime().maxMemory()/1024/1024)+"}m 已分配内存: {"+(Runtime.getRuntime().totalMemory()/1024/1024)+"}m 已分配内存中的剩余空间: {"+(Runtime.getRuntime().freeMemory()/1024/1024+"}m 最大可用内存: {"+(Runtime.getRuntime().maxMemory()-Runtime.getRuntime().totalMemory()+Runtime.getRuntime().freeMemory())/1024/1024)+"}m") ; } } }
自定义拦截器会针对 /user/** 和 /childs/** 的请求进行拦截,输出日志。
测试后发现,错误日志既没有在控制台打印出来也没有输出到文件,因为我们需要配置spring-mvc的全局异常处理器,实现 HandlerExceptionResolver 接口
public class DefaultExceptionHandler implements HandlerExceptionResolver {
private static final Logger logger = org.apache.log4j.Logger.getLogger(DefaultExceptionHandler.class);
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
logger.error("异常信息", ex);
String url = request.getRequestURL().toString();
if (url.contains("api")) {
try {
/**
* 来自app的请求异常处理
*/
response.setStatus(HttpStatus.OK.value());
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.setCharacterEncoding("UTF-8");
response.getWriter().write(new Gson().toJson("系统错误"));
} catch (IOException e) {
logger.error("", e);
}
} else {
ModelAndView mv = new ModelAndView();
mv.setViewName("error");
return mv;
}
return null;
}
}
还需要在spring-mvc.xml中配置这个bean
<bean id="exceptionHandler" class="com.utils.DefaultExceptionHandler" />
再次运行项目,系统出现错误的时候,会跳转到 error.jsp,错误信息会被输出到 error_log 文件。