第三章 Logback configuration

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

配置logback

将日志请求插入到应用程序代码中需要大量的计划和努力。观察表明,大约4%的代码专门用于日志记录。因此,即使是中等规模的应用程序也会在其代码中包含数千条日志语句。考虑到它们的数量,我们需要工具来管理这些日志语句。
Logback可以通过编程方式配置,也可以使用XML或Groovy格式的配置脚本进行配置。顺便说一下,现有的log4j用户可以使用PropertiesTranslator web应用程序将他们的log4j.properties转换为logback.xml。
让我们从logback尝试配置自身的初始化步骤开始讨论:

  1. Logback试图在类路径中找到一个名为Logback -test.xml的文件。
  2. 如果没有找到这样的文件,logback将尝试在类路径中查找名为logback.groovy的文件。
  3. 如果没有找到这样的文件,它会检查类路径中的文件logback.xml。
  4. 如果没有找到这样的文件,服务提供者加载工具(在JDK 1.6中引入)将被用来解析com.qos.logback.classic.spi.Configurator接口的实现,方法是通过查找META-INF\services\ch.qos.logback.classic.spi类路径中的配置器。它的内容应该指定所需的Configurator实现的完全限定类名。
  5. 如果上述操作都不成功,logback将使用BasicConfigurator自动配置自己,这将导致日志输出被定向到控制台。

最后一步是在没有配置文件的情况下提供默认(但非常基本)日志功能的最后一步。
如果您正在使用Maven,并且将logback-test.xml放在src/test/resources文件夹下,Maven将确保它不会包含在生成的artifact中。因此,您可以在测试期间使用一个不同的配置文件,即logback-test.xml,在生产中使用另一个文件,即logback.xml。
快速启动大约需要100毫秒Joran解析给定的logback配置文件。为了节省应用程序启动时的毫秒数,您可以使用服务提供者加载工具(上面的第4项)来加载您自己的自定义配置器类,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!");
  }
}

为了运行本章中的示例,需要确保类路径上存在某些jar文件。详情请参阅安装页面。
假设配置文件logback-test.xml或logback.xml不存在,logback将默认调用BasicConfigurator,这将设置最小配置。这个最小配置包括一个附加到根logger的ConsoleAppender。输出使用设置为模式%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n.。而且,默认情况下,根logger被分配为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,而不是logback。

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

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

