Chapter 3: Logback configuration

学习一套日志框架,以便在后续项目中使用

 

Logback配置方式

Logback can be configured either programmatically or with a configuration script expressed in XML

基于编程方式
XML配置(推荐)

 

Logback初始化步骤

 在classpath路径下,依次寻找,如果找到,则使用此配置:
  1. logback.groovy
  2. logback-test.xml
  3. logback.xml
  4. Automatically using the BasicConfigurator which will cause logging output to be directed to the console. By default the root logger is assigned the DEBUG level
     最后一步,确保了logback始终有1个可用配置

 

Automatically configuring logback

自动配置,level=DEBUG,向控制台进行输出

package manual.configuration;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class MyApp1 {
  final static Logger logger = LoggerFactory.getLogger(MyApp1.class);

  public static void main(String[] args) {
    logger.info("Entering application.");

    Foo foo = new Foo();
    foo.doIt();
    logger.info("Exiting application.");
  }
}

 

package chapters.configuration;
  
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
   
public class Foo {
  static final Logger logger = LoggerFactory.getLogger(Foo.class);
  
  public void doIt() {
    logger.debug("Did it again!");
  }
}

 

Logback将使用默认的配置进行日志输出,控制台输出: 

16:06:09.031 [main] INFO chapters.configuration.MyApp1 - Entering application. 
16:06:09.046 [main] DEBUG chapters.configuration.Foo - Did it again! 
16:06:09.046 [main] INFO chapters.configuration.MyApp1 - Exiting application.

 

Automatic configuration with logback-test.xml or logback.xml

自动读取配置文件进行日志输出,如配置向控制台输出:

 

 <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>

 

Automatic printing of status messages in case of warning or errors

 默认,logback在读取配置文件出错时,会打印错误信息
但是,如果配置了listener,为防止重复打印错误消息,默认机制将取消
而且,没有错误发生,又想查看logback的status,可通过 StatusPrinter 的printf()进行输出

logback-test.xml

  public static void main(String[] args) {
    // assume SLF4J is bound to logback in the current environment
    LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
    // print logback's internal status
    StatusPrinter.print(lc);
    ...
  }

 将看到控制台打印出如下信息

17:44:58,578 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Found resource [logback-test.xml]
17:44:58,671 |-INFO in ch.qos.logback.classic.joran.action.ConfigurationAction - debug attribute not set
17:44:58,671 |-INFO in ch.qos.logback.core.joran.action.AppenderAction - About to instantiate appender of type [ch.qos.logback.core.ConsoleAppender]
17:44:58,687 |-INFO in ch.qos.logback.core.joran.action.AppenderAction - Naming appender as [STDOUT]
17:44:58,812 |-INFO in ch.qos.logback.core.joran.action.AppenderAction - Popping appender named [STDOUT] from the object stack
17:44:58,812 |-INFO in ch.qos.logback.classic.joran.action.LevelAction - root level set to DEBUG
17:44:58,812 |-INFO in ch.qos.logback.core.joran.action.AppenderRefAction - Attaching appender named [STDOUT] to Logger[root]

17:44:58.828 [main] INFO  chapters.configuration.MyApp2 - Entering application.
17:44:58.828 [main] DEBUG chapters.configuration.Foo - Did it again!
17:44:58.828 [main] INFO  chapters.configuration.MyApp2 - Exiting application.

 

 另一种在没有错误的情况下,想看到logger初始化过程的方式:

 在configuration标签上设置属性debug="true"

 debug="true"能工作的前提:配置文件被找到,并且没有错误

<configuration debug="true"> 

  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> 
    <!-- encoders are  by default assigned the type
         ch.qos.logback.classic.encoder.PatternLayoutEncoder -->
    <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>

 

Automatically reloading configuration file upon modification

 当配置文件发生改变之后,Logback会自动加载配置文件

 机制:当若干个logger被执行后,将进行一次扫描,扫描频率还与CPU能力相关

 Values can be specified in units of milliseconds, seconds, minutes or hours.

 If no unit of time is specified, then the unit of time is assumed to be milliseconds

<configuration scan="true" scanPeriod="30 seconds" > 
  ...
