第 3 章:Logback 配置

**在符号中,人们发现发现的优势是最大的,因为它们可以简短地表达事物的确切性质并照原样描绘事物;那么,实际上思想的工作就大大减少了.

-威廉·莱布尼兹(**)

我们首先通过许多示例配置脚本介绍配置logback的方法。 Joran,logback所依赖的配置框架将在下一章中介绍。

logback中的配置

将日志请求插入应用程序代码需要大量的计划和工作。观察表明,大约百分之四的代码专用于日志记录。因此,即使大小适中的应用程序也将在其代码中嵌入数千个日志记录语句。给定它们的数量,我们需要工具来 Management 这些日志语句。

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

让我们开始讨论logback后尝试进行自我配置的初始化步骤:

  • Logback 尝试查找名为* logback-test.xml * 在 Classpath 中的文件。

  • 如果未找到此类文件,则 logback 尝试查找名为* logback.groovy * 在 Classpath 中的文件。

  • 如果找不到这样的文件,它将检查文件* logback.xml * 在 Classpath 中 ..

  • 如果找不到此类文件,则通过在类中查找文件* META-INF\services\ch.qos.logback.classic.spi.Configurator *,使用服务提供者加载设施(在 JDK 1.6 中引入)来解决com.qos.logback.classic.spi.Configurator接口的实现。路径。其内容应指定所需的Configurator实现的完全限定的类名。

  • 如果以上方法均未成功,则 logback 会使用BasicConfigurator自动进行自我配置,这会将日志输出定向到控制台。

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

如果您使用的是 Maven,并且将* logback-test.xml 放在 src/test/resources 文件夹下,则 Maven 将确保它不会包含在生成的工件中。因此,您可以在测试过程中使用其他配置文件 logback-test.xml ,在生产环境中使用另一个文件 logback.xml *。

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

自动配置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!");
  }
}

为了运行本章中的示例,您需要确保在 Classpath 中存在某些 jar 文件。有关更多详细信息,请参阅setup page

假设不存在配置文件* logback-test.xml logback.xml ,则默认情况下,logback 将调用BasicConfigurator来设置最小配置。此最小配置由连接到根 Logger 的ConsoleAppender组成。使用PatternLayoutEncoder设置为格式%d{HH:mm:ss.SSS} [%thread]%-5level%logger{36}-%msg%n *来格式化输出。此外,默认情况下,根 Logger 被分配为DEBUG级别。

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

16:06:09.031 [main] INFO 章节。configuration.MyApp1-Importing 应用程序。 16:06:09.046 [main] DEBUG 章节。configuration.Foo-又做了一次! 16:06:09.046 [main] INFO 章节。configuration.MyApp1-退出应用程序。

除了用于配置回送的代码(如果存在此类代码),Client 端代码不需要依赖于回送。使用 logback 作为其日志框架的应用程序将对 SLF4J 具有编译时依赖性,但对 logback 没有依赖性。

MyApp1应用程序通过对org.slf4j.LoggerFactoryorg.slf4j.Logger类的调用链接到注销,检索希望使用的 Logger,然后启动。请注意,Foo类在logback时的唯一依赖关系是通过org.slf4j.LoggerFactoryorg.slf4j.Logger导入。除了用于配置回送的代码(如果存在此类代码),Client 端代码不需要依赖于回送。由于 SLF4J 允许在其抽象层下使用任何日志记录框架,因此很容易将大量代码从一个日志记录框架迁移到另一个日志记录框架。

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

如前所述,logback 将尝试使用文件* logback-test.xml logback.xml *(如果在 Classpath 上找到)进行自我配置。这是一个等效于我们刚刚看到的BasicConfigurator构建的配置文件。

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

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

将* sample0.xml 重命名为 logback.xml (或 logback-test.xml )后,将其放入可从 Classpath 访问的目录中。运行 MyApp1 *应用程序应获得与其先前运行相同的结果。

在出现警告或错误的情况下自动打印状态消息

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

如果在配置文件解析期间发生警告或错误,则 logback 将自动在控制台上打印其内部状态数据。请注意,为避免重复,如果用户明确注册了状态侦听器(定义如下),则会禁用自动状态打印。

