spring-boot与日志
使用slf4j
如何让系统中所有的日志都统一到slf4j
- 将系统中其他日志框架先排除出去。
- 用中间包来替换原有的日志框架。
- 我们导入slf4j其他的实现。
spring-boot的日志依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring‐boot‐starter‐logging</artifactId>
</dependency>
总结:
- spring-boot底层选用的是slf4j+logback进行日志记录。
- spring-boot把其他的日志都替换成了slf4j。
- 如果我们要引入其他框架,需要把默认的日志依赖移除掉。
spring-boot的日志使用
导入slf4j的jar和logback的实现jar
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@RunWith(SpringRunner.class)
@SpringBootTest
public class LoggerApplicationTests {
@Test
public void contextLoads() {
Logger logger = LoggerFactory.getLogger(LoggerApplicationTests.class);
logger.trace("trace");
logger.debug("debug");
logger.info("info");
logger.warn("warn");
logger.error("error");
}
}
日志级别
spring-boot默认日志级别是info
1. trace
2. debug
3. info
4. warn
5. error
日志默认配置修改
日志输出格式:
%d:表示日期时间,
%thread:表示线程名,
%‐5level:级别从左显示5个字符宽度
%logger{50}:表示logger名字最长50个字符,否则按照句点分割。
%msg:日志消息,
%n:是换行符
例子:
%d{yyyy‐MM‐dd HH:mm:ss} [%thread] %-5level %logger- %msg%n
控制台:
//修改默认日志级别,level后面跟着包名
logging.level.com.bafan.springboot.logger=trace
//修改控制台
logging.pattern.console=%d{yyyy/MM/dd-HH:mm:ss} [%thread] %-5level %logger- %msg%n
指定文件输出:
在实际的项目开发中,我们习惯将日志输出到服务器的某个文件下
- 需要将日志的配置文件放在类路径下(spring-boot就不使用他默认的配置了)。
- logback.xml:直接被日志框架识别。
- logback-spring.xml:日志框架不直接加载日志的配置项,由spring-boot解析日志配置,可以使用spring-boot的高级profile功能。(推荐)。(<springProfile name="dev">可以根据环境来决定功能)
spring-boot识别logback.xml文件
1--LoggingApplicationListener的initialize方法
protected void initialize(ConfigurableEnvironment environment, ClassLoader classLoader) {
(new LoggingSystemProperties(environment)).apply();
LogFile logFile = LogFile.get(environment);
if (logFile != null) {
logFile.applyToSystemProperties();
}
this.initializeEarlyLoggingLevel(environment);
//进入
this.initializeSystem(environment, this.loggingSystem, logFile);
this.initializeFinalLoggingLevels(environment, this.loggingSystem);
this.registerShutdownHookIfNecessary(environment, this.loggingSystem);
}
2--LoggingApplicationListener的initializeSystem方法
private void initializeSystem(ConfigurableEnvironment environment, LoggingSystem system, LogFile logFile) {
LoggingInitializationContext initializationContext = new LoggingInitializationContext(environment);
String logConfig = environment.getProperty("logging.config");
if (this.ignoreLogConfig(logConfig)) {
//进入
system.initialize(initializationContext, (String)null, logFile);
} else {
try {
ResourceUtils.getURL(logConfig).openStream().close();
system.initialize(initializationContext, logConfig, logFile);
} catch (Exception var7) {
System.err.println("Logging system failed to initialize using configuration from '" + logConfig + "'");
var7.printStackTrace(System.err);
throw new IllegalStateException(var7);
}
}
}
3--LogbackLoggingSystem的initialize方法
public void initialize(LoggingInitializationContext initializationContext, String configLocation, LogFile logFile) {
LoggerContext loggerContext = this.getLoggerContext();
if (!this.isAlreadyInitialized(loggerContext)) {
//调用父类的初始化方法
super.initialize(initializationContext, configLocation, logFile);
loggerContext.getTurboFilterList().remove(FILTER);
this.markAsInitialized(loggerContext);
if (StringUtils.hasText(System.getProperty("logback.configurationFile"))) {
this.getLogger(LogbackLoggingSystem.class.getName()).warn("Ignoring 'logback.configurationFile' system property. Please use 'logging.config' instead.");
}
}
}
4--AbstractLoggingSystem的initialize方法
public void initialize(LoggingInitializationContext initializationContext, String configLocation, LogFile logFile) {
if (StringUtils.hasLength(configLocation)) {
this.initializeWithSpecificConfig(initializationContext, configLocation, logFile);
} else {
//进入
this.initializeWithConventions(initializationContext, logFile);
}
}
5--AbstractLoggingSystem的initializeWithConventions方法
private void initializeWithConventions(LoggingInitializationContext initializationContext, LogFile logFile) {
//查找自己的配置(logback.xml)
String config = this.getSelfInitializationConfig();
if (config != null && logFile == null) {
this.reinitialize(initializationContext);
} else { //如果没有找到,就去找spring的文件
if (config == null) {
//查找spring的配置(logback-spring.xml)
config = this.getSpringInitializationConfig();
}
if (config != null) {
this.loadConfiguration(initializationContext, config, logFile);
} else { //如果都没有找到,只使用properties默认的配置
this.loadDefaults(initializationContext, logFile);
}
}
}
6--AbstractLoggingSystem的getSelfInitializationConfig方法,执行结束后到7
protected String getSelfInitializationConfig() {
//获取spring-boot标准的配置
return this.findConfig(this.getStandardConfigLocations());
}
protected String[] getStandardConfigLocations() {
return new String[]{"logback-test.groovy", "logback-test.xml", "logback.groovy", "logback.xml"};
}
7--AbstractLoggingSystem的findConfig方法,执行结束后到5
private String findConfig(String[] locations) {
String[] var2 = locations;
int var3 = locations.length;
//如果能够找到配置文件的位置,则返回配置文件位置,否则返回null
for(int var4 = 0; var4 < var3; ++var4) {
String location = var2[var4];
ClassPathResource resource = new ClassPathResource(location, this.classLoader);
if (resource.exists()) {
return "classpath:" + location;
}
}
return null;
}
8--AbstractLoggingSystem的getSpringConfigLocations方法,执行结束后到7
protected String[] getSpringConfigLocations() {
String[] locations = this.getStandardConfigLocations();
for(int i = 0; i < locations.length; ++i) {
//加上-spring后缀再在跟路径下查找
String extension = StringUtils.getFilenameExtension(locations[i]);
locations[i] = locations[i].substring(0, locations[i].length() - extension.length() - 1) + "-spring." + extension;
}
return locations;
}
logback常用配置
1--根节点configuration
- 通常不加任何属性。
2--configuration的子节点
2.1 property
//用来定义变量
<property name="FILE_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level [%thread] %c{35} %M %L - %msg%n"/>
...
<encoder>
<pattern>${FILE_PATTERN}</pattern>
</encoder>
2.2 logger
- name:用来指定受此logger约束的某一个包或者具体的某一个类。
- level:用来打印日志级别。(root<append<logger)
- additivity:是否向上级传递打印信息,默认是true,项目中都用false
<logger name="com.mogujie.raptor" level="@root.log.level@" additivity="false">
<appender-ref ref="RAPTOR_FILE"/>
</logger>
2.3 root
- 也属于logger标签,只有一个属性,定义日志级别,默认是全路径。
<root level="INFO">
<appender-ref ref="STDOUT" />
<appender-ref ref="FILE" />
</root>
3--appender和它的子节点
- appender是configuration的子节点。
- name:指定appender名称,class指定appender的全限名。
3.1 ConsoleAppender
- 控制台日志
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${CONSOLE_LOG_PATTERN}</pattern>
</encoder>
</appender>
3.2 RollingFileAppender
滚动日志文件:先将日志记录到指定文件,当符合某个条件的时候,将日志记录到 其它文件。FileAppender没有滚动功能,要么追加要么覆盖,项目中几乎不用。
- file:写入文件的名字。
- append:默认是true、追加;false是覆盖。
- encoder:对记录事件进行格式化。一是把日志信息转成字节数组,二是把字节数组写入输出流。
- rollingPolicy:发生滚动时,涉及文件移动和重命名。
rollingPolicy:
- TimeBasedRollingPolicy:最常用的滚动方式,根据时间制定滚动策略,既负责滚动,也负责触发滚动。
- fileNamePattern:包含文件名及“%d”转换符。
- maxHistory:保留最大时间,根据fileNamePattern的时间决定单位是年月日。
- timeBasedFileNamingAndTriggeringPolicy:当文件大小超过多少时触发滚动,里面配置maxFileSize,例如500MB。
<appender name="errorLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
<encoder>
<pattern>${FILE_PATTERN}</pattern>
</encoder>
<Encoding>UTF-8</Encoding>
<file>${CATALINA_APPLOG}/finance_mall_error.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${CATALINA_APPLOG}/finance_mall_error_%d{yyyy_MM_dd}-%i.log</fileNamePattern>
<MaxHistory>10</MaxHistory>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>500MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
</appender>
4. filter
属于appender下的标签,一般用于日志级别过滤
- level:日志级别
- onMatch:如果匹配上,接受(ACCEPT)
- onMismatch:如果没有匹配上,拒绝(DENY)
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
网友评论