实习周记(十一):异常和日志
异常
项目开发过程中,准确无误的异常信息可以便于开发人员定位错误内容,为前端提供报错信息提示,提高工作效率,关于Java的异常可以看这里
此处仅以开发中涉及的进行举例
自定义异常枚举类
@Getter
public enum WorkExceptionEnum implements IResultCode {
USER_IS_NULL(1001,"该用户不存在,请重新确认"),
;
private int code;
private String msg;
CircleExceptionEnum(int code, String msg) {
this.code = code;
this.msg = msg;
}
}
public interface IResultCode {
int getCode();
String getMsg();
default RuntimeException build() {
return new RuntimeException(getMsg());
}
default RuntimeException build(String msg) {
return new RuntimeException(msg);
}
}
自定义异常
@Data
public class WorkRuntimeException extends RuntimeException {
private Integer code;
public WorkRuntimeException(ResultCode resultCode) {
super(resultCode.getMsg());
this.code = resultCode.getCode();
}
public WorkRuntimeException(IResultCode resultCode) {
super(resultCode.getMsg());
this.code = resultCode.getCode();
}
public WorkRuntimeException(Integer code, String msg) {
super(msg);
this.code = code;
}
public WorkRuntimeException(String msg) {
super(msg);
}
public WorkRuntimeException(Throwable throwable) {
super(throwable);
}
public WorkRuntimeException(String msg, Throwable throwable) {
super(msg, throwable);
}
}
异常的使用
public Work test(WorkDTO dto) {
if (CollectionUtils.isEmpty(dto.getId())) {
throw new WorkRuntimeException(WorkExceptionEnum.USER_IS_NULL);
}
return new Work();
}
准确的异常描述可以帮助我们快速定位问题
日志
日志记录是应用程序运行中必不可少的一部分。具有良好格式和完备信息的日志记录可以在程序出现问题时帮助开发人员迅速地定位错误的根源
抽象层日志框架SLF4J
简单日志门面(Simple Logging Facade For Java) SLF4J主要是为了给Java日志访问提供一套标准、规范的API框架,其主要意义在于提供接口,具体的实现可以交由其他日志框架,但本身也有提供一定的日志功能
- 添加依赖
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.30</version>
</dependency>
- 测试日志输出
@Test
public void testQuick() {
// 打印日志信息
LOGGER.error("error");
LOGGER.warn("warn");
LOGGER.info("info"); // 默认级别
LOGGER.debug("debug");
LOGGER.trace("trace");
// 使用占位符输出日志信息
String name = "one fine";
Integer age = 18;
LOGGER.info("用户:{}, 年龄:{}", name, age);
// 将系统的日常信息输出
try {
int i = 1 / 0;
} catch (Exception e) {
// e.printStackTrace();
LOGGER.error("出现异常", e);
}
}
特点
- 使用SLF4J框架,可以在部署时迁移到所需的日志记录框架。
- SLF4J提供了对所有流行的日志框架的绑定,例如log4j,JUL,Simple logging和NOP。因此可以在部署时切换到任何这些流行的框架。
- 无论使用哪种绑定,SLF4J都支持参数化日志记录消息。由于SLF4J将应用程序和日志记录框架分离,因此可以轻松编写独立于日志记录框架的应用程序。而无需担心用于编写应用程序的日志记录框架。
- SLF4J提供了一个简单的Java工具,称为迁移器。使用此工具,可以迁移现有项目,这些项目使用日志框架(如Jakarta Commons Logging(JCL)或log4j或Java.util.logging(JUL))到SLF4J。
- spring boot自动导入日志框架,只需导入Lombok即可
Logback
项目使用的日志框架为logback,spring-boot-starter其中包含了spring-boot-starter-logging,该依赖内容就是 Spring Boot 默认的日志框架 logback
spring boot的默认配置
SpringBoot为Logback提供了默认的配置文件base.xml,base.xml文件里定义了默认的root输出级别为INFO
默认情况下,
- Spring Boot将日志输出到控制台,但不会写到日志文件。
- 我们可以通过application.properties或application.yml进行配置,但是只能配置简单的场景,保存路径、日志格式等,
- 复杂的场景(区分 info 和 error 的日志、每天产生一个日志文件等)需要自己定制
自定义logback的配置文件
这里提供一个项目使用的配置文件,详细的各节点配置请看这里
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="10 seconds" debug="false">
<!-- 将日志输出在当前项目的根目录下 -->
<property name="contextPath" value="logs"/>
<!-- 日志的上下文路径 -->
<property name="logPath" value="${contextPath}"/>
<!-- 配置日志的滚动时间 -->
<property name="maxHistory" value="30"/>
<property name="logPattern"
value="%d{HH:mm:ss.SSS} [%thread] [%X{traceId}] %-5level %logger{36}.%M - %msg%n"/>
<property name="consoleLogPattern"
value="%d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] [%X{traceId}] %highlight(%-5level) %cyan(%logger{36}) - %msg%n"/>
<!-- 打印日志到控制台 -->
<appender name="rootConsole" class="ch.qos.logback.core.ConsoleAppender">
<!-- encoder 在控制台打印日志的格式 -->
<encoder>
<pattern>${consoleLogPattern}</pattern>
</encoder>
<!-- <filter class="ch.qos.logback.classic.filter.ThresholdFilter">-->
<!-- <level>INFO</level>-->
<!-- <level>DEBUG</level>-->
<!-- </filter>-->
</appender>
<appender name="rootRollingInfo" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${logPath}/log/info.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${logPath}/log/info.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 设置日志的滚动时间 -->
<maxHistory>${maxHistory}</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${logPattern}</pattern>
<charset>UTF-8</charset>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<appender name="rootRollingDebug" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${logPath}/log/debug.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${logPath}/log/debug.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 设置日志的滚动时间 -->
<maxHistory>${maxHistory}</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${logPattern}</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="rootRollingError" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${logPath}/log/error.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${logPath}/log/error.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 设置日志的滚动时间 -->
<maxHistory>${maxHistory}</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${logPattern}</pattern>
<charset>UTF-8</charset>
</encoder>
<!-- error/root.log文件中的日志级别是 ERROR以上的级别 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<appender name="emailError" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${logPath}/email/info/info.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${logPath}/email/info/%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 设置日志的滚动时间 -->
<maxHistory>${maxHistory}</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<appender name="KDInfo" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${logPath}/log/kd-info.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${logPath}/log/kd-info.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 设置日志的滚动时间 -->
<maxHistory>${maxHistory}</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<appender name="KDError" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${logPath}/log/kd-error.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${logPath}/log/kd-error.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 设置日志的滚动时间 -->
<maxHistory>${maxHistory}</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<root level="INFO">
<appender-ref ref="rootRollingError"/>
<appender-ref ref="rootConsole"/>
<appender-ref ref="rootRollingInfo"/>
</root>
<logger name="com.miniw.community" level="DEBUG">
<appender-ref ref="rootRollingDebug"/>
</logger>
<logger name="emailError" level="INFO" additivity="false">
<appender-ref ref="emailError"/>
</logger>
</configuration>

浙公网安备 33010602011771号