log4j的延续
划分为3个模块:logback-core, logback-classic, logback-access
logback-core是其他两个模块的基础. logback-classic模块可以看作是log4j的升级版.提供了SLF4J API, 以便轻易在在其他日志框架间切换. logback-access整合了servlet容器,如tomcat和jetty,以提供HTTP-access日志
官网: https://logback.qos.ch/index.html
quick-start: https://wiki.base22.com/btg/how-to-setup-slf4j-and-logback-in-a-web-app-fast-35488048.html
一个看起来更舒服的网站: https://www.baeldung.com/logback
e.g.
属性:
scan: true/false; default:true 配置文件发生改变时重新加载
scanPeriod: 数字; 设置检测配置文件是否有修改的时间间隔, 默认单位为毫秒, scan=true时生效,默认间隔为1分钟.
debug: true/false; default:false 当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态.
根logger,是所有的上级。参见
level: 用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL和OFF,不能设置为INHERITED或者同义词NULL。 默认是DEBUG.
属性:
name: logger名称,可以获取logger的属性
addtivity: 是否向上级loger传递打印信息。默认是true。
level: 用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL和OFF,还有一个特俗值INHERITED或者同义词NULL,代表强制执行上级的级别。
如果未设置此属性,那么当前loger将会继承上级的级别。
appender-ref: 可以包含零个或多个
获取logger的常用方法:
static final Logger LOG = LoggerFactory.getLogger(XXX.class);
static final Logger LOG = LoggerFactory.getLogger("logger_name");
注:
通过logger名称获取logger,通常在logback.xml中已定义.
若使用未定义的logger_name,则将在logger"树形结构"中成一个新的logger.
这个logger本身不持有任何appender,将向上级传递打印信息.
若使用XXX.class,且类名未在xml中定义,则按照包分割符'.'和类分隔符'$'的路径生成一个树枝的logger,并返回叶子节点的logger
#ch.qos.logback.classic.LoggerContext
public final Logger getLogger(final Class clazz) {
return getLogger(clazz.getName());
}
public final Logger getLogger(final String name) {
if (name == null) {
throw new IllegalArgumentException("name argument cannot be null");
}
// if we are asking for the root logger, then let us return it without
// wasting time
if (Logger.ROOT_LOGGER_NAME.equalsIgnoreCase(name)) {
return root;
}
int i = 0;
Logger logger = root;
// check if the desired logger exists, if it does, return it
// without further ado.
Logger childLogger = (Logger) loggerCache.get(name);
// if we have the child, then let us return it without wasting time
if (childLogger != null) {
return childLogger;
}
// if the desired logger does not exist, them create all the loggers
// in between as well (if they don't already exist)
String childName;
while (true) {
int h = LoggerNameUtil.getSeparatorIndexOf(name, i);
if (h == -1) {
childName = name;
} else {
childName = name.substring(0, h);
}
// move i left of the last point
i = h + 1;
synchronized (logger) {
childLogger = logger.getChildByName(childName);
if (childLogger == null) {
childLogger = logger.createChildByName(childName);
loggerCache.put(childName, childLogger);
incSize();
}
}
logger = childLogger;
if (h == -1) {
return childLogger;
}
}
}
logback把日志时间写出到组件的任务成为appender。 所有的appender都必须实现appender接口。 appender中的泛型E,在logback-classic中为ILoggingEvent,在logback-access中为AccessEvent。
事件实际被写出时,格式化的步骤将交给encoder/Layout。(区别及对比见下)
抽象类AppenderBase中的doAppend方法被声明为synchronized,是同步,即,在多线程情况下,该方法是阻塞的。 抽象类UnsynchronizedAppenderBase中的doAppend方法则不是同步的,并采用将成员guard声明为ThreadLocal。即在多线程下,该方法是异步非阻塞的。
常用appender: ConsoleAppender FileAppender RollingFileAppender DailyRollingFileAppender
上述常用appender均继承自UnsynchronizedAooenderBase。
虽然上述appender都有一些独有的属性。详情见参考。
共通原理:
filter用于判断事件是否可以被append。
事件被append后,调用subAppend方法来写出。写出时,OutputStreamAppender中存在锁,需要同步。
写出时,调用encoder。encoder的核心功能为:将事件转化为字符串,并写出到对应输出流。
配置时,encoder节点中若包含layout和charset节点,则在将事件转化为字符串的过程中,用调用layout的方法来格式化字符串,指定对应字符集。
参考: https://www.jianshu.com/p/5f79f69fa24e https://logback.qos.ch/manual/appenders.html
encoder负责将事件转化为字符串的字符数组,并且将其写出到输出流。
encoder在0.9.19后才被引入logback。
在之前的版本,logback使用layout来将事件转化为String,然后用java.io.Writer写出。
且,在FileAppender中,则必须使用PatternLayout。
layout仅能将事件转化为String,而encoder既可以控制对事件的转化,又可以控制其写出。
对于0.9.19之前的版本,提供了LayoutWrappingEncoder,内持有Layout作为成员变量。 来弥补layout和encoder使用上的衔接。
更常用的类是PatternLoyoutEncoder。为LayoutWriapping的子类。
p.s: layout可以用于自定义样式。
参考: https://logback.qos.ch/manual/encoders.html https://logback.qos.ch/manual/layouts.html
个人理解:
接口: slf4j common-logging-api 实现框架: log4j logback log4j2 common-logging-impl
使用logback依赖:
slf4j-api (slf4j接口)
logback-classic (logback服务于slf4j的”驱动”)
logback-core (logback日志实现)
使用log4j依赖:
slf4j-api (slf4j接口)
slf4j-log4j (log4j 服务于slf4j的”驱动”)
log4j (log4j 日志实现)
如果系统有依赖log4j日志体系,想统一对接到logback,则需要依赖:log4j-over-slf4j
logback性能优于log4j
https://stackoverflow.com/questions/39562965/what-is-the-difference-between-log4j-slf4j-and-logback https://blog.csdn.net/butingnal/article/details/53946841
log4j2性能由于logback? logback vs log4j2: https://blog.csdn.net/yjh1271845364/article/details/70888262
log4j2个人理解:
如何控制项目里的第三方依赖打印出的日志? 日志桥接? 参考spring文档介绍,
p.s. 其实还写了ppt。没上传。