在没有警告或错误的情况下,如果您仍然希望检查 logback 的内部状态,则可以通过调用StatusPrinter类的print()来指示 logback 打印状态数据。如下所示的* MyApp2 应用程序与 MyApp1 *相同,除了增加了两行代码以打印内部状态数据外。

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

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.

在此输出的结尾,您可以识别上一个示例中打印的行。您还应该注意logback的内部消息,也就是Status对象,它们可以方便地访问logback的内部状态。

Status data

在诊断回送问题时,通常启用状态数据输出会走很长一段路。因此,强烈建议您使用它,并且应将其视为“首选”手段。

您可以指示配置文件转储状态数据,即使没有错误也不必从代码中以编程方式调用StatusPrinter。为此,您需要设置* configuration 元素的 debug 属性,即配置文件中最顶部的元素,如下所示。请注意,此调试属性仅与状态数据有关。否则,它不会影响logback的配置,尤其是在 Logger 级别方面。 (如果您询问,否,则根 Logger 将不*设置为DEBUG.)

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

观看为.groovy

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

在\ 元素内设置debug="true"将输出状态信息,假设:

  • 找到配置文件

  • 配置文件是格式正确的 XML。

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

强制状态输出在没有状态消息的情况下,很难追踪流氓* logback.xml *配置文件,尤其是在 Producing,其中应用程序源不容易被修改。为了帮助识别恶意配置文件的位置,可以通过“ logback.statusListenerClass”系统属性(defined below)设置StatusListener以强制输出状态消息。系统属性“ 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" />  

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

通过 debug 属性或等效地通过安装OnConsoleStatusListener来启用状态数据输出,将对帮助您诊断 logback 问题大有帮助。因此,强烈建议启用logback状态数据,并且应将其视为“首选”手段。

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

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

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

请注意,文件 extensions 必须为“ .xml”或“ .groovy”。其他 extensions 将被忽略。 明确注册状态监听器可能有助于调试查找配置文件的问题。

由于"logback.configurationFile"是 Java 系统属性,因此也可以在您的应用程序中设置它。但是,必须在创建任何 Logger 实例之前设置系统属性。

import ch.qos.logback.classic.util.ContextInitializer;

public class ServerMain {
    public static void main(String args[]) throws IOException, InterruptedException {
       // must be set before the first call to  LoggerFactory.getLogger();
       // ContextInitializer.CONFIG_FILE_PROPERTY is set to "logback.configurationFile"
       System.setProperty(ContextInitializer.CONFIG_FILE_PROPERTY, "/path/to/config.xml");
       ...
    }   
}

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

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

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

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

观看为.groovy

<configuration scan="true"> 
  ... 
</configuration>

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

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

观看为.groovy

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

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

在后台,将 scan 属性设置为true时,将安装ReconfigureOnChangeTask。该任务在单独的线程中运行,将检查您的配置文件是否已更改。 ReconfigureOnChangeTask也会自动监视任何included个文件。

由于在编辑配置文件时很容易出错,因此如果最新版本的配置文件存在 XML 语法错误,则它将退回到没有 XML 语法错误的先前配置文件。

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

打包数据虽然有用,但计算起来却很昂贵,尤其是在经常出现异常的应用程序中。

注意从版本 1.1.4 开始,包装数据默认为禁用。

如果指示这样做,则 logback 可以包括其输出的堆栈跟踪行的每一行的打包数据。打包数据由 jar 文件的名称和版本组成,而堆栈跟踪行的源于此。打包数据对于识别软件版本控制问题可能非常有用。但是,计算起来相当昂贵,尤其是在经常引发异常的应用程序中。这是一个示例输出:

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 的默认配置机制在其在 Classpath 上找到的默认配置文件上调用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,设置将在其上运行的上下文,重置 Logger 上下文,然后最终要求配置器使用作为参数传递给应用程序的配置文件来配置上下文。如果出现警告或错误,将打印内部状态数据。请注意,对于多步配置,应省略context.reset()调用。

查看状态消息

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

