最近在学习Spring Boot,发现Spring Boot自身集成logback日志记录,造成我希望使用log4j的时候出现问题,百度了一下发现logback更新更好用,所以这里记录一下配置流程。
Java框架是SSM,所以只捕获controller层异常,其他层不处理异常信息,将所有的异常都交到controller层。
以下为logback.xml配置文件内容:
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">
<!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径 -->
<property name="testName" value="E:/logs" />
<!-- 控制台输出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符 -->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} -
%msg%n</pattern>
</encoder>
</appender>
<!-- 按照每天生成日志文件,所有日志信息 -->
<appender name="FILE"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--日志文件输出的文件名 -->
<FileNamePattern>${testName}/all/PetAll-%d{yyyy-MM-dd}.%i.log
</FileNamePattern>
<!--日志文件保留天数 -->
<MaxHistory>30</MaxHistory>
<!-- 设置当前日志的文件的大小,决定日志翻滚 -->
<timeBasedFileNamingAndTriggeringPolicy
class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<!-- 除按日志记录之外,还配置了日志文件不能超过10M(默认),若超过10M,日志文件会以索引0开始, -->
<maxFileSize>20MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符 -->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} -
%msg%n</pattern>
</encoder>
<!--日志文件最大的大小 -->
<triggeringPolicy
class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<MaxFileSize>10MB</MaxFileSize>
</triggeringPolicy>
</appender>
<!-- 按照每天生成日志文件,info级别错误信息 -->
<appender name="FILE-INFO"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 这里添加一个过滤器 -->
<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>${testName}/info/PetInfo-%d{yyyy-MM-dd}.%i.log
</FileNamePattern>
<maxHistory>50</maxHistory>
<timeBasedFileNamingAndTriggeringPolicy
class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>30MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n
</pattern>
</encoder>
</appender>
<!-- 报错信息,error级别 -->
<appender name="FILE-ERROR"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 这里添加一个过滤器 -->
<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>${testName}/error/PetError-%d{yyyy-MM-dd}.%i.log
</FileNamePattern>
<maxHistory>10</maxHistory>
<timeBasedFileNamingAndTriggeringPolicy
class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>10MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n%n
</pattern>
</encoder>
</appender>
<!-- 日志输出级别 -->
<logger name="org.pet.king" additivity="false">
<appender-ref ref="FILE" />
<appender-ref ref="FILE-INFO" />
<appender-ref ref="FILE-ERROR" />
</logger>
<root level="DEBUG">
<appender-ref ref="STDOUT" />
</root>
</configuration>
此处将日志信息分类存放,学习的时候可以只考虑一个文件,具体的标签含义已经有注释,其中logger标签的name属性为项目包名,考虑到可能会有多个地方使用日志(全局异常、用户操作记录等)所以此处为上层目录。
下面为全局异常捕获的类(GlobalExceptionHandler):
package org.pet.king.exception;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Map;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import ch.qos.logback.classic.Logger;
/**
* 全局异常捕获,捕获所有的控制层提供的接口错误<br>
* 1、将异常写入日志文件 <br>
* 2、根据异常类型返回指定数据<br>
*/
@ControllerAdvice(basePackages = "org.pet.king.controller")
public class GlobalExceptionHandler {
/**
* 日志类
*/
private final static Logger logger = (Logger) LoggerFactory.getLogger(GlobalExceptionHandler.class);
/**
* 异常信息转化为String类型,等同于e.printStackTrace()输出参数
*
* @param t
* 异常
* @return 异常详细信息
* @author single-聪
* @date 2019年4月15日
* @version 1.0.0
*/
public static String getTrace(Throwable t) {
StringWriter stringWriter = new StringWriter();
PrintWriter writer = new PrintWriter(stringWriter);
t.printStackTrace(writer);
StringBuffer buffer = stringWriter.getBuffer();
return buffer.toString();
}
/**
* 全局异常捕获,暂时为区分异常类型,所有运行时异常统一在此方法中
*
* @param e
* 异常
* @return map集合,info为error
* @author single-聪
* @date 2019年4月15日
* @version 1.0.0
*/
@ResponseBody
@ExceptionHandler(RuntimeException.class)
public Map<String, Object> RuntimeException(Exception e) {
Map<String, Object> map = new HashMap<>();
System.out.println("全局捕获运行时异常,同时写入日志文件");
e.printStackTrace();
logger.error(getTrace(e));
map.put("info", "error");
return map;
}
}
为了方便,此处捕获所有的运行时异常,实际开发中需要考虑到不同的异常种类返回不同值,getTrace的目的是将异常信息转换成String类型,否则写到日志文件中的就只有异常类型那一行而无法知道具体是哪里报的错误。
logger.error("")
是将错误信息写入到error等级日志文件中,同时又info、debug、trace等方法,这样就可以将不同的信息打印到不同的文件中去。