logback学习速记

大部分内容均来自Logback官网

Logback

Logback是一种日志框架,它是由log4j和SLF4J日志框架的设计者设计,意在取代log4j。通常和SLF4J配合使用。

1 架构(Architecture)

Logback框架分为3个模块,分别是logback-corelogback-classiclogback-access

  • 顾名思义,core模块是其它两个模块的基础。

  • classic模块继承自core模块,它是对log4j的重大改进。Logback-classic原生实现了SLF4J的API,这样就可以让使用者在logback和其它日志系统之间自由切换,比如log4j或者java.util.logging(JUL)。

  • access模块集成了Servlet容器,提供了基于HTTP访问的日志功能。

2 Logger,Appenders和Layouts

Logback框架主要基于3个类(接口):LoggerAppenderLayout

通过上述3种组件的联合使用,可以帮助开发者针对不同的消息类型和等级记录日志,并控制应用运行时的日志格式和输出位置。

Logger类是logback-classic模块的一部分,而AppenderLayout接口是logback-core的一部分。Logger类没有包含在logback-core中是考虑到模块的通用性。

2.1 Logger上下文(Logger context)

相比于普通的System.out.println而言,任何一种日志API首要且最重要的优势就在于选择性输出或打印特定的日志语句(log statements)。这种能力通常假设存在一个日志空间(logging space),该空间里包含了所有可能的日志语句,开发者能根据设定的某些准则将这些语句划分为不同的类别。简单地说,比如info、warn、error等。

注:不管是logback,还是slf4j,亦或是log4j中,对“记录日志”这样的行为都是基于一种模型假设:日志器(logger)负责记录日志(log)。这有点类似于英文的work和worker的关系,其中work表示工作,worker表示工人。同样的道理,log表示日志,logger表示记录日志的主体——日志器(p.s. 译得很low,但确实没想到更好的译名)

每个独立的日志器(logger)都将绑定一个日志上下文LoggerContext,它负责产生日志器,并在一个类似层级结构的树结构中安置日志器。

日志器(loggers)是命名的实体(named entities)。它们的名字是大小写敏感,并遵循层级命名规则:

Named Hierarchy
A logger is said to be an ancestor of another logger if its name followed by a dot is a prefix of the descendant logger name. A logger is said to be a parent of a child logger if there are no ancestors between itself and the descendant logger.

熟悉Java包命名规则的一定会觉得上述规则很眼熟。是的,没错,该规则跟Java的包命名规则基本是相同的。例如,名为“com.codershangfeng”的日志器是名为“com.codershangfeng.backup”日志器的父一级日志器。

根日志器(root logger)位于所有日志器层级结构的顶部。任何一个日志器层级结构中都包含这样一个根日志器。它也可以像获取其他日志器一样,通过它的名字来获取,如下:

Logger rootLogger = LoggerFactory.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME);
所有日志器都包含5类打印方法,还有很多重载(overload)的方法未逐一列出(远不止下面的5个)。

package org.slf4j; 
public interface Logger {

  // Printing methods: 
  public void trace(String message);
  public void debug(String message);
  public void info(String message); 
  public void warn(String message); 
  public void error(String message); 
}

开发者根据开发需要调用合适的方法打印输出日志。

2.2 日志等级

从刚才的Logger接口中可以看到,每个日志器其实包含了5种日志输出等级,即:TRACE(跟踪)、DEBUG(调试)、INFO(信息)、WARN(警告)和ERROR(错误)。TRACE等级最低,ERROR等级最高。

例如,当指定日志器的输出等级为TRACE时,那么,该日志器调用的trace()debug()info()warn()error()方法都将输出日志。反之,若指定该日志器的输出等级为ERROR,则仅输出该日志器调用的error()方法的日志。

每个日志器都可以指定它的输出等级,当未指定时,则选用它的非空父一级日志器的等级,若非空父一级日志器也未指定,则继续上溯,最终可上溯至日志层级结构的顶级日志器——root,并采用root的输出等级作为该日志器的输出等级。

可以参考官方的解释:

The effective level for a given logger L, is equal to the first non-null level in its hierarchy, starting at L itself and proceeding upwards in the hierarchy towards the root logger.

特别注意,这与实际使用日志器时,在方法里实际调用的Logger方法无关!也就是说,在方法里你仍然可以调用某个日志器实例的logger.×××()方法,但至于是否输出打印,则取决于开发者对该Logger及其父一级,甚至根日志器的输出等级配置。

再来几个例子解释下日志器的日志等级设置:

  • 例1
Logger name Assigned level Effective level
root DEBUG DEBUG
X none DEBUG
X.Y none DEBUG
X.Y.Z none DEBUG

