日志等级一般分为5个等级(依次递增)
debug
开发时需要关注的一些信息info
程序正常运转的一些关键点的信息warn
一些异常情况, 不影响程序的逻辑, 但需要提醒开发人员error
一些错误提示, 需要中断操作的错误fatal
严重错误, 基本上服务就挂掉。 logback中的
ch.qos.logback.classic.encoder.PatternLayoutEncoder 是唯一有用的且默认的encoder。PatternLayoutEncoder 的PatternLayout对象定义了一些特殊字符串。在
defaultConverterMap.putAll(Parser.DEFAULT_COMPOSITE_CONVERTER_MAP);
defaultConverterMap.put("d", DateConverter.class.getName());
defaultConverterMap.put("date", DateConverter.class.getName());
defaultConverterMap.put("r", RelativeTimeConverter.class.getName());
defaultConverterMap.put("relative", RelativeTimeConverter.class.getName());
defaultConverterMap.put("level", LevelConverter.class.getName());
defaultConverterMap.put("le", LevelConverter.class.getName());
defaultConverterMap.put("p", LevelConverter.class.getName());
defaultConverterMap.put("t", ThreadConverter.class.getName());
defaultConverterMap.put("thread", ThreadConverter.class.getName());
defaultConverterMap.put("lo", LoggerConverter.class.getName());
defaultConverterMap.put("logger", LoggerConverter.class.getName());
defaultConverterMap.put("c", LoggerConverter.class.getName());
defaultConverterMap.put("m", MessageConverter.class.getName());
defaultConverterMap.put("msg", MessageConverter.class.getName());
defaultConverterMap.put("message", MessageConverter.class.getName());
defaultConverterMap.put("C", ClassOfCallerConverter.class.getName());
defaultConverterMap.put("class", ClassOfCallerConverter.class.getName());
defaultConverterMap.put("M", MethodOfCallerConverter.class.getName());
defaultConverterMap.put("method", MethodOfCallerConverter.class.getName());
defaultConverterMap.put("L", LineOfCallerConverter.class.getName());
defaultConverterMap.put("line", LineOfCallerConverter.class.getName());
defaultConverterMap.put("F", FileOfCallerConverter.class.getName());
defaultConverterMap.put("file", FileOfCallerConverter.class.getName());
defaultConverterMap.put("X", MDCConverter.class.getName());
defaultConverterMap.put("mdc", MDCConverter.class.getName());
defaultConverterMap.put("ex", ThrowableProxyConverter.class.getName());
defaultConverterMap.put("exception", ThrowableProxyConverter.class.getName());
defaultConverterMap.put("rEx", RootCauseFirstThrowableProxyConverter.class.getName());
defaultConverterMap.put("rootException", RootCauseFirstThrowableProxyConverter.class.getName());
defaultConverterMap.put("throwable", ThrowableProxyConverter.class.getName());
defaultConverterMap.put("xEx", ExtendedThrowableProxyConverter.class.getName());
defaultConverterMap.put("xException", ExtendedThrowableProxyConverter.class.getName());
defaultConverterMap.put("xThrowable", ExtendedThrowableProxyConverter.class.getName());
defaultConverterMap.put("nopex", NopThrowableInformationConverter.class.getName());
defaultConverterMap.put("nopexception", NopThrowableInformationConverter.class.getName());
defaultConverterMap.put("cn", ContextNameConverter.class.getName());
defaultConverterMap.put("contextName", ContextNameConverter.class.getName());
defaultConverterMap.put("caller", CallerDataConverter.class.getName());
defaultConverterMap.put("marker", MarkerConverter.class.getName());
defaultConverterMap.put("property", PropertyConverter.class.getName());
defaultConverterMap.put("n", LineSeparatorConverter.class.getName());
defaultConverterMap.put("black", BlackCompositeConverter.class.getName());
defaultConverterMap.put("red", RedCompositeConverter.class.getName());
defaultConverterMap.put("green", GreenCompositeConverter.class.getName());
defaultConverterMap.put("yellow", YellowCompositeConverter.class.getName());
defaultConverterMap.put("blue", BlueCompositeConverter.class.getName());
defaultConverterMap.put("magenta", MagentaCompositeConverter.class.getName());
defaultConverterMap.put("cyan", CyanCompositeConverter.class.getName());
defaultConverterMap.put("white", WhiteCompositeConverter.class.getName());
defaultConverterMap.put("gray", GrayCompositeConverter.class.getName());
defaultConverterMap.put("boldRed", BoldRedCompositeConverter.class.getName());
defaultConverterMap.put("boldGreen", BoldGreenCompositeConverter.class.getName());
defaultConverterMap.put("boldYellow", BoldYellowCompositeConverter.class.getName());
defaultConverterMap.put("boldBlue", BoldBlueCompositeConverter.class.getName());
defaultConverterMap.put("boldMagenta", BoldMagentaCompositeConverter.class.getName());
defaultConverterMap.put("boldCyan", BoldCyanCompositeConverter.class.getName());
defaultConverterMap.put("boldWhite", BoldWhiteCompositeConverter.class.getName());
defaultConverterMap.put("highlight", HighlightingCompositeConverter.class.getName());
defaultConverterMap.put("lsn", LocalSequenceNumberConverter.class.getName());
例如:
%d
: 表示日期。%d{yyyy-MM-dd'T'HH:mm:ss.SSSXXX} 指定日期的格式
%thread
: 表示线程名
%-5level
: 级别从左显示5个字符宽度
%logger:表示打印出日志所在类的路径,%logger{number},number是数字,是显示类路径的长度控制
%line:显示哪一行打印了日志。
%msg
: 日志消息
%n
: 是换行符
1. 通过日志中是否包含 "过滤日志" 来决定是否要在控制台打印日志。
return message.contains("过滤日志");
ACCEPT
DENY
%d{yyyy-MM-dd'T'HH:mm:ss.SSSXXX} [%thread] %-5level %logger{50}:%line - %msg %n
java测试代码:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class LoggerTest {
public static void main(String [] args){
Thread thread = new Thread(){
@Override
public void run() {
Logger logger = LoggerFactory.getLogger(LoggerTest.class);
while (true){
logger.error("-----logger-----LoggerTest [过滤日志] [error]-----------");
logger.debug("-----logger-----LoggerTest [过滤日志] [debug]-----------");
logger.info("-----logger-----LoggerTest [过滤日志] [info]-----------");
logger.error("----logger------LoggerTest [不过滤-日志] [error]-----------");
logger.debug("-----logger-----LoggerTest [不过滤-日志] [debug]-----------");
logger.info("-----logger-----LoggerTest [不过滤-日志] [info]-----------");
try {
Thread.currentThread().sleep(1000 * 3);
} catch (InterruptedException e) {
logger.error("----------LoggerTest[run error]-----------");
}
}
}
};
thread.start();
}
}
结果:
2020-09-24T16:37:33.838+08:00 [Thread-0] ERROR z.t.s.usultestdemo.demo.demo_15_logger.LoggerTest:265 - -----logger-----LoggerTest [过滤日志] [error]-----------
2020-09-24T16:37:33.839+08:00 [Thread-0] INFO z.t.s.usultestdemo.demo.demo_15_logger.LoggerTest:169 - -----logger-----LoggerTest [过滤日志] [info]-----------
2020-09-24T16:37:36.839+08:00 [Thread-0] ERROR z.t.s.usultestdemo.demo.demo_15_logger.LoggerTest:265 - -----logger-----LoggerTest [过滤日志] [error]-----------
2020-09-24T16:37:36.839+08:00 [Thread-0] INFO z.t.s.usultestdemo.demo.demo_15_logger.LoggerTest:169 - -----logger-----LoggerTest [过滤日志] [info]-----------
2020-09-24T16:37:39.841+08:00 [Thread-0] ERROR z.t.s.usultestdemo.demo.demo_15_logger.LoggerTest:265 - -----logger-----LoggerTest [过滤日志] [error]-----------
2. 输出日志级别大于info的日志到指定的日志文件
INFO
${LOG_HOME}/info.log
true
%d{yyyy-MM-dd'T'HH:mm:ss.SSSXXX} [%thread] %-5level %logger{30}: %line - %msg %n
java测试代码:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class LoggerTest {
public static void main(String [] args){
Thread thread1 = new Thread(){
@Override
public void run() {
Logger logger1 = LoggerFactory.getLogger("FileAppenderLogger");
while (true){
logger1.error("-----logger1-----LoggerTest [error]-----------");
logger1.debug("-----logger1-----LoggerTest [debug]-----------");
logger1.info("-----logger1-----LoggerTest [info]-----------");
try {
Thread.currentThread().sleep(1000 * 3);
} catch (InterruptedException e) {
logger1.error("----------LoggerTest[run error]-----------");
}
}
}
};
thread1.start();
}
}
测试结果:
3. 使用 RollingFileAppender:滚动记录文件, 先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件。
${LOG_HOME}/rollingFileAppender.%d{yyyy-MM-dd}.log 2
${LOG_HOME}/rollingFileAppender.%d{yyyy-MM-dd'T'HH}.log 2
${LOG_HOME}/rollingFileAppender.%d{yyyy-MM-dd'T'HH-mm}.log.zip 2
${LOG_HOME}/rollingFileAppender.log
true
INFO
ACCEPT
DENY
${LOG_HOME}/rollingFileAppender.%d{yyyy-MM-dd'T'HH-mm}.log
2
%d{yyyy-MM-dd'T'HH:mm:ss.SSSXXX} [%thread] %-5level %logger{30}: %line - %msg %n
测试代码:
public static void main(String [] args){
Thread thread1 = new Thread(){
@Override
public void run() {
Logger logger1 = LoggerFactory.getLogger("RollingFileAppenderLogger");
while (true){
logger1.error("-----RollingFileAppenderLogger-----LoggerTest [error]-----------");
logger1.debug("-----RollingFileAppenderLogger-----LoggerTest [debug]-----------");
logger1.info("-----RollingFileAppenderLogger-----LoggerTest [info]-----------");
try {
Thread.currentThread().sleep(1000 * 3);
} catch (InterruptedException e) {
logger1.error("----------LoggerTest[run error]-----------");
}
}
}
};
thread1.start();
}
SizeAndTimeBasedRollingPolicy :它根据时间来制定滚动策略,也限制每个文件的大小,既负责滚动也负责出发滚动。 中的日期格式和配合可以限制是每天生成一个文件还是每小时(每分钟)生成一个文件。需要注意的是:日志文件命名中 %i和%d命令都是必需的。每当当前日志文件在当前时间段结束前达到maxFileSize时,它将以递增的索引进行归档,从0开始不能包含不支持的特殊字符例如冒号“:”。文件名称中可以以. ".zip" 结尾。表示要进行压缩。
例子:每个日志文件最多20kb。对多保留两分钟的日志。
${LOG_HOME}/rollingFileAppender.log
true
INFO
${LOG_HOME}/rollingFileAppender.%d{yyyy-MM-dd'T'HH-mm}.log%i.zip
20KB
2
%d{yyyy-MM-dd'T'HH:mm:ss.SSSXXX} [%thread] %-5level %logger{30}: %line - %msg %n
测试代码:
public static void main(String [] args){
Thread thread1 = new Thread(){
@Override
public void run() {
Logger logger1 = LoggerFactory.getLogger("RollingFileAppenderLogger");
while (true){
logger1.error("-----RollingFileAppenderLogger-----LoggerTest [error]-----------");
logger1.debug("-----RollingFileAppenderLogger-----LoggerTest [debug]-----------");
logger1.info("-----RollingFileAppenderLogger-----LoggerTest [info]-----------");
try {
Thread.currentThread().sleep(1000 * 3);
} catch (InterruptedException e) {
logger1.error("----------LoggerTest[run error]-----------");
}
}
}
};
thread1.start();
}
测试结果:
4. ch.qos.logback.core.rolling.FixedWindowRollingPolicy
FixedWindowRollingPolicy 限制文件个数, 达到文件个数后删除旧的。配合回滚触发配置 ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy 可以达到限制日志文件大小和日志文件数量的目的。需要注意的是FixedWindowRollingPolicy的子节点
例如:当日志文件达到20kb是旧触发回滚。同时最多保留三个日志压缩文件。达到限制时删除旧的日志文件。
${LOG_HOME}/rollingFileAppender.log
true
INFO
${LOG_HOME}/rollingFileAppender.log%i.zip
3
1
20kb
%d{yyyy-MM-dd'T'HH:mm:ss.SSSXXX} [%thread] %-5level %logger{30}: %line - %msg %n