logback手册-第三章 Logback配置

第3章:Logback配置

在符号中,人们发现了一个优点,那就是当他们简单地表达一个事物的确切性质时,它就是最大的发现。那么思想的工作确实是奇妙地减少了。

-GOTTFRIED WILHELM LEIBNIZ

我们首先介绍配置logback的方法,并配置了许多示例配置脚本。Joran,logback所依赖的配置框架将在后面的章节中介绍

在的logback中配置

将日志请求插入到应用程序代码中需要进行相当多的计划和努力。观察表明,大约百分之四的代码是专门用来记录的。因此,即使是中等大小的应用程序也会包含嵌入代码中的数千条日志语句。鉴于他们的数量,我们需要工具来管理这些日志语句。

Logback可以通过编程或用XML或Groovy格式表示的配置脚本进行配置。顺便说一下,现有的log4j用户可以使用我们的 PropertiesTranslator web应用程序将他们的log4j.properties文件转换 为logback.xml

让我们从讨论logback的初始化步骤开始,尝试配置它自己:

1.Logback试图在类路径中找到名为logback-test.xml 的文件 。

2.如果找不到这样的文件,logback会尝试在类路径中找到一个名为logback.groovy 的文件 。

3.如果找不到这样的文件,它会检查类路径中的文件 logback.xml 。

4.如果没有找到这样的文件,服务提供者加载器(jdk1.6中介绍,ServiceLoader)会在类路径中,查找META-INF\services\ch.qos.logback.classic.spi.Configurator文件,来解析com.qos.logback.classic.spi.Configurator接口的实现。其内容应该指定Configurator实现类的全限定名。

5.如果以上都不成功,则使用logback自动配置BasicConfigurator ,这将导致日志记录输出被定向到控制台。

最后一步的意思是在没有配置文件的情况下提供默认(但非常基本的)日志记录功能。

如果您使用的是Maven,并且如果将 logback-test.xml放在src/test/resources 文件夹下,Maven将确保它不会包含在编译的文件中。因此,您可以使用不同的配置文件,即测试期间的logback-test.xml和生产中的另一个文件(即logback.xml)。

快速启动 Joran解析给定的logback配置文件需要大约100毫秒的时间。为了在应用程序启动时削减这些毫秒数,可以使用服务提供者加载工具(上面的第4项)来用BasicConfigrator加载您自己的自定义Configurator类作为一个很好的起点 。

自动配置的logback

配置logback的最简单方法是让logback回到默认配置。让我们尝试一下如何在一个名为虚构的应用程序中完成这项工作 MyApp1。

示例:简单 BasicConfigurator使用示例(logback-examples / src / main / java / chapters / configuration / MyApp1.java

package chapters.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.");

  }

}

这个类定义了一个静态logger变量。然后它实例化一个Foo对象。这个Foo类如下所示:

例子:做日志的小类 (logback-examples / src / main / java / chapters / configuration / Foo.java

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!");

  }

}

为了运行本章中的示例,您需要确保某些jar文件存在于类路径中。请参阅设置页面了解更多详情。

假设配置文件logback-test.xml或 logback.xml不存在,logback将默认调用BasicConfigurator 将设置最小配置。这个最小的配置包括一个ConsoleAppender附加到根记录器。输出的格式PatternLayoutEncoder设置为 %d {HH:mm:ss.SSS} [%thread]%-5level%logger {36} - %msg%n。而且,默认情况下根记录器被分配DEBUG 级别。

因此,命令java chapters.configuration.MyApp1的输出 应该类似于:

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.

除了配置logback的代码(如果存在这样的代码),客户端代码不需要依赖于logback。使用logback作为其日志框架的应用程序将对SLF4J具有编译时间依赖性,但不包括logb​​ack。

该MyApp1应用程序链接到通过调用的logback org.slf4j.LoggerFactory和 org.slf4j.Logger类,检索它希望使用的logger。请注意,Foo类的唯一依赖关系是通过 org.slf4j.LoggerFactory和 org.slf4j.Logger导入。除了配置logback的代码(如果存在这样的代码),客户端代码不需要依赖于logback。由于SLF4J允许在其抽象层下使用任何日志框架,所以很容易将大量代码从一个日志框架迁移到另一个日志框架。

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

如前所述,logback将尝试使用文件logback-test.xmllogback.xml进行自我配置。这是一个相当于BasicConfigurator我们刚刚看到的配置文件。

示例:基本配置文件(logback-examples / src / main / resources / chapters / configuration / sample0.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>

sample0.xml重命名为 logback.xml(或logback-test.xml)后,将其放入可从类路径访问的目录中。运行MyApp1 应用程序应该与它以前的运行相同的结果。

在出现警告或错误时自动打印状态消息

如果在解析配置文件的过程中发生警告或错误,则logback将自动在控制台上打印其内部状态消息。

如果在解析配置文件的过程中出现警告或错误,logback将自动将其内部状态数据打印在控制台上。请注意,为避免重复,如果用户显式注册状态监听器(以下定义),则禁用自动状态打印。

在没有警告或错误的,如果你还希望检查的logback的内部状态,那么你就可以指示的logback通过调用打印状态数据print()的的 StatusPrinter类。所述MyApp2下面所示的应用是相同的MyApp1除了添加的两行代码打印内部状态数据。

例如:打印logback的内部状态信息(logback-examples / src / main / java / chapters / configuration/MyApp2.java

public static void main String [] args ){  

  //假定SLF4J在当前环境中被绑定到logback

  LoggerContext lc = LoggerContext LoggerFactory.getILoggerFactory ();

  //打印logback的内部状态

  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.

在输出结束时,您可以识别上例中打印的行。你还应该注意到logback的内部消息,也就是Status对象,它允许方便地访问logback的内部状态。

状态数据

状态数据的输出通常在诊断logback问题方面有很长的路要走。因此,这是强烈建议,应该考虑作为第一手段的追索 。

而不是StatusPrinter从代码中以编程方式调用,即使没有错误,也可以指示配置文件转储状态数据。为此,需要设置configuration元素的debug属性 ,即配置文件中最顶层的元素,如下所示。请注意,这个debug属性只与状态数据有关。它并不会影响logback的配置,特别是相对于logger级别。(如果你想问根logger将会不会被设置DEBUG。) 

示例:使用调试模式的基本配置文件(logback-examples / src / main / resources / chapters / configuration / sample1.xml)

<configuration debug = “true” > 

  <appender name = “STDOUT” class = “ch.qos.logback.core.ConsoleAppender” >  

    <! - 编码器是默认分配的类型

         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>

设置debug="true"在<configuration>元素会输出状态信息,前提是:

  1. 找到配置文件
  2. 配置文件是格式良好的XML。

如果这两个条件中的任何一个没有满足,Joran不能解释debug属性,因为配置文件不能被读取。如果找到配置文件但格式不正确,则logback将检测到错误情况并自动在控制台上打印其内部状态。但是,如果找不到配置文件,logback将不会自动打印其状态数据,因为这不一定是错误状态。StatusPrinter.print()如 上面MyApp2应用程序中所示,以编程方式调用 可确保在每种情况下都打印状态信息。

强制状态输出在缺少状态消息的情况下,追踪恶意logback.xml 配置文件可能会很困难,尤其是在应用程序源不易修改的生产环境中。为了帮助识别流氓配置文件的位置,可以 StatusListener通过“logback.statusListenerClass”系统属性(定义如下)设置强制输出状态消息。“logback.statusListenerClass”系统属性也可用于在发生错误时自动生成静音输出。

顺便说一句,设置debug="true"严格等于安装一个 OnConsoleStatusListener。状态监听器在下面进一步讨论。下面显示安装 OnConsoleStatusListener。

示例:注册状态侦听器(logback-examples / src / main / resources / chapters / configuration / onConsoleStatusListener.xml)

查看为.groovy

<configuration>

<statusListener class = “ch.qos.logback.core.status.OnConsoleStatusListener” />

  ... ... 配置文件的其余部分  

</configuration>

通过调试属性或等效地安装来启用状态数据的输出OnConsoleStatusListener将有助于诊断回退问题。因此,非常强烈地建议启用回溯状态数据,并且应该被视为第一手段的追索。

指定默认配置文件的位置作为系统属性

您可以使用名为system的属性来指定默认配置文件的位置 "logback.configurationFile"。此属性的值可以是URL,类路径上的资源或应用程序外部文件的路径。

java -Dlogback.configurationFile = /path/to/config.xml chapters.configuration.MyApp1

请注意,文件扩展名必须是“.xml”或“.groovy”。其他扩展名被忽略。显式注册状态监听器可能有助于调试定位配置文件的问题。

修改后自动重新加载配置文件

Logback-classic可以扫描其配置文件中的更改,并在配置文件更改时自动重新配置自身。

如果指示这样做,logback-classic将扫描其配置文件中的更改,并在配置文件更改时自动重新配置自身。为了指示logback-classic扫描其配置文件中的更改,并自动重新配置自身,请将元素的scan属性 设置<configuration>为true,如下所示。

示例:扫描配置文件中的更改并自动重新配置(logback-examples / src / main / resources / chapters / configuration / scan1.xml)

查看为.groovy

<configuration scan = “true” > 

  ...

</configuration>

默认情况下,配置文件将每分钟扫描一次更改。您可以通过设置元素的scanPeriod属性 来指定不同的扫描周期<configuration>。值可以以毫秒,秒,分钟或小时为单位指定。这里是一个例子:

示例:指定不同的扫描周期(logback-examples / src / main / resources / chapters / configuration / scan2.xml)

查看为.groovy

<configuration scan = “true” scanPeriod = “30 seconds” >   

  ...

<configuration >

注意如果没有指定时间单位,则时间单位被认为是毫秒,这通常是不合适的。如果更改默认的扫描周期,请不要忘记指定一个时间单位。

在幕后,当您将scan属性设置为true时, 将会安装一个 名为ReconfigureOnChangeFilterTurboFilter。TurboFilters将在后面的章节中介绍。因此,扫描是在“线程内”完成的,也就是说,任何时候都可以调用logger的打印方法。例如,对于名为myLogger的logger,在编写“myLogger.debug(”hello“);”时,如果scan属性设置为true,ReconfigureOnChangeFilter则将被调用。而且,即使myLogger在DEBUG级别被禁用,所述过滤器也将被调用 。

当一个配置文件改变时,它将被自动重新加载,但是只有在多个logger调用之后并且在由扫描周期确定的延迟之后。

鉴于ReconfigureOnChangeFilter每次调用任何logger时都会调用,而不管logger级别如何,ReconfigureOnChangeFilter绝对是性能至关重要的。事实上,检查扫描周期是否已经过去,本身太昂贵了。为了提高性能, ReconfigureOnChangeFilter实际上在每N次日志作业中“活着”一次。根据您的应用程序记录的频率,N的值可以通过logback实时修改。默认情况下,N是16,但对于CPU密集型应用程序来说,它可以高达2 ^ 16(= 65536)。

简而言之,当一个配置文件发生变化时,它将被自动重新加载,但是只有在几个logger调用 之后以及由扫描周期确定的延迟之后。

在堆栈跟踪中启用打包数据

封装数据虽然有用,但计算起来很昂贵,特别是在频繁出现异常的应用中。

注意从版本1.1.4开始,打包数据默认是禁用的。

如果确定这样做,logback可以输出它包括的每一行的堆栈跟踪行的打包数据。打包数据由栈文件的名称和版本组成,从而产生堆栈跟踪行的类。打包数据在识别软件版本问题方面非常有用。但是,计算起来相当昂贵,特别是在频繁抛出异常的应用程序中。这是一个示例输出:

14:28:48.835 [btpool0-7] INFO  c.q.l.demo.prime.PrimeAction - 99 is not a valid value

java.lang.Exception: 99 is invalid

  at ch.qos.logback.demo.prime.PrimeAction.execute(PrimeAction.java:28) [classes/:na]

  at org.apache.struts.action.RequestProcessor.processActionPerform(RequestProcessor.java:431) [struts-1.2.9.jar:1.2.9]

  at org.apache.struts.action.RequestProcessor.process(RequestProcessor.java:236) [struts-1.2.9.jar:1.2.9]

  at org.apache.struts.action.ActionServlet.doPost(ActionServlet.java:432) [struts-1.2.9.jar:1.2.9]

  at javax.servlet.http.HttpServlet.service(HttpServlet.java:820) [servlet-api-2.5-6.1.12.jar:6.1.12]

  at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:502) [jetty-6.1.12.jar:6.1.12]

  at ch.qos.logback.demo.UserServletFilter.doFilter(UserServletFilter.java:44) [classes/:na]

  at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1115) [jetty-6.1.12.jar:6.1.12]

  at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:361) [jetty-6.1.12.jar:6.1.12]

  at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:417) [jetty-6.1.12.jar:6.1.12]

  at org.mortbay.jetty.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:230) [jetty-6.1.12.jar:6.1.12]