给定一个StatusManager,您可以访问与回送上下文关联的所有状态数据。为了将内存使用率保持在合理的水平,默认的StatusManager实现将状态消息存储在两个单独的部分中:Headers 部分和尾部部分。头部分存储前* H 状态消息,而尾部分存储最后 T 消息。目前, H * = * T * = 150,尽管这些值在将来的版本中可能会更改。

经典的 Logback 附带了一个称为 ViewStatusMessagesServlet 的 servlet。该 Servlet 将与当前LoggerContext关联的StatusManager的内容打印为 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>

ViewStatusMessages Servlet 将在 URL http://host/yourWebapp/lbClassicStatus上可见

收听状态消息

您还可以将StatusListener附加到StatusManager,以便您可以立即采取措施来响应状态消息,尤其是对配置了注销配置后发生的消息。注册状态侦听器是一种方便的方法来监视回发的内部状态,而无需人工干预。

Logback 附带了一个名为OnConsoleStatusListenerStatusListener实现,顾名思义,该实现将在控制台上显示所有* new *传入状态消息。

这是sample code,用于向 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”系统属性

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

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

Stopping logback-classic

为了释放经典的 logback 资源,停止 logback 上下文总是一个好主意。停止上下文将关闭所有附加到该上下文定义的 Logger 的附加程序,并有序地停止所有活动线程。另请阅读下面有关“关机钩”的部分。

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 应用程序中,可以从ServletContextListenercontextDestroyed方法内部调用上述代码,以停止经典的 logback 并释放资源。从版本 1.1.10 开始,将自动为您安装相应的ServletContextListener(见下面)。

通过关闭钩子停止经典的 logback

安装 JVM 关机钩子是关闭日志回发和释放关联资源的便捷方法。

<configuration debug="true">
   <!-- in the absence of the class attribute, assume 
   ch.qos.logback.core.hook.DefaultShutdownHook -->
   <shutdownHook/>
  .... 
</configuration>

请注意,您可以通过将 class 属性设置为与您的关机钩子的类名相对应来安装自己的关机钩子。

默认的关闭钩子DefaultShutdownHook将在指定的延迟(默认为 0)后“停止”logback上下文。停止上下文将使在后台运行的任何日志文件压缩任务最多需要 30 秒才能完成。在独立的 Java 应用程序中,向配置文件中添加<shutdownHook/>指令是确保在退出 JVM 之前完成所有正在进行的压缩任务的简便方法。在 Web 服务器中的应用程序中,将自动安装webShutdownHook,从而使<shutdownHook/>指令相当多余且不必要。

WebShutdown 在 Web 应用程序中挂接或停止经典的 logback

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

您可以通过在 Web 应用程序的 web.xml 文件中设置名为logbackDisableServletContainerInitializer的\ 来禁用LogbackServletContextListener的自动安装。这是相关的代码段。

<web-app>
    <context-param>
        <param-name>logbackDisableServletContainerInitializer</param-name>
        <param-value>true</param-value>
    </context-param>
    .... 
</web-app>

请注意,也可以将logbackDisableServletContainerInitializer变量设置为 OS 环境变量的 Java 系统属性。最本地的设置具有优先权,即,首先是 Web 应用程序,其次是系统属性,最后是 OS 环境。

配置文件语法

到目前为止,您已经在手册中看到了很多示例,但 logback 允许您重新定义日志记录行为,而无需重新编译代码。确实,您可以轻松配置 logback,以便对应用程序的某些部分禁用日志记录,或者将输出定向到 UNIX Syslog 守护程序,数据库,日志可视化器,或者将日志记录事件转发到远程 logback 服务器,该服务器将记录日志。根据本地服务器策略,例如通过将日志事件转发到第二个 Logback 服务器。

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

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

basic Syntax

如果不确定给定标签名称使用哪种情况,只需遵循camelCase convention,这几乎总是正确的约定。

标签名称区分大小写

从 Logback 版本 0.9.17 开始,与显式规则有关的标记名称不区分大小写。例如,<logger><Logger><LOGGER>是有效的配置元素,并且将以相同的方式进行解释。请注意,XML 格式规则仍然适用,如果以<xyz>的形式打开标签,则必须以</xyz>的形式将其关闭,而</XyZ>将不起作用。对于implicit rules,标签名称区分大小写,但首字母除外。因此,<xyz><Xyz>是等效的,但不是<xYz>。隐式规则通常遵循 Java 世界中常见的camelCase约定。由于很难区分标记何时与显式动作相关联以及标记与隐式动作相关联,因此说 XML 标记相对于第一个字母区分大小写还是不区分大小写并非易事。如果不确定给定标签名使用哪种情况,只需遵循 camelCase 约定,几乎总是正确的约定。

