统一异常处理与统一日志处理

一、什么是统一异常处理

1、制造异常

除以0

int a=10/0;

2、什么是统一异常处理

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


二、统一异常处理

1、创建统一异常处理器

创建统一异常处理类GlobalExceptionHandler.java:

/**

* 统一异常处理类

*/

@ControllerAdvice

public class GlobalExceptionHandler{

    @ExceptionHandler(Exception.class)

    @ResponseBody

    public R error(Exception e){

        e.printStackTrace();

        return R.error();

    }

}

2、测试

返回统一错误结果

三、处理特定异常

1、添加异常处理方法

GlobalExceptionHandler.java中添加

@ExceptionHandler(ArithmeticException.class)

@ResponseBody

public R error(ArithmeticException e){

e.printStackTrace();

return R.error().message("执行了自定义异常");

}

2、测试

四、自定义异常

1、创建自定义异常类

@Data

@AllArgsConstructor

@NoArgsConstructor

public class BruceException extends RuntimeException{

@ApiModelProperty(value="状态码")

private Integer code;

private String msg;

}

2、业务中需要的位置抛出BruceException

try{

int a=10/0;

}catch(Exception e) {

throw new BruceException(20001,"出现自定义异常");

}

3、添加异常处理方法

GlobalExceptionHandler.java中添加

@ExceptionHandler(BruceException.class)

@ResponseBody

public R error(BruceException e){

e.printStackTrace();

return R.error().message(e.getMsg()).code(e.getCode());

}

4、测试

需要注意的是,在使用@ControllerAdvice注解时,需要将其扫描到Spring容器中,可以使用@ComponentScan或者在配置类中添加@Bean注解来实现。




统一日志处理

一、日志

1、配置日志级别

日志记录器(Logger)的行为是分等级的。如下表所示:

分为:OFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL

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

# 设置日志级别

logging.level.root=WARN

这种方式只能将日志打印在控制台上


二、Logback日志

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

Logback和log4j非常相似,如果你对log4j很熟悉,那对logback很快就会得心应手。

logback相对于log4j的一些优点:https://blog.csdn.net/caisini_vc/article/details/48551287

1、配置logback日志

删除application.properties中的日志配置

安装idea彩色日志插件:grep-console

resources 中创建 logback-spring.xml 

<?xml version="1.0" encoding="UTF-8"?>

