在一个系统中日志管理是一个很重要的部分,因为当系统发布到线网后出了问题只能看系统日志了,这个时候系统日志起到了一个错误排查功能,同时也可以通过系统日志统计用户吞吐量等等,总之系统日志是系统管理一个重点。
本系统架构为SpringMVC,myBatis,Shrio等等。
1.SpringMVC异常处理
SpringMVC负责接收用户请求并进行处理然后将结果返回给用户,那么为了不让异常抛给用户,我们一般在Controller类下每个方法都加上一个try{}catch(Exception
e){},实例代码如下:
/** * pengweikang 20170220 用户登陆 * * @param cgbUser * 用户信息 * @param session *
@return */ @RequestMapping(value = "/login", method = RequestMethod.POST)
public @ResponseBody String userLogin(HttpServletRequest request) { try { .....
//Service方法调用 } catch (Exception e) { ..... //异常处理 } return null; }
该方法的缺点是代码冗余,不利于维护,一看就不想是一个专业的软件工程师应该写的,优化办法如下:
其实SpringMVC给我们提供了一个控制器增强标签,名称为@ControllerAdvice,通过这个标签就可以统一实现异常处理,代码如下:
创建统一的异常处理类CGBExceptionHandler.java
import javax.servlet.http.HttpServletRequest; import
org.apache.commons.lang.exception.ExceptionUtils; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import
org.springframework.stereotype.Controller; import
org.springframework.web.bind.annotation.ControllerAdvice; import
org.springframework.web.bind.annotation.ExceptionHandler; import
org.springframework.web.bind.annotation.ResponseBody; import
org.springframework.web.bind.annotation.RestController; import
org.springframework.web.servlet.config.annotation.EnableWebMvc; import
ch.qos.logback.classic.Level; import net.sf.json.JSONObject; /** *@author
create by pengweikang *@date 2018年6月27日--下午12:49:23 *@problem *@answer *@action
*/ @ControllerAdvice public class CGBExceptionHandler {
ch.qos.logback.classic.Logger loggerback =
(ch.qos.logback.classic.Logger)LoggerFactory.getLogger("error"); {
loggerback.setLevel(Level.ERROR); } @ExceptionHandler(Exception.class)
@ResponseBody public Object handleException(Exception e,HttpServletRequest
rquest) { loggerback.error("错误日志记录"); Map dataMap =
rquest.getParameterMap(); Set<String> keySet = dataMap.keySet();
for(String key : keySet) { String [] datas =
(String[])dataMap.get(key); String value = new String();
for(String data : datas) { value +=data+","; }
loggerback.error("Param:"+key+" = "+ value.substring(0, value.length()
- 1));//将请求参数保存在日志中 }
loggerback.error(ExceptionUtils.getFullStackTrace(e)); // 记录错误信息 String msg =
e.getMessage(); if (msg == null || msg.equals("")) { msg = "服务器出错"; }
JSONObject jsonObject = new JSONObject(); jsonObject.put("message", msg);
jsonObject.put("state", 0); return jsonObject.toString(); } }
这个时候你的Controller就不用在添加try-catch异常捕获了,
一但方法出了异常就会跳转到CGBExceptionHandler.java这个类的handleException方法。
2.logback日志管理
在这个方法中我们将方法调用的的错误消息都记录在日志中,并且将方法调用的参数也报错在错误日志中,logback配置内容如下:
<?xml version="1.0" encoding="UTF-8"?> <configuration
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://www.padual.com/java/logback.xsd"
debug="false" scan="true" scanPeriod="30 second"> <property name="PROJECT"
value="recognizeSystem" /> <property name="ROOT"
value="/opt/apache-tomcat-7.0.82/logs/${PROJECT}/" /> <property name="FILESIZE"
value="50MB" /> <property name="MAXHISTORY" value="100" /> <timestamp
key="DATETIME" datePattern="yyyy-MM-dd HH:mm:ss" /> <!-- 控制台打印 --> <appender
name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <filter
class="ch.qos.logback.classic.filter.LevelFilter"> <level>ERROR</level>
<onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> <encoder
charset="utf-8"> <pattern>[%-5level] %d{${DATETIME}} [%thread] %logger{36} -
%m%n </pattern> </encoder> </appender> <!-- ERROR 输入到文件,按日期和文件大小 --> <appender
name="ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender"> <encoder
charset="utf-8"> <pattern>[%-5level] %d{${DATETIME}} [%thread] %logger{36} -
%m%n </pattern> </encoder> <filter
class="ch.qos.logback.classic.filter.LevelFilter"> <level>ERROR</level>
<onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${ROOT}%d/error.%i.log</fileNamePattern>
<maxHistory>${MAXHISTORY}</maxHistory> <timeBasedFileNamingAndTriggeringPolicy
class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>${FILESIZE}</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy> </rollingPolicy> </appender> <!--
WARN 输入到文件,按日期和文件大小 --> <appender name="WARN"
class="ch.qos.logback.core.rolling.RollingFileAppender"> <encoder
charset="utf-8"> <pattern>[%-5level] %d{${DATETIME}} [%thread] %logger{36} -
%m%n </pattern> </encoder> <filter
class="ch.qos.logback.classic.filter.LevelFilter"> <level>WARN</level>
<onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${ROOT}%d/warn.%i.log</fileNamePattern>
<maxHistory>${MAXHISTORY}</maxHistory> <timeBasedFileNamingAndTriggeringPolicy
class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>${FILESIZE}</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy> </rollingPolicy> </appender> <!--
INFO 输入到文件,按日期和文件大小 --> <appender name="INFO"
class="ch.qos.logback.core.rolling.RollingFileAppender"> <encoder
charset="utf-8"> <pattern>[%-5level] %d{${DATETIME}} [%thread] %logger{36} -
%m%n </pattern> </encoder> <filter
class="ch.qos.logback.classic.filter.LevelFilter"> <level>INFO</level>
<onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${ROOT}%d/info.%i.log</fileNamePattern>
<maxHistory>${MAXHISTORY}</maxHistory> <timeBasedFileNamingAndTriggeringPolicy
class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>${FILESIZE}</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy> </rollingPolicy> </appender> <!--
DEBUG 输入到文件,按日期和文件大小 --> <appender name="DEBUG"
class="ch.qos.logback.core.rolling.RollingFileAppender"> <encoder
charset="utf-8"> <pattern>[%-5level] %d{${DATETIME}} [%thread] %logger{36} -
%m%n </pattern> </encoder> <filter
class="ch.qos.logback.classic.filter.LevelFilter"> <level>DEBUG</level>
<onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${ROOT}%d/debug.%i.log</fileNamePattern>
<maxHistory>${MAXHISTORY}</maxHistory> <timeBasedFileNamingAndTriggeringPolicy
class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>${FILESIZE}</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy> </rollingPolicy> </appender> <!--
TRACE 输入到文件,按日期和文件大小 --> <appender name="TRACE"
class="ch.qos.logback.core.rolling.RollingFileAppender"> <encoder
charset="utf-8"> <pattern>[%-5level] %d{${DATETIME}} [%thread] %logger{36} -
%m%n </pattern> </encoder> <filter
class="ch.qos.logback.classic.filter.LevelFilter"> <level>TRACE</level>
<onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${ROOT}%d/trace.%i.log</fileNamePattern>
<maxHistory>${MAXHISTORY}</maxHistory> <timeBasedFileNamingAndTriggeringPolicy
class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>${FILESIZE}</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy> </rollingPolicy> </appender> <!--
SQL相关日志输出--> <logger name="org.apache.ibatis" level="INFO" additivity="false"
/> <logger name="org.mybatis.spring" level="INFO" additivity="false" /> <logger
name="com.github.miemiedev.mybatis.paginator" level="INFO" additivity="false"
/> <!-- Logger 根目录 --> <root level="DEBUG"> <appender-ref ref="STDOUT" />
<appender-ref ref="DEBUG" /> <appender-ref ref="ERROR" /> <appender-ref
ref="WARN" /> <appender-ref ref="INFO" /> <appender-ref ref="TRACE" /> </root>
</configuration>
该配置文件内容为将不同类型的日志按不同文件进行报错,并且每天记录不同的日志,文件夹按日期进行命名,儿控制台只打印错误日志。
3.测试
测试代码如下:
@Controller @RequestMapping(value="/test") public class TestController {
@RequestMapping(value="/exception") public @ResponseBody String throwexcep(int
data) throws Exception { int a = data/0;// 一定会抛出 java.lang.ArithmeticException:
/ by zero return null; } }请求
http://localhost:8080/logSystem/test/exception?data=100
首先看tomcat的log文件夹如下图所示:
error.0.log日志记录如下:
[ERROR] 2018-07-06 15:05:39 [http-bio-8080-exec-3] error - 错误日志记录 [ERROR]
2018-07-06 15:09:30 [http-bio-8080-exec-2] error - 错误日志记录 [ERROR] 2018-07-06
15:09:30 [http-bio-8080-exec-2] error - Param:data = 100 [ERROR] 2018-07-06
15:09:30 [http-bio-8080-exec-2] error -
ParameterMap:org.apache.catalina.util.ParameterMap@c7832d1 [ERROR] 2018-07-06
15:09:30 [http-bio-8080-exec-2] error - java.lang.ArithmeticException: / by
zero at
com.goldenbridge.recognizesystem.controller.ActivitiController.throwexcep(ActivitiController.java:137)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498) at
org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:222)
at
org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:137)
at
org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110)
at
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:814)
at
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:737)
at
org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
at
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959)
at
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893)
at
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:969)
at
org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:860)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:624) at
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:845)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:731) at
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
at
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) at
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at
com.alibaba.druid.support.http.WebStatFilter.doFilter(WebStatFilter.java:123)
at
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at
org.apache.shiro.web.servlet.ProxiedFilterChain.doFilter(ProxiedFilterChain.java:61)
at
org.apache.shiro.web.servlet.AdviceFilter.executeChain(AdviceFilter.java:108)
at
org.apache.shiro.web.servlet.AdviceFilter.doFilterInternal(AdviceFilter.java:137)
at
org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:125)
at
org.apache.shiro.web.servlet.ProxiedFilterChain.doFilter(ProxiedFilterChain.java:66)
at
org.apache.shiro.web.servlet.AbstractShiroFilter.executeChain(AbstractShiroFilter.java:449)
at
org.apache.shiro.web.servlet.AbstractShiroFilter$1.call(AbstractShiroFilter.java:365)
at
org.apache.shiro.subject.support.SubjectCallable.doCall(SubjectCallable.java:90)
at
org.apache.shiro.subject.support.SubjectCallable.call(SubjectCallable.java:83)
at
org.apache.shiro.subject.support.DelegatingSubject.execute(DelegatingSubject.java:383)
at
org.apache.shiro.web.servlet.AbstractShiroFilter.doFilterInternal(AbstractShiroFilter.java:362)
at
org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:125)
at
org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
at
org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
at
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at
org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:121)
at
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at
com.goldenbridge.recognizesystem.utils.SimpleCORSFilter.doFilter(SimpleCORSFilter.java:34)
at
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at
org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219)
at
org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:110)
at
org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:506)
at
org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:169)
at
org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:962) at
org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:445)
at
org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1115)
at
org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:637)
at
org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:316)
at
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at
org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:748)
到此系统日志管理配置完成!
热门工具 换一换