配置 Logger 或\ 元素

此时,您至少应该对level inheritance基本选择规则有一定的了解。否则,除非您是埃及 maven,否则logback配置对您而言不会比象形 Literals 有意义。

使用<logger>元素配置 Logger。 <logger>元素仅具有一个必填名称属性,一个可选的 level 属性和一个可选的可加性属性,允许使用* true false 值。允许使用不区分大小写的字符串值 TRACE,DEBUG,INFO,WARN,ERROR,ALL 或 OFF 之一的 level 属性值。不区分大小写的特殊值 INHERITED 或其同义词 NULL *,将强制 Logger 的级别从层次结构中的更高层次继承。如果您设置了 Logger 的级别,后来又决定它应该继承其级别,那么这将派上用场。

请注意,与 log4j 不同,logback-classic 在配置给定 Logger 时不会关闭或删除任何以前引用的追加器。

<logger>元素可以包含零个或多个<appender-ref>元素;如此引用的每个附加程序都会添加到命名 Logger 中。请注意,与 log4j 不同,logback-classic 在配置给定 Logger 时不会关闭或删除任何以前引用的追加器。

配置 rootLogger 或\ 元素

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

请注意,与 log4j 不同,logback-classic 在配置根记录程序时不会关闭或删除任何以前引用的追加程序。

类似于<logger>元素,<root>元素可以包含零个或多个<appender-ref>元素;如此引用的每个附加程序都会添加到根 Logger 中。请注意,与 log4j 不同,logback-classic 在配置根记录程序时不会关闭或删除任何以前引用的追加程序。

Example

设置 Logger 或根 Logger 的级别就像声明和设置其级别一样简单,如下面的示例所示。假设我们不再希望看到来自属于“ 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