打包数据默认是禁用的,但可以通过配置启用:

<configuration packagingData = “true” >

  ...

</configuration >

或者,可以在LoggerContext内通过调用setPackagingDataEnabled(boolean 方法以编程方式启用/禁用打包数据,如下所示:

LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();

  lc.setPackagingDataEnabled(true);

 

JoranConfigurator直接调用

Logback依赖于称为Joran的配置库,它是logback-core的一部分。Logback的默认配置机制会调用 JoranConfigurator它在类路径上找到的默认配置文件。如果您希望覆盖logback的默认配置机制,可以通过JoranConfigurator直接调用来实现。下一个程序,MyApp3,调用上作为参数传递的配置文件JoranConfigurator。

示例:JoranConfigurator 直接调用(logback-examples / src / main / java / chapters / configuration / MyApp3.java

package chapters.configuration;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import ch.qos.logback.classic.LoggerContext;

import ch.qos.logback.classic.joran.JoranConfigurator;

import ch.qos.logback.core.joran.spi.JoranException;

import ch.qos.logback.core.util.StatusPrinter;

public class MyApp3 {

  final static Logger logger = LoggerFactory.getLogger(MyApp3.class);

  public static void main(String[] args) {

    // assume SLF4J is bound to logback in the current environment

    LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();

   

    try {

      JoranConfigurator configurator = new JoranConfigurator();

      configurator.setContext(context);

      // Call context.reset() to clear any previous configuration, e.g. default

      // configuration. For multi-step configuration, omit calling context.reset().

      context.reset();

      configurator.doConfigure(args[0]);

    } catch (JoranException je) {

      // StatusPrinter will handle this

    }

    StatusPrinter.printInCaseOfErrorsOrWarnings(context);

    logger.info("Entering application.");

    Foo foo = new Foo();

    foo.doIt();

    logger.info("Exiting application.");

  }

}

此应用程序获取LoggerContext 当前有效的信息,创建一个新的信息JoranConfigurator,设置它将在其上运行的上下文,重置记录器上下文,然后最终要求配置器使用作为参数传递给应用程序的配置文件来配置上下文。在出现警告或错误的情况下打印内部状态数据。请注意,对于多步骤配置, context.reset()应该省略调用。

查看状态消息

Logback将其内部状态数据收集到一个StatusManager 对象中,可通过LoggerContext访问。

给定一个StatusManager你可以访问所有与一个logback上下文相关的状态数据。为了将内存使用保持在合理的水平,默认StatusManager 实现将状态消息存储在两个独立的部分:头部分和尾部分。标题部分存储第一个 H状态消息,尾部存储最后的 T消息。目前时间H = T = 150,尽管这些值在未来的版本中可能会改变。

Logback-classic,带有一个叫做ViewStatusMessagesServlet的servlet。这个servlet StatusManager将当前关联 的内容打印 LoggerContext成HTML表格。这里是示例输出。

点击放大

要将此servlet添加到您的Web应用程序,请将以下行添加到其WEB-INF/web.xml文件中。

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

该ViewStatusMessagesservlet将在URL中可见http://host/yourWebapp/lbClassicStatus

收听状态消息

您也可以添加一个StatusListener到StatusManager,以便您可以立即采取措施来响应状态消息,尤其是对于在logback配置发生的消息。注册一个状态监听器是一个方便的方式来监督logback的内部状态,无需人工干预。

Logback附带一个名为OnConsoleStatusListener 的StatusListener实现,如名称所示,在控制台上打印所有新的传入状态消息。

以下是 使用StatusManager 注册实例的示例代码OnConsoleStatusListener。

   LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();

   StatusManager statusManager = lc.getStatusManager();

   OnConsoleStatusListener onConsoleListener = new OnConsoleStatusListener();

   statusManager.add(onConsoleListener);

请注意,注册状态监听器只会在注册后接收状态事件。它不会收到事先的消息。因此,在其他指令之前,将状态监听器注册指令放置在配置文件的顶部通常是一个好主意。

也可以在配置文件中注册一个或多个状态监听器。这是一个例子。

示例:注册状态侦听器(logback-examples/src/main/resources/chapters/configuration/onConsoleStatusListener.xml)

查看为.groovy

<configuration>

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

  ... the rest of the configuration file  

</configuration>

“logback.statusListenerClass”系统属性

也可以通过“logback.statusListenerClass”Java系统属性,去设置您希望注册的侦听器类的名称。例如,

java -Dlogback.statusListenerClass = ch.qos.logback.core.status.OnConsoleStatusListener ...

Logback附带有几个状态监听器实现。OnConsoleStatusListener 在控制台上打印传入的状态消息,即在System.out上。OnErrorConsoleStatusListener 在System.err上打印传入的状态消息。NopStatusListener 丢弃传入的状态消息。

请注意,如果在配置期间注册了状态侦听器,并且特别是在用户通过“logback.statusListenerClass”系统指定状态侦听器时,自动状态打印(如果有错误)将被禁用。因此,通过设置NopStatusListener状态监听器,可以完全禁止内部状态打印。

java -Dlogback.statusListenerClass = ch.qos.logback.core.status.NopStatusListener ...

停止logback-classic

为了释放logback-classic使用的资源,停止logback上下文总是一个好主意。停止上下文将关闭所有附加到由上下文定义的记录器的appender,并停止任何活动的线程。

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();

在web应用程序中,可以从contextDestroyed 方法中调用上面的代码ServletContextListener,以停止logback-classic和release资源。从版本1.1.10开始,适合ServletContextListener自动安装(见下文)。

通过关闭挂钩停止logback-classic

安装JVM关闭挂钩是关闭logback和释放相关资源的一种便捷方式。

<configuration debug = “true” >

   <! - 在没有class属性的情况下,假设

   ch.qos.logback.core.hook.DelayingShutdownHook  - >

   <shutdownHook />

  ....

</configuration >

默认关闭挂钩,即DelayingShutdownHook,可以延迟用户指定的持续时间关机。请注意,您可以通过设置class属性来对应您的关闭钩子的类名称来安装自己的关闭钩子。

在web应用程序中停止logback-classic

自从1.1.10 Logback-classic会 自动要求Web服务器安装一个LogbackServletContainerInitializer 实现ServletContainerInitializer接口(在servlet-api 3.x和更高版本中可用)。这个初始化器将依次安装和实例化LogbackServletContextListener。这个监听器将停止或重新加载Web应用程序时停止当前的logback-classic上下文。

您可以在web应用程序的web.xml文件中通过设置一个名为logbackDisableServletContainerInitializer的<context-param> 来禁用自动安装 LogbackServletContextListener。这是相关的片段。

<web-app>

    <的context-param>

        <param-name>logbackDisableServletContainerInitializer</ param-name>

        <param-value>true</ param-value>

    </的context-param>

    ....

</ web-app>

请注意, logbackDisableServletContainerInitializer变量也可以被设置为Java系统属性的OS环境变量。最本地的设置有优先级,即Web应用优先,系统属性优先和OS环境优先。

配置文件语法

正如您在手册中所看到的,还有大量示例仍然遵循,logback允许您重新定义日志记录行为,而无需重新编译代码。事实上,您可以轻松地配置logback,以便禁用应用程序某些部分的日志记录,或者直接输出到UNIX Syslog守护进程,数据库,日志可视化器或将日志记录事件转发到远程Logback服务器,Log根据本地服务器策略,例如通过将日志事件转发到第二个Logback服务器。

本节的其余部分介绍了配置文件的语法。

正如一遍又一遍地演示的那样,logback配置文件的语法是非常灵活的。因此,使用DTD文件或XML模式指定允许的语法是不可能的。尽管如此,配置文件的基本结构可以被描述为<configuration>元素,包含零个或多个<appender>元素,后面是零个或多个<logger>元素,最多是一个<root>元素。下图说明了这个基本结构。

基本的语法

如果您不确定给定标签名称使用哪种情况,只需按照几乎总是正确的惯例的camelCase约定即可。

标签名称的大小写敏感性

自从logback版本0.9.17以来,与显式规则相关的标签名是不区分大小写的。例如,<logger>,<Logger>和 <LOGGER>是有效的配置元素,并将以同样的方式来解释。请注意,XML格式良好的规则仍然适用,如果您打开一个标签,因为<xyz>您必须关闭它</xyz>,</XyZ> 将无法正常工作。至于隐式规则,除第一个字母外,标签名称区分大小写。因此,<xyz>和<Xyz>是等价的,但不是<xYz>。隐式规则通常遵循camelCase 约定,在Java世界中很常见。由于不容易判断一个标签何时与一个明确的动作相关联,以及何时与一个隐含的动作相关联,所以说一个XML标签对于第一个字母是区分大小写还是不灵敏。如果您不确定给定标签名称使用哪种情况,只需遵循几乎总是正确的惯例的camelCase约定。

配置loggers或<logger>元素

在这一点上,你应该至少有一些水平继承的理解和基本的选择规则。否则,除非你是埃及学家,否则logback配置对你来说不会比象形文字更有意义。

记录器使用该<logger> 元素进行配置。一个<logger>元素只需要一个强制name属性,一个可选的level属性和一个可选的additivity属性,允许值为 truefalselevel属性的值允许不区分大小写的字符串值TRACE,DEBUG,INFO,WARN,ERROR,ALL或OFF之一。不区分大小写的特殊值INHERITED,或其同义词NULL,将强制logger的层次从层次结构中的较高层继承。如果您设置logger的级别并稍后决定它应该继承它的级别,这将派上用场。

需要注意的是不同的log4j,的logback-classic确实没有关闭,也没有在配置给定的logger时,删除任何先前提及appenders程序。

该<logger>元件可含有零个或多个 <appender-ref>元素; 每个这样引用的appender被添加到指定的logger。需要注意的是不同的log4j,的logback-classic确实没有关闭,也没有配置给定的logger时,删除任何先前提及appenders程序。

配置根logger或<root>元素

<root>元素配置根logger。它仅支持一个属性,即level属性。它不允许任何其他属性,因为可加性标志不适用于根logger。而且,由于根logger已经被命名为“ROOT”,所以它也不允许名称属性。level属性的值可以是不区分大小写的字符串之一TRACE,DEBUG,INFO,WARN,ERROR,ALL或OFF。请注意,根logger的level不能设置为INHERITED或NULL。

需要注意的是不同的log4j,的logback-classic确实没有关闭,也没有在配置给定的logger时,删除任何先前提及appenders程序。

与<logger>元素类似, <root>元素可以包含零个或多个 <appender-ref>元素; 由此引用的每个appender被添加到根logger。需要注意的是不同的log4j,的logback-classic确实没有关闭,也没有配置给定的logger时,删除任何先前提及appenders程序。

如下例所示,设置logger或根logger的level与声明和设置level一样简单。假设我们不再有兴趣看到来自属于“chapters.configuration”包的任何组件的任何DEBUG消息。以下配置文件显示了如何实现这一点。

示例:设置logger的级别(logback-examples/src/main/resources/chapters/configuration/sample2.xml)

查看为.groovy

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

当上面的配置文件作为MyApp3应用程序的参数给出时 ,它将产生以下输出:

17:34:07.578 [main] INFO  chapters.configuration.MyApp3 - Entering application. 17:34:07.578 [main] INFO  chapters.configuration.MyApp3 - Exiting application.

请注意,由“chapters.configuration.Foo” logger生成的DEBUG级别消息已被取消。另见Foo类。

您可以根据需要配置尽可能多的logger的级别。在下一个配置文件中,我们将chapters.configuration logger的级别设置 为INFO,但同时设置chapters.configuration.Foo logger的级别为DEBUG。

示例:设置多个记录器的级别(logback-examples/src/main/resources/chapters/configuration/sample3.xml)

查看为.groovy

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

MyApp3使用此配置文件运行将在控制台上产生以下输出:

17:39:27.593 [main] INFO chapters.configuration.MyApp3 - Entering application. 17:39:27.593 [main] DEBUG chapters.configuration.Foo - Did it again! 17:39:27.593 [main] INFO chapters.configuration.MyApp3 - Exiting application.

下表列出了JoranConfigurator使用sample3.xml配置文件配置logback 之后的记录器及其级别 。

Logger名称

指定level

有效的level

root

DEBUG

DEBUG

chapters.configuration

INFO

INFO

chapters.configuration.MyApp3

null

INFO

chapters.configuration.Foo

DEBUG

DEBUG

由此可见,水平两个记录语句 INFO中MyApp3类以及在调试消息Foo.doIt()都被启用。请注意,根logger的级别始终设置为非空值,默认情况下为DEBUG。

让我们注意到基本选择规则 取决于被调用的logger的有效等级,而不是附加器附加的logger的等级。Logback将首先确定是否启用日志记录语句,如果启用,则将调用logger层次结构中的appender,而不管其级别如何。配置文件 sample4.xml就是一个例子:

示例:记录器级别示例(logback-examples/src/main/resources/chapters/configuration/sample4.xml)

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

下表列出了应用sample4.xml配置文件后的记录器及其级别。

logger名称

指定级别

有效的水平

root

OFF

OFF

chapters.configuration

INFO

INFO

chapters.configuration.MyApp3

null

INFO

chapters.configuration.Foo

null

INFO

命名为STDOUT的ConsoleAppender 是sample4.xml中唯一配置的appender ,连接到级别设置为OFF的根logger。但是,运行 MyApp3与配置脚本sample4.xml将产生:

17:52:23.609 [main] INFO chapters.configuration.MyApp3 - Entering application. 17:52:23.609 [main] INFO chapters.configuration.MyApp3 - Exiting application.

因此,根记录器的级别没有明显的效果,因为级别中的记录器chapters.configuration.MyApp3和 chapters.configuration.Foo类都已启用 INFO。作为一个方面说明chapters.configuration logger凭借其在配置文件中的声明而存在 - 即使Java源代码不直接引用它。

配置Appender

appender配置了这个<appender> 元素,这个元素需要两个强制属性nameclass。该name属性声明appender的名称,class属性指定的appender类实例化的全限定名。该<appender>元件可含有零个或一个<layout>元素,零个或多个 <encoder>元件以及零层或更多 <filter>的元件。除了这三个公共元素之外,<appender>元素可以包含与appender类的JavaBean属性相对应的任意数量的元素。无缝支持给定logback组件的任何属性是Joran的主要优势之一正如后面的章节所讨论的那样。下图说明了常见的结构。请注意,对属性的支持不可见。

Appender语法

该<layout>元素采用强制性的类属性来指定要实例化的布局类的完全限定名。与<appender>元素一样, <layout>可以包含与布局实例的属性相对应的其他元素。由于这是一个常见的情况,如果布局类是PatternLayout,那么class属性可以省略默认的类映射 规则指定。

该<encoder>元素采用指定编码器类的完全限定名实例化的强制类属性。由于这是一个常见的情况,如果编码器类是PatternLayoutEncoder,那么class属性可以省略,如默认的类映射 规则所指定的。

记录到多个appender就像定义各个appender并在记录器中引用它们一样简单,如下面的配置文件所示:

例如:多个记录器(logback-examples / src / main / resources / chapters / configuration / multiple.xml)

查看为.groovy

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

这些配置脚本定义了两个称为FILESTDOUT的 appender 。该文件附加器日志到一个名为myApp.log。此appender的编码器是PatternLayoutEncoder输出日志请求所在的日期,级别,线程名称,记录器名称,文件名和行号,消息和行分隔符。第二个appender调用STDOUT输出到控制台。此appender的编码器仅输出消息字符串,后跟一个行分隔符。

appender通过在appender-ref元素中的名字引用它们来连接到根记录器。请注意,每个appender都有自己的编码器。编码器通常不是被多个appender共享的。布局也是如此。因此,logback配置文件不提供共享编码器或布局的任何语法手段。

Appenders积累

默认情况下,appender是累积的:记录器将记录到附属于自身的appender(如果有的话)以及附属于其祖先的所有appender。因此,将同一appender附加到多个记录器将导致日志记录输出重复。

示例:重复的appender(logback-examples / src / main / resources / chapters / configuration / duplicate.xml)

查看为.groovy

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

MyApp3使用duplicate.xml运行将产生以下输出:

14:25:36.343 [main] INFO  chapters.configuration.MyApp3 - Entering application. 14:25:36.343 [main] INFO  chapters.configuration.MyApp3 - Entering application. 14:25:36.359 [main] DEBUG chapters.configuration.Foo - Did it again! 14:25:36.359 [main] DEBUG chapters.configuration.Foo - Did it again! 14:25:36.359 [main] INFO  chapters.configuration.MyApp3 - Exiting application. 14:25:36.359 [main] INFO  chapters.configuration.MyApp3 - Exiting application.

注意重复的输出。appender命名为STDOUT 附加到两个记录器,root和chapters.configuration。由于根记录器是所有记录器和章节的始祖。chapters.configurationchapters.configuration.MyApp3 andchapters.configuration.Foo的父级,使用这两个记录器的每个记录请求将被输出两次,一次是因为STDOUT 被附加到chapters.configuration,一次因为它附加到root

Appender的兼容性并不意味着成为新用户的陷阱。这是一个非常方便的logback功能。例如,您可以配置日志记录,以使日志消息显示在控制台上(对于系统中的所有日志记录器),而仅来自某些特定记录器的消息流入特定的appender。

示例:多个appender(logback-examples / src / main / resources / chapters / configuration / restricted.xml)

查看为.groovy

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

在这个例子中,控制台appender将记录所有消息(对于系统中的所有记录器),而只有记录源自chapters.configuration记录器及其子项的请求才会进入myApp.log文件。

覆盖默认的累积行为

如果默认的累积行为结果不适合您的需要,您可以通过将可加性标志设置为false来覆盖它。因此,记录器树中的一个分支可能会将输出引导到一组不同于那些树的其余部分的appender。

示例:可加性标志(logback-examples / src / main / resources / chapters / configuration / additivityFlag.xml)

查看为.groovy

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

这个例子中,名为FILE的appender 被附加到了 chapter.configuration.Foo记录器。此外,chapter.configuration.Foo记录器将其可加性标志设置为false,以使其日志输出将被发送到名为FILE的appender,但不发送给层次结构中更高级别的appender。其他记录器仍然无视chapters.configuration.Foo记录器的可加性设置。MyApp3使用additivityFlag.xml配置文件运行应用程序 将从chapters.configuration.MyApp3记录器在控制台上输出结果。但是,从chapter.configuration.Foo输出记录器将出现在 foo.log文件中,并且只出现在该文件中。

设置上下文名称

正如在前面的章节中提到,每个记录器都附加到记录器上下文中。默认情况下,记录器上下文称为“default”。但是,您可以借助<contextName>配置指令设置不同的名称。请注意,一旦设置,记录器上下文名称不能更改。设置上下文名称是一个简单而直接的方法,以便区分登录到同一个目标的多个应用程序。

示例:设置上下文名称并显示它(logback-examples / src / main / resources / chapters / configuration / contextName.xml)

查看为.groovy

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

最后一个例子说明了记录器上下文的命名。 在布局模式中添加contextName转换字将输出所述名称。

变量替代

注意此文档的早期版本使用术语“属性替换”而不是术语“变量”。请考虑这两个术语是可以互换的,尽管后一个术语表达了更清楚的含义。

和许多脚本语言一样,logback配置文件支持定义和替换变量。变量有一个 范围(见下文)。而且,变量可以在配置文件本身,外部文件,外部资源中定义,甚至可以在运行中进行计算和定义

变量替换可以发生在配置文件中可以指定值的任何位置。

变量替换可以发生在配置文件中可以指定值的任何位置。变量替换的语法与Unix shell相似。开始$ {和关闭}之间的字符串被解释为对该属性的引用。对于属性 aName,字符串“$ {aName}”将被替换为aName属性所持有的值。

由于它们经常派上用场,所以HOSTNAME和CONTEXT_NAME变量是自动定义的,并具有上下文范围。鉴于在某些环境下,计算主机名可能需要一些时间,其值是延迟计算(仅在需要时)。而且,HOSTNAME可以直接配置中设置

定义变量

可以在配置文件中一次定义一个变量,或者从外部属性文件或外部资源批量加载变量。由于历史的原因,用于定义变量的XML元素<property>虽然在logback 1.0.7以后,元素<variable>可以互换使用。

下一个示例显示在配置文件的开头声明的变量。然后在文件中使用它来指定输出文件的位置。

示例:简单变量替换(logback-examples / src / main / resources / chapters / configuration / variableSubstitution1.xml)

查看为.groovy

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

下一个示例显示使用System属性来实现相同的结果。该属性没有在配置文件中声明,因此logback将在系统属性中查找它。Java系统属性可以在命令行上设置,如下所示:

java -DUSER_HOME="/home/sebastien" MyApp2

示例:系统变量替换(logback-examples / src / main / resources / chapters / configuration / variableSubstitution2.xml)

查看为.groovy

<configuration>

  <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-examples / src / main / resources / chapters / configuration / variableSubstitution3.xml)

查看为.groovy

<configuration>

  <property file="src/main/java/chapters/configuration/variables1.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>

该配置文件包含对名为variables1.properties的文件的引用 。包含在该文件中的变量将被读取,然后在本地范围内定义。这是variable.properties文件的样子。

示例:变量文件(logback-examples / src / main / resources / chapters / configuration / variables1.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>

领域

可以定义一个属性来插入本地范围上下文范围系统范围中。本地范围是默认的。尽管可以从OS环境中读取变量,但是无法写入OS环境。

局部作用域本地作用域的属性从配置文件定义的角度直到解释/执行所述配置文件结束。作为推论,每当配置文件被解析和执行时,局部范围内的变量都被重新定义。

上下文作用域具有上下文作用域的属性被插入到上下文中,并且与上下文一样长或直到被清除。一旦定义,上下文范围内的属性就是上下文的一部分。因此,它可用于所有日志事件,包括通过序列化发送到远程主机的日志事件。

系统作用域具有系统作用域的属性被插入到JVM的系统属性中,并与JVM一样长或直到被清除。

属性在本地范围中首先查找,在上下文范围内,在系统属性范围内,在OS环境中。

在替换过程中,首先在本地范围内查找属性,在​​上下文范围内,在系统属性范围内,在OS环境中第四个和最后一个。

元素, 元素或元素的范围属性 可用于设置属性的范围。该范围 属性承认“本地”,“环境”和“系统”的字符串作为可能的值。如果未指定,范围始终假定为“本地”。 <property><define><insertFromJNDI>

示例:在“上下文”范围中定义的变量(logback-examples / src / main / resources / chapters / configuration / contextScopedVariable.xml)

查看为.groovy

<configuration>

  <property scope="context" name="nodeId" value="firstNode" />

  <appender name="FILE" class="ch.qos.logback.core.FileAppender">

    <file>/opt/${nodeId}/myApp.log</file>

    <encoder>

      <pattern>%msg%n</pattern>

    </encoder>

  </appender>

  <root level="debug">

    <appender-ref ref="FILE" />

  </root>

</configuration>

在上面的例子中,假设在上下文范围中定义了nodeId属性,它将在每个日志事件中都可用,即使是通过序列化发送到远程主机的日志事件。

变量的默认值

在某些情况下,如果一个变量没有被声明或者它的值为null,那么可能有一个默认值。和Bash shell一样,可以使用“: - ” 运算符来指定默认值。例如,假设名称为aName的变量未定义,将被解释为“黄金”。"${aName:-golden}"

嵌套变量

变量嵌套完全受支持。变量的名称,默认值和值定义都可以引用其他变量。

值嵌套

变量的值定义可以包含对其他变量的引用。假设您希望使用变量来指定目标目录以及文件名,并将这两个变量合并到名为“destination”的第三个变量中。下面显示的属性文件给出了一个例子。

示例:嵌套变量引用(logback-examples / src / main / resources / chapters / configuration / variables2.properties)

USER_HOME=/home/sebastien fileName=myApp.logdestination=${USER_HOME}/${fileName}

请注意,在上面的属性文件中,“destination”由两个其他变量组成,即“USER_HOME”和“fileName”。

示例:使用单独文件进行变量替换(logback-examples / src / main / resources / chapters / configuration / variableSubstitution4.xml)

<configuration>

  <property file="variables2.properties" />

  <appender name="FILE" class="ch.qos.logback.core.FileAppender">

    <file>${destination}</file>

    <encoder>

      <pattern>%msg%n</pattern>

    </encoder>

  </appender>

  <root level="debug">

    <appender-ref ref="FILE" />

  </root>

</configuration>

名称嵌套

引用变量时,变量名称可能包含对另一个变量的引用。例如,如果名为“userid”的变量被分配值“alice”,则“$ {$ {userid} .password}”引用具有名称“alice.password”的变量。

默认值嵌套

变量的默认值可以引用另一个变量。例如,假设变量“id”未赋值,变量“userid”赋值为“alice”,则表达式“$ {id : - $ {userid}}”将返回“alice”。

HOSTNAME属性

由于它经常派上用场,因此HOSTNAME在使用上下文范围进行配置期间,会自动定义该属性。

CONTEXT_NAME属性

如其名称所示,该CONTEXT_NAME属性对应于当前日志记录上下文的名称。

设置时间戳

所述时间戳元件可以根据当前日期和时间定义一个属性。所述时间戳元件在随后的章节说明

动态定义属性

您可以使用<define>元素动态定义属性 。define元素具有两个强制属性:名称。该名称 属性指定设置,而属性的名称 属性指定执行的任何类PropertyDefiner 接口。实例的getPropertyValue()方法返回的值PropertyDefiner将是指定属性的值。你也可以指定一个范围内通过指定的命名属性 范围的属性。

这是一个例子。

<configuration>

  <property file="variables2.properties" />

  <appender name="FILE" class="ch.qos.logback.core.FileAppender">

    <file>${destination}</file>

    <encoder>

      <pattern>%msg%n</pattern>

    </encoder>

  </appender>

  <root level="debug">

    <appender-ref ref="FILE" />

  </root>

</configuration>

在上面的例子中,形状,颜色和大小是“a.class.implementing.PropertyDefiner”的属性。只要在实现PropertyDefiner实例时给定一个属性的setter ,logback就会按照配置文件中的指定注入适当的值。

目前,logback包含两个相当简单的实现PropertyDefiner。

实现名称

描述

FileExistsPropertyDefiner

如果path属性指定的文件存在,则将命名变量设置为“true” ,否则设置为“false”。

ResourceExistsPropertyDefiner

如果用户指定的资源在类路径中可用,则将命名变量设置为“true” ,否则设置为“false”。

有条件处理配置文件

开发人员通常需要在针对不同环境(例如开发,测试和生产)的多个logback配置文件之间进行操作。这些配置文件只有少数几个地方有很多共同之处。为了避免重复,支持的logback用的帮助下配置文件条件处理<if>, <then>和<else>元素,以便一个配置文件能充分瞄准几个环境。请注意,条件处理需要Janino

条件语句的一般格式如下所示。

      <!-- if-then form -->

   <if condition="some conditional expression">

    <then>

      ...

    </then>

  </if>

 

  <!-- if-then-else form -->

  <if condition="some conditional expression">

    <then>

      ...

    </then>

    <else>

      ...

    </else>    

  </if>

该条件是一个只能访问上下文属性或系统属性的Java表达式。对于作为参数传递的键,property()或其较短的equivalent p()方法返回属性的String值。例如,要使用键“k”访问一个属性的值,你可以写property("k")或等价 p("k")。如果具有键“k”的属性未定义,则属性方法将返回空字符串,而不是空值。这避免了需要检查空值。

该isDefined()方法可以用来检查属性是否被定义。例如,要检查是否定义了属性“k”,您将编写isDefined("k") 类似的,如果您需要检查属性是否为空,isNull()则提供该 方法。例如: isNull("k")。

<configuration debug="true">

  <if condition='property("HOSTNAME").contains("torino")'>

    <then>

      <appender name="CON" class="ch.qos.logback.core.ConsoleAppender">

        <encoder>

          <pattern>%d %-5level %logger{35} - %msg %n</pattern>

        </encoder>

      </appender>

      <root>

        <appender-ref ref="CON" />

      </root>

    </then>

  </if>

  <appender name="FILE" class="ch.qos.logback.core.FileAppender">

    <file>${randomOutputDir}/conditional.log</file>

    <encoder>

      <pattern>%d %-5level %logger{35} - %msg %n</pattern>

   </encoder>

  </appender>

  <root level="ERROR">

     <appender-ref ref="FILE" />

  </root>

</configuration>

条件处理在 元素的任何地方都受支持<configuration>。嵌套的if-then-else语句也被支持。但是,XML语法非常麻烦,不适合作为通用编程语言的基础。因此,太多的条件会很快使您的配置文件无法理解,包括您自己在内的后续读者。

从JNDI获取变量

在某些情况下,您可能想要使用存储在JNDI中的env-entries。所述<insertFromJNDI> 配置指令提取存储在一个JNDI ENV-条目,并插入与由指定键在本地范围的属性作为属性。作为所有属性,可以使用scope属性将新属性插入到不同的作用域中

示例:插入作为通过JNDI获取的属性env-entries(logback-examples / src / main / resources / chapters / configuration / insertFromJNDI.xml)

<configuration>

  <insertFromJNDI env-entry-name="java:comp/env/appName" as="appName" />

  <contextName>${appName}</contextName>

  <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">

    <encoder>

      <pattern>%d ${CONTEXT_NAME} %level %msg %logger{50}%n</pattern>

    </encoder>

  </appender>

  <root level="DEBUG">

    <appender-ref ref="CONSOLE" />

  </root>

</configuration>

在这最后一个示例中,“java:comp / env / appName”env-entry作为appName属性插入。请注意,该<contextName>指令根据 前 一条指令插入的appName属性的值来设置上下文名称<insertFromJNDI>。

文件包含

Joran支持从另一个文件中包含配置文件的一部分。这是通过声明一个<include> 元素完成的,如下所示:

示例:文件包括(logback-examples / src / main / resources / chapters / configuration / containedConfig.xml)

<configuration>

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

  <root level="DEBUG">

    <appender-ref ref="includedConsole" />

  </root>

</configuration>

目标文件必须将其元素嵌套在 <included>元素中。例如,一个 ConsoleAppender可以被声明为:

示例:文件include(logback-examples / src / main / resources / chapters / configuration / includedConfig.xml)

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

请再次注意强制性 <included>元素。

要包含的内容可以作为文件,资源或URL来引用。

  1. 作为文件:

要包含文件,请使用文件属性。您可以使用相对路径,但请注意,当前目录由应用程序定义,并不一定与配置文件的路径相关。

  1. 作为资源:

要包含资源,即在类路径中找到的文件,请使用资源属性。

<include resource = “includedConfig.xml” />

  1. 作为URL:

要包含URL的内容,请使用url属性。

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

如果找不到要包含的文件,logback将通过打印状态消息来投诉。如果包含的文件是可选的,则可以通过在 元素中设置可选属性来禁止警告消息。true<include>

<include optional = “true” .... />

添加一个上下文监听器

LoggerContextListener 接口的实例监听关于记录器上下文生命周期的事件。

JMXConfigurator是LoggerContextListener界面的一个实现 。这在后面的章节中有描述。

LevelChangePropagator

从版本0.9.25开始,logback-classic带有LevelChangePropagator,它的一个实现LoggerContextListener将对任何logback-classic记录器级别的更改传播到java.util.logging框架。这种传播消除了禁用的日志语句对性能的影响。LogRecord实例 将仅发送到logback(通过SLF4J)用于启用日志语句。这使得真实世界的应用程序使用jul-to-slf4j 桥是合理的。

contextListener元素可以用来安装LevelChangePropagator,如下所示。

<configuration debug="true">

  <contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator"/>

  ....

</configuration>

设置LevelChangePropagator的resetJUL属性将重置所有

第3章:Logback配置

 

在符号中,人们发现了一个优点,那就是当他们简单地表达一个事物的确切性质时,它就是最大的发现。那么思想的工作确实是奇妙地减少了。

-GOTTFRIED WILHELM LEIBNIZ

 

我们首先介绍配置logback的方法,并配置了许多示例配置脚本。Joran,logback所依赖的配置框架将在后面的章节中介绍

在的logback中配置

将日志请求插入到应用程序代码中需要进行相当多的计划和努力。观察表明,大约百分之四的代码是专门用来记录的。因此,即使是中等大小的应用程序也会包含嵌入代码中的数千条日志语句。鉴于他们的数量,我们需要工具来管理这些日志语句。

Logback可以通过编程或用XML或Groovy格式表示的配置脚本进行配置。顺便说一下,现有的log4j用户可以使用我们的 PropertiesTranslator web应用程序将他们的log4j.properties文件转换 为logback.xml

让我们从讨论logback的初始化步骤开始,尝试配置它自己:

1.Logback试图在类路径中找到名为logback-test.xml 的文件 。

2.如果找不到这样的文件,logback会尝试在类路径中找到一个名为logback.groovy 的文件 。

3.如果找不到这样的文件,它会检查类路径中的文件 logback.xml 。

4.如果没有找到这样的文件,服务提供者加载器(jdk1.6中介绍,ServiceLoader)会在类路径中,查找META-INF\services\ch.qos.logback.classic.spi.Configurator文件,来解析com.qos.logback.classic.spi.Configurator接口的实现。其内容应该指定Configurator实现类的全限定名。

5.如果以上都不成功,则使用logback自动配置BasicConfigurator ,这将导致日志记录输出被定向到控制台。

最后一步的意思是在没有配置文件的情况下提供默认(但非常基本的)日志记录功能。

如果您使用的是Maven,并且如果将 logback-test.xml放在src/test/resources 文件夹下,Maven将确保它不会包含在编译的文件中。因此,您可以使用不同的配置文件,即测试期间的logback-test.xml和生产中的另一个文件(即logback.xml)。

快速启动 Joran解析给定的logback配置文件需要大约100毫秒的时间。为了在应用程序启动时削减这些毫秒数,可以使用服务提供者加载工具(上面的第4项)来用BasicConfigrator加载您自己的自定义Configurator类作为一个很好的起点 。

自动配置的logback

配置logback的最简单方法是让logback回到默认配置。让我们尝试一下如何在一个名为虚构的应用程序中完成这项工作 MyApp1。

示例:简单 BasicConfigurator使用示例(logback-examples / src / main / java / chapters / configuration / MyApp1.java

package chapters.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.");

  }

}

这个类定义了一个静态logger变量。然后它实例化一个Foo对象。这个Foo类如下所示:

例子:做日志的小类 (logback-examples / src / main / java / chapters / configuration / Foo.java

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!");

  }

}