如前所述,如果在类路径上找到logback-test.xml或logback.xml文件,logback将尝试使用这些文件配置自己。下面的配置文件与我们刚才看到的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的内部状态,那么您可以通过调用StatusPrinter类的print()来指示logback打印状态数据。下面所示的MyApp2应用程序与MyApp1完全相同,只是增加了两行用于打印内部状态数据的代码。
示例:打印logback的内部状态信息(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的内部消息,即状态对象,它允许方便地访问logback的内部状态。

状态数据

在诊断logback问题时,启用状态数据的输出通常有很长的路要走。注意,错误也可能发生在配置后,例如,当磁盘已满或日志文件无法归档时,由于权限错误。因此,强烈建议您按照下面讨论的方式注册statuslistener。
下一个示例演示了OnConsoleStatusListener的安装。
示例:注册一个状态监听器(logback-examples/src/main/resources/chapters/configuration/onConsoleStatusListener.xml)

<configuration>
  <-- Recommendation: place status listeners towards the the top of the configuration file -->
  <statusListener class="ch.qos.logback.core.status.OnConsoleStatusListener" />  

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

statusListener可以通过配置文件安装,假设:

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

如果没有满足这两个条件中的任何一个,Joran就不能解释配置文件,特别是元素。如果找到了配置文件,但是配置文件的格式是错误的,那么logback将检测错误条件,并自动在控制台上打印其内部状态。但是,如果找不到配置文件,logback将不会自动打印它的状态数据,因为这不一定是一个错误条件。如上面的MyApp2应用程序所示,以编程方式调用StatusPrinter.print()可以确保在每种情况下都打印状态信息。
在没有状态消息的情况下,跟踪错误的logback.xml配置文件可能会很困难,特别是在无法轻松修改应用程序源代码的生产环境中。为了帮助识别错误配置文件的位置,可以通过logback.statusListenerClass设置StatusListener系统属性(将在下面讨论),用于强制输出状态消息。logback.statusListenerClass的系统属性也可以用于在出现错误时自动生成的输出。

速记

作为简写,可以通过将元素中的debug属性设置为true来注册OnConsoleStatusListener,如下所示。
示例:使用调试模式的基本配置文件(logback-examples/src/main/resources/chapters/configuration/sample1.xml)

<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"完全等同于前面所示的安装OnConsoleStatusListener。

“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在StatusManager对象中收集其内部状态数据,通过LoggerContext进行访问。
给定一个StatusManager,您可以访问与logback上下文关联的所有状态数据。为了将内存使用保持在合理的水平,默认的StatusManager实现将状态消息存储在两个独立的部分:头部分和尾部分。头部分存储第一个H状态消息,而尾部分存储最后一个T消息。目前,H=T=150,尽管这些值可能在未来的版本中改变。
Logback-classic附带一个名为ViewStatusMessagesServlet的servlet。这个servlet以HTML表的形式打印与当前LoggerContext关联的StatusManager的内容。下面是示例输出。

在这里插入图片描述

要将这个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>

通过代码监听状态信息

您也可以通过Java代码注册StatusListener。下面是示例代码。

   LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory(); 
   StatusManager statusManager = lc.getStatusManager();
   OnConsoleStatusListener onConsoleListener = new OnConsoleStatusListener();
   statusManager.add(onConsoleListener);

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

通过系统属性设置配置文件的位置

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

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

注意,文件扩展名必须是".xml"或".groovy"。其他扩展被忽略。显式注册状态监听器可能有助于调试定位配置文件的问题。
鉴于logback.configurationFile是一个Java系统属性,它也可以在您的应用程序中设置。但是,必须在创建任何logger实例之前设置system属性。

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-classic可以扫描配置文件中的更改,并在配置文件更改时自动重新配置自己。
如果指示这样做,logback-classic将扫描配置文件中的更改,并在配置文件更改时自动重新配置自己。为了指示logback-classic在其配置文件中扫描更改并自动重新配置自身,将元素的scan属性设置为true,如下所示。
示例:扫描配置文件中的更改并自动重新配置(logback-examples/src/main/resources/chapters/configuration/scan1.xml)

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

默认情况下,每分钟扫描一次配置文件的更改。您可以通过设置元素的scanPeriod属性来指定不同的扫描周期。可以以毫秒、秒、分钟或小时为单位指定值。下面是一个例子:
示例:指定不同的扫描周期(logback-examples/src/main/resources/chapters/configuration/scan2.xml)

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

说明如果没有指定时间单位,则假设时间单位为毫秒,这通常是不合适的。当修改默认扫描周期时,请不要忘记指定时间单位。
在幕后,当您将扫描属性设置为true时,ReconfigureOnChangeTask将被安装。此任务在单独的线程中运行,并将检查您的配置文件是否已更改。ReconfigureOnChangeTask也会自动监视任何包含的文件。
由于在编辑配置文件时很容易出错,所以如果配置文件的最新版本有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);

Invoking JoranConfigurator directly

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