示例:设置多个 Logger 的级别(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 章节。configuration.MyApp3-Importing 应用程序。 17:39:27.593 [main] DEBUG 章节。configuration.Foo-又做了一次! 17:39:27.593 [main] INFO 章节。configuration.MyApp3-退出应用程序。

JoranConfigurator使用* sample3.xml *配置文件配置了logback后,下表列出了 Logger 及其级别。

Logger nameAssigned LevelEffective Level
rootDEBUGDEBUG
chapters.configurationINFOINFO
chapters.configuration.MyApp3nullINFO
chapters.configuration.FooDEBUGDEBUG

因此,都启用了MyApp3类中级别INFO的两个日志记录语句以及Foo.doIt()中的 DEBUG 消息。请注意,根 Logger 的级别始终设置为非空值,默认情况下为 DEBUG。

让我们注意到basic-selection rule取决于所调用 Logger 的有效级别,而不是附加了附加程序的 Logger 的级别。 Logback 首先将确定是否启用了日志记录语句,如果启用,它将调用在 Logger 层次结构中找到的附加程序,而不管其级别如何。配置文件* sample4.xml *是一个很好的例子:

示例:Logger 级别示例(logback-examples/src/main/resources/chapters/configuration/sample4.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" />

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

</configuration>

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

Logger nameAssigned LevelEffective Level
rootOFFOFF
chapters.configurationINFOINFO
chapters.configuration.MyApp3nullINFO
chapters.configuration.FoonullINFO

名为* STDOUT 的 ConsoleAppender 是 sample4.xml 中唯一配置的附加程序,已附加到设置为OFF的根 Logger。但是,使用配置脚本 sample4.xml 运行 MyApp3 *将产生:

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

因此,根 Logger 的级别没有明显的作用,因为chapters.configuration.MyApp3chapters.configuration.Foo类的 Logger 都已针对INFO级别启用。附带说明,* chapters.configuration *Logger 凭借其在配置文件中的声明而存在-即使 Java 源代码未直接引用它也是如此。

Configuring Appenders

使用<appender>元素配置了一个附加程序,该元素具有两个必需属性 name 和 class。 name 属性指定附加程序的名称,而 class 属性指定要实例化的附加程序类的全限定名称。 <appender>元素可以包含零个或一个<layout>元素,零个或多个<encoder>元素和零个或多个<filter>元素。除了这三个公共元素之外,<appender>元素可以包含任意数量的与 appender 类的 JavaBean 属性相对应的元素。无缝支持给定的 logback 组件的任何属性是Joran的主要优势之一,如下一章所述。下图说明了通用结构。请注意,对属性的支持不可见。

Appender Syntax

<layout>元素采用强制类属性,该属性指定要实例化的布局类的全限定名称。与<appender>元素一样,<layout>可以包含与布局实例的属性相对应的其他元素。由于这是一种常见情况,因此,如果布局类为PatternLayout,则可以按默认类 Map规则指定的方式忽略 class 属性。

<encoder>元素具有必填类属性,该属性指定要实例化的编码器类的全限定名称。由于这种情况很常见,因此如果编码器类为PatternLayoutEncoder,则可以按照默认类 Map规则所指定的那样省略 class 属性。

logback到多个追加程序就像定义各种追加程序并在 Logger 中引用它们一样容易,就像下一个配置文件所示:

示例:多个 Logger(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>

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

附加程序通过在* appender-ref *元素中按名称引用而附加到根记录程序。请注意,每个附加程序都有其自己的编码器。编码器通常不设计为由多个附加程序共享。布局也是如此。因此,logback 配置文件不提供用于共享编码器或布局的任何语法手段。

Appenders accumulate

默认情况下, appenders 是累积 **:Logger 将记录到附加到其自身的附加程序(如果有)以及附加到其祖先的所有附加程序。因此,将同一附加程序附加到多个 Logger 将导致记录输出重复。

示例:重复的追加程序(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>

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

14:25:36.343 [main] INFO 章节。configuration.MyApp3-Importing 应用程序。 14:25:36.343 [main] INFO 章节。configuration.MyApp3-Importing 应用程序。 14:25:36.359 [main] DEBUG 章节。configuration.Foo-又做了一次! 14:25:36.359 [main] DEBUG 章节。configuration.Foo-又做了一次! 14:25:36.359 [main] INFO 章节。configuration.MyApp3-退出应用程序。 14:25:36.359 [main] INFO 章节。configuration.MyApp3-退出应用程序。

注意重复的输出。名为* STDOUT 的附加程序附加到两个 Logger,root 和 chapters.configuration 。由于根 Logger 是所有 Logger 的祖先,并且 chapters.configuration chapters.configuration.MyApp3 chapters.configuration.Foo 的父级,因此使用这两个 Logger 进行的每个记录请求将被输出两次,一次是因为 STDOUT 附加到 chapters.configuration ,一次是因为它附加到 root *。

Appender 可加性不旨在成为新用户的陷阱。这是一个非常方便的注销功能。例如,您可以配置日志记录,以使日志消息出现在控制台上(对于系统中的所有 Logger),而仅来自某些特定 Logger 集的消息流入特定的附加程序。

示例:多个附加程序(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>

在此示例中,控制台附加程序将记录所有消息(对于系统中的所有 Logger),而仅记录来自* chapters.configuration Logger 及其子级的请求将进入 myApp.log *文件。

覆盖默认的累积行为

如果默认的累积行为证明不适合您的需求,则可以通过将可加性标志设置为 false 来覆盖它。因此,Logger 树中的分支可能会将输出定向到与树的其余部分不同的一组附加程序。

示例:可加性标志(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 的附加程序附加到 chapters.configuration.Foo Logger。此外, chapters.configuration.Foo Logger 的可加性标志设置为 false,以便其记录输出将发送到名为 FILE 的附加程序,但不发送到层次结构中较高位置附加的任何附加程序。其他 Logger 仍然忽略 chapters.configuration.Foo Logger 的可加性设置。使用 additivityFlag.xml 配置文件运行MyApp3应用程序将从 chapters.configuration.MyApp3 Logger 在控制台上输出结果。但是, chapters.configuration.Foo Logger 的输出将显示在 foo.log *文件中,并且仅显示在该文件中。

设置上下文名称

在前面的章节中所述,每个 Logger 都附加到 Logger 上下文。默认情况下,Logger 上下文称为“默认”。但是,可以在<contextName>配置指令的帮助下设置其他名称。请注意,设置后,Logger 上下文名称不能改变。设置上下文名称是一种简单明了的方法,以区分logback到同一目标的多个应用程序。

示例:设置上下文名称并显示它(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>

最后一个示例说明了 Logger 上下文的命名。在布局的样式中添加contextName 转换词将输出上述名称。

Variable substitution

注意本文档的早期版本使用术语“属性替换”代替术语“变量”。请考虑两个术语的互换性,尽管后一个术语传达了更清晰的含义。

与许多脚本语言一样,logback 配置文件支持变量的定义和替换。变量具有scope(请参见下文)。此外,可以在配置文件本身中,在外部文件中,在外部资源中甚至是计算后的即时定义定义变量。

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

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

由于经常会派上用场,因此会自动定义 HOSTNAME 和 CONTEXT_NAME 变量并具有上下文范围。考虑到在某些环境中可能需要花费一些时间来计算主机名,因此它的值是延迟计算的(仅在需要时)。此外,可以在configuration directly.内设置 HOSTNAME

Defining variables

变量可以一次在配置文件本身中定义,也可以从外部属性文件或外部资源中批量加载。由于历史原因,用于定义变量的 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 将在 System 属性中查找它。可以在命令行上设置 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

您也可以在 Classpath 上引用资源而不是文件。

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

Scopes

可以定义一个属性,以便在* local scope context scope system scope *中插入。本地范围是默认设置。尽管可以从 OS 环境中读取变量,但是无法写入 OS 环境中。

本地范围从配置文件中定义其属性的位置到该配置文件的解释/执行结束为止,都存在具有本地范围的属性。因此,每次解析和执行配置文件时,都会重新定义本地作用域中的变量。

上下文范围具有上下文范围的属性被插入到上下文中,并且持续时间与上下文一样长,直到被清除为止。一旦定义,上下文范围内的属性就是上下文的一部分。这样,它在所有日志记录事件中都可用,包括那些通过序列化发送到远程主机的事件。

系统范围具有系统范围的属性被插入 JVM 的系统属性中,并且持续时间与 JVM 一样长,或者直到被清除为止。

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

在替换过程中,首先在本地范围内查找属性,然后在上下文范围内查找属性,在系统属性范围内查找第三属性,在OS environment范围内查找最后一个属性。

<property>元素,<define>元素或<insertFromJNDI>元素的 scope 属性可用于设置属性的范围。 scope 属性允许将“ local”,“ context”和“ system”字符串作为可能的值。如果未指定,则范围始终假定为“本地”。

示例:在“上下文”范围内定义的变量(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 *属性在上下文范围中定义,则它将在每个日志记录事件中可用,即使是那些通过序列化发送到远程主机的事件。

变量的默认值

在某些情况下,如果未声明变量或其值为空,则可能希望变量具有默认值。与Bash shell一样,可以使用 “:-” 运算符指定默认值。例如,假设未定义名为* aName *的变量,则"${aName:-golden}"将被解释为“黄金”。

Nested variables

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

value nesting

变量的值定义可以包含对其他变量的引用。假设您希望使用变量不仅指定目标目录,还指定文件名,然后将这两个变量组合到称为“目标”的第三个变量中。下面显示的属性文件提供了一个示例。

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

USER_HOME=/home/sebastien
fileName=myApp.log
destination=${USER_HOME}/${fileName}

请注意,在上面的属性文件中,“目的地”由其他两个变量组成,即“ 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>

name nesting

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

默认值嵌套

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

HOSTNAME property

通常使用起来很方便,HOSTNAME属性是在配置上下文范围时自动定义的。

CONTEXT_NAME property

顾名思义,CONTEXT_NAME属性对应于当前日志记录上下文的名称。

设置时间戳

  • timestamp *元素可以根据当前日期和时间定义属性。 * timestamp *元素是在下一章中解释

即时定义属性

您可以使用<define>元素动态定义属性。 define 元素具有两个必填属性:name 和 class。 name 属性指定要设置的属性的名称,而 class 属性则指定实现PropertyDefiner接口的任何类。 PropertyDefiner实例的getPropertyValue()方法返回的值将是指定属性的值。您还可以通过指定范围属性为命名属性指定scope

这是一个例子。

<configuration>

  <define name="rootLevel" class="a.class.implementing.PropertyDefiner">
    <shape>round</shape>
    <color>brown</color>
    <size>24</size>
  </define>
 
  <root level="${rootLevel}"/>
</configuration>

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

目前,logback 确实提供了两个非常简单的PropertyDefiner实现。

Implementation nameDescription
CanonicalHostNamePropertyDefiner将命名变量设置为 localhost 的规范主机名。请注意,获取规范的主机名可能需要花费几秒钟。
FileExistsPropertyDefiner如果 path 属性指定的文件存在,则将命名变量设置为“ true”,否则设置为“ false”。
ResourceExistsPropertyDefiner如果用户指定的资源在 Classpath 上可用,则将命名变量设置为“ true”,否则设置为“ false”。

有条件地处理配置文件

开发人员经常需要在针对不同环境(例如开发,测试和生产)的多个 logback 配置文件之间进行切换。这些配置文件有很多共同点,仅在几个地方有所不同。为避免重复,logback 支持在<if><then><else>元素的帮助下对配置文件进行有条件的处理,因此单个配置文件可以充分地针对多个环境。请注意,条件处理需要Janino library

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

<!-- 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()或更短的等效p()方法返回属性的 String 值。例如,要使用键“ k”访问属性的值,应编写property("k")或等效的p("k")。如果未定义键为“ k”的属性,则该属性方法将返回空字符串,而不是 null。这避免了需要检查空值。

isDefined()方法可用于检查是否定义了属性。例如,要检查是否定义了属性“ k”,您可以编写isDefined("k")。类似地,如果需要检查属性是否为 null,则提供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 语法非常繁琐,不适合用作通用编程语言的基础。因此,太多的条件将使后续的 Reader(包括您自己)难以理解您的配置文件。

从 JNDI 获取变量

在某些情况下,您可能需要使用存储在 JNDI 中的环境。 <insertFromJNDI>配置伪指令提取一个存储在 JNDI 中的环境,并使用 as 属性指定的键将属性插入本地范围。作为所有属性,可以借助* scope *属性将新属性插入到different scope中。

示例:插入通过 JNDI 获得的属性 env 条目(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 条目作为 appName 属性插入。请注意,<contextName>指令根据前一个<insertFromJNDI>指令插入的 appName 属性的值来设置上下文名称。

File inclusion

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

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

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

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

</configuration>

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

示例:文件包括(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。

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

  • 作为资源:
    要包括资源,即在 Classpath 上找到的文件,请使用 resource 属性。

<include resource="includedConfig.xml"/>
  • 作为 URL:
    要包含 URL 的内容,请使用 url 属性。
<include url="http://some.host.com/includedConfig.xml"/>

如果找不到要包含的文件,则将通过打印状态消息来进行注销。如果包含的文件是可选的,则可以通过将<include>元素中的 optional 属性设置为true来禁止显示警告消息。

<include optional="true" ..../>

添加上下文监听器

LoggerContextListener接口的实例侦听与 Logger 上下文的生命周期有关的事件。

JMXConfiguratorLoggerContextListener接口的一种实现。在subsequent chapter中描述。

LevelChangePropagator

从 0.9.25 版本开始,经典的 logback 附带LevelChangePropagatorLoggerContextListener的实现将对任何经典的 loglogger 级别所做的更改传播到 java.util.logging 框架中。这种传播消除了禁用日志语句对性能的影响。 LogRecord实例将仅通过已启用的日志语句发送到 logback(通过 SLF4J)。这使得实际应用程序可以使用jul-to-slf4jbridge。

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

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

设置 LevelChangePropagator 的 resetJUL 属性将重置所有 j.u.l 的所有以前的级别配置。Logger。但是,以前安装的处理程序将保持不变。

<configuration debug="true">
  <contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator">
    <resetJUL>true</resetJUL>
  </contextListener>
  ....
</configuration>