为了运行本章中的示例,您需要确保某些jar文件存在于类路径中。请参阅设置页面了解更多详情。

假设配置文件logback-test.xml或 logback.xml不存在,logback将默认调用BasicConfigurator 将设置最小配置。这个最小的配置包括一个ConsoleAppender附加到根记录器。输出的格式PatternLayoutEncoder设置为 %d {HH:mm:ss.SSS} [%thread]%-5level%logger {36} - %msg%n。而且,默认情况下根记录器被分配DEBUG 级别。

因此,命令java chapters.configuration.MyApp1的输出 应该类似于:

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.

除了配置logback的代码(如果存在这样的代码),客户端代码不需要依赖于logback。使用logback作为其日志框架的应用程序将对SLF4J具有编译时间依赖性,但不包括logb​​ack。

该MyApp1应用程序链接到通过调用的logback org.slf4j.LoggerFactory和 org.slf4j.Logger类,检索它希望使用的logger。请注意,Foo类的唯一依赖关系是通过 org.slf4j.LoggerFactory和 org.slf4j.Logger导入。除了配置logback的代码(如果存在这样的代码),客户端代码不需要依赖于logback。由于SLF4J允许在其抽象层下使用任何日志框架,所以很容易将大量代码从一个日志框架迁移到另一个日志框架。

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

