在日常的开发中,Logback配置文件中一般都会定义多个 logger,那它们之间互相的关系又是什么呢?
命令层次结构
首先声明一下 logger 命令层次结构:
如果一个 logger 的名字加上一个
.
作为另一个 logger 名字的前缀,那么该 logger 就是另一个 logger 的祖先。如果一个 logger 与另一个 logger 之间没有其它的 logger ,则该 logger 就是另一个 logger 的父级。
这段话,可能比较抽象,那么举个例子来说:
<logger name="x" level="DEBUG"/>
<logger name="x.y" level="DEBUG"/>
<logger name="x.y.z" level="DEBUG"/>
例子中,定义了 x,x.y,x.y.z 三个 logger,其中 x 是 x.y,x.y.z 的祖先,但是由于 x 与 x.y 之间不存在其它的 logger,所以 x 也是 x.y 的父级。
PS: 这里需要强调一下,代码中创建的 logger 和配置文件中定义的 logger 是相同的,如下面定义了名为 x.y.z 的 logger,和上面声明里的 x.y.z 相同:
private static Logger logger = LoggerFactory.getLogger("x.y.z");
等级继承
配置文件中,logger 的 level 属性不是必选参数,此外代码中创建时也没设置 logger 的等级,那么这些 logger 的等级又是啥呢?
如果一个给定的 logger 没有指定一个等级,那么它就会继承离它最近的一个祖先的等级。
在举例讲解之前,先声明一下,<root>
也属于 logger,只不过它是特殊的 logger,是根 logger,是所有 logger 的祖先。如果它未声明等级,那么会有个默认等级 DEBUG。接下来用表格来展示:
logger 的名字 | 指定的层级 | 有效层级 |
---|---|---|
root | DEBUG | DEBUG |
A | none | DEBUG |
A.B | INFO | INFO |
A.B.C | none | INFO |
A.B.C.D | ERROR | ERROR |
X | INFO | INFO |
X.Y | DEBUG | DEBUG |
X.Y.Z | WARN | WARN |
很明显:
- root 为 DEBUG,而 A 未指定,所以 A 继承 root 的 DEBUG,为 DEBUG;
- A 为 DEBUG,而 A.B 指定了 INFO,所以 A.B 为 INFO;
- A.B 为 INFO,而 A.B.C 未指定,所以 A.B.C 继承 A.B 的 INFO,为 INFO;
- A.B.C 为 INFO,而 A.B.C.D 指定了 ERROR,所以 A.B.C.D 为 ERROR;
- root 为 DEBUG,而 X 指定了 INFO,所以 X 为 INFO;
- X 为 INFO,而 X.Y 指定了 DEBUG,所以 X.Y 为 DEBUG;
- X.Y 为 DEBUG,而 X.Y.Z 指定了 WARN,所以 X.Y.Z 为 WARN。
appender 的叠加性
当定义完了 logger,需要再定义日志输出组件 appender,但是并不是每个 logger 会显示的声明日志输出组件 appender,那么日志输出组件 appender 是如何在 logger 之间叠加继承的呢?
首先,先定义两个 <appender>
:
<appender name="CONSOLE1" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%-4relative \[%thread\] %-5level %logger{35} - %msg %n</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="CONSOLE2" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%-4relative \[%thread\] %-5level %logger{35} - %msg %n</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
这两个名叫 CONSOLE1,CONSOLE2 的 appender 是两个单独的组件,两者功能相同,皆是在控制台根据一定的格式打印日志。
同时,定义三个 logger,具体如下:
<logger name="x" level="DEBUG"/>
<logger name="x.y" level="WARN"/>
<logger name="x.y.z" level="INFO"/>
现在,把 CONSOLE1 的 appender 添加到名为 x 的 logger 上,由于默认 additivity 为 true,所以 CONSOLE1 的 appender 会被 x.y,x.y.z 继承叠加,所以如果 x.y.z 如果有日志输出,能通过 CONSOLE1 的 appender 进行输出,同理 x.y 的日志也一样。
接着,把 CONSOLE1,CONSOLE2 的 appender 添加到名为 x.y 的 logger 上,由于继承叠加了 CONSOLE1 的 appender,所以这个 logger 具有三个 appender。系统不会对 appender 进行去重操作,所以如果有日志输出的话,日志会在 CONSOLE1 的 appender 中输出两遍。
如果想要防止在同一个 appender 多次输出的问题,可以通过设置 additivity 为 false 进行处理。合理的设置 appender 和 logger 的关系,防止日志重复输出,是关键。
PS:以上内容均参考 Logback中文网
来源:oschina
链接:https://my.oschina.net/flytofree/blog/3171810