欢迎阅读另一篇关于SpringBoot中日志的文章 SpringBoot动态修改日志级别
本文基于SpringBoot2.6讲解
本文内容:
初始化一个SpringBoot后启动项目,控制台会带有彩色日志样式.但是当我们配置了自己的logback-spring.xml日志文件时,样式可能就不存在了,console控制台变成了黑白屏。
其实彩色日志样式是SpringBoot自己做了特殊处理,实现了Logback的conversionRule
,源码参见:org.springframework.boot.logging.logback.DefaultLogbackConfiguration
我们可以直接在logback-spring.xml中使用SpringBoot实现的conversionRule,让console日志变成彩屏。
logback-spring.xml中如下几个参数
CONSOLE_LOG_PATTERN
FILE_LOG_PATTERN
LOG_DATEFORMAT_PATTERN
LOG_LEVEL_PATTERN
LOG_EXCEPTION_CONVERSION_WORD
LOG_PATH
CONSOLE_LOG_CHARSET
FILE_LOG_CHARSET
对应SpringBoot的几个配置
logging.pattern.console=
logging.pattern.file=
logging.pattern.level=
logging.pattern.dateformat=
logging.exception-conversion-word=
logging.file.path=logs
logging.charset.console=UTF-8
logging.charset.file=UTF-8
logback-spring.xml放到resources
目录即可被SpringBoot识别
<configuration debug="false">
<conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter"/>
<conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter"/>
<conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter"/>
<property name="LOG_HOME" value="${LOG_PATH:-logs}"/>
<property name="FILE_LOG_CHARSET" value="${FILE_LOG_CHARSET:-UTF-8}"/>
<property name="CONSOLE_LOG_CHARSET" value="${CONSOLE_LOG_CHARSET:-UTF-8}"/>
<property name="FILE_LOG_PATTERN" value="${FILE_LOG_PATTERN:-%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}} ${LOG_LEVEL_PATTERN:-%5p} ${PID:- } [%t] %-40.40logger{39} %-4line : %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
<appender name="Console" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>pattern>
<charset>${CONSOLE_LOG_CHARSET}charset>
encoder>
appender>
<appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/debug.logfile>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<FileNamePattern>${LOG_HOME}/debug.%d{yyyy-MM-dd}.%i.logFileNamePattern>
<MaxHistory>5MaxHistory>
<maxFileSize>100MBmaxFileSize>
rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${FILE_LOG_PATTERN}pattern>
<charset>${FILE_LOG_CHARSET}charset>
encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>DEBUGlevel>
<onMatch>ACCEPTonMatch>
<onMismatch>DENYonMismatch>
filter>
appender>
<appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/info.logfile>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<FileNamePattern>${LOG_HOME}/info.%d{yyyy-MM-dd}.%i.logFileNamePattern>
<MaxHistory>5MaxHistory>
<maxFileSize>100MBmaxFileSize>
rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${FILE_LOG_PATTERN}pattern>
<charset>${FILE_LOG_CHARSET}charset>
encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFOlevel>
<onMatch>ACCEPTonMatch>
<onMismatch>DENYonMismatch>
filter>
appender>
<appender name="WARN_ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/warn-error.logfile>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<FileNamePattern>${LOG_HOME}/warn-error.%d{yyyy-MM-dd}.%i.logFileNamePattern>
<MaxHistory>5MaxHistory>
<maxFileSize>100MBmaxFileSize>
rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${FILE_LOG_PATTERN}pattern>
<charset>${FILE_LOG_CHARSET}charset>
encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>WARNlevel>
<onMatch>ACCEPTonMatch>
<onMismatch>NEUTRALonMismatch>
filter>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERRORlevel>
<onMatch>ACCEPTonMatch>
<onMismatch>DENYonMismatch>
filter>
appender>
<root level="INFO">
<appender-ref ref="Console"/>
<appender-ref ref="INFO_FILE"/>
<appender-ref ref="WARN_ERROR_FILE"/>
root>
<appender name="environmentAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/environment.logfile>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<FileNamePattern>${LOG_HOME}/environment.%d{yyyy-MM-dd}.%i.logFileNamePattern>
<MaxHistory>5MaxHistory>
<maxFileSize>100MBmaxFileSize>
rollingPolicy>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFOlevel>
<onMatch>ACCEPTonMatch>
<onMismatch>ACCEPTonMismatch>
filter>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %5p ${PID:- } [%t] %-10.40logger{39} : %m%n%wExpattern>
<charset>${FILE_LOG_CHARSET}charset>
encoder>
appender>
<logger name="environment" level="INFO" additivity="false">
<appender-ref ref="environmentAppender"/>
logger>
<appender name="customAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/custom.logfile>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<FileNamePattern>${LOG_HOME}/custom.%d{yyyy-MM-dd}.%i.logFileNamePattern>
<MaxHistory>5MaxHistory>
<maxFileSize>100MBmaxFileSize>
rollingPolicy>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFOlevel>
<onMatch>ACCEPTonMatch>
<onMismatch>ACCEPTonMismatch>
filter>
<encoder>
<pattern>${FILE_LOG_PATTERN}pattern>
<charset>${FILE_LOG_CHARSET}charset>
encoder>
appender>
<logger name="com.bruce.kafka">
<appender-ref ref="customAppender"/>
logger>
configuration>
environment 日志配置的使用
通过LoggerFactory获取名称为environment的Logger对象即可
@SpringBootApplication
public class KafkaProducerApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(KafkaProducerApplication.class, args);
Logger envLogger = LoggerFactory.getLogger("environment");
ConfigurableEnvironment environment = context.getEnvironment();
MutablePropertySources propertySources = environment.getPropertySources();
for (PropertySource<?> propertySource : propertySources) {
envLogger.info(propertySource.getName());
}
for (PropertySource<?> propertySource : propertySources) {
if (propertySource instanceof EnumerablePropertySource) {
EnumerablePropertySource<?> enumerablePropertySource = (EnumerablePropertySource<?>) propertySource;
String[] propertyNames = enumerablePropertySource.getPropertyNames();
for (String propertyName : propertyNames) {
envLogger.info("[{}] {} = {}", propertySource.getName(), propertyName, enumerablePropertySource.getProperty(propertyName));
}
}
}
}
}
如果想让environment中的日志在控制台展示,但不输入到info.log, warn-error.log中,可以将additivity设置为true,并在INFO
, WARN-ERROR
appender中使用自定义的Filter,过滤掉LoggerName为environment的日志. 参见: ch.qos.logback.classic.filter.LevelFilter
/**
* Created by bruce on 2021/11/30 20:05
*/
public class LevelAndNameFilter extends AbstractMatcherFilter<ILoggingEvent> {
Level level;
@Override
public FilterReply decide(ILoggingEvent event) {
if (!isStarted()) {
return FilterReply.NEUTRAL;
}
if (event.getLoggerName().equals("environment")){
return onMismatch;
}
if (event.getLevel().equals(level)) {
return onMatch;
} else {
return onMismatch;
}
}
public void setLevel(Level level) {
this.level = level;
}
public void start() {
if (this.level != null) {
super.start();
}
}
}
按照SpringBoot环境配置日志
<springProfile name="default">
<root level="debug">
<appender-ref ref="Console"/>
<appender-ref ref="DEBUG_FILE"/>
<appender-ref ref="INFO_FILE"/>
<appender-ref ref="WARN_ERROR_FILE"/>
root>
springProfile>
<springProfile name="fat | uat">
<root level="info">
<appender-ref ref="DEBUG_FILE"/>
<appender-ref ref="INFO_FILE"/>
<appender-ref ref="WARN_ERROR_FILE"/>
root>
springProfile>
<springProfile name="pro">
<root level="warn">
<appender-ref ref="WARN_ERROR_FILE"/>
root>
springProfile>
当应用不以SpringBoot方式启动,仅仅作为一个普通main时,发现控制台彩色日志没有了,此时需要手动调用
AnsiOutput.setEnabled(AnsiOutput.Enabled.ALWAYS);
public static void main(String[] args) {
System.setProperty("java.awt.headless", "true");
AnsiOutput.setEnabled(AnsiOutput.Enabled.ALWAYS);
//SpringApplication.run(NettyHttp2Application.class, args);
Http2Server http2Server = new Http2Server();
http2Server.start(8443);
}
最少依赖为
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-bootartifactId>
<exclusions>
<exclusion>
<groupId>*groupId>
<artifactId>*artifactId>
exclusion>
exclusions>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-coreartifactId>
<exclusions>
<exclusion>
<groupId>*groupId>
<artifactId>*artifactId>
exclusion>
exclusions>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-loggingartifactId>
dependency>