(八)同一异常处理、日志处理

318 阅读2分钟

统一异常处理器

让异常结果也显示为统一的返回结果对象,并且统一处理系统的异常信息,那么需要统一异常处理。

统一异常处理的目的:在切面中处理异常、返回统一的异常结果对象

@ControllerAdvice注解:ControllerAdvice本质上是一个Component,aop,起到一个拦截作用。

Spring的@ExceptionHandler注解,可以用来统一处理方法抛出的异常。

@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(Exception.class)
    @ResponseBody
    public R error(Exception e){
        e.printStackTrace();
        return R.error();
    }
}

当然也会有一些特定异常需要额外进行处理的。

处理特定异常

那么就可以在GlobalExceptionHandler这个类中添加一个处理方法。

在@ExceptionHandler中指定需要处理的特定异常。

@ExceptionHandler(BadSqlGrammarException.class)
@ResponseBody
public R error(BadSqlGrammarException e){
    e.printStackTrace();
    return R.setResult(ResultCodeEnum.BAD_SQL_GRAMMAR);
}

统一日志处理

通过日志可以查看程序的运行过程,运行信息,异常信息等

目的

  1. 将日志记录在文件中,方便运维和开发做错误排查
  2. 文件日志需要做滚动输出(输出到更多的日志文件中),避免单日志体积过大,拖垮服务器。
  3. 可以方便的在开发环境和生产环境中切换输出方式,例如在控制台和日志文件中灵活输出。

日志级别

分为FATAL、ERROR、WARN、INFO、DEBUG。

默认情况下,spring boot从控制台打印出来的日志级别只有INFO及以上级别,可以配置日志级别。

# 设置日志级别
logging:
  level:
    root: ERROR

这种方式能将ERROR级别以及以上级别的日志打印在控制台上。

Logback日志

Springboot内部使用Logback作为日志实现的框架。

配置logback日志

删除application.yml中的日志配置

安装idea彩色日志插件:grep console(高版本idea会自带)

resource中创建logback-spring.xml(这是默认日志文件的名字)

<?xml version="1.0" encoding="UTF-8"?>
<configuration  scan="true" scanPeriod="10 seconds">

    <contextName>logback</contextName>
    <property name="log.path" value="D:/project/edu/project" />

    <!--控制台日志格式:彩色日志-->
    <!-- magenta:洋红 -->
    <!-- boldMagenta:粗红-->
    <!-- cyan:青色 -->
    <!-- white:白色 -->
    <!-- magenta:洋红 -->
    <property name="CONSOLE_LOG_PATTERN"
              value="%yellow(%date{yyyy-MM-dd HH:mm:ss}) |%highlight(%-5level) |%blue(%thread) |%blue(%file:%line) |%green(%logger) |%cyan(%msg%n)"/>

    <!--文件日志格式-->
    <property name="FILE_LOG_PATTERN"
              value="%date{yyyy-MM-dd HH:mm:ss} |%-5level |%thread |%file:%line |%logger |%msg%n" />

    <!--编码-->
    <property name="ENCODING"
              value="UTF-8" />

    <!--输出到控制台-->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <!--日志级别-->
            <level>DEBUG</level>
        </filter>
        <encoder>
            <!--日志格式-->
            <Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
            <!--日志字符集-->
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>

    <!--输出到文件-->
    <appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!--日志过滤器:此日志文件只记录INFO级别的-->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>INFO</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <!-- 正在记录的日志文件的路径及文件名 -->
        <file>${log.path}/log_info.log</file>
        <encoder>
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 每天日志归档路径以及格式 -->
            <fileNamePattern>${log.path}/info/log-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文件保留天数-->
            <maxHistory>15</maxHistory>
        </rollingPolicy>
    </appender>

    <appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 日志过滤器:此日志文件只记录WARN级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>WARN</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <!-- 正在记录的日志文件的路径及文件名 -->
        <file>${log.path}/log_warn.log</file>
        <encoder>
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset> <!-- 此处设置字符集 -->
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${log.path}/warn/log-warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文件保留天数-->
            <maxHistory>15</maxHistory>
        </rollingPolicy>
    </appender>

    <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 日志过滤器:此日志文件只记录ERROR级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <!-- 正在记录的日志文件的路径及文件名 -->
        <file>${log.path}/log_error.log</file>
        <encoder>
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset> <!-- 此处设置字符集 -->
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${log.path}/error/log-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文件保留天数-->
            <maxHistory>15</maxHistory>
        </rollingPolicy>
    </appender>

    <!--开发环境-->
    <springProfile name="dev">
        <!--可以灵活设置此处,从而控制日志的输出-->
        <root level="INFO">
            <appender-ref ref="CONSOLE" />
            <appender-ref ref="INFO_FILE" />
            <appender-ref ref="WARN_FILE" />
            <appender-ref ref="ERROR_FILE" />
        </root>
    </springProfile>

    <!--生产环境-->
    <springProfile name="pro">
        <root level="ERROR">
            <appender-ref ref="ERROR_FILE" />
        </root>
    </springProfile>

</configuration>

控制日志级别

通过在开发环境设置以下<root>节点的level属性的值,调节日志的级别。

<!--开发环境-->
<springProfile name="dev">
    <!--可以灵活设置此处,从而控制日志的输出-->
    <root level="INFO">
        <appender-ref ref="CONSOLE" />
        <appender-ref ref="INFO_FILE" />
        <appender-ref ref="WARN_FILE" />
        <appender-ref ref="ERROR_FILE" />
    </root>
</springProfile>

输出日志,需要在类上添加@Slf4j注解

@Slf4j
public class MyController {}

打印日志

public R listAll(){
    log.info("info级别....................");
	log.warn("warn级别....................");
	}

错误日志处理

  1. 日志记录器记录错误日志

    在GlobalExceptionHandler类上加注解@Slf4j,将异常输出语句改为。

    //e.printStackTrace();
    log.error(e.getMessage());
    
  2. 为了保证日志的对战信息能够被输出,修改异常输出语句。

    引入工具类

    import org.apache.commons.lang3.exception.ExceptionUtils;
    

    修改异常输出语句

    //e.printStackTrace();
    //log.error(e.getMessage());
    log.error(ExceptionUtils.getStackTrace(e));