</configuration>

  

Viewing status messages

Logback-classic ships with a servlet called ViewStatusMessagesServlet

在WEB应用中,可以从网页上查看Logger的状态

To add this servlet to your web-application, add the following lines to its WEB-INF/web.xml file.

  <servlet>
    <servlet-name>ViewStatusMessages</servlet-name>
    <servlet-class>ch.qos.logback.classic.ViewStatusMessagesServlet</servlet-class>
  </servlet>

  <servlet-mapping>
    <servlet-name>ViewStatusMessages</servlet-name>
    <url-pattern>/lbClassicStatus</url-pattern>
  </servlet-mapping>

 The ViewStatusMessages servlet will be viewable at the URL

  http://host/yourWebapp/lbClassicStatus

 

Listening to status messages

配置一个状态监听器,自动输出Logger的状态

It is also possible to register one or more status listeners within a configuration file

<configuration>
  <statusListener class="ch.qos.logback.core.status.OnConsoleStatusListener" />  

  ... the rest of the configuration file  
</configuration>

 

Stopping logback-classic

在应用结束的时候,释放资源(关闭已激活的日志线程)

通过ServletContextListener 的contextDestroyed(ServletContextEvent sce)调用

import org.sflf4j.LoggerFactory;
import ch.qos.logback.classic.LoggerContext;
...

// assume SLF4J is bound to logback-classic in the current environment
LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
loggerContext.stop();

 

Configuration file syntax

logback可以控制APP中某部分的日志打开,某部分日志关闭

可以往控制台、文件、数据库、邮件、日志查看器等进行日志输出

 

配置文件语法

最基本原则:

<configuration>中只能有1个 <root> ,0个或多个<appender>,0个或多个<logger>

 

Configuring loggers, or the <logger> element

Effective Level aka Level Inheritance

Logger的Level继承原则:

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.   

如果没有具体指定level,则向上查找非空的那个父类logger,使用其level作为自己的level

 

To ensure that all loggers can eventually inherit a level, the root logger always has an assigned level. By default, this level is DEBUG.  

为了确保每个logger最终都能有一个level,root logger的级别默认设置为了DEBUG



 

logger的属性配置

唯一的name属性,可选的level属性,可选的additivity属性

name attribute: logger的名称,一般为大写

level attribute:大小写不敏感的TRACE, DEBUG, INFO, WARN, ERROR, ALL or OFF

additivity attribute: ture/false

<logger>中可以配置0个或多个 <appender-ref>

与log4j不同,logback-classic不会移除前面设置的appender,而是采用追加方式

 

Configuring the root logger, or the <root> element

 root logger,只支持1个属性,即level属性

 由于是根logger,因此没有additivity 属性

 由于默认为名称为“ROOT”,因此没有name属性

 level属性合法的值:

 case-insensitive strings TRACE, DEBUG, INFO, WARN, ERROR, ALL or OFF

 不允许设置为 INHERITED or NULL.   

 

 允许0个或多个 <appender-ref>

 与log4j不同,logback-classic不会移除前面设置的appender,而是采用追加方式

 

为Logger设置级别level

指定某个包下的logger级别,覆盖从父类继承下来的level

"chapters.configuration" package的level设置为了INFO,因此,

"chapters.configuration" package下的debug级别将不会输出!

 

<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>

 

 为某个类指定logger的Level

 set the level of the chapters.configuration.Foo logger to DEBUG

 设置chapters.configuration.Foo 的logger级别为DEBUG,则该类的debug将被输出!

<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>

 

 

 

子Logger的配置会覆盖root logger的配置

即使root logger处于关闭,但子logger仍可以正常工作

chapters.configuration由于有自己的logger配置,因此,正常工作

chapters.configuration之外的logger,将被关闭,因为root logger已经处理OFF状态

<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" />

  <!-- turn OFF all logging (children can override) -->
  <root level="OFF">
    <appender-ref ref="STDOUT" />
  </root>

</configuration>

 

 

 

 

 Logger的appender追加原则:

Configuring Appenders

 <appender> 只有两个可用属性:

name 属性: appender的名称

class 属性: appender对应的类

 

 <appender>可以有