<configuration scan="true" scanPeriod="10 seconds">

    <!-- 日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL,如果设置为WARN,则低于WARN的信息都不会输出 -->

    <!-- scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true -->

    <!-- scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。 -->

    <!-- debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 -->

    <contextName>logback</contextName>

    <!-- name的值是变量的名称,value的值时变量定义的值。通过定义的值会被插入到logger上下文中。定义变量后,可以使“${}”来使用变量。 -->

    <property name="log.path" value="D:/bruce_log/edu"/>

    <!-- 彩色日志 -->

    <!-- 配置格式变量:CONSOLE_LOG_PATTERN 彩色日志格式 -->

    <!-- 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)"/>

    <!--输出到控制台-->

    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">

        <!--此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息-->

        <!-- 例如:如果此处配置了INFO级别,则后面其他位置即使配置了DEBUG级别的日志,也不会被输出 -->

        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">

            <level>INFO</level>

        </filter>

        <encoder>

            <Pattern>${CONSOLE_LOG_PATTERN}</Pattern>

            <!-- 设置字符集 -->

            <charset>UTF-8</charset>

        </encoder>

    </appender>

    <!--输出到文件-->

    <!-- 时间滚动输出 level为 INFO 日志 -->

    <appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">

        <!-- 正在记录的日志文件的路径及文件名 -->

        <file>${log.path}/log_info.log</file>

        <!--日志文件输出格式-->

        <encoder>

            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>

            <charset>UTF-8</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>

        <!-- 此日志文件只记录info级别的 -->

        <filter class="ch.qos.logback.classic.filter.LevelFilter">

            <level>INFO</level>

            <onMatch>ACCEPT</onMatch>

            <onMismatch>DENY</onMismatch>

        </filter>

    </appender>

    <!-- 时间滚动输出 level为 WARN 日志 -->

    <appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">

        <!-- 正在记录的日志文件的路径及文件名 -->

        <file>${log.path}/log_warn.log</file>

        <!--日志文件输出格式-->

        <encoder>

            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>

            <charset>UTF-8</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>

        <!-- 此日志文件只记录warn级别的 -->

        <filter class="ch.qos.logback.classic.filter.LevelFilter">

            <level>warn</level>

            <onMatch>ACCEPT</onMatch>

            <onMismatch>DENY</onMismatch>

        </filter>

    </appender>

    <!-- 时间滚动输出 level为 ERROR 日志 -->

    <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">

        <!-- 正在记录的日志文件的路径及文件名 -->

        <file>${log.path}/log_error.log</file>

        <!--日志文件输出格式-->

        <encoder>

            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>

            <charset>UTF-8</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>

        <!-- 此日志文件只记录ERROR级别的 -->

        <filter class="ch.qos.logback.classic.filter.LevelFilter">

            <level>ERROR</level>

            <onMatch>ACCEPT</onMatch>

            <onMismatch>DENY</onMismatch>

        </filter>

    </appender>

    <!--

        <logger>用来设置某一个包或者具体的某一个类的日志打印级别、以及指定<appender>。

        <logger>仅有一个name属性,

        一个可选的level和一个可选的addtivity属性。

        name:用来指定受此logger约束的某一个包或者具体的某一个类。

        level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,

              如果未设置此属性,那么当前logger将会继承上级的级别。

    -->

    <!--

        使用mybatis的时候,sql语句是debug下才会打印,而这里我们只配置了info,所以想要查看sql语句的话,有以下两种操作:

        第一种把<root level="INFO">改成<root level="DEBUG">这样就会打印sql,不过这样日志那边会出现很多其他消息

        第二种就是单独给mapper下目录配置DEBUG模式,代码如下,这样配置sql语句会打印,其他还是正常DEBUG级别:

    -->

    <!--开发环境:打印控制台-->

    <springProfile name="dev">

        <!--可以输出项目中的debug日志,包括mybatis的sql日志-->

        <logger name="com.bruce" level="INFO"/>

        <!--

            root节点是必选节点,用来指定最基础的日志输出级别,只有一个level属性

            level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,默认是DEBUG

            可以包含零个或多个appender元素。

        -->

        <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="INFO">

            <appender-ref ref="CONSOLE"/>

            <appender-ref ref="DEBUG_FILE"/>

            <appender-ref ref="INFO_FILE"/>

            <appender-ref ref="ERROR_FILE"/>

            <appender-ref ref="WARN_FILE"/>

        </root>

    </springProfile>

</configuration>

2、将错误日志输出到文件

GlobalExceptionHandler.java 中

类上添加注解

@Slf4j

异常输出语句

log.error(e.getMessage());

3、将日志堆栈信息输出到文件

定义工具类

创建ExceptionUtil.java工具类

public class ExceptionUtil {

public static String getMessage(Exception e) {

StringWriter sw =null;

PrintWriter pw =null;

try {

sw =new StringWriter();

pw =new PrintWriter(sw);

// 将出错的栈信息输出到printWriter中

            e.printStackTrace(pw);

pw.flush();

sw.flush();

}finally {

if (sw !=null) {

try {

sw.close();

}catch (IOException e1) {

e1.printStackTrace();

}

}

if (pw !=null) {

pw.close();

}

}

return sw.toString();

}

}


调用

log.error(ExceptionUtil.getMessage(e));

BruceException中创建toString方法

@Override

public String toString() {

return "BruceException{"+

"message="+this.getMessage()+

", code="+code+

'}';

}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,752评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,100评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,244评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,099评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,210评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,307评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,346评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,133评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,546评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,849评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,019评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,702评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,331评论 3 319
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,030评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,260评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,871评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,898评论 2 351

推荐阅读更多精彩内容