例1中,只有root日志器(根日志器)设定了输出等级——DEBUG,则该应用中所有继承自根日志器(root)的日志器,如XX.YX.Y.Z都将继承root日志器的DEBUG输出等级。

  • 例2
Logger name Assigned level Effective level
root ERROR ERROR
X INFO INFO
X.Y DEBUG DEBUG
X.Y.Z WARN WARN

例2中,每个日志器都指定了输出等级,不需要再使用继承关系进行指定输出等级。

  • 例3
Logger name Assigned level Effective level
root DEBUG DEBUG
X INFO INFO
X.Y none INFO
X.Y.Z none INFO

例3中,rootX分别指定DEBUG和INFO的输出等级;X.YX.Y.Z继承它最近的父一级的日志器X,故其输出等级为INFO。

2.3 获取日志器

例如:

Logger x = LoggerFactory.getLogger("wombat"); 
Logger y = LoggerFactory.getLogger("wombat");

日志器xy都指向名为wombat的相同日志器实例。

1.2.4 Appenders and Layouts

如果说,输出等级表示的是选择哪些日志进行输出,那么,Layouts和Appenders则分别是选择以哪些格式输出日志,将日志输出到哪些地方。

在logback的术语中,一个输出目的地被称为一个附加器(Appender)。目前,可供选择的附加器包括控制台(console),文件(files),远程套接字服务器(remote socket server),MySQL、PostgreSQL和其它数据库,Java消息服务(JMS),远程UNIX系统日志守护线程(remote UNIX Syslog daemons)。

一个日志器可以绑定多个附加器(appender)。

类似日志器的输出等级层级结构,附加器也存在类似的继承关系,但是其决定关系刚好是逆向的,即“子-->父”:

Appender Additivity

The output of a log statement of logger L will go to all the appenders in L and its ancestors. This is the meaning of the term "appender additivity".

However, if an ancestor of logger L, say P, has the additivity flag set to false, then L's output will be directed to all the appenders in L and its ancestors up to and including P but not the appenders in any of the ancestors of P.

Loggers have their additivity flag set to true by default.

从上述定义可以得出三点结论:

(1)子一级日志器产生的日志将输出至父一级的所有附加器中;

(2)若父一级日志器(假设为P)的additivity标识位设置为false,则子一级日志器(假设为L)的日志将输出至L自己的附加器,P的附加器,但不包含P的父一级日志器的附加器;

(3)所有日志器的additivity标识位默认为ture(root除外)。

举例:

Logger Name Attached Appenders Additivity Flag Output Targets Comment
root A1 not applicable A1 Since the root logger stands at the top of the logger hierarchy, the additivity flag does not apply to it.
x A-x1, A-x2 true A1, A-x1, A-x2 Appenders of "x" and of root.
x.y none true A1, A-x1, A-x2 Appenders of "x" and of root.
x.y.z A-xyz1 true A1, A-x1, A-x2, A-xyz1 Appenders of "x.y.z", "x" and of root.
security A-sec false A-sec No appender accumulation since the additivity flag is set to false. Only appender A-sec will be used.
security.access none true A-sec Only appenders of "security" because the additivity flag in "security" is set to false.

至于Layout,标准logback中发布PatternLayout可以帮助使用者利用类似C语言中printf函数的方法转换日志的输出格式。

例如,转换格式"%-4relative [%thread] %-5level %logger{32} - %msg%n"将输出类似如下:

176  [main] DEBUG manual.architecture.HelloWorld2 - Hello world.

2 配置

logback在查找配置文件遵循以下规则:

  1. Logback tries to find a file called logback-test.xml in the classpath.

  2. If no such file is found, logback tries to find a file called logback.groovy in the classpath.

  3. If no such file is found, it checks for the file logback.xml in the classpath.

  4. If no such file is found, service-provider loading facility ( introduced in JDK 1.6) is used to resolve the implementation of com.qos.logback.classic.spi.Configurator interface by looking up the META-INF\services\ch.qos.logback.classic.spi.Configurator in the class path. It contents should specify the fully qualified class name of the desired Configurator implementation.

  5. If none of the above succeeds, logback configures itself automatically using the BasicConfigurator which will cause logging output to be directed to the console.

其中,1-3都是通过文件直接进行配置;4-5是通过接口或类进行配置。

较为常见的是第3种,即通过logback.xmlXML文件进行配置。

如果使用Maven进行项目开发,可以将logback-test.xml放到src/test/resources文件夹下,这样就可以在测试时使用logback-test.xml配置文件,而在产品中使用logback.xml配置文件。

不过,即使不配置,logback也能利用第5种方案进行默认配置(有兴趣可参考链接)。