0个或多个 <layout>元素

0个或多个 <encoder> 元素

0个或多个  <filter>元素

还可以设置对应class的JavaBean属性

 

  <layout>默认对应的类PatternLayout,则可以省略不写

  <encoder> 默认对应的类为PatternLayoutEncoder,可以省略不写

 

 1个logger引用多个appender

  注意: 每个appender都有属于自己的encoder,encoder没有提供共享功能!

              layout也是如此!

<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>

 

 

Appenders accumulate

叠加性

一个记录器会记录到连接到其自身的appender (如果有的话) ,以及所有连接到它的祖先的appender

Logger的Level受继承关系影响,Logger的appender也受继承关系影响

不同的是:

Logger的level会根据自己是否被指定level,再决定是否使用父类的level

Logger的appender则默认会叠加父类的appender,除非明确说明不叠加

 

chapters.configuration包下的日志将记录到文件,同时,也会输出到控制台

因为, chapters.configuration对应的logger继承了root logger中的appender!

<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>
 

chapters.configuration.Foo 对应的logger只会将日志往文件中输出,而不会往控制台输出

因为,明确指定了additivity="false",将不会叠加root logger中的appender!

 当某个logger使用了additivity="false",则它的子logger也不会继承root logger的appender~

<configuration>

  <appender name="FILE" class="ch.qos.logback.core.FileAppender">
    <file>foo.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.Foo" additivity="false">
    <appender-ref ref="FILE" />
  </logger>

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

 

Setting the context name

为每个Logger设置不同的context名称

这样,不同logger所记录的日志将很好的区分开

<configuration>
  <contextName>myAppName</contextName>
  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>%d %contextName [%t] %level %logger{36} - %msg%n</pattern>
    </encoder>
  </appender>

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

 

Variable substitution

定义变量,实现属性替换By  "${aName}"

 

Defining variables

在配置文件configuration中定义

在外部properties文件中定义

在外部resource文件中定义

 

在configuration文件中设置变量:指定文件的输出位置 

<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>

 

logback解析到配置文件中有${aName},如果没有对应的属性定义,将查询 Java system properties。因此,也可以通过设置 Java system properties 实现变量的定义。 

System.setProperty("USER_HOME", "home/sebastien");

 

当有多个变量属性需要定义时,通过1个专门的属性配置文件进行实现,再好不过

variables.properties

USER_HOME=home/sebastien

引入外部properties文件

<configuration>

  <property file="src/main/java/chapters/configuration/variables.properties" />

  <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>

 

还可以引入classpath下的资源文件,更方便

variables.properties

USER_HOME=home/sebastien

 引入外部资源文件  

<configuration>

  <property resource="resource1.properties" />

  <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>

 

 

Logback预定义的变量

 HOSTNAME   主机名
 CONTEXT_NAME

 Timestamp

<configuration>

  <!-- Insert the current time formatted as "yyyyMMdd'T'HHmmss" under
       the key "bySecond" into the logger context. This value will be
       available to all subsequent configuration elements. -->
  <timestamp key="bySecond" datePattern="yyyyMMdd'T'HHmmss"/>

  <appender name="FILE" class="ch.qos.logback.core.FileAppender">
    <!-- use the previously created timestamp to create a uniquely
         named log file -->
    <file>log-${bySecond}.txt</file>
    <encoder>
      <pattern>%logger{35} - %msg%n</pattern>
    </encoder>
  </appender>

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

 

 

File inclusion

分离配置文件

通过<include>标签导入其它配置文件

<configuration>
  <include file="src/main/java/chapters/configuration/includedConfig.xml"/>

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

</configuration>

 

被include的文件必须包含在<included/>标签中

 

<included>
  <appender name="includedConsole" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>"%d - %m%n"</pattern>
    </encoder>
  </appender>
</included>

 

As a file:

使用file属性进行引入,相对路径是相对与项目根路径的,不是configuration文件

As a resource:

从classpath进行导入

<include resource="includedConfig.xml"/>

As a URL:

从网络上导入

<include url="http://some.host.com/includedConfig.xml"/>

 

 

 

 

猜你喜欢

转载自schy-hqh.iteye.com/blog/2025596