如前所述,logback将尝试使用文件logback-test.xmllogback.xml进行自我配置。这是一个相当于BasicConfigurator我们刚刚看到的配置文件。

示例:基本配置文件(logback-examples / src / main / resources / chapters / configuration / sample0.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>

sample0.xml重命名为 logback.xml(或logback-test.xml)后,将其放入可从类路径访问的目录中。运行MyApp1 应用程序应该与它以前的运行相同的结果。

在出现警告或错误时自动打印状态消息

如果在解析配置文件的过程中发生警告或错误,则logback将自动在控制台上打印其内部状态消息。

如果在解析配置文件的过程中出现警告或错误,logback将自动将其内部状态数据打印在控制台上。请注意,为避免重复,如果用户显式注册状态监听器(以下定义),则禁用自动状态打印。

在没有警告或错误的,如果你还希望检查的logback的内部状态,那么你就可以指示的logback通过调用打印状态数据print()的的 StatusPrinter类。所述MyApp2下面所示的应用是相同的MyApp1除了添加的两行代码打印内部状态数据。

例如:打印logback的内部状态信息(logback-examples / src / main / java / chapters / configuration/MyApp2.java

public static void main String [] args ){  

  //假定SLF4J在当前环境中被绑定到logback

  LoggerContext lc = LoggerContext LoggerFactory.getILoggerFactory ();

  //打印logback的内部状态

  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.

在输出结束时,您可以识别上例中打印的行。你还应该注意到logback的内部消息,也就是Status对象,它允许方便地访问logback的内部状态。

状态数据

状态数据的输出通常在诊断logback问题方面有很长的路要走。因此,这是强烈建议,应该考虑作为第一手段的追索 。

而不是StatusPrinter从代码中以编程方式调用,即使没有错误,也可以指示配置文件转储状态数据。为此,需要设置configuration元素的debug属性 ,即配置文件中最顶层的元素,如下所示。请注意,这个debug属性只与状态数据有关。它并不会影响logback的配置,特别是相对于logger级别。(如果你想问根logger将会不会被设置DEBUG。) 

示例:使用调试模式的基本配置文件(logback-examples / src / main / resources / chapters / configuration / sample1.xml)

 

<configuration debug = “true” > 

  <appender name = “STDOUT” class = “ch.qos.logback.core.ConsoleAppender” >  

    <! - 编码器是默认分配的类型

         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>

设置debug="true"在<configuration>元素会输出状态信息,前提是:

  1. 找到配置文件
  2. 配置文件是格式良好的XML。

如果这两个条件中的任何一个没有满足,Joran不能解释debug属性,因为配置文件不能被读取。如果找到配置文件但格式不正确,则logback将检测到错误情况并自动在控制台上打印其内部状态。但是,如果找不到配置文件,logback将不会自动打印其状态数据,因为这不一定是错误状态。StatusPrinter.print()如 上面MyApp2应用程序中所示,以编程方式调用 可确保在每种情况下都打印状态信息。

强制状态输出在缺少状态消息的情况下,追踪恶意logback.xml 配置文件可能会很困难,尤其是在应用程序源不易修改的生产环境中。为了帮助识别流氓配置文件的位置,可以 StatusListener通过“logback.statusListenerClass”系统属性(定义如下)设置强制输出状态消息。“logback.statusListenerClass”系统属性也可用于在发生错误时自动生成静音输出。

顺便说一句,设置debug="true"严格等于安装一个 OnConsoleStatusListener。状态监听器在下面进一步讨论。下面显示安装 OnConsoleStatusListener。

示例:注册状态侦听器(logback-examples / src / main / resources / chapters / configuration / onConsoleStatusListener.xml)

查看为.groovy

<configuration>

<statusListener class = “ch.qos.logback.core.status.OnConsoleStatusListener” />

  ... ... 配置文件的其余部分  

</configuration>

通过调试属性或等效地安装来启用状态数据的输出OnConsoleStatusListener将有助于诊断回退问题。因此,非常强烈地建议启用回溯状态数据,并且应该被视为第一手段的追索。

指定默认配置文件的位置作为系统属性

您可以使用名为system的属性来指定默认配置文件的位置 "logback.configurationFile"。此属性的值可以是URL,类路径上的资源或应用程序外部文件的路径。

java -Dlogback.configurationFile = /path/to/config.xml chapters.configuration.MyApp1

请注意,文件扩展名必须是“.xml”或“.groovy”。其他扩展名被忽略。显式注册状态监听器可能有助于调试定位配置文件的问题。

修改后自动重新加载配置文件

Logback-classic可以扫描其配置文件中的更改,并在配置文件更改时自动重新配置自身。

如果指示这样做,logback-classic将扫描其配置文件中的更改,并在配置文件更改时自动重新配置自身。为了指示logback-classic扫描其配置文件中的更改,并自动重新配置自身,请将元素的scan属性 设置<configuration>为true,如下所示。

示例:扫描配置文件中的更改并自动重新配置(logback-examples / src / main / resources / chapters / configuration / scan1.xml)

查看为.groovy

<configuration scan = “true” > 

  ...

</configuration>

默认情况下,配置文件将每分钟扫描一次更改。您可以通过设置元素的scanPeriod属性 来指定不同的扫描周期<configuration>。值可以以毫秒,秒,分钟或小时为单位指定。这里是一个例子:

示例:指定不同的扫描周期(logback-examples / src / main / resources / chapters / configuration / scan2.xml)

查看为.groovy

<configuration scan = “true” scanPeriod = “30 seconds” >   

  ...

<configuration >

注意如果没有指定时间单位,则时间单位被认为是毫秒,这通常是不合适的。如果更改默认的扫描周期,请不要忘记指定一个时间单位。

在幕后,当您将scan属性设置为true时, 将会安装一个 名为ReconfigureOnChangeFilterTurboFilter。TurboFilters将在后面的章节中介绍。因此,扫描是在“线程内”完成的,也就是说,任何时候都可以调用logger的打印方法。例如,对于名为myLogger的logger,在编写“myLogger.debug(”hello“);”时,如果scan属性设置为true,ReconfigureOnChangeFilter则将被调用。而且,即使myLogger在DEBUG级别被禁用,所述过滤器也将被调用 。

当一个配置文件改变时,它将被自动重新加载,但是只有在多个logger调用之后并且在由扫描周期确定的延迟之后。

鉴于ReconfigureOnChangeFilter每次调用任何logger时都会调用,而不管logger级别如何,ReconfigureOnChangeFilter绝对是性能至关重要的。事实上,检查扫描周期是否已经过去,本身太昂贵了。为了提高性能, ReconfigureOnChangeFilter实际上在每N次日志作业中“活着”一次。根据您的应用程序记录的频率,N的值可以通过logback实时修改。默认情况下,N是16,但对于CPU密集型应用程序来说,它可以高达2 ^ 16(= 65536)。

简而言之,当一个配置文件发生变化时,它将被自动重新加载,但是只有在几个logger调用 之后以及由扫描周期确定的延迟之后。

 

在堆栈跟踪中启用打包数据

封装数据虽然有用,但计算起来很昂贵,特别是在频繁出现异常的应用中。

注意从版本1.1.4开始,打包数据默认是禁用的。

如果确定这样做,logback可以输出它包括的每一行的堆栈跟踪行的打包数据。打包数据由栈文件的名称和版本组成,从而产生堆栈跟踪行的类。打包数据在识别软件版本问题方面非常有用。但是,计算起来相当昂贵,特别是在频繁抛出异常的应用程序中。这是一个示例输出:

14:28:48.835 [btpool0-7] INFO  c.q.l.demo.prime.PrimeAction - 99 is not a valid value

java.lang.Exception: 99 is invalid

  at ch.qos.logback.demo.prime.PrimeAction.execute(PrimeAction.java:28) [classes/:na]

  at org.apache.struts.action.RequestProcessor.processActionPerform(RequestProcessor.java:431) [struts-1.2.9.jar:1.2.9]

  at org.apache.struts.action.RequestProcessor.process(RequestProcessor.java:236) [struts-1.2.9.jar:1.2.9]

  at org.apache.struts.action.ActionServlet.doPost(ActionServlet.java:432) [struts-1.2.9.jar:1.2.9]

  at javax.servlet.http.HttpServlet.service(HttpServlet.java:820) [servlet-api-2.5-6.1.12.jar:6.1.12]

  at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:502) [jetty-6.1.12.jar:6.1.12]

  at ch.qos.logback.demo.UserServletFilter.doFilter(UserServletFilter.java:44) [classes/:na]

  at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1115) [jetty-6.1.12.jar:6.1.12]

  at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:361) [jetty-6.1.12.jar:6.1.12]

  at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:417) [jetty-6.1.12.jar:6.1.12]

  at org.mortbay.jetty.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:230) [jetty-6.1.12.jar:6.1.12]