2.1 使用logback-test.xml或logback.xml自动配置

例1:基本配置

<configuration>

  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <!-- encoders are assigned the type
         ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
    <encoder>
      <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
    </encoder>
  </appender>

  <root level="debug">
    <appender-ref ref="STDOUT" />
  </root>
</configuration>

例1中,“<”和“>”两个尖括号表示XML文件结构中的一个元素或标签;“<foo>”和“</foo>”表示元素“foo”的起始和结束位置;'appender'标签表示日志最终输出的目的地,类似通信模型中的“信宿”;encoder标签就相当于上文提到的Layout(也可以用继承接口或抽象类的方法实现更为复杂的格式逻辑,但通常来说用encoder的字符串格式符就足够了),用于以C语言的printf函数形式设置每条日志语句的格式;'root'是根日志器的标签;appender-ref表示该日志器所指向或挂靠的附加器。

例2:为日志器设置输出等级

<configuration>

  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <!-- encoders are assigned the type
         ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
    <encoder>
      <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
    </encoder>
  </appender>

  <logger name="chapters.configuration" level="INFO"/>

  <!-- Strictly speaking, the level attribute is not necessary since -->
  <!-- the level of the root level is set to DEBUG by default.       -->
  <root level="DEBUG">          
    <appender-ref ref="STDOUT" />
  </root>  
  
</configuration>

例2中,对名为“chapter.configuration”的日志器设置了INFO输出等级,并按照logback框架日志器层级关系,“chapter.configuration”日志器也将使用root日志器的附加器,即“STDOUT”,这一点有别于log4j(没用过,文档里这么说的)。

例3:为多个日志器设置输出等级

<configuration>

  <appender name="STDOUT"
    class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>
        %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
     </pattern>
    </encoder>
  </appender>

  <logger name="chapters.configuration" level="INFO" />
  <logger name="chapters.configuration.Foo" level="DEBUG" />

  <root level="DEBUG">
    <appender-ref ref="STDOUT" />
  </root>

</configuration>

例4: 多个附加器

<configuration>

  <appender name="FILE" class="ch.qos.logback.core.FileAppender">
    <file>myApp.log</file>

    <encoder>
      <pattern>%date %level [%thread] %logger{10} [%file:%line] %msg%n</pattern>
    </encoder>
  </appender>

  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>%msg%n</pattern>
    </encoder>
  </appender>

  <root level="debug">
    <appender-ref ref="FILE" />
    <appender-ref ref="STDOUT" />
  </root>
</configuration>

例5:附加器复用

<configuration>

  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
    </encoder>
  </appender>

  <logger name="chapters.configuration">
    <appender-ref ref="STDOUT" />
  </logger>

  <root level="debug">
    <appender-ref ref="STDOUT" />
  </root>
</configuration>

例6:多日志器,多附加器

<configuration>

  <appender name="FILE" class="ch.qos.logback.core.FileAppender">
    <file>myApp.log</file>
    <encoder>
      <pattern>%date %level [%thread] %logger{10} [%file:%line] %msg%n</pattern>
    </encoder>
  </appender>

  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>%msg%n</pattern>
    </encoder>
  </appender>

  <logger name="chapters.configuration">
    <appender-ref ref="FILE" />
  </logger>

  <root level="debug">
    <appender-ref ref="STDOUT" />
  </root>
</configuration>

例7:定义变量

<configuration>

  <property name="USER_HOME" value="/home/sebastien" />

  <appender name="FILE" class="ch.qos.logback.core.FileAppender">
    <file>${USER_HOME}/myApp.log</file>
    <encoder>
      <pattern>%msg%n</pattern>
    </encoder>
  </appender>

  <root level="debug">
    <appender-ref ref="FILE" />
  </root>
</configuration>

还有关于Layout、Filter、JMX Configuration、Using SSL等内容暂不记录。

所有代码均来自logback官网文档The logback manual

EOF

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容

  • 在应用程序中添加日志记录总的来说基于三个目的:监视代码中变量的变化情况,周期性的记录到文件中供其他应用进行统计分析...
    时待吾阅读 4,933评论 1 13
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,580评论 18 139
  • (http://www.cnblogs.com/zhangchenliang/p/4546352.html) 1、...
    凌雲木阅读 2,397评论 0 2
  • 在应用程序中添加日志记录总的来说基于三个目的:监视代码中变量的变化情况,周期性的记录到文件中供其他应用进行统计分析...
    时待吾阅读 4,953评论 0 6
  • 9月28日咖啡冥想 1、早上八点多开始告别手机,到下午五点多,不去用手机联网,回归以前手机无网状态,专注干该干的活...