Example: Invoking JoranConfigurator directly (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()调用。

Stopping logback-classic

为了释放logback-classic所使用的资源,停止logback上下文总是一个好主意。停止上下文将关闭上下文定义的所有附加到日志记录器的追加器,并以有序的方式停止任何活动线程。请同时阅读下面的“关机钩子”部分。

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

Stopping logback-classic via a shutdown hook

安装JVM关闭钩子是关闭日志回退和释放相关资源的一种方便的方法。

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

注意,你可以通过设置class属性来对应你的shutdown钩子的类名来安装你自己制作的shutdown钩子。

默认的关闭钩子,即DefaultShutdownHook,将在指定的延迟(默认为0)之后停止logback上下文。停止上下文将允许在后台运行的任何日志文件压缩任务在30秒内完成。在独立的Java应用程序中,向配置文件中添加指令是确保JVM退出前允许任何正在进行的压缩任务完成的简单方法。在Web服务器中的应用程序中,webShutdownHook将被自动安装,使得指令显得非常多余和不必要。

WebShutdownHook or stopping logback-classic in web-applications

从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变量也可以设置为Java系统属性,即OS环境变量。大多数本地设置有优先级,即web-app第一,系统属性第二,操作系统环境最后。

Configuration file syntax

正如您到目前为止已经在手册中看到的(还有大量示例要参考),logback允许您重新定义日志记录行为,而不需要重新编译代码。实际上,您可以很容易地配置logback,以便禁用应用程序某些部分的日志记录,或直接将日志输出到UNIX Syslog守护进程、数据库、日志可视化程序,或将日志记录事件转发到远程logback服务器,该服务器将根据本地服务器策略进行日志记录。例如,通过将日志事件转发到第二台logback服务器。
本节的其余部分介绍配置文件的语法。
正如我们将反复演示的那样,logback配置文件的语法非常灵活。因此,不可能用DTD文件或XML模式指定允许的语法。然而,配置文件的基本结构可以描述为,元素,包含0个或多个元素,后跟0个或多个元素,后跟最多一个元素。下面的图表说明了这个基本结构。
在这里插入图片描述
如果你不确定一个给定的标签名应该使用哪种大小写,只要遵循camelCase约定,这几乎总是正确的约定。

Case sensitivity of tag names

由于logback版本0.9.17,与显式规则相关的标记名不区分大小写。例如,、和是有效的配置元素,将以相同的方式解释。注意,XML格式良好性规则仍然适用,如果你以打开标签,你必须以关闭它,将不起作用。对于隐式规则,除了第一个字母外,标签名是区分大小写的。因此,和是等价的,但不等于。隐式规则通常遵循在Java世界中很常见的驼峰式约定。由于很难区分标记何时与显式操作相关联,何时与隐式操作相关联,因此判断XML标记对第一个字母是区分大小写还是不敏感就不重要了。如果您不确定对给定的标记名使用哪种大小写,只需遵循camelCase约定,这几乎总是正确的约定。

Configuring loggers, or the element

此时,您至少应该对级别继承和基本选择规则有一些了解。否则,除非你是埃及古物学家,logback配置对你来说不会比象形文字更有意义。
使用元素配置记录器。元素只接受一个强制名称属性、一个可选级别属性和一个可选加法属性,允许值为true或false。level属性的值,允许不区分大小写的字符串值TRACE、DEBUG、INFO、WARN、ERROR、ALL或OFF之一。特殊的不区分大小写的值INHERITED,或其同义词NULL,将强制从层次结构中的更高层继承记录器级别。如果您设置了日志记录器的级别,然后决定它应该继承它的级别,那么这将非常方便。
注意,与log4j不同,logback-classic在配置给定的日志记录器时不会关闭或删除以前引用的任何追加器。
元素可以包含0个或多个元素;这样引用的每个追加器都被添加到指定的记录器中。注意,与log4j不同,logback-classic在配置给定的日志记录器时不会关闭或删除以前引用的任何追加器。

Configuring the root logger, or the element

元素配置根记录器。它支持一个属性,即level属性。它不允许任何其他属性,因为可加性标志不适用于根日志记录器。此外,由于根日志记录器已经被命名为“root”,所以它也不允许name属性。level属性的值可以是不区分大小写的字符串TRACE、DEBUG、INFO、WARN、ERROR、ALL或OFF之一。请注意,根日志记录器的级别不能设置为INHERITED或NULL。
注意,与log4j不同,在配置根日志记录器时,logback-classic不会关闭或删除以前引用的任何追加器。

类似于元素,元素可以包含0个或多个元素;因此引用的每个appender被添加到根日志记录器。注意,与log4j不同,在配置根日志记录器时,logback-classic不会关闭或删除以前引用的任何追加器。

Example

设置日志记录器或根日志记录器的级别就像声明它和设置它的级别一样简单,下面的示例将演示。假设我们不再有兴趣看到任何来自属于“章节”的组件的DEBUG消息。配置”包。下面的配置文件展示了如何实现这一点

Example: Setting the level of a logger (logback-examples/src/main/resources/chapters/configuration/sample2.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>

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

注意,DEBUG级别的消息是由“chapter .configuration.”生成的。Foo" logger已被禁止。请参见Foo类。

您可以配置任意多个日志记录器的级别。在下一个配置文件中,我们设置章节的级别。configuration logger设置为INFO,但同时将章节.configuration. foo logger的级别设置为DEBUG。

Example: Setting the level of multiple loggers (logback-examples/src/main/resources/chapters/configuration/sample3.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" />
  <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 name Assigned Level Effective Level
root DEBUG DEBUG
chapters.configuration INFO INFO
chapters.configuration.MyApp3 null INFO
chapters.configuration.Foo DEBUG DEBUG
这样,MyApp3类中INFO级别的两个日志语句以及Foo.doIt()中的DEBUG消息都被启用了。注意,根日志记录器的级别总是设置为一个非空值,默认为DEBUG。

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

Example: Logger level sample (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>

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

Logger name Assigned Level Effective Level
root OFF OFF
chapters.configuration INFO INFO
chapters.configuration.MyApp3 null INFO
chapters.configuration.Foo null INFO
名为STDOUT的ConsoleAppender是sample4.xml中唯一配置的appender,它被附加到级别设置为OFF的根日志记录器。然而,使用配置脚本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.

因此,根日志记录器的级别没有明显的影响,因为章节.configuration中的日志记录器。MyApp3和chapter .configuration. foo类都为INFO级别启用。顺便提一下,这些章节。配置记录器通过在配置文件中的声明而存在——即使Java源代码没有直接引用它。

Configuring Appenders

appender使用元素配置,该元素接受两个强制性属性name和class。name属性指定了追加器的名称,而class属性指定了要实例化的追加器类的完全限定名。元素可以包含0个或一个元素,0个或多个元素和0个或多个元素。除了这三个常见元素外,元素可以包含与appender类的JavaBean属性相对应的任意数量的元素。如后面章节所述,无缝支持给定logback组件的任何属性是Joran的主要优势之一。下面的图表说明了常见的结构。注意,对属性的支持是不可见的。
在这里插入图片描述

Appender Syntax

元素接受一个强制性的class属性,指定要实例化的布局类的完全限定名。与元素一样,可能包含与布局实例的属性相对应的其他元素。由于这种情况很常见,如果布局类是PatternLayout,那么class属性可以按照默认类映射规则的规定省略。

元素接受一个强制性的class属性,指定要实例化的编码器类的完全限定名。由于这种情况很常见,如果编码器类是PatternLayoutEncoder,那么可以按照默认类映射规则的规定省略class属性。

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

Example: Multiple loggers (logback-examples/src/main/resources/chapters/configuration/multiple.xml)

<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 appender记录到一个名为myApp.log的文件。这个appender的编码器是一个PatternLayoutEncoder,输出日期、级别、线程名、记录器名、文件名和日志请求所在的行号、消息和行分隔符。第二个追加器称为STDOUT输出到控制台。此追加器的编码器只输出后跟行分隔符的消息字符串。

通过在appender-ref元素中通过名称引用追加器,追加器被附加到根日志记录器。注意,每个追加器都有自己的编码器。编码器通常不是被设计成由多个追加器共享的。布局也是如此。因此,logback配置文件不提供任何用于共享编码器或布局的语法方法。

Appenders accumulate

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

Example: Duplicate appender (logback-examples/src/main/resources/chapters/configuration/duplicate.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">
    <appender-ref ref="STDOUT" />
  </logger>

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

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

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.

注意重复的输出。名为STDOUT的appender被附加到两个日志记录器上,分别附加到root和chapter .configuration。因为根日志记录器是所有日志记录器和章节的祖先。Configuration是这两章的父章。MyApp3 chapters.configuration。Foo,使用这两个记录器发出的每个日志请求将被输出两次,一次是因为STDOUT附加到章节。因为它连接到根。

Appender的可加性不是为新用户设计的陷阱。这是一个非常方便的日志返回特性。例如,您可以配置日志记录,使日志消息显示在控制台上(对于系统中的所有日志记录器),而只有来自某些特定日志记录器集的消息流到特定的appender。

Example: Multiple appender (logback-examples/src/main/resources/chapters/configuration/restricted.xml)

<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将记录所有消息(针对系统中的所有日志记录器),而只记录来自章节的请求。配置记录器及其子程序将进入myApp.log文件。

Overriding the default cumulative behaviour

如果发现默认的累积行为不适合您的需要,您可以通过将可加性标志设置为false来覆盖它。因此,日志记录器树中的一个分支可以将输出直接指向一组不同于树中其他部分的追加器。

Example: Additivity flag (logback-examples/src/main/resources/chapters/configuration/additivityFlag.xml)

<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 logger。此外,章.configuration. foo logger的可加性标志被设置为false,这样它的日志输出将被发送到名为FILE的appender,而不是发送到层次结构中更高的任何appender。其他记录器对章节.configuration. foo logger的可加性设置保持不在意。使用additivityFlag.xml配置文件运行MyApp3应用程序将在控制台上从章.configuration输出结果。MyApp3记录器。然而,来自章。configuration. foo logger的输出将出现在foo.log文件中,并且只出现在该文件中。

Setting the context name

如前一章所述,每个记录器都附加到记录器上下文。默认情况下,记录器上下文被称为“default”。但是,您可以在配置指令的帮助下设置一个不同的名称。注意,一旦设置,记录器上下文名称就不能更改。设置上下文名称是一种简单而直观的方法,可以区分记录到同一目标的多个应用程序。

Example: Set the context name and display it (logback-examples/src/main/resources/chapters/configuration/contextName.xml)

<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转换词将输出该名称。

Variable substitution

说明在本文档的早期版本中,使用的术语是“属性替换”而不是“变量”。请认为这两个术语是可以互换的,尽管后者的意思更清楚一些。

与许多脚本语言一样,logback配置文件支持变量的定义和替换。变量有一个作用域(见下面)。此外,变量可以在配置文件本身、外部文件、外部资源中定义,甚至可以动态地计算和定义。

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

变量替换可以发生在配置文件中可以指定值的任何位置。变量替换的语法类似于Unix shell。开始 和 结 束 之 间 的 字 符 串 被 解 释 为 对 属 性 值 的 引 用 。 对 于 属 性 a N a m e , 字 符 串 “ {和结束}之间的字符串被解释为对属性值的引用。对于属性aName,字符串“ aName{aName}”将被aName属性持有的值替换。

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

Defining variables

变量可以在配置文件本身中一次定义一个,也可以从外部属性文件或外部资源批量加载。由于历史原因,用于定义变量的XML元素是<属性>,尽管在logback 1.0.7和以后的版本中,元素<变量>可以互换使用。

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

Example: Simple Variable substitution (logback-examples/src/main/resources/chapters/configuration/variableSubstitution1.xml)

<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

Example: System Variable substitution (logback-examples/src/main/resources/chapters/configuration/variableSubstitution2.xml)

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

当需要多个变量时,创建包含所有变量的单独文件可能更方便。下面是如何进行这样的设置。

Example: Variable substitution using a separate file (logback-examples/src/main/resources/chapters/configuration/variableSubstitution3.xml)

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

这个配置文件包含一个对名为variables .properties文件的引用。该文件中包含的变量将被读取,然后在局部作用域中定义。这是变量。属性文件可能如下所示。

Example: Variable file (logback-examples/src/main/resources/chapters/configuration/variables1.properties)
USER_HOME=/home/sebastien
You may also reference a resource on the class path instead of a file.

<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

属性可以定义为在局部作用域、上下文作用域或系统作用域中插入。本地作用域是默认的。尽管可以从操作系统环境中读取变量,但不可能写入操作系统环境。

局部作用域一个具有局部作用域的属性从它在配置文件中的定义开始就存在,直到该配置文件的解释/执行结束。因此,每次解析和执行配置文件时,都会重新定义局部作用域中的变量。

具有上下文作用域的属性被插入到上下文中,并持续到上下文被清除为止。定义之后,上下文范围内的属性就是上下文的一部分。因此,它在所有日志事件中都可用,包括那些通过序列化发送到远程主机的事件。

系统作用域一个具有系统作用域的属性被插入到JVM的系统属性中,并一直持续到JVM被清除为止。

属性首先在本地作用域中查找,其次在上下文作用域中查找,第三在系统属性作用域中查找,最后在操作系统环境中查找。

在替换过程中,属性首先在本地作用域中查找,其次在上下文作用域中查找,第三在系统属性作用域中查找,最后在操作系统环境中查找。

元素、元素或元素的scope属性可用于设置属性的范围。scope属性允许“local”、“context”和“system”字符串作为可能的值。如果没有指定,作用域总是假定为“局部的”。

Example: A variable defined in “context” scope (logback-examples/src/main/resources/chapters/configuration/contextScopedVariable.xml)

<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属性是在上下文中定义的,那么它将在每个日志事件中可用,即使是那些通过序列化发送到远程主机的日志事件。

Default values for variables

在某些情况下,如果变量没有被声明或者它的值是空的,那么它有一个默认值是可取的。在Bash shell中,可以使用“:-”操作符指定默认值。例如,假设没有定义名为aName的变量,“${aName:-golden}”将被解释为“golden”。

Nested variables

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

value nesting

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

Example: Nested variable references (logback-examples/src/main/resources/chapters/configuration/variables2.properties)

USER_HOME=/home/sebastien
fileName=myApp.log
destination=${USER_HOME}/${fileName}
Note that in the properties file above, "destination" is composed from two other variables, namely "USER_HOME" and "fileName".

Example: Variable substitution using a separate file (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",则为"KaTeX parse error: Expected '}', got 'EOF' at end of input: {{userid} "。Password}"引用名为"alice.password"的变量。

default value nesting

一个变量的默认值可以引用另一个变量。例如,假设变量’id’未赋值,变量’userid’赋值为"alice",那么表达式"KaTeX parse error: Expected '}', got 'EOF' at end of input: {id:-{userid}}“将返回"alice”。

HOSTNAME property

由于HOSTNAME属性通常很方便,所以在配置上下文作用域时自动定义它。

CONTEXT_NAME property

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

Setting a timestamp

timestamp元素可以根据当前日期和时间定义一个属性。时间戳元素将在后续章节中解释。

Defining properties on the fly

可以使用元素动态定义属性。define元素有两个强制属性:name和class。name属性指定要设置的属性的名称,而class属性指定实现PropertyDefiner接口的任何类。PropertyDefiner实例的getPropertyValue()方法返回的值将是指定属性的值。您也可以通过指定范围属性来指定指定属性的范围。

下面是一个例子。

<configuration>

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

在上面的例子中,shape, color和size都是“a.class. implementing.com propertydefiner”的属性。只要在PropertyDefiner实例的实现中存在给定属性的setter, logback就会注入配置文件中指定的适当值。

目前,logback提供了两个相当简单的PropertyDefiner实现。

实现名称描述

canonicalhostnamepropertydefiner将named变量设置为本地主机的规范主机名。注意,获取规范主机名可能需要几秒钟。

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

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

配置文件的条件处理

开发人员经常需要在针对不同环境(如开发、测试和生产)的多个日志回退配置文件之间来回切换。这些配置文件有很多共同之处,只是在少数地方有所不同。为了避免重复,logback支持在、和元素的帮助下对配置文件进行有条件的处理,以便单个配置文件能够充分针对多个环境。注意,条件处理需要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()或其更短的等效p()方法返回该属性的String值。例如,要访问键为“k”的属性的值,您可以写入property(“k”)或等价的p(“k”)。如果带有“k”键的属性未定义,property方法将返回一个不为空的空字符串。这避免了检查空值的需要。

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>

在元素中的任何地方都支持条件处理。还支持嵌套if-then-else语句。然而,XML语法非常繁琐,不适合作为通用编程语言的基础。因此,过多的条件将很快使您的配置文件对后续读者(包括您自己)难以理解。

Obtaining variables from JNDI

在某些情况下,您可能希望使用JNDI中存储的环境项。配置指令提取JNDI中存储的一个环境条目,并使用as属性指定的键将该属性插入到本地作用域中。与所有属性一样,可以在scope属性的帮助下将新属性插入到不同的作用域。

Example: Insert as properties env-entries obtained via JNDI (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属性插入。注意,指令根据前一个指令插入的appName属性的值设置上下文名称。

File inclusion

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

Example: File include (logback-examples/src/main/resources/chapters/configuration/containingConfig.xml)

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

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

</configuration>

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

Example: File 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>

同样,请注意必须包含的元素。

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

作为一个文件:

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

作为一个资源:

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

<include resource="includedConfig.xml"/>

作为一个网址:

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

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

如果找不到要包含的文件,logback将打印状态消息来报错。如果所包含的文件是可选的,则可以通过在元素中将optional属性设置为true来抑制警告消息。

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

添加上下文侦听器

LoggerContextListener接口的实例监听与logger上下文生命周期相关的事件。

JMXConfigurator是LoggerContextListener接口的一个实现。这在以后的一章中有描述。

LevelChangePropagator

从0.9.25版本开始,经典日志带有LevelChangePropagator,这是LoggerContextListener的一个实现,它可以将对任何经典logger级别的更改传播到java.util.logging框架上。这种传播消除了禁用日志语句对性能的影响。LogRecord实例只会被发送到logback(通过SLF4J)用于启用的日志语句。这使得实际应用程序使用七月到slf4j桥是合理的。

contextListener元素可用于安装如下所示的LevelChangePropagator。

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

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

<configuration debug="true">
  <contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator">
    <resetJUL>true</resetJUL>
  </contextListener>
  ....
</configuration>
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值