打包数据默认是禁用的,但可以通过配置启用:

<configuration packagingData = “true” >

  ...

</configuration >

或者,可以在LoggerContext内通过调用setPackagingDataEnabled(boolean 方法以编程方式启用/禁用打包数据,如下所示:

LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();

  lc.setPackagingDataEnabled(true);

 

JoranConfigurator直接调用

Logback依赖于称为Joran的配置库,它是logback-core的一部分。Logback的默认配置机制会调用 JoranConfigurator它在类路径上找到的默认配置文件。如果您希望覆盖logback的默认配置机制,可以通过JoranConfigurator直接调用来实现。下一个程序,MyApp3,调用上作为参数传递的配置文件JoranConfigurator。

示例:JoranConfigurator 直接调用(logback-examples / src / main / java / chapters / configuration / MyApp3.java

package chapters.configuration;

 

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

 

import ch.qos.logback.classic.LoggerContext;

import ch.qos.logback.classic.joran.JoranConfigurator;

import ch.qos.logback.core.joran.spi.JoranException;

import ch.qos.logback.core.util.StatusPrinter;

 

public class MyApp3 {

  final static Logger logger = LoggerFactory.getLogger(MyApp3.class);

 

  public static void main(String[] args) {

    // assume SLF4J is bound to logback in the current environment

    LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();

   

    try {

      JoranConfigurator configurator = new JoranConfigurator();

      configurator.setContext(context);

      // Call context.reset() to clear any previous configuration, e.g. default

      // configuration. For multi-step configuration, omit calling context.reset().

      context.reset();

      configurator.doConfigure(args[0]);

    } catch (JoranException je) {

      // StatusPrinter will handle this

    }

    StatusPrinter.printInCaseOfErrorsOrWarnings(context);

 

    logger.info("Entering application.");

 

    Foo foo = new Foo();

    foo.doIt();

    logger.info("Exiting application.");

  }

}

此应用程序获取LoggerContext 当前有效的信息,创建一个新的信息JoranConfigurator,设置它将在其上运行的上下文,重置记录器上下文,然后最终要求配置器使用作为参数传递给应用程序的配置文件来配置上下文。在出现警告或错误的情况下打印内部状态数据。请注意,对于多步骤配置, context.reset()应该省略调用。

查看状态消息

Logback将其内部状态数据收集到一个StatusManager 对象中,可通过LoggerContext访问。

给定一个StatusManager你可以访问所有与一个logback上下文相关的状态数据。为了将内存使用保持在合理的水平,默认StatusManager 实现将状态消息存储在两个独立的部分:头部分和尾部分。标题部分存储第一个 H状态消息,尾部存储最后的 T消息。目前时间H = T = 150,尽管这些值在未来的版本中可能会改变。

Logback-classic,带有一个叫做ViewStatusMessagesServlet的servlet。这个servlet StatusManager将当前关联 的内容打印 LoggerContext成HTML表格。这里是示例输出。

 

点击放大

要将此servlet添加到您的Web应用程序,请将以下行添加到其WEB-INF/web.xml文件中。

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

该ViewStatusMessagesservlet将在URL中可见http://host/yourWebapp/lbClassicStatus

收听状态消息

您也可以添加一个StatusListener到StatusManager,以便您可以立即采取措施来响应状态消息,尤其是对于在logback配置发生的消息。注册一个状态监听器是一个方便的方式来监督logback的内部状态,无需人工干预。

Logback附带一个名为OnConsoleStatusListener 的StatusListener实现,如名称所示,在控制台上打印所有新的传入状态消息。

以下是 使用StatusManager 注册实例的示例代码OnConsoleStatusListener。

   LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();

   StatusManager statusManager = lc.getStatusManager();

   OnConsoleStatusListener onConsoleListener = new OnConsoleStatusListener();

   statusManager.add(onConsoleListener);

请注意,注册状态监听器只会在注册后接收状态事件。它不会收到事先的消息。因此,在其他指令之前,将状态监听器注册指令放置在配置文件的顶部通常是一个好主意。

也可以在配置文件中注册一个或多个状态监听器。这是一个例子。

示例:注册状态侦听器(logback-examples/src/main/resources/chapters/configuration/onConsoleStatusListener.xml)

查看为.groovy

<configuration>

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

 

  ... the rest of the configuration file  

</configuration>

“logback.statusListenerClass”系统属性

也可以通过“logback.statusListenerClass”Java系统属性,去设置您希望注册的侦听器类的名称。例如,

java -Dlogback.statusListenerClass = ch.qos.logback.core.status.OnConsoleStatusListener ...

Logback附带有几个状态监听器实现。OnConsoleStatusListener 在控制台上打印传入的状态消息,即在System.out上。OnErrorConsoleStatusListener 在System.err上打印传入的状态消息。NopStatusListener 丢弃传入的状态消息。

请注意,如果在配置期间注册了状态侦听器,并且特别是在用户通过“logback.statusListenerClass”系统指定状态侦听器时,自动状态打印(如果有错误)将被禁用。因此,通过设置NopStatusListener状态监听器,可以完全禁止内部状态打印。

java -Dlogback.statusListenerClass = ch.qos.logback.core.status.NopStatusListener ...

停止logback-classic

为了释放logback-classic使用的资源,停止logback上下文总是一个好主意。停止上下文将关闭所有附加到由上下文定义的记录器的appender,并停止任何活动的线程。

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();

在web应用程序中,可以从contextDestroyed 方法中调用上面的代码ServletContextListener,以停止logback-classic和release资源。从版本1.1.10开始,适合ServletContextListener自动安装(见下文)。

通过关闭挂钩停止logback-classic

安装JVM关闭挂钩是关闭logback和释放相关资源的一种便捷方式。

<configuration debug = “true” >

   <! - 在没有class属性的情况下,假设

   ch.qos.logback.core.hook.DelayingShutdownHook  - >

   <shutdownHook />

  ....

</configuration >

默认关闭挂钩,即DelayingShutdownHook,可以延迟用户指定的持续时间关机。请注意,您可以通过设置class属性来对应您的关闭钩子的类名称来安装自己的关闭钩子。

在web应用程序中停止logback-classic

自从1.1.10 Logback-classic会 自动要求Web服务器安装一个LogbackServletContainerInitializer 实现ServletContainerInitializer接口(在servlet-api 3.x和更高版本中可用)。这个初始化器将依次安装和实例化LogbackServletContextListener。这个监听器将停止或重新加载Web应用程序时停止当前的logback-classic上下文。

您可以在web应用程序的web.xml文件中通过设置一个名为logbackDisableServletContainerInitializer的<context-param> 来禁用自动安装 LogbackServletContextListener。这是相关的片段。

<web-app>

    <的context-param>

        <param-name>logbackDisableServletContainerInitializer</ param-name>

        <param-value>true</ param-value>

    </的context-param>

    ....

</ web-app>

请注意, logbackDisableServletContainerInitializer变量也可以被设置为Java系统属性的OS环境变量。最本地的设置有优先级,即Web应用优先,系统属性优先和OS环境优先。

配置文件语法

正如您在手册中所看到的,还有大量示例仍然遵循,logback允许您重新定义日志记录行为,而无需重新编译代码。事实上,您可以轻松地配置logback,以便禁用应用程序某些部分的日志记录,或者直接输出到UNIX Syslog守护进程,数据库,日志可视化器或将日志记录事件转发到远程Logback服务器,Log根据本地服务器策略,例如通过将日志事件转发到第二个Logback服务器。

本节的其余部分介绍了配置文件的语法。

正如一遍又一遍地演示的那样,logback配置文件的语法是非常灵活的。因此,使用DTD文件或XML模式指定允许的语法是不可能的。尽管如此,配置文件的基本结构可以被描述为<configuration>元素,包含零个或多个<appender>元素,后面是零个或多个<logger>元素,最多是一个<root>元素。下图说明了这个基本结构。

基本的语法

如果您不确定给定标签名称使用哪种情况,只需按照几乎总是正确的惯例的camelCase约定即可。

标签名称的大小写敏感性

自从logback版本0.9.17以来,与显式规则相关的标签名是不区分大小写的。例如,<logger>,<Logger>和 <LOGGER>是有效的配置元素,并将以同样的方式来解释。请注意,XML格式良好的规则仍然适用,如果您打开一个标签,因为<xyz>您必须关闭它</xyz>,</XyZ> 将无法正常工作。至于隐式规则,除第一个字母外,标签名称区分大小写。因此,<xyz>和<Xyz>是等价的,但不是<xYz>。隐式规则通常遵循camelCase 约定,在Java世界中很常见。由于不容易判断一个标签何时与一个明确的动作相关联,以及何时与一个隐含的动作相关联,所以说一个XML标签对于第一个字母是区分大小写还是不灵敏。如果您不确定给定标签名称使用哪种情况,只需遵循几乎总是正确的惯例的camelCase约定。

配置loggers或<logger>元素

在这一点上,你应该至少有一些水平继承的理解和基本的选择规则。否则,除非你是埃及学家,否则logback配置对你来说不会比象形文字更有意义。

记录器使用该<logger> 元素进行配置。一个<logger>元素只需要一个强制name属性,一个可选的level属性和一个可选的additivity属性,允许值为 truefalselevel属性的值允许不区分大小写的字符串值TRACE,DEBUG,INFO,WARN,ERROR,ALL或OFF之一。不区分大小写的特殊值INHERITED,或其同义词NULL,将强制logger的层次从层次结构中的较高层继承。如果您设置logger的级别并稍后决定它应该继承它的级别,这将派上用场。

需要注意的是不同的log4j,的logback-classic确实没有关闭,也没有在配置给定的logger时,删除任何先前提及appenders程序。

该<logger>元件可含有零个或多个 <appender-ref>元素; 每个这样引用的appender被添加到指定的logger。需要注意的是不同的log4j,的logback-classic确实没有关闭,也没有配置给定的logger时,删除任何先前提及appenders程序。

配置根logger或<root>元素

<root>元素配置根logger。它仅支持一个属性,即level属性。它不允许任何其他属性,因为可加性标志不适用于根logger。而且,由于根logger已经被命名为“ROOT”,所以它也不允许名称属性。level属性的值可以是不区分大小写的字符串之一TRACE,DEBUG,INFO,WARN,ERROR,ALL或OFF。请注意,根logger的level不能设置为INHERITED或NULL。

需要注意的是不同的log4j,的logback-classic确实没有关闭,也没有在配置给定的logger时,删除任何先前提及appenders程序。

与<logger>元素类似, <root>元素可以包含零个或多个 <appender-ref>元素; 由此引用的每个appender被添加到根logger。需要注意的是不同的log4j,的logback-classic确实没有关闭,也没有配置给定的logger时,删除任何先前提及appenders程序。

如下例所示,设置logger或根logger的level与声明和设置level一样简单。假设我们不再有兴趣看到来自属于“chapters.configuration”包的任何组件的任何DEBUG消息。以下配置文件显示了如何实现这一点。

示例:设置logger的级别(logback-examples/src/main/resources/chapters/configuration/sample2.xml)

查看为.groovy

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

当上面的配置文件作为MyApp3应用程序的参数给出时 ,它将产生以下输出:

17:34:07.578 [main] INFO  chapters.configuration.MyApp3 - Entering application. 17:34:07.578 [main] INFO  chapters.configuration.MyApp3 - Exiting application.

请注意,由“chapters.configuration.Foo” logger生成的DEBUG级别消息已被取消。另见Foo类。

您可以根据需要配置尽可能多的logger的级别。在下一个配置文件中,我们将chapters.configuration logger的级别设置 为INFO,但同时设置chapters.configuration.Foo logger的级别为DEBUG。

示例:设置多个记录器的级别(logback-examples/src/main/resources/chapters/configuration/sample3.xml)

查看为.groovy

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

MyApp3使用此配置文件运行将在控制台上产生以下输出:

17:39:27.593 [main] INFO chapters.configuration.MyApp3 - Entering application. 17:39:27.593 [main] DEBUG chapters.configuration.Foo - Did it again! 17:39:27.593 [main] INFO chapters.configuration.MyApp3 - Exiting application.

下表列出了JoranConfigurator使用sample3.xml配置文件配置logback 之后的记录器及其级别 。

Logger名称

指定level

有效的level

root

DEBUG

DEBUG

chapters.configuration

INFO

INFO

chapters.configuration.MyApp3

null

INFO

chapters.configuration.Foo

DEBUG

DEBUG

由此可见,水平两个记录语句 INFO中MyApp3类以及在调试消息Foo.doIt()都被启用。请注意,根logger的级别始终设置为非空值,默认情况下为DEBUG。

让我们注意到基本选择规则 取决于被调用的logger的有效等级,而不是附加器附加的logger的等级。Logback将首先确定是否启用日志记录语句,如果启用,则将调用logger层次结构中的appender,而不管其级别如何。配置文件 sample4.xml就是一个例子:

示例:记录器级别示例(logback-examples/src/main/resources/chapters/configuration/sample4.xml)

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

下表列出了应用sample4.xml配置文件后的记录器及其级别。

logger名称

指定级别

有效的水平

root

OFF

OFF

chapters.configuration

INFO

INFO

chapters.configuration.MyApp3

null

INFO

chapters.configuration.Foo

null

INFO

命名为STDOUT的ConsoleAppender 是sample4.xml中唯一配置的appender ,连接到级别设置为OFF的根logger。但是,运行 MyApp3与配置脚本sample4.xml将产生:

17:52:23.609 [main] INFO chapters.configuration.MyApp3 - Entering application. 17:52:23.609 [main] INFO chapters.configuration.MyApp3 - Exiting application.

因此,根记录器的级别没有明显的效果,因为级别中的记录器chapters.configuration.MyApp3和 chapters.configuration.Foo类都已启用 INFO。作为一个方面说明chapters.configuration logger凭借其在配置文件中的声明而存在 - 即使Java源代码不直接引用它。

配置Appender

appender配置了这个<appender> 元素,这个元素需要两个强制属性nameclass。该name属性声明appender的名称,class属性指定的appender类实例化的全限定名。该<appender>元件可含有零个或一个<layout>元素,零个或多个 <encoder>元件以及零层或更多 <filter>的元件。除了这三个公共元素之外,<appender>元素可以包含与appender类的JavaBean属性相对应的任意数量的元素。无缝支持给定logback组件的任何属性是Joran的主要优势之一正如后面的章节所讨论的那样。下图说明了常见的结构。请注意,对属性的支持不可见。

Appender语法

该<layout>元素采用强制性的类属性来指定要实例化的布局类的完全限定名。与<appender>元素一样, <layout>可以包含与布局实例的属性相对应的其他元素。由于这是一个常见的情况,如果布局类是PatternLayout,那么class属性可以省略默认的类映射 规则指定。

该<encoder>元素采用指定编码器类的完全限定名实例化的强制类属性。由于这是一个常见的情况,如果编码器类是PatternLayoutEncoder,那么class属性可以省略,如默认的类映射 规则所指定的。

记录到多个appender就像定义各个appender并在记录器中引用它们一样简单,如下面的配置文件所示:

例如:多个记录器(logback-examples / src / main / resources / chapters / configuration / multiple.xml)

查看为.groovy

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

这些配置脚本定义了两个称为FILESTDOUT的 appender 。该文件附加器日志到一个名为myApp.log。此appender的编码器是PatternLayoutEncoder输出日志请求所在的日期,级别,线程名称,记录器名称,文件名和行号,消息和行分隔符。第二个appender调用STDOUT输出到控制台。此appender的编码器仅输出消息字符串,后跟一个行分隔符。

appender通过在appender-ref元素中的名字引用它们来连接到根记录器。请注意,每个appender都有自己的编码器。编码器通常不是被多个appender共享的。布局也是如此。因此,logback配置文件不提供共享编码器或布局的任何语法手段。

Appenders积累

默认情况下,appender是累积的:记录器将记录到附属于自身的appender(如果有的话)以及附属于其祖先的所有appender。因此,将同一appender附加到多个记录器将导致日志记录输出重复。

示例:重复的appender(logback-examples / src / main / resources / chapters / configuration / duplicate.xml)

查看为.groovy

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

MyApp3使用duplicate.xml运行将产生以下输出:

14:25:36.343 [main] INFO  chapters.configuration.MyApp3 - Entering application. 14:25:36.343 [main] INFO  chapters.configuration.MyApp3 - Entering application. 14:25:36.359 [main] DEBUG chapters.configuration.Foo - Did it again! 14:25:36.359 [main] DEBUG chapters.configuration.Foo - Did it again! 14:25:36.359 [main] INFO  chapters.configuration.MyApp3 - Exiting application. 14:25:36.359 [main] INFO  chapters.configuration.MyApp3 - Exiting application.

注意重复的输出。appender命名为STDOUT 附加到两个记录器,root和chapters.configuration。由于根记录器是所有记录器和章节的始祖。chapters.configurationchapters.configuration.MyApp3 andchapters.configuration.Foo的父级,使用这两个记录器的每个记录请求将被输出两次,一次是因为STDOUT 被附加到chapters.configuration,一次因为它附加到root

Appender的兼容性并不意味着成为新用户的陷阱。这是一个非常方便的logback功能。例如,您可以配置日志记录,以使日志消息显示在控制台上(对于系统中的所有日志记录器),而仅来自某些特定记录器的消息流入特定的appender。

示例:多个appender(logback-examples / src / main / resources / chapters / configuration / restricted.xml)

查看为.groovy

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

在这个例子中,控制台appender将记录所有消息(对于系统中的所有记录器),而只有记录源自chapters.configuration记录器及其子项的请求才会进入myApp.log文件。

覆盖默认的累积行为

如果默认的累积行为结果不适合您的需要,您可以通过将可加性标志设置为false来覆盖它。因此,记录器树中的一个分支可能会将输出引导到一组不同于那些树的其余部分的appender。

示例:可加性标志(logback-examples / src / main / resources / chapters / configuration / additivityFlag.xml)

查看为.groovy

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

这个例子中,名为FILE的appender 被附加到了 chapter.configuration.Foo记录器。此外,chapter.configuration.Foo记录器将其可加性标志设置为false,以使其日志输出将被发送到名为FILE的appender,但不发送给层次结构中更高级别的appender。其他记录器仍然无视chapters.configuration.Foo记录器的可加性设置。MyApp3使用additivityFlag.xml配置文件运行应用程序 将从chapters.configuration.MyApp3记录器在控制台上输出结果。但是,从chapter.configuration.Foo输出记录器将出现在 foo.log文件中,并且只出现在该文件中。

设置上下文名称

正如在前面的章节中提到,每个记录器都附加到记录器上下文中。默认情况下,记录器上下文称为“default”。但是,您可以借助<contextName>配置指令设置不同的名称。请注意,一旦设置,记录器上下文名称不能更改。设置上下文名称是一个简单而直接的方法,以便区分登录到同一个目标的多个应用程序。

示例:设置上下文名称并显示它(logback-examples / src / main / resources / chapters / configuration / contextName.xml)

查看为.groovy

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

最后一个例子说明了记录器上下文的命名。 在布局模式中添加contextName转换字将输出所述名称。

变量替代

注意此文档的早期版本使用术语“属性替换”而不是术语“变量”。请考虑这两个术语是可以互换的,尽管后一个术语表达了更清楚的含义。

和许多脚本语言一样,logback配置文件支持定义和替换变量。变量有一个 范围(见下文)。而且,变量可以在配置文件本身,外部文件,外部资源中定义,甚至可以在运行中进行计算和定义

变量替换可以发生在配置文件中可以指定值的任何位置。

变量替换可以发生在配置文件中可以指定值的任何位置。变量替换的语法与Unix shell相似。开始$ {和关闭}之间的字符串被解释为对该属性的引用。对于属性 aName,字符串“$ {aName}”将被替换为aName属性所持有的值。

由于它们经常派上用场,所以HOSTNAME和CONTEXT_NAME变量是自动定义的,并具有上下文范围。鉴于在某些环境下,计算主机名可能需要一些时间,其值是延迟计算(仅在需要时)。而且,HOSTNAME可以直接配置中设置

定义变量

可以在配置文件中一次定义一个变量,或者从外部属性文件或外部资源批量加载变量。由于历史的原因,用于定义变量的XML元素<property>虽然在logback 1.0.7以后,元素<variable>可以互换使用。

下一个示例显示在配置文件的开头声明的变量。然后在文件中使用它来指定输出文件的位置。

示例:简单变量替换(logback-examples / src / main / resources / chapters / configuration / variableSubstitution1.xml)

查看为.groovy

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

下一个示例显示使用System属性来实现相同的结果。该属性没有在配置文件中声明,因此logback将在系统属性中查找它。Java系统属性可以在命令行上设置,如下所示:

java -DUSER_HOME="/home/sebastien" MyApp2

示例:系统变量替换(logback-examples / src / main / resources / chapters / configuration / variableSubstitution2.xml)

查看为.groovy

<configuration>

 

  <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-examples / src / main / resources / chapters / configuration / variableSubstitution3.xml)

查看为.groovy

<configuration>

 

  <property file="src/main/java/chapters/configuration/variables1.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>

该配置文件包含对名为variables1.properties的文件的引用 。包含在该文件中的变量将被读取,然后在本地范围内定义。这是variable.properties文件的样子。

示例:变量文件(logback-examples / src / main / resources / chapters / configuration / variables1.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>

领域

可以定义一个属性来插入本地范围上下文范围系统范围中。本地范围是默认的。尽管可以从OS环境中读取变量,但是无法写入OS环境。

局部作用域本地作用域的属性从配置文件定义的角度直到解释/执行所述配置文件结束。作为推论,每当配置文件被解析和执行时,局部范围内的变量都被重新定义。

上下文作用域具有上下文作用域的属性被插入到上下文中,并且与上下文一样长或直到被清除。一旦定义,上下文范围内的属性就是上下文的一部分。因此,它可用于所有日志事件,包括通过序列化发送到远程主机的日志事件。

系统作用域具有系统作用域的属性被插入到JVM的系统属性中,并与JVM一样长或直到被清除。

属性在本地范围中首先查找,在上下文范围内,在系统属性范围内,在OS环境中。

在替换过程中,首先在本地范围内查找属性,在​​上下文范围内,在系统属性范围内,在OS环境中第四个和最后一个。

元素, 元素或元素的范围属性 可用于设置属性的范围。该范围 属性承认“本地”,“环境”和“系统”的字符串作为可能的值。如果未指定,范围始终假定为“本地”。 <property><define><insertFromJNDI>

示例:在“上下文”范围中定义的变量(logback-examples / src / main / resources / chapters / configuration / contextScopedVariable.xml)

查看为.groovy

<configuration>

 

  <property scope="context" name="nodeId" value="firstNode" />

 

  <appender name="FILE" class="ch.qos.logback.core.FileAppender">

    <file>/opt/${nodeId}/myApp.log</file>

    <encoder>

      <pattern>%msg%n</pattern>

    </encoder>

  </appender>

 

  <root level="debug">

    <appender-ref ref="FILE" />

  </root>

</configuration>

在上面的例子中,假设在上下文范围中定义了nodeId属性,它将在每个日志事件中都可用,即使是通过序列化发送到远程主机的日志事件。

变量的默认值

在某些情况下,如果一个变量没有被声明或者它的值为null,那么可能有一个默认值。和Bash shell一样,可以使用“: - ” 运算符来指定默认值。例如,假设名称为aName的变量未定义,将被解释为“黄金”。"${aName:-golden}"

嵌套变量

变量嵌套完全受支持。变量的名称,默认值和值定义都可以引用其他变量。

值嵌套

变量的值定义可以包含对其他变量的引用。假设您希望使用变量来指定目标目录以及文件名,并将这两个变量合并到名为“destination”的第三个变量中。下面显示的属性文件给出了一个例子。

示例:嵌套变量引用(logback-examples / src / main / resources / chapters / configuration / variables2.properties)

USER_HOME=/home/sebastien fileName=myApp.logdestination=${USER_HOME}/${fileName}

请注意,在上面的属性文件中,“destination”由两个其他变量组成,即“USER_HOME”和“fileName”。

示例:使用单独文件进行变量替换(logback-examples / src / main / resources / chapters / configuration / variableSubstitution4.xml)

<configuration>

 

  <property file="variables2.properties" />

 

  <appender name="FILE" class="ch.qos.logback.core.FileAppender">

    <file>${destination}</file>

    <encoder>

      <pattern>%msg%n</pattern>

    </encoder>

  </appender>

 

  <root level="debug">

    <appender-ref ref="FILE" />

  </root>

</configuration>

名称嵌套

引用变量时,变量名称可能包含对另一个变量的引用。例如,如果名为“userid”的变量被分配值“alice”,则“$ {$ {userid} .password}”引用具有名称“alice.password”的变量。

默认值嵌套

变量的默认值可以引用另一个变量。例如,假设变量“id”未赋值,变量“userid”赋值为“alice”,则表达式“$ {id : - $ {userid}}”将返回“alice”。

HOSTNAME属性

由于它经常派上用场,因此HOSTNAME在使用上下文范围进行配置期间,会自动定义该属性。

CONTEXT_NAME属性

如其名称所示,该CONTEXT_NAME属性对应于当前日志记录上下文的名称。

设置时间戳

所述时间戳元件可以根据当前日期和时间定义一个属性。所述时间戳元件在随后的章节说明

动态定义属性

您可以使用<define>元素动态定义属性 。define元素具有两个强制属性:名称。该名称 属性指定设置,而属性的名称 属性指定执行的任何类PropertyDefiner 接口。实例的getPropertyValue()方法返回的值PropertyDefiner将是指定属性的值。你也可以指定一个范围内通过指定的命名属性 范围的属性。

这是一个例子。

<configuration>

 

  <property file="variables2.properties" />

 

  <appender name="FILE" class="ch.qos.logback.core.FileAppender">

    <file>${destination}</file>

    <encoder>

      <pattern>%msg%n</pattern>

    </encoder>

  </appender>

 

  <root level="debug">

    <appender-ref ref="FILE" />

  </root>

</configuration>

在上面的例子中,形状,颜色和大小是“a.class.implementing.PropertyDefiner”的属性。只要在实现PropertyDefiner实例时给定一个属性的setter ,logback就会按照配置文件中的指定注入适当的值。

目前,logback包含两个相当简单的实现PropertyDefiner。

实现名称

描述

FileExistsPropertyDefiner

如果path属性指定的文件存在,则将命名变量设置为“true” ,否则设置为“false”。

ResourceExistsPropertyDefiner

如果用户指定的资源在类路径中可用,则将命名变量设置为“true” ,否则设置为“false”。

有条件处理配置文件

开发人员通常需要在针对不同环境(例如开发,测试和生产)的多个logback配置文件之间进行操作。这些配置文件只有少数几个地方有很多共同之处。为了避免重复,支持的logback用的帮助下配置文件条件处理<if>, <then>和<else>元素,以便一个配置文件能充分瞄准几个环境。请注意,条件处理需要Janino

条件语句的一般格式如下所示。

      <!-- if-then form -->

   <if condition="some conditional expression">

    <then>

      ...

    </then>

  </if>

 

  <!-- if-then-else form -->

  <if condition="some conditional expression">

    <then>

      ...

    </then>

    <else>

      ...

    </else>    

  </if>

该条件是一个只能访问上下文属性或系统属性的Java表达式。对于作为参数传递的键,property()或其较短的equivalent p()方法返回属性的String值。例如,要使用键“k”访问一个属性的值,你可以写property("k")或等价 p("k")。如果具有键“k”的属性未定义,则属性方法将返回空字符串,而不是空值。这避免了需要检查空值。

该isDefined()方法可以用来检查属性是否被定义。例如,要检查是否定义了属性“k”,您将编写isDefined("k") 类似的,如果您需要检查属性是否为空,isNull()则提供该 方法。例如: isNull("k")。

<configuration debug="true">

 

  <if condition='property("HOSTNAME").contains("torino")'>

    <then>

      <appender name="CON" class="ch.qos.logback.core.ConsoleAppender">

        <encoder>

          <pattern>%d %-5level %logger{35} - %msg %n</pattern>

        </encoder>

      </appender>

      <root>

        <appender-ref ref="CON" />

      </root>

    </then>

  </if>

 

  <appender name="FILE" class="ch.qos.logback.core.FileAppender">

    <file>${randomOutputDir}/conditional.log</file>

    <encoder>

      <pattern>%d %-5level %logger{35} - %msg %n</pattern>

   </encoder>

  </appender>

 

  <root level="ERROR">

     <appender-ref ref="FILE" />

  </root>

</configuration>

条件处理在 元素的任何地方都受支持<configuration>。嵌套的if-then-else语句也被支持。但是,XML语法非常麻烦,不适合作为通用编程语言的基础。因此,太多的条件会很快使您的配置文件无法理解,包括您自己在内的后续读者。

从JNDI获取变量

在某些情况下,您可能想要使用存储在JNDI中的env-entries。所述<insertFromJNDI> 配置指令提取存储在一个JNDI ENV-条目,并插入与由指定键在本地范围的属性作为属性。作为所有属性,可以使用scope属性将新属性插入到不同的作用域中

示例:插入作为通过JNDI获取的属性env-entries(logback-examples / src / main / resources / chapters / configuration / insertFromJNDI.xml)

<configuration>

  <insertFromJNDI env-entry-name="java:comp/env/appName" as="appName" />

  <contextName>${appName}</contextName>

 

  <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">

    <encoder>

      <pattern>%d ${CONTEXT_NAME} %level %msg %logger{50}%n</pattern>

    </encoder>

  </appender>

 

  <root level="DEBUG">

    <appender-ref ref="CONSOLE" />

  </root>

</configuration>

在这最后一个示例中,“java:comp / env / appName”env-entry作为appName属性插入。请注意,该<contextName>指令根据 前 一条指令插入的appName属性的值来设置上下文名称<insertFromJNDI>。

文件包含

Joran支持从另一个文件中包含配置文件的一部分。这是通过声明一个<include> 元素完成的,如下所示:

示例:文件包括(logback-examples / src / main / resources / chapters / configuration / containedConfig.xml)

<configuration>

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

 

  <root level="DEBUG">

    <appender-ref ref="includedConsole" />

  </root>

 

</configuration>

目标文件必须将其元素嵌套在 <included>元素中。例如,一个 ConsoleAppender可以被声明为:

示例:文件include(logback-examples / src / main / resources / chapters / configuration / includedConfig.xml)

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

请再次注意强制性 <included>元素。

要包含的内容可以作为文件,资源或URL来引用。

  1. 作为文件:

要包含文件,请使用文件属性。您可以使用相对路径,但请注意,当前目录由应用程序定义,并不一定与配置文件的路径相关。

  1. 作为资源:

要包含资源,即在类路径中找到的文件,请使用资源属性。

<include resource = “includedConfig.xml” />

  1. 作为URL:

要包含URL的内容,请使用url属性。

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

如果找不到要包含的文件,logback将通过打印状态消息来投诉。如果包含的文件是可选的,则可以通过在 元素中设置可选属性来禁止警告消息。true<include>

<include optional = “true” .... />

添加一个上下文监听器

LoggerContextListener 接口的实例监听关于记录器上下文生命周期的事件。

JMXConfigurator是LoggerContextListener界面的一个实现 。这在后面的章节中有描述。

LevelChangePropagator

从版本0.9.25开始,logback-classic带有LevelChangePropagator,它的一个实现LoggerContextListener将对任何logback-classic记录器级别的更改传播到java.util.logging框架。这种传播消除了禁用的日志语句对性能的影响。LogRecord实例 将仅发送到logback(通过SLF4J)用于启用日志语句。这使得真实世界的应用程序使用jul-to-slf4j 桥是合理的。

contextListener元素可以用来安装LevelChangePropagator,如下所示。

<configuration debug="true">

  <contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator"/>

  ....

</configuration>

设置LevelChangePropagator的resetJUL属性将重置所有jul记录器的所有以前的配置。但是,以前安装的处理程序将保持不变。

<configuration debug="true">

  <contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator">

    <resetJUL>true</resetJUL>

  </contextListener>

  ....

</configuration>

jul记录器的所有以前的配置。但是,以前安装的处理程序将保持不变。

<configuration debug="true">

  <contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator">

    <resetJUL>true</resetJUL>

  </contextListener>

  ....

</configuration>

 

发布了57 篇原创文章 · 获赞 39 · 访问量 20万+

猜你喜欢

转载自blog.csdn.net/SJZYLC/article/details/81230821