第四章:Appender

**那天有太多关于西方国家的新闻,很难知道从哪里开始。一件事引发了另外一百件事。问题在于决定先告诉哪个人.

-约翰·斯坦贝克,伊甸之东**

什么是 Appender?

Logback 将编写日志记录事件的任务委托给称为附加程序的组件。Appender必须实现ch.qos.logback.core.Appender接口。该接口的主要方法总结如下:

package ch.qos.logback.core;
  
import ch.qos.logback.core.spi.ContextAware;
import ch.qos.logback.core.spi.FilterAttachable;
import ch.qos.logback.core.spi.LifeCycle;
  

public interface Appender<E> extends LifeCycle, ContextAware, FilterAttachable {

  public String getName();
  public void setName(String name);
  void doAppend(E event);
  
}

Appender接口中的大多数方法是设置器和获取器。一个明显的 exception 是doAppend()方法将* E *类型的对象实例作为其唯一参数。 * E 的实际类型将取决于logback模块。在经典的 logback 模块 E *中,类型为ILoggingEvent;在经典的 logback-access 模块中,类型为AccessEventdoAppend()方法可能是 logback 框架中最重要的方法。它负责以适当的格式将日志记录事件输出到适当的输出设备。

Appender 被称为实体。这样可以确保可以按名称引用它们,这种质量在配置脚本中被证明是有用的。 Appender接口扩展了FilterAttachable接口。因此,可以将一个或多个过滤器附加到附加程序实例。过滤器将在下一章中详细讨论。

Appender 最终负责输出日志记录事件。但是,他们可以将事件的实际格式委托给LayoutEncoder对象。每个布局/编码器都与一个且只有一个附加程序(称为拥有附加程序)相关联。一些追加程序具有内置或固定的事件格式。因此,它们不需要布局/编码器。例如,SocketAppender只是将记录事件串行化,然后再通过网络传输它们。

AppenderBase

ch.qos.logback.core.AppenderBase类是实现Appender接口的抽象类。它提供了所有附加程序共享的基本功能,例如获取或设置其名称的方法,其激活状态,其布局和其过滤器。它是 Logback 附带的所有附加程序的超类。 AppenderBase虽然是抽象类,但实际上在Append接口中实现了doAppend()方法。讨论AppenderBase类的最清晰方法也许是通过提供实际源代码的摘录。

public synchronized void doAppend(E eventObject) {

  // prevent re-entry.
  if (guard) {
    return;
  }

  try {
    guard = true;

    if (!this.started) {
      if (statusRepeatCount++ < ALLOWED_REPEATS) {
        addStatus(new WarnStatus(
            "Attempted to append to non started appender [" + name + "].",this));
      }
      return;
    }

    if (getFilterChainDecision(eventObject) == FilterReply.DENY) {
      return;
    }
    
    // ok, we now invoke the derived class's implementation of append
    this.append(eventObject);

  } finally {
    guard = false;
  }
}

doAppend()方法的此实现已同步。因此,从不同的线程logback到相同的追加程序是安全的。当一个线程(例如* T )执行doAppend()方法时,其他线程的后续调用将排队,直到 T 离开doAppend()方法,从而确保 T *对附加程序具有独占访问权。

由于这种同步并非总是适当的,因此 Logback 附带的ch.qos.logback.core.UnsynchronizedAppenderBaseAppenderBase类非常相似。为了简洁起见,我们将在本文档的其余部分中讨论UnsynchronizedAppenderBase

doAppend()方法要做的第一件事是检查防护措施是否设置为 true。如果是,它将立即退出。如果未设置防护,则在下一条语句中将其设置为 true。警卫人员确保doAppend()方法不会递归调用自身。试想一下,一个名为append()方法之外的地方的组件想要记录一些东西。它的调用可能直接指向刚刚调用它的附加程序,从而导致无限循环和堆栈溢出。

在以下语句中,我们检查started字段是否为 true。如果不是,则doAppend()将发送警告消息并返回。换句话说,一旦关闭了附加器,就无法对其进行写入。 Appender对象实现LifeCycle接口,这意味着它们实现start()stop()isStarted()方法。设置了附加程序的所有属性之后,logback 的配置框架 Joran 调用start()方法来向附加程序发出 signal 以激活其属性。根据其种类,如果缺少某些属性或由于各种属性之间的干扰,追加程序可能无法启动。例如,假设文件创建取决于截断模式,则FileAppender不能在其File选项的值上起作用,直到确定添加选项的值为止。显式的激活步骤可确保在知道其值之后,附加程序对其属性进行操作。

如果追加器无法启动或已停止,则将通过 logback 的内部状态 Management 系统发出警告消息。经过几次尝试,为避免内部状态系统被相同警告消息的副本淹没,doAppend()方法将停止发出这些警告。

下一条if语句检查附加过滤器的结果。根据过滤器链产生的决定,可以拒绝或明确接受事件。如果过滤器链没有做出决定,则默认情况下会接受事件。

然后,doAppend()方法调用派生类对append()方法的实现。此方法完成了将事件附加到适当设备的实际工作。

最后,释放防护,以允许随后调用doAppend()方法。

在本手册的其余部分中,对于通过 setter 和 getter 方法使用 JavaBeans 内省法动态推断的任何属性,我们都保留术语“选项”或“属性”。

Logback-core

Logback-core 为构建其他 logback 模块奠定了基础。通常,logback-core 中的组件需要一些(尽管最少)定制。但是,在接下来的几节中,我们将介绍几个准备就绪即可使用的附加程序。

OutputStreamAppender

OutputStreamAppender将事件附加到java.io.OutputStream。此类提供其他附加程序所基于的基本服务。用户通常不直接实例化OutputStreamAppender对象,因为通常无法方便地将java.io.OutputStream类型 Map 到字符串,因为无法在配置脚本中指定目标OutputStream对象。简而言之,您无法通过配置文件配置OutputStreamAppender。但是,这并不意味着OutputStreamAppender缺少可配置的属性。接下来将描述这些属性。

Property NameTypeDescription
encoderEncoder确定将事件写入基础OutputStreamAppender的方式。 dedicated chapter中描述了编码器。
immediateFlushbooleanInstantFlush 的默认值为“ true”。立即刷新输出流可确保立即写出日志记录事件,并且在您的应用程序未正确关闭附加程序而退出的情况下也不会丢失。另一方面,将此属性设置为“ false”可能会使日志记录吞吐量增加四倍(您的里程可能会有所不同)。同样,如果将 InstantFlush 设置为“ false”,并且在应用程序退出时未正确关闭附加程序,则尚未写入磁盘的日志记录事件可能会丢失。

OutputStreamAppender是其他三个附加器的超类,即ConsoleAppenderFileAppender,它们又是RollingFileAppender的超类。下图说明了OutputStreamAppender及其子类的类图。

显示 OutputStreamAppender 和子类的 UML 图

ConsoleAppender

顾名思义,ConsoleAppender附加在控制台上,或更确切地说附加在* System.out System.err *上,前者是默认目标。 ConsoleAppender借助用户指定的编码器来格式化事件。编码器将在下一章中讨论。 * System.out System.err *均为java.io.PrintStream类型。因此,它们被包装在OutputStreamWriter内,该OutputStreamWriter缓冲 I/O 操作。

Property NameTypeDescription
encoderEncoder请参阅OutputStreamAppender属性。
targetString字符串值之一* System.out System.err 。默认目标是 System.out *。
withJansiboolean默认情况下,withJansi 属性设置为false。将 withJansi 设置为true会激活Jansi库,该库为 Windows 计算机上的 ANSI 颜色代码提供支持。在 Windows 主机上,如果将此属性设置为 true,则应在 Classpath 上放置“ org.fusesource.jansi:jansi:1.17”。请注意,默认情况下,基于 Unix 的 os(例如 Linux 和 Mac OS X)支持 ANSI 颜色代码。


在 Eclipse IDE 下,您可能需要尝试Eclipse 控制台中的 ANSI插件。

这是使用ConsoleAppender的示例配置。

示例:ConsoleAppender 配置(logback-examples/src/main/resources/chapters/appenders/conf/logback-Console.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>%-4relative [%thread] %-5level %logger{35} - %msg %n</pattern>
    </encoder>
  </appender>

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

在将当前路径设置为* logback-examples *目录和设置Classpath之后,可以通过发出以下命令来对上述配置文件进行旋转:

Java chapters.appenders.ConfigurationTester src/main/java/chapters/appenders/conf/logback-Console.xml

FileAppender

FileAppenderOutputStreamAppender的子类,将日志事件附加到文件中。目标文件由“文件”选项指定。如果文件已经存在,则根据 append 属性的值将其追加或截断。

Property NameTypeDescription
appendboolean如果为 true,则事件将附加到现有文件的末尾。否则,如果 append 为 false,则任何现有文件都会被截断。默认情况下,append 选项设置为 true。
encoderEncoder请参阅OutputStreamAppender属性。
fileString要写入的文件名。如果该文件不存在,则会创建它。在 MS Windows 平台上,用户经常忘记转义反斜杠。例如,值* c:\ temp\test.log 不太可能正确解释为' t'是转义序列,被解释为单个制表符( u0009)。正确的值可以指定为 c:/temp/test.log*,也可以指定为* c:\ temp \ test.log *。 File 选项没有默认值。


如果文件的父目录不存在,FileAppender将自动创建它,包括任何必需但不存在的父目录。
|谨慎| boolean |在审慎模式下,即使存在其他FileAppender实例在不同的 JVM 中运行(可能在不同的主机上运行)的情况下,FileAppender也会安全地写入指定的文件。谨慎模式的默认值为false
谨慎模式可以与RollingFileAppender结合使用,尽管有些restrictions apply
谨慎模式表示 append 属性会自动设置为 true。
谨慎地更依赖于独占文件锁。实验表明,文件锁定的成本大约是写入日志事件的三倍(x3)。在“平均” PC 上写入位于“本地”硬盘上的文件时,如果谨慎模式关闭,则写入单个日志记录事件大约需要 10 微秒。谨慎模式打开时,大约需要 30 微秒来输出单个日志记录事件。这意味着在关闭谨慎模式时,日志记录吞吐量为每秒 100'000 个事件,而在谨慎模式下,日志吞吐量为每秒约 33'000 事件。
谨慎模式有效地序列化了所有写入同一文件的 JVM 之间的 I/O 操作。因此,随着竞争访问文件的 JVM 数量的增加,每个 I/O 操作所引起的延迟也会增加。只要 I/O 操作的“总数”约为每秒 20 个日志请求,那么对性能的影响应该可以忽略不计。每秒产生 100 个或更多 I/O 操作的应用程序可能会对性能产生影响,因此应避免使用审慎模式。
联网文件锁定当日志文件位于联网文件系统上时,谨慎模式的代价更大。同样重要的是,有时会强烈偏重网络文件系统上的文件锁,以使当前拥有该锁的进程在释放锁后立即重新获得该锁。因此,尽管一个进程为日志文件锁定了锁,但其他进程却饿死了,await 锁出现僵局。
谨慎模式的影响高度取决于网络速度以及 os 的实现细节。我们提供了一个名为FileLockSimulator的非常小的应用程序,它可以帮助您模拟环境中谨慎模式的行为。

立即刷新默认情况下,每个日志事件都会立即刷新到基础输出流。从某种意义上说,这种默认方法更安全,因为在您的应用程序未正确关闭附加程序的情况下退出时,不会丢失日志记录事件。但是,为了显着提高日志记录吞吐量,您可能需要将 InstantFlush 属性设置为false

以下是FileAppender的配置文件示例:

示例:FileAppender 配置(logback-examples/src/main/resources/chapters/appenders/conf/logback-fileAppender.xml)

观看为.groovy

<configuration>

  <appender name="FILE" class="ch.qos.logback.core.FileAppender">
    <file>testFile.log</file>
    <append>true</append>
    <!-- set immediateFlush to false for much higher logging throughput -->
    <immediateFlush>true</immediateFlush>
    <!-- encoders are assigned the type
         ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
    <encoder>
      <pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
    </encoder>
  </appender>
	
  <root level="DEBUG">
    <appender-ref ref="FILE" />
  </root>
</configuration>

在将当前目录更改为* logback-examples *之后,通过启动以下命令来运行此示例:

Java Chapters.appenders.ConfigurationTester src/main/java/chapters/appenders/conf/logback-fileAppender.xml

唯一命名的文件(按时间戳记)

在应用程序开发阶段或应用程序生命周期较短的情况下,例如对于批处理应用程序,希望在每次启动新应用程序时创建一个新的日志文件。借助<timestamp>元素,这很容易做到。这是一个例子。

示例:按时间戳唯一命名的 FileAppender 配置(logback-examples/src/main/resources/chapters/appenders/conf/logback-timestamp.xml)

观看为.groovy

<configuration>

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

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

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

timestamp 元素具有两个必需属性 key 和 datePattern 以及一个可选的 timeReference 属性。 key 属性是密钥的名称,在该名称下时间戳可用于后续配置元素作为变量。 datePattern 属性表示用于将当前时间(解析配置文件)转换为字符串的日期模式。日期模式应遵循SimpleDateFormat中定义的约定。 timeReference 属性表示时间戳的时间参考。默认值为配置文件的解释/解析时间,即当前时间。但是,在某些情况下,使用上下文出生时间作为时间参考可能会很有用。这可以通过将 timeReference 属性设置为"contextBirth"来完成。

通过运行以下命令来测试<timestamp>元素:

Java Chapters.appenders.ConfigurationTester src/main/resources/chapters/appenders/conf/logback-timestamp.xml

要将 Logger 上下文的生日作为时间参考,您可以将 timeReference 属性设置为“ contextBirth”,如下所示。

示例:使用上下文出生日期作为时间参考的时间戳(logback-examples/src/main/resources/chapters/appenders/conf/logback-timestamp-contextBirth.xml)

观看为.groovy

<configuration>
  <timestamp key="bySecond" datePattern="yyyyMMdd'T'HHmmss" 
             timeReference="contextBirth"/>
  ...
</configuration>

RollingFileAppender

RollingFileAppender扩展了FileAppender的功能,可以滚动日志文件。例如,RollingFileAppender可以logback到名为* log.txt *的文件,并且一旦满足特定条件,就可以将其日志记录目标更改为另一个文件。

RollingFileAppender交互的有两个重要的子组件。第一个RollingFileAppender子组件,即RollingPolicy,(see below)负责执行过渡所需的操作。 RollingFileAppender的第二个子组件,即TriggeringPolicy(see below)将确定是否以及何时准确发生翻转。因此,RollingPolicy负责什么TriggeringPolicy负责* when *。

为了发挥作用,RollingFileAppender必须同时设置RollingPolicyTriggeringPolicy。但是,如果它的RollingPolicy也实现了TriggeringPolicy接口,则仅需要明确指定前者。

以下是RollingFileAppender的可用属性:

Property NameTypeDescription
fileString请参阅FileAppender属性。
appendboolean请参阅FileAppender属性。
encoderEncoder请参阅OutputStreamAppender属性。
rollingPolicyRollingPolicy此选项是指示发生翻转时RollingFileAppender行为的组件。请参阅下面的更多信息。
triggeringPolicyTriggeringPolicy此选项是告诉RollingFileAppender何时激活过渡过程的组件。请参阅下面的更多信息。
prudentboolean谨慎模式不支持FixedWindowRollingPolicy

RollingFileAppenderTimeBasedRollingPolicy一起支持谨慎模式,尽管有两个限制。
在谨慎模式下,不支持也不允许文件压缩。 (我们不能让一个 JVM 写入文件,而另一个 JVM 对其进行压缩.)
FileAppender的文件属性无法设置,必须保留为空白。实际上,大多数 os 不允许在打开另一个进程的同时重命名文件。
另请参见FileAppender的属性。

滚动 Policy 概述

RollingPolicy负责涉及文件移动和重命名的过渡过程。

RollingPolicy界面如下所示:

package ch.qos.logback.core.rolling;  

import ch.qos.logback.core.FileAppender;
import ch.qos.logback.core.spi.LifeCycle;

public interface RollingPolicy extends LifeCycle {

  public void rollover() throws RolloverFailure;
  public String getActiveFileName();
  public CompressionMode getCompressionMode();
  public void setParent(FileAppender appender);
}

rollover方法完成了归档当前日志文件所涉及的工作。调用getActiveFileName()方法以计算当前日志文件的名称(将实时日志写入该文件)。如getCompressionMode方法所示,RollingPolicy 还负责确定压缩模式。最后,通过setParent方法为RollingPolicy提供对其父对象的引用。

TimeBasedRollingPolicy

TimeBasedRollingPolicy可能是最受欢迎的滚动策略。它基于时间定义了过渡策略,例如按天或按月。 TimeBasedRollingPolicy负责转存以及触发所述转存。确实,TimeBasedTriggeringPolicy实现* 4 和TriggeringPolicy接口。

TimeBasedRollingPolicy的配置具有一个必需的 fileNamePattern 属性和几个可选属性。

Property NameTypeDescription
fileNamePatternString强制性的 fileNamePattern 属性定义了过渡(存档)日志文件的名称。它的值应包括文件名以及适当放置的*%d *转换说明符。 *%d 转换说明符可以包含java.text.SimpleDateFormat类指定的日期和时间模式。如果省略了日期和时间模式,则采用默认模式 yyyy-MM-dd *。 从 fileNamePattern 的值推断出过渡期.


请注意,可以设置或省略RollingFileAppender(TimeBasedRollingPolicy的父级)中的文件属性。通过设置包含FileAppender的 file 属性,您可以将活动日志文件的位置和已归档日志文件的位置分离。当前日志将始终以 file 属性指定的文件为目标。因此,当前活动日志文件的名称将不会随时间变化。但是,如果选择忽略 file 属性,则将根据 fileNamePattern 的值在每个期间重新计算活动文件。下面的示例应阐明这一点。
在%d{}的赞誉中找到的日期和时间模式遵循 java.text.SimpleDateFormat 约定。 fileNamePattern 属性内或日期和时间模式内任何位置的正斜杠“ /”或反斜杠“ \”字符都将被解释为目录分隔符。
多个%d 说明符
可以指定多个%d 说明符,但其中只有一个可以是主要的,即用于推断过渡期。 必须通过传递'aux'参数将所有其他标记标记为辅助标记(请参见下面的示例)。
多个%d 指示符使您可以将存档文件组织为不同于过渡期的文件夹结构。例如,下面显示的文件名模式按年和月组织日志文件夹,但每天午夜都将日志文件翻转。
/var/log/%d{yyyy/MM, aux}/myapplication.%d{yyyy-MM-dd}.log 时区
在某些情况下,您可能希望根据与主机不同的时区中的时钟来滚动日志文件。可以在%d 转换说明符中的日期和时间模式之后传递一个时区参数。例如:
aFolder/test.%d{yyyy-MM-dd-HH, UTC}.log
如果指定的时区标识符未知或拼写错误,则认为 GMT 时区是由TimeZone.getTimeZone(String)方法规范指定的。
| maxHistory | int |可选的 maxHistory 属性控制要保留的最大归档文件数,以异步方式删除较旧的文件。例如,如果您指定每月滚动,并将 maxHistory 设置为 6,则将保留 6 个月的归档文件,并删除 6 个月以上的文件。请注意,由于删除了旧的归档日志文件,因此将适当删除为日志文件归档而创建的所有文件夹。 |
| totalSizeCap | int |可选的 totalSizeCap 属性控制所有存档文件的总大小。当超过总大小上限时,最早的 Files 将被异步删除。 totalSizeCap 属性还需要设置 maxHistory 属性。此外,始终首先应用“最大历史记录”限制,然后再应用“总大小上限”限制。
| cleanHistoryOnStart | boolean |如果设置为 true,则在启动附加程序时将执行归档删除。默认情况下,此属性设置为 false。
通常在过渡期间执行归档删除。但是,某些应用程序的生存时间可能不足以触发翻转。由此可见,对于这样短暂的应用程序,归档删除可能永远不会有执行的机会。通过将 cleanHistoryOnStart 设置为 true,将在附加程序启动时执行归档删除。

以下是一些fileNamePattern值及其作用说明。

fileNamePatternRollover scheduleExample
/wombat/foo.%d每日展期(午夜)。由于省略了*%d 令牌说明符的可选时间和日期模式,因此假定使用 yyyy-MM-dd *的默认模式,该模式对应于每日滚动。未设置文件属性:在 2006 年 11 月 23 日,日志记录输出将移至文件*/wombat/foo.2006-11-23 。在午夜以及 24 日的其余时间,日志记录输出将定向到/wombat/foo.2006-11-24 *。


文件属性设置为*/wombat/foo.txt :在 2006 年 11 月 23 日,日志输出将转到文件/wombat/foo.txt 。在午夜, foo.txt 将重命名为/wombat/foo.2006-11-23 。将创建一个新的/wombat/foo.txt 文件,并在 11 月 24 日的其余时间将日志输出定向到 foo.txt
| /wombat /%d{yyyy/MM} /foo.txt |每个月初都有鼠标悬停。|未设置文件属性:在 2006 年 10 月,日志记录输出将转到
/wombat/2006/10/foo。文本* 。在 10 月 31 日午夜之后和 11 月下旬,日志记录输出将定向到*/wombat/2006/11/foo.txt
文件属性设置为
/wombat/foo.txt :活动日志文件将始终为/wombat/foo.txt 。在 2006 年 10 月,日志输出将转到/wombat/foo.txt 。在 10 月 31 日午夜,/wombat/foo.txt 将重命名为/wombat/2006/10/foo.txt 。将创建一个新的/wombat/foo.txt 文件,该文件的日志输出将在 11 月的剩余时间进行。在 11 月 30 日午夜,/wombat/foo.txt 将重命名为/wombat/2006/11/foo.txt *,依此类推。
| */wombat/foo。%d{yyyy-ww} .log * |每周的第一天都结余。请注意,一周的第一天取决于区域设置。|与先前的情况类似,不同的是,翻转将在每个新的星期开始时发生。 |
| */wombat/foo%d{yyyy-MM-dd_HH} .log * |隔夜在每小时的顶部。|类似于先前的情况,除了隔夜将在每小时的顶部发生。 |
| */wombat/foo%d{yyyy-MM-dd_HH-mm} .log * |在每分钟开始时进行翻转。|与之前的情况类似,不同的是,在每分钟开始时进行翻转。 |
| /wombat/foo%d{yyyy-MM-dd_HH-mm, UTC} .log * |每分钟开始时都有翻转。|与以前的情况类似,除了文件名将以 UTC 表示。 |
| /foo /%d{yyyy-MM, aux } /%d.log |每天悬停。存档位于包含年和月的文件夹下。 |在此示例中,第一个%d 令牌被标记为 aux iliary。然后假定第二个%d 令牌是主要令牌,其中省略了时间和日期模式。因此,过渡将每天发生一次(%d 的默认设置),并且文件夹名称将取决于年份和月份。例如,在 2006 年 11 月,归档文件将全部放在/ foo/2006-11 /文件夹下,例如
/foo/2006-11/2006-11-14.log *。 |

任何正斜杠或反斜杠字符都将解释为文件夹(目录)分隔符。将根据需要创建任何所需的文件夹。因此,您可以轻松地将日志文件放在单独的文件夹中。

TimeBasedRollingPolicy支持自动文件压缩。如果 fileNamePattern 选项的值以* .gz .zip *结尾,则启用此功能。

fileNamePatternRollover scheduleExample
/wombat/foo.%d.gz每日翻转(在午夜),对存档文件进行自动 GZIP 压缩。未设置文件属性:在 2009 年 11 月 23 日期间,日志记录输出将转到文件*/wombat/foo.2009-11-23 。但是,在午夜该文件将被压缩为/wombat/foo.2009-11-23.gz 。在 11 月 24 日之前,日志记录输出将定向到/wombat/folder/foo.2009-11-24 *,直到第二天开始将其翻转为止。


文件属性设置为/wombat/foo.txt:在 2009 年 11 月 23 日,日志记录输出将进入文件*/wombat/foo.txt 。在午夜,该文件将被压缩并重命名为/wombat/foo.2009-11-23.gz 。将创建一个新的/wombat/foo.txt 文件,日志输出将在 11 月 24 日的其余时间发送。在 11 月 24 日午夜,/wombat/foo.txt 将被压缩并重命名为/wombat/foo.2009-11-24.gz *,依此类推。

fileNamePattern 具有双重用途。首先,通过研究模式,logback 会计算请求的翻转周期。其次,它计算每个存档文件的名称。注意,两个不同的模式可以指定相同的周期性。模式* yyyy-MM yyyy @ MM *都指定了月度过渡,尽管生成的归档文件将带有不同的名称。

通过设置文件属性,您可以将活动日志文件的位置与已归档日志文件的位置分离。日志记录输出将定向到 file 属性指定的文件中。因此,活动日志文件的名称不会随时间变化。但是,如果选择忽略 file 属性,则将根据 fileNamePattern 的值在每个期间重新计算活动文件。通过不设置文件选项,可以避免文件renaming errors的发生,当存在外部文件句柄在过渡期间引用日志文件时,该文件就会出现。

maxHistory 属性控制要保留的存档文件的最大数量,从而删除较旧的文件。例如,如果您指定每月滚动,并将 maxHistory 设置为 6,则将保留 6 个月的归档文件,并删除 6 个月以上的文件。请注意,由于删除了旧的归档日志文件,因此将适当删除为日志文件归档而创建的所有文件夹。

由于各种技术原因,翻转不是由时钟驱动的,而是取决于日志记录事件的到达。例如,在 2002 年 3 月 8 日,假设 fileNamePattern 设置为* yyyy-MM-dd *(每日翻转),则午夜之后第一个事件的到来将触发翻转。如果在午夜之后的 23 分 47 秒内没有日志记录事件,那么实际上将在 3 月 9 日凌晨 00:23'47 AM 而非 0:00 AM 发生翻转。因此,根据事件的到达率,可能会以一定的延迟触发翻转。但是,无论延迟如何,从某种意义上讲,已知过渡算法都是正确的,因为在一定时间段内生成的所有日志记录事件都将在界定该时间段的正确文件中输出。

这是RollingFileAppenderTimeBasedRollingPolicy结合的示例配置。

示例:使用TimeBasedRollingPolicy配置RollingFileAppender的示例(logback-examples/src/main/resources/chapters/appenders/conf/logback-RollingTimeBased.xml)

观看为.groovy

<configuration>
  <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>logFile.log</file>
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
      <!-- daily rollover -->
      <fileNamePattern>logFile.%d{yyyy-MM-dd}.log</fileNamePattern>

      <!-- keep 30 days' worth of history capped at 3GB total size -->
      <maxHistory>30</maxHistory>
      <totalSizeCap>3GB</totalSizeCap>

    </rollingPolicy>

    <encoder>
      <pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
    </encoder>
  </appender> 

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

下一个配置示例说明了在谨慎模式下与RollingFileAppenderTimeBasedRollingPolicy关联的用法。

示例:使用TimeBasedRollingPolicy配置RollingFileAppender的示例(logback-examples/src/main/resources/chapters/appenders/conf/logback-PrudentTimeBasedRolling.xml)

观看为.groovy

<configuration>
  <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <!-- Support multiple-JVM writing to the same log file -->
    <prudent>true</prudent>
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
      <fileNamePattern>logFile.%d{yyyy-MM-dd}.log</fileNamePattern>
      <maxHistory>30</maxHistory> 
      <totalSizeCap>3GB</totalSizeCap>
    </rollingPolicy>

    <encoder>
      <pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
    </encoder>
  </appender> 

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

基于大小和时间的滚动策略

有时您可能希望基本上按日期归档文件,但同时限制每个日志文件的大小,尤其是如果后处理工具对日志文件施加大小限制时。为了满足此要求,logback 附带SizeAndTimeBasedRollingPolicy

请注意,TimeBasedRollingPolicy已经允许限制归档日志文件的组合大小。如果仅希望限制日志归档文件的总大小,则上述TimeBasedRollingPolicy和设置totalSizeCap属性应足够。

这是一个示例配置文件,展示了基于时间和大小的日志文件归档。

示例:SizeAndTimeBasedFNATP的配置示例(logback-examples/src/main/resources/chapters/appenders/conf/logback-sizeAndTime.xml)

观看为.groovy

<configuration>
  <appender name="ROLLING" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>mylog.txt</file>
    <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
      <!-- rollover daily -->
      <fileNamePattern>mylog-%d{yyyy-MM-dd}.%i.txt</fileNamePattern>
       <!-- each file should be at most 100MB, keep 60 days worth of history, but at most 20GB -->
       <maxFileSize>100MB</maxFileSize>    
       <maxHistory>60</maxHistory>
       <totalSizeCap>20GB</totalSizeCap>
    </rollingPolicy>
    <encoder>
      <pattern>%msg%n</pattern>
    </encoder>
  </appender>

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

</configuration>

请注意,除了“%d”外,还包括“%i”转换令牌。 %i 和%d 标记都是必需的. 每次当前日志文件在当前时间段结束之前达到 maxFileSize 时,它将以从 0 开始的递增索引进行归档。

基于大小和时间的归档支持删除旧的归档文件。您需要使用 maxHistory 属性指定要保留的周期数。当您的应用程序停止并重新启动时,日志记录将在正确的位置 continue 进行,即在当前期间以最大的索引号进行记录。

在 1.1.7 之前的版本中,本文档提到了一个名为SizeAndTimeBasedFNATP的组件。但是,鉴于SizeAndTimeBasedFNATP提供了更简单的配置结构,我们不再编写SizeAndTimeBasedFNATP。不过,使用SizeAndTimeBasedFNATP的早期配置文件将 continue 正常运行。实际上,SizeAndTimeBasedRollingPolicy是通过SizeAndTimeBasedFNATP子组件实现的。

FixedWindowRollingPolicy

翻转时,FixedWindowRollingPolicy会根据固定窗口算法重命名文件,如下所述。

fileNamePattern 选项代表已归档(滚动)日志文件的文件名模式。此选项是必需的,并且必须在模式中的某个位置包含整数标记*%i *。

以下是FixedWindowRollingPolicy的可用属性

Property NameTypeDescription
minIndexint此选项代表窗口索引的下限。
maxIndexint此选项代表窗口索引的上限。
fileNamePatternString此选项表示重命名日志文件时FixedWindowRollingPolicy遵循的模式。它必须包含字符串*%i *,它将指示当前窗口索引值将插入的位置。


例如,使用与* 1 3 的最小值和最大值关联的 MyLogFile%i.log 将生成名为 MyLogFile1.log MyLogFile2.log MyLogFile3.log 的存档文件。
请注意,文件压缩也是通过此属性指定的。例如,将 fileNamePattern 设置为
MyLogFile%i.log.zip 意味着必须使用 zip 格式压缩存档文件;还支持 gz *格式。

鉴于固定的窗口滚动策略需要与窗口大小一样多的文件重命名操作,因此强烈建议不要使用较大的窗口大小。当用户指定大值时,当前实现将自动将窗口大小减小到 20.

让我们看看固定窗口翻转策略的更具体示例。假设 minIndex 设置为* 1 ,maxIndex 设置为 3 ,fileNamePattern 属性设置为 foo%i.log ,并且 file 属性设置为 foo.log *。

展期数有效输出目标存档的日志文件Description
0foo.log-尚未发生过渡,重新logback将logback到初始文件。
1foo.logfoo1.log第一次翻转。 * foo.log 重命名为 foo1.log 。将创建一个新的 foo.log *文件,并成为活动的输出目标。
2foo.logfoo1.log, foo2.log第二次翻转。 * foo1.log 重命名为 foo2.log *。 * foo.log 重命名为 foo1.log 。将创建一个新的 foo.log *文件,并成为活动的输出目标。
3foo.logfoo1.log,foo2.log,foo3.log第三轮过渡。 * foo2.log 重命名为 foo3.log *。 * foo1.log 重命名为 foo2.log *。 * foo.log 重命名为 foo1.log 。将创建一个新的 foo.log *文件,并成为活动的输出目标。
4foo.logfoo1.log,foo2.log,foo3.log在本轮及随后的回合中,过渡通过删除* foo3.log *开始。如先前步骤所示,通过增加其索引来重命名其他文件。在此和后续过渡中,将有三个归档日志和一个活动日志文件。

以下配置文件给出了配置RollingFileAppenderFixedWindowRollingPolicy的示例。请注意,即使 File 选项包含与 fileNamePattern 选项传达的信息相同的信息,也是必须的。

示例:使用FixedWindowRollingPolicy配置RollingFileAppender的示例(logback-examples/src/main/resources/chapters/appenders/conf/logback-RollingFixedWindow.xml)

观看为.groovy

<configuration>
  <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>test.log</file>

    <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
      <fileNamePattern>tests.%i.log.zip</fileNamePattern>
      <minIndex>1</minIndex>
      <maxIndex>3</maxIndex>
    </rollingPolicy>

    <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
      <maxFileSize>5MB</maxFileSize>
    </triggeringPolicy>
    <encoder>
      <pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
    </encoder>
  </appender>
	
  <root level="DEBUG">
    <appender-ref ref="FILE" />
  </root>
</configuration>

触发策略概述

TriggeringPolicy实现负责指导RollingFileAppender何时进行过渡。

TriggeringPolicy界面仅包含一种方法。

package ch.qos.logback.core.rolling;

import java.io.File;
import ch.qos.logback.core.spi.LifeCycle;

public interface TriggeringPolicy<E> extends LifeCycle {

  public boolean isTriggeringEvent(final File activeFile, final <E> event);
}

isTriggeringEvent()方法将当前正在处理的活动文件和日志记录事件作为参数。具体的实现基于这些参数来确定是否应进行翻转。

最广泛使用的触发策略,即TimeBasedRollingPolicy,也可以作为滚动策略加倍使用,已经与其他滚动策略一起成为discussed earlier

SizeBasedTriggeringPolicy

SizeBasedTriggeringPolicy查看当前活动文件的大小。如果它增长到大于指定的大小,它将向拥有RollingFileAppender的 signal 发送 signal 以触发现有活动文件的翻转。

SizeBasedTriggeringPolicy仅接受一个参数,即 maxFileSize,默认值为 10 MB。

通过用* KB MB GB 分别后缀数字值,可以以字节,千字节,兆字节或千兆字节指定 maxFileSize 选项。例如, 5000000 5000KB 5MB 2GB *都是有效值,前三个等效。

这是一个示例配置,其中RollingFileAppender结合SizeBasedTriggeringPolicy在日志文件大小达到 5MB 时触发翻转。

示例:使用SizeBasedTriggeringPolicy配置RollingFileAppender的示例(logback-examples/src/main/resources/chapters/appenders/conf/logback-RollingSizeBased.xml)

观看为.groovy

<configuration>
  <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>test.log</file>
    <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
      <fileNamePattern>test.%i.log.zip</fileNamePattern>
      <minIndex>1</minIndex>
      <maxIndex>3</maxIndex>
    </rollingPolicy>

    <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
      <maxFileSize>5MB</maxFileSize>
    </triggeringPolicy>
    <encoder>
      <pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
    </encoder>
  </appender>
	
  <root level="DEBUG">
    <appender-ref ref="FILE" />
  </root>
</configuration>

Logback Classic

虽然日志记录事件在 logback-core 中是通用的,但在 logback-classic 中,它们始终是ILoggingEvent的实例。经典的 Logback 就是专门处理ILoggingEvent实例的处理管道。

SocketAppender 和 SSLSocketAppender

到目前为止,所涉及的附加程序只能logback到本地资源。相反,SocketAppender被设计为通过在线传输序列化的ILoggingEvent实例来logback到远程实体。使用SocketAppender时,线路上的日志记录事件以明文形式发送。但是,使用SSLSocketAppender时,日志记录事件是通过安全通道传递的。

序列化事件的实际类型是LoggingEventVO,它实现了ILoggingEvent接口。但是,就日志事件而言,远程日志是非侵入性的。在反序列化后的接收端,可以记录该事件,就好像它是本地生成的一样。在不同计算机上运行的多个SocketAppender实例可以将其日志输出定向到固定格式的中央日志服务器。 SocketAppender不采用关联的布局,因为它将序列化的事件发送到远程服务器。 SocketAppender在“传输控制协议”(TCP)*层之上运行,该层提供可靠的,有序的,流控制的端到端八位字节流。因此,如果远程服务器可访问,则日志事件最终将到达那里。否则,如果远程服务器已关闭或无法访问,则将简单地删除日志记录事件。如果服务器重新启动,则事件传输将透明地恢复。此透明重新连接由连接器线程执行,该连接器线程会定期尝试连接到服务器。

日志事件由本机 TCP 实现自动缓冲。这意味着,如果到服务器的链接很慢,但仍比 Client 端的事件产生速率快,则 Client 端将不会受到网络连接速度慢的影响。但是,如果网络连接的速度比事件产生的速度慢,则 Client 端只能以网络速度前进。特别是,在极端情况下,到服务器的网络链接已断开,最终将阻止 Client 端。或者,如果网络链接已打开,但服务器已关闭,则 Client 端将不会被阻止,尽管由于服务器不可用,日志事件也会丢失。

即使不再将SocketAppender附加到任何 Logger,也不会在存在连接器线程的情况下对其进行垃圾回收。仅当与服务器的连接断开时,连接器线程才存在。为避免此垃圾回收问题,应显式关闭SocketAppender。创建/销毁许多SocketAppender实例的长期应用程序应注意此垃圾回收问题。大多数其他应用程序可以放心地忽略它。如果托管SocketAppender的 JVM 在关闭SocketAppender之前(显式地或在垃圾回收之后)退出,则管道中可能存在未传输的数据,这可能会丢失。这是基于 Windows 的系统上的常见问题。为了避免丢失数据,通常在退出应用程序之前,显式close() SocketAppender或通过调用LoggerContextstop()方法就足够了。

远程服务器由 remoteHost 和 port 属性标识。下表中列出了SocketAppender个属性。 SSLSocketAppender支持许多其他配置属性,有关详细信息,请参见标题为Using SSL的小节。

Property NameTypeDescription
includeCallerDatabooleanincludeCallerData 选项采用布尔值。如果为 true,则呼叫者数据将可用于远程主机。默认情况下,没有主叫方数据发送到服务器。
portint远程服务器的端口号。
reconnectionDelayDurationreconnectionDelay 选项采用一个持续时间字符串,例如“ 10 秒”,表示在每次尝试与服务器的失败连接之间 await 的时间。此选项的默认值为 30 秒。将此选项设置为零将关闭重新连接功能。请注意,在成功连接到服务器的情况下,将不存在连接器线程。
queueSizeintqueueSize 属性采用一个整数(大于零),该整数表示要保留以传递给远程接收器的日志事件的数量。当队列大小为 1 时,到远程接收器的事件传递是同步的。当队列大小大于 1 时,假定队列中有可用空间,新事件将进入队列。使用大于 1 的队列长度可以消除由瞬时网络延迟引起的延迟,从而提高性能。


另请参见 eventDelayLimit 属性。
| eventDelayLimit | Duration | eventDelayLimit 选项采用持续时间字符串,例如“ 10 秒”。它表示在本地队列已满(即已经包含 queueSize 事件)的情况下,丢弃事件之前要 await 的时间。如果远程主机持续缓慢地接受事件,则可能会发生这种情况。此选项的默认值为 100 毫秒。 |
| remoteHost | String |服务器的主机名。 |
| ssl | SSLConfiguration |仅针对SSLSocketAppender支持,此属性提供了将由附加程序使用的 SSL 配置,如Using SSL中所述。 |

记录服务器选项

标准的 Logback Classic 发行版包括两个服务器选项,可用于从SocketAppenderSSLSocketAppender接收日志记录事件。

  • ServerSocketReceiver及其启用 SSL 的副本SSLServerSocketReceiver是接收器组件,可以在应用程序的* logback.xml *配置文件中对其进行配置,以便从远程套接字附加程序接收事件。有关配置的详细信息和用法示例,请参见Receivers

  • SimpleSocketServer及其支持 SSL 的SimpleSSLSocketServer都提供了易于使用的独立 Java 应用程序,该应用程序旨在通过 shell 的命令行界面进行配置和运行。这些应用程序只是 await 来自SocketAppenderSSLSocketAppenderClient 端的日志事件。根据本地服务器策略记录每个收到的事件。使用示例如下。

Using SimpleSocketServer

SimpleSocketServer应用程序接受两个命令行参数:* port configFile ;其中 port 是要侦听的端口,而 configFile *是 XML 格式的配置脚本。

假设您位于* logback-examples/*目录中,请使用以下命令启动SimpleSocketServer

java ch.qos.logback.classic.net.SimpleSocketServer 6000\src/main/java/chapters/appenders/socket/server1.xml

其中 6000 是要侦听的端口号,而* server1.xml *是一个配置脚本,该脚本向根 Logger 添加了ConsoleAppenderRollingFileAppender。启动SimpleSocketServer之后,可以使用SocketAppender从多个 Client 端向其发送日志事件。与本手册相关的示例包括两个这样的 Client 端:chapters.appenders.SocketClient1chapters.appenders.SocketClient2两个 Client 端都 await 用户在控制台上键入一行文本。文本封装在级别为 debug 的日志事件中,然后发送到远程服务器。两个 Client 端的SocketAppender配置不同。 SocketClient1以编程方式配置附加程序,而SocketClient2需要配置文件。

假设SimpleSocketServer在 localhost 上运行,请使用以下命令连接到它:

java chapters.appenders.socket.SocketClient1localhost6000

您键入的每一行都应出现在上一步启动的SimpleSocketServer的控制台上。如果停止并重新启动SimpleSocketServer,则 Client 端将透明地重新连接到新的服务器实例,尽管断开连接时生成的事件将简单(且不可撤消)丢失。

SocketClient1不同,示例应用程序SocketClient2不会自行配置回传。它需要 XML 格式的配置文件。下面显示的配置文件* client1.xml *创建一个SocketAppender并将其附加到根 Logger。

示例:SocketAppender 配置(logback-examples/src/main/resources/chapters/appenders/socket/client1.xml)

观看为.groovy

<configuration>
	  
  <appender name="SOCKET" class="ch.qos.logback.classic.net.SocketAppender">
    <remoteHost>${host}</remoteHost>
    <port>${port}</port>
    <reconnectionDelay>10000</reconnectionDelay>
    <includeCallerData>${includeCallerData}</includeCallerData>
  </appender>

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

</configuration>

请注意,在上述配置脚本中,remoteHost,port 和 includeCallerData 属性的值不是直接给出的,而是作为替换变量键给出的。变量的值可以指定为系统属性:

java -Dhost = localhost -Dport = 6000 -DincludeCallerData = false\chapters.appenders.socket.SocketClient2 src/main/java/chapters/appenders/socket/client1.xml

此命令应提供与前面的SocketClient1示例相似的结果。

让我们再次强调一下,日志记录事件的序列化不是侵入性的。反序列化事件携带的信息与任何其他日志记录事件相同。可以像在本地生成一样对其进行操作;除了默认情况下序列化的日志记录事件不包含调用方数据外,其他信息均不包括在内。这是一个例子来说明这一点。首先,使用以下命令启动SimpleSocketServer

java ch.qos.logback.classic.net.SimpleSocketServer 6000\src/main/java/chapters/appenders/socket/server2.xml

配置文件* server2.xml 创建一个ConsoleAppender,其布局输出呼叫者的文件名和行号以及其他信息。如果像以前一样使用配置文件 client1.xml *运行SocketClient2,则会注意到服务器端的输出将在括号之间包含两个问号,而不是文件名和调用方的行号:

2006 -11-06 17:37:30,968 调试[Thread-0] [?:?] pages.appenders.socket.SocketClient2-嗨

通过将 includeCallerData 选项设置为 true 来指示SocketAppender包含呼叫者数据,可以轻松更改结果。使用以下命令可以解决问题:

java -Dhost=localhost -Dport=6000 -DincludeCallerData=true \
  chapters.appenders.socket.SocketClient2 src/main/java/chapters/appenders/socket/client1.xml

由于可以用与本地生成的事件相同的方式来处理反序列化事件,因此甚至可以将它们发送到第二台服务器进行进一步处理。作为练习,您可能希望设置两个服务器,其中第一个服务器将其从 Client 端接收的事件传送到第二个服务器。

Using SimpleSSLSocketServer

SimpleSSLSocketServer需要与SimpleSocketServer使用的相同的* port configFile *命令行参数。此外,您必须使用命令行上指定的系统属性提供日志服务器 X.509 凭据的位置和密码。

假设您位于* logback-examples/*目录中,请使用以下命令启动SimpleSSLSocketServer

java -Djavax.net.ssl.keyStore = src/main/java/chapters/appenders/socket/ssl/keystore.jks-Djavax.net.ssl.keyStorePassword = changeit\ch.qos.logback.classic.net.SimpleSSLSocketServer 6000\src/main/java/chapters/appenders/socket/ssl/server.xml

本示例使用仅适用于测试和实验的 X.509 凭据运行SimpleSSLSocketServer在生产设置中使用SimpleSSLSocketServer之前,您应获取适当的 X.509 凭据来标识您的日志记录服务器 。有关更多详细信息,请参见Using SSL

由于服务器配置在根元素上指定了debug="true",因此您将在服务器启动时看到将要使用的 SSL 配置的日志记录。这对于验证是否正确实施了本地安全策略很有用。

运行SimpleSSLSocketServer后,您可以使用SSLSocketAppender连接到服务器。以下示例显示所需的附加程序配置:

示例:SSLSocketAppender 配置(logback-examples/src/main/resources/chapters/appenders/socket/ssl/client.xml)

观看为.groovy

<configuration debug="true">
	  
  <appender name="SOCKET" class="ch.qos.logback.classic.net.SSLSocketAppender">
    <remoteHost>${host}</remoteHost>
    <port>${port}</port>
    <reconnectionDelay>10000</reconnectionDelay>
    <ssl>
      <trustStore>
        <location>${truststore}</location>
        <password>${password}</password>
      </trustStore>
    </ssl>
  </appender>

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

</configuration>

请注意,就像在前面的示例中一样,remoteHost,port 的值是使用替换变量键指定的。此外,请注意 ssl 属性及其嵌套的 trustStore 属性的存在,该属性使用替代变量指定信任库的位置和密码。因为我们的示例服务器使用的是自签名证书,所以此配置是必需的。有关SSLSocketAppender的 SSL 配置属性的更多信息,请参见Using SSL

通过在命令行上将替换变量值指定为系统属性,我们可以使用此配置运行 Client 端应用程序:

java -Dhost = localhost -Dport = 6000-Dtruststore = file:src/main/java/chapters/appenders/socket/ssl/truststore.jks-Dpassword = changeit\chapters.appenders.socket.SocketClient2 src/main/java /chapters/appenders/socket/ssl/client.xml

与前面的示例一样,您可以在 Client 端应用程序提示时键入一条消息,然后该消息将传递到日志服务器(现在通过安全通道),并在控制台上显示该消息。

请注意,命令行上的* truststore *属性指定了标识信任库位置的文件 URL。您还可以使用Using SSL中所述的 ClasspathURL。

如我们先前在服务器启动时所看到的,由于 Client 端配置在根元素上指定了debug="true",因此 Client 端的启动日志记录包括 SSL 配置的详细信息,以帮助审核本地策略的一致性。

ServerSocketAppender 和 SSLServerSocketAppender

前面讨论的SocketAppender组件(及其支持 SSL 的组件)旨在允许应用程序通过网络连接到远程日志记录服务器,以便将日志记录事件传递到服务器。在某些情况下,让应用程序启动与远程日志记录服务器的连接可能不方便或不可行。对于这些情况,Logback 提供了ServerSocketAppender

ServerSocketAppender而不是启动与远程日志记录服务器的连接,而是被动地侦听 TCP 套接字,以 await 来自远程 Client 端的传入连接。传递到附加程序的日志事件将分发到每个连接的 Client 端。没有 Client 端连接时发生的日志记录事件将被“暂时丢弃”。

除了基本的ServerSocketAppender,Logback 还提供SSLServerSocketAppender,它使用安全的加密通道将日志记录事件分发给每个连接的 Client 端。此外,启用 SSL 的附加程序完全支持基于相互证书的身份验证,可用于确保只有授权的 Client 端才能连接到附加程序以接收日志事件。

编码日志事件以在线上传输的方法与SocketAppender相同;每个事件都是ILoggingEvent的序列化实例。仅连接启动方向相反。 SocketAppender在构建与日志服务器的连接时充当主动对等方,而ServerSocketAppender是被动的;它侦听来自 Client 端的传入连接。

ServerSocketAppender子类型只能与 Logback * receiver *组件一起使用。有关此组件类型的更多信息,请参见Receivers

ServerSocketAppender支持以下配置属性:

Property NameTypeDescription
addressString追加程序将在其上侦听的本地网络接口地址。如果未指定此属性,则追加程序将在所有网络接口上侦听。
includeCallerDataboolean如果为 true,则呼叫者数据将可用于远程主机。默认情况下,没有呼叫者数据发送到 Client 端。
portint追加程序将监听的端口号。
sslSSLConfiguration仅支持SSLServerSocketAppender,此属性提供将由附加程序使用的 SSL 配置,如Using SSL中所述。

以下示例说明了使用ServerSocketAppender的配置:

示例:基本的 ServerSocketAppender 配置(logback-examples/src/main/resources/chapters/appenders/socket/server4.xml)

<configuration debug="true">
  <appender name="SERVER" 
    class="ch.qos.logback.classic.net.server.ServerSocketAppender">
    <port>${port}</port>
    <includeCallerData>${includeCallerData}</includeCallerData>
  </appender>

  <root level="debug">
    <appender-ref ref="SERVER" />
  </root>  

</configuration>

请注意,此配置与仅在为附加程序指定的* class *中使用SocketAppender的先前示例不同,并且没有 remoteHost 属性-该附加程序被动地 await 来自远程主机的入站连接,而不是打开与远程日志记录服务器的连接。

以下示例说明了使用SSLServerSocketAppender的配置。

示例:SSLServerSocketAppender 基本配置(logback-examples/src/main/resources/chapters/appenders/socket/ssl/server3.xml)

<configuration debug="true">
  <appender name="SERVER" 
    class="ch.qos.logback.classic.net.server.SSLServerSocketAppender">
    <port>${port}</port>
    <includeCallerData>${includeCallerData}</includeCallerData>
    <ssl>
      <keyStore>
        <location>${keystore}</location>
        <password>${password}</password>
      </keyStore>
    </ssl>
  </appender>

  <root level="debug">
    <appender-ref ref="SERVER" />
  </root>  

</configuration>

此配置与以前的配置之间的主要区别在于,附加程序的* class *属性标识SSLServerSocketAppender类型,并且存在嵌套的 ssl 元素,该元素在此示例中指定了包含 X.509 凭证的密钥存储区的配置追加器。有关 SSL 配置属性的信息,请参见Using SSL

由于ServerSocketAppender子类型旨在与接收器组件一起使用,因此我们将向Receivers章节介绍示例性示例。

SMTPAppender

SMTPAppender会在一个或多个固定大小的缓冲区中累积日志记录事件,并在发生用户指定的事件后在电子邮件中发送适当缓冲区的内容。 SMTP 电子邮件传输(发送)是异步执行的。默认情况下,电子邮件传输是由级别为 ERROR 的日志记录事件触发的。此外,默认情况下,所有事件都使用单个缓冲区。

下表总结了SMTPAppender的各种属性。

Property NameTypeDescription
smtpHostStringSMTP 服务器的主机名。此参数是必需的。
smtpPortintSMTP 服务器正在侦听的端口。默认为 25.
toString收件人的电子邮件地址,作为* pattern *。使用触发事件作为每个外发电子邮件的 Importing 来重新评估该模式。可以通过用逗号分隔目标地址来指定多个收件人。另外,也可以使用多个<to>元素来指定多个收件人。
fromStringSMTPAppender通常的电子邮件地址格式中发送的电子邮件的始发者。如果您希望包含发件人的姓名,请使用格式“ Adam SmithƋ[email protected]ƌ”,以使消息显示为源自“ Adam Smith<[email protected]>”。
subjectString电子邮件的主题。可以是PatternLayout接受为有效转换模式的任何值。布局将在下一章中讨论。


外发电子邮件将具有一个主题行,该主题行对应于在触发电子邮件的记录事件上应用模式。
假设主题选项设置为“日志:%logger-%msg”,并且触发事件的 Logger 名为“ com.foo.Bar”,并且包含消息“ Hello world”,则传出电子邮件的主题行为“日志:com.foo.Bar-Hello World”。
默认情况下,此选项设置为“%logger{20}-%m”。
|判别器| Discriminator |在鉴别符的帮助下,SMTPAppender可以根据鉴别符返回的值将传入事件分散到不同的缓冲区中。默认的鉴别符始终返回相同的值,以便对所有事件使用相同的缓冲区。
通过指定除默认标识符以外的标识符,可以接收包含与特定用户,用户会话或 Client 端 IP 地址有关的事件的电子邮件。
|评估者| IEvaluator |通过创建新的<EventEvaluator/>元素来声明此选项。需要通过 class 属性指定用户希望用作SMTPAppenderEvaluator的类的名称。
在没有此选项的情况下,为SMTPAppender分配了一个OnErrorEvaluator实例,该实例在遇到* ERROR 或更高级别的事件时触发电子邮件传输。
Logback 附带了其他几个评估器,即OnMarkerEvaluator(在下面讨论)和功能强大的评估器JaninoEventEvaluator,在another chapter中进行了讨论。最新版本的 logback 附带了一个更强大的评估器GEventEvaluator
| cyclicBufferTracker | CyclicBufferTracker |顾名思义,CyclicBufferTracker类的实例跟踪循环缓冲区。这样做是基于鉴别器返回的键(请参见上文)。
如果您未指定 cyclicBufferTracker,则会自动创建CyclicBufferTracker的实例。默认情况下,该实例会将事件保留在大小为 256 的循环缓冲区中。您可以在 bufferSize 选项的帮助下更改大小(请参见下文)。
|用户名| String |在普通用户/密码身份验证期间使用的用户名值。默认情况下,此参数为 null。 |
|密码| String |用于普通用户/密码验证的密码值。默认情况下,此参数为 null。 |
| STARTTLS | boolean |如果将此参数设置为 true,则此附加程序将发出 STARTTLS 命令(如果服务器支持),导致连接切换到 SSL。请注意,该连接最初是未加密的。默认情况下,此参数设置为 false。 |
| SSL | boolean |如果将此参数设置为 true,则此附加程序将打开与服务器的 SSL 连接。默认情况下,此参数设置为 false。 |
| charsetEncoding | String |外发电子邮件将被编码为指定的charset。默认字符集编码为“ UTF-8”,在大多数情况下效果很好。 |
| localhost | String |如果未正确配置 SMTPClient 端的主机名,例如如果 Client 端主机名不完全合格,则某些 SMTP 服务器可能会拒绝 Client 端发送的 HELO/EHLO 命令。要解决此问题,可以将 localhost 属性的值设置为 Client 端主机的标准名称。另请参见com.sun.mail.smtp软件包的文档中的“ mail.smtp.localhost”属性。
| asynchronousSend | boolean |此属性确定电子邮件传输是否异步完成。默认情况下,asynchronousSending 属性为“ true”。但是,在某些情况下,异步发送可能是不合适的。例如,如果您的应用程序使用SMTPAppender发送警报以响应致命错误,然后退出,则相关线程可能没有时间发送警报电子邮件。在这种情况下,请将异步发送属性设置为“ false”以进行同步电子邮件传输。 |
| includeCallerData | boolean |默认情况下,includeCallerData 设置为false。如果启用了异步发送,并且您希望在日志中包含调用者数据,则应将 includeCallerData 设置为true。 |
| sessionViaJNDI | boolean | SMTPAppender依靠javax.mail.Session发送电子邮件。默认情况下,sessionViaJNDI 设置为false,因此javax.mail.Session实例由SMTPAppender自身使用用户指定的属性构建。如果 sessionViaJNDI 属性设置为true,则将通过 JNDI 检索javax.mail.Session对象。另请参见 jndiLocation 属性。
通过 JNDI 检索Session可以减少配置/重新配置相同信息所需的位置数,从而使应用程序成为dryer。有关在 Tomcat 中配置资源的更多信息,请参见JNDI 资源方法。注意,如该文档中所述,从 JNDI 检索Session时,请确保从 Web 应用程序
WEB-INF/lib 文件夹中删除 mail.jar activation.jar *。
| jndi 位置| String |在 JNDI 中放置 javax.mail.Session 的位置。默认情况下,jndiLocation 设置为“ java:comp/env/mail/Session”。 |

SMTPAppender仅将最后的 256 个日志记录事件保留在其循环缓冲区中,当缓冲区已满时将丢弃较旧的事件。因此,在SMTPAppender发送的任何电子邮件中传递的日志事件的数量上限为 256.这使内存需求受到限制,同时仍传递合理数量的应用程序上下文。

SMTPAppender依赖于 JavaMail API。已通过 JavaMail API 1.4 版进行了测试。 JavaMail API 需要 JavaBeans 激活框架软件包。您可以从各自的网站下载JavaMail APIJavaBeans 激活框架。在尝试以下示例之前,请确保将这两个 jar 文件放置在 Classpath 中。

一个示例应用程序chapters.appenders.mail.EMail会生成许多日志消息,然后是一条错误消息。它有两个参数。第一个参数是一个整数,对应于要生成的日志事件的数量。第二个参数是 logback 配置文件。 * EMail *应用程序生成的最后一个日志记录事件(错误)将触发电子邮件的传输。

这是供Email应用程序使用的示例配置文件:

示例:SMTPAppender配置示例(logback-examples/src/main/resources/chapters/appenders/mail/mail1.xml)

观看为.groovy

在使用上述配置文件试用chapters.appenders.mail.Email应用程序之前,必须将 smtpHost 设置为与环境相适应的属性值。在配置文件中设置了正确的值后,执行以下命令:

您指定的收件人应收到一封电子邮件,其中包含 100 个记录事件,格式为PatternLayout。下图是显示的电子邮件消息,如 Mozilla Thunderbird 所示。

resulting email

在下一个示例配置文件* mail2.xml 中,smtpHost 与属性之间的值由变量替换确定。这是 mail2.xml *的相关部分。

您可以在命令行中传递所需的参数:

<appender name="EMAIL" class="ch.qos.logback.classic.net.SMTPAppender">
  <smtpHost>${smtpHost}</smtpHost>
  <to>${to}</to>
  <from>${from}</from>
  <layout class="ch.qos.logback.classic.html.HTMLLayout"/>
</appender>

确保用适合您的环境的值替换。

请注意,在此最新示例中,将PatternLayout替换为HTMLLayout,该格式将日志格式设置为 HTML 表。您可以更改列的列表和 Sequences 以及表格的 CSS。有关更多详细信息,请参阅HTMLLayout文档。

假定循环缓冲区的大小为 256,则收件人应看到一封电子邮件,其中包含 256 个事件,这些事件在 HTML 表中方便地设置了格式。请注意,此chapters.appenders.mail.Email应用程序的运行生成了 10'000 个事件,其中仅最后 256 个事件包含在传出电子邮件中。

2nd email

诸如 Mozilla Thunderbird,Eudora 或 MS Outlook 之类的电子邮件 Client 端为 HTML 电子邮件提供了相当不错的 CSS 支持。但是,它们有时会自动将 HTML 降级为纯文本。例如,要在 Thunderbird 中查看 HTML 电子邮件,必须设置“查看→消息正文为→原始 HTML”选项。雅虎! Mail 对 HTML 电子邮件的支持,特别是 CSS 的支持非常好。另一方面,Gmail 遵循基本的 HTML 表结构,却忽略了内部 CSS 格式。 Gmail 支持内联 CSS 格式,但是由于内联 CSS 会使输出结果过于繁琐,因此HTMLLayout不使用内联 CSS。

自定义缓冲区大小

默认情况下,传出消息将包含SMTPAppender看到的最后 256 条消息。如果您的心愿,可以设置下一个示例所示的其他缓冲区大小。

示例:具有自定义缓冲区大小的SMTPAppender配置(logback-examples/src/main/resources/chapters/appenders/mail/customBufferSize.xml)

Triggering event

如果未设置 Evaluator 属性,则SMTPAppender默认为OnErrorEvaluator实例,该实例在遇到错误级别 ERROR 时触发电子邮件传输。虽然响应错误而触发传出电子邮件相对合理,但可以通过提供EventEvaluator接口的不同实现来覆盖此默认行为。

SMTPAppender通过调用evaluate()方法将每个传入事件提交给其评估器,以检查该事件是应该触发电子邮件还是将其放置在循环缓冲区中。当评估者对其评估给出肯定的答案时,将发送一封电子邮件。 SMTPAppender包含一个且只有一个评估器对象。该对象可以 Management 自己的内部状态。出于说明目的,接下来列出的CounterBasedEvaluator类实现了一个事件评估器,借此,每第 1024 个事件都会触发一封电子邮件。

示例:一个EventEvaluator实现,每第 1024 个事件(logback-examples/src/main/java/chapters/appenders/mail/CounterBasedEvaluator.java)得出true

请注意,此类扩展了ContextAwareBase并实现了EventEvaluator。这使用户可以专注于其EventEvaluator的核心功能,并让 Base Class 提供通用功能。

将“评估程序”选项设置为SMTPAppender会指示其使用自定义评估程序。下一个配置文件将SMTPAppender附加到根 Logger。此追加器将CounterBasedEvaluator实例用作其事件评估器。

示例:具有自定义Evaluator和缓冲区大小的SMTPAppender(logback-examples/src/main/resources/chapters/appenders/mail/mail3.xml)

观看为.groovy

基于标记的触发

尽管合理,但是默认的触发策略(每个级别为 ERROR 的事件都会触发外发电子邮件)可能导致电子邮件过多,从而使目标用户的邮箱混乱。 Logback 附带了另一个触发策略,称为OnMarkerEvaluator。它基于标记。本质上,仅当事件用用户指定的标记标记时,才会触发电子邮件。下一个示例应该更清楚地说明这一点。

Marked_EMail应用程序包含多个日志记录语句,其中一些语句的级别为 ERROR。一个值得注意的 Statements 包含一个标记。这是相关的代码。

下一个配置文件将仅在出现带有 NOTIFY_ADMIN 或 TRANSACTION_FAILURE 标记的事件时触发外发电子邮件。

示例:SMTPAppenderOnMarkerEvaluator(logback-examples/src/main/resources/chapters/appenders/mail/mailWithMarker.xml)

观看为.groovy

使用以下命令旋转一下:

<configuration>
  <appender name="EMAIL" class="ch.qos.logback.classic.net.SMTPAppender">
    <evaluator class="ch.qos.logback.classic.boolex.OnMarkerEvaluator">
      <marker>NOTIFY_ADMIN</marker>
      <!-- you specify add as many markers as you want -->
      <marker>TRANSACTION_FAILURE</marker>
    </evaluator>
    <smtpHost>${smtpHost}</smtpHost>
    <to>${to}</to>
    <from>${from}</from>
    <layout class="ch.qos.logback.classic.html.HTMLLayout"/>
  </appender>

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

使用 JaninoEventEvaluator 进行基于标记的触发

注意,代替使用以标记为中心的OnMarkerEvaluator,我们可以使用更通用的JaninoEventEvaluator或更强大的表亲GEventEvaluator。例如,以下配置文件使用JaninoEventEvaluator而不是OnMarkerEvaluator,但在其他方面等效于先前的配置文件。

示例:SMTPAppenderJaninoEventEvaluator(logback-examples/src/main/resources/chapters/appenders/mail/mailWithMarker_Janino.xml)

观看为.groovy

使用 GEventEvaluator 进行基于标记的触发

这是使用GEventEvaluator的等效评估器。

示例:与GEventEvaluator相同(logback-examples/src/main/resources/chapters/appenders/mail/mailWithMarker_GEvent.xml)

观看为.groovy

注意,由于事件可能缺少标记,因此 e.marker 的值可以为 null。因此,使用 Groovy 的安全解引用运算符,即。?。操作员。

Authentication/STARTTLS/SSL

SMTPAppender支持通过普通用户密码以及 STARTTLS 和 SSL 协议进行身份验证。请注意,STARTTLS 与 SSL 的不同之处在于,在 STARTTLS 中,连接最初是未加密的,并且只有在 Client 端发出 STARTTLS 命令(如果服务器支持)之后,连接才会切换到 SSL。在 SSL 模式下,连接从一开始就被加密。

Gmail(SMTP)的 SMTPAppender 配置

下一个示例说明如何使用 SSL 协议为 Gmail 配置SMTPAppender

范例:: SMTPAppender使用 SSL 连线至 Gmail(logback-examples/src/main/resources/chapters/appenders/mail/gmailSSL.xml)

观看为.groovy

Gmail 的 SMTPAppender(STARTTLS)

下一个示例向您展示如何为 STARTTLS 协议的 Gmail 配置SMTPAppender

示例:使用 STARTTLS SMTPAppender到 GMAIL(logback-examples/src/main/resources/chapters/appenders/mail/gmailSTARTTLS.xml)

观看为.groovy

带有 MDCDiscriminator 的 SMTPAppender

如前所述,通过指定除默认标识符以外的标识符,SMTPAppender将生成电子邮件,其中包含与特定用户,用户会话或 Client 端 IP 地址有关的事件,具体取决于指定的标识符。

下一个示例说明了MDCBasedDiscriminator与名为“ req.remoteHost”的 MDC 密钥的结合使用,假定该 MDC 密钥包含访问虚拟应用程序的远程主机的 IP 地址。在 Web 应用程序中,您可以使用MDCInsertingServletFilter来填充 MDC 值。

示例:带有 MDCBasedDsicriminator 的SMTPAppender(logback-examples/src/main/resources/chapters/appenders/mail/mailWithMDCBasedDiscriminator.xml)

观看为.groovy

因此,由SMTPAppender生成的每个传出电子邮件将属于一个* unique *远程主机,从而极大地促进了问题诊断。

非常繁忙的系统中的缓冲区 Management

在内部,鉴别器返回的每个不同的值都将导致创建新的循环缓冲区。但是,最多将保留 maxNumberOfBuffers(默认为 64)。只要缓冲区的数量超过 maxNumberOfBuffers,就会自动丢弃最近更新的缓冲区。作为第二个安全措施,最近 30 分钟内未更新的任何缓冲区也将被自动丢弃。

在每分钟处理大量事务的系统上,只允许少量的 maxNumberOfBuffers(默认为 64)通常会导致传出电子邮件中的事件数不必要地少。实际上,在存在大量事务的情况下,与同一事务相关联的缓冲区将不止一个,因为对于相同的区分值(或事务),缓冲区将被终止并相继重生。请注意,即使在这种非常繁忙的系统中,循环缓冲区的最大数量也受 maxNumberOfBuffers 的限制。

为避免这种溜溜球效应,SMTPAppender会在看到标记为“ FINALIZE_SESSION”的事件后立即释放与给定标识符键关联的缓冲区。这将导致在每个事务结束时丢弃适当的缓冲区。然后,您可以安全地将 maxNumberOfBuffers 的值增加到较大的值,例如 512 或 1024,而不必担心内存不足。

有三种不同但互补的机制可以共同 Management 循环缓冲区。它们确保即使在非常繁忙的系统中,在任何给定的 Moment,只有相关的缓冲区仍保持活动状态。

DBAppender

DBAppender以独立于 Java 编程语言的格式将日志记录事件插入到三个数据库表中。

这三个表是* logging_event logging_event_property logging_event_exception 。它们必须存在,才能使用DBAppender。 Logback 附带将创建表的 SQL 脚本。它们可以在 logback-classic/src/main/java/ch/qos/logback/classic/db/script *文件夹下找到。每个最受欢迎的数据库系统都有一个特定的脚本。如果缺少用于您特定类型的数据库系统的脚本,那么以已经存在的脚本为例,应该很容易编写一个脚本。如果您将它们发送给我们,我们将很乐意在将来的版本中包含缺少的脚本。

如果您的 JDBC 驱动程序支持 JDBC 3.0 规范中引入的getGeneratedKeys方法,并假设您已如上所述创建了适当的数据库表,则不需要其他步骤。否则,必须有一个适合您的数据库系统的SQLDialect。当前,logback 具有适用于 H2,HSQL,MS SQL Server,MySQL,Oracle,PostgreSQL,SQLLite 和 Sybase 的方言。

下表总结了数据库类型及其对getGeneratedKeys()方法的支持。

RDBMS测试版本测试的 JDBC 驱动程序版本支持
getGeneratedKeys()方法
是方言
由 logback 提供
DB2untesteduntestedunknownNO
H21.2.132-unknownYES
HSQL1.8.0.7-NOYES
Microsoft SQL Server20052.0.1008.2(sqljdbc.jar)
MySQL5.0.225.0.8 (mysql-connector.jar)YESYES
PostgreSQL8.x8.4-701.jdbc4NOYES
Oracle10g10.2.0.1 (ojdbc14.jar)YESYES
SQLLite3.7.4-unknownYES
Sybase SQLAnywhere10.0.1-unknownYES

实验表明,在“标准” PC 上,将单个事件写入数据库大约需要 10 毫秒。如果使用池连接,则该数字下降到大约 1 毫秒。请注意,大多数 JDBC 驱动程序已经附带连接池支持。

可以通过几种不同的方式来配置logback回以使用DBAppender,这取决于一个必须连接到数据库的工具以及数据库本身。我们很快就会发现,配置DBAppender的关键问题在于设置其ConnectionSource对象。

为数据库配置DBAppender后,日志记录事件将发送到指定的数据库。如前所述,logback 使用三个表来存储日志记录事件数据。

  • logging_event *表包含以下字段:
FieldTypeDescription
timestampbig int创建日志事件时有效的时间戳。
formatted_messagetext如果将对象与消息一起传递,则使用org.slf4j.impl.MessageFormatter格式化后添加到日志记录事件中的消息。
logger_namevarchar用于发出记录请求的 Logger 的名称。
level_stringvarchar日志记录事件的级别。
reference_flagsmallintLogback 使用此字段来标识具有异常或关联的MDC属性值的日志记录事件。


其值由ch.qos.logback.classic.db.DBHelper计算。包含MDCContext属性的日志记录事件的标志号为* 1 。包含异常的标志的标记号为 2 。包含这两个元素的日志事件的标志号为 3 *。
| caller_filename | varchar |发出记录请求的文件的名称。
| caller_class | varchar |发出记录请求的类。
| caller_method | varchar |发出记录请求的方法的名称。
| caller_line | char |发出记录请求的行号。
| event_id | int |日志记录事件的数据库 ID。

  • logging_event_property *用于存储MDCContext中包含的键和值。它包含以下字段:
FieldTypeDescription
event_idint日志记录事件的数据库标识。
mapped_keyvarcharMDC属性的键
mapped_valuetextMDC属性的值
  • logging_event_exception *表包含以下字段:
FieldTypeDescription
event_idint日志记录事件的数据库标识。
ismallint行在完整堆栈跟踪中的索引。
trace_linevarchar对应行

为了更直观地说明DBAppender完成的工作,下面是一个 MySQL 数据库的屏幕截图,其中包含DBAppender提供的内容。

  • logging_event *表:

记录事件表

  • logging_event_exception *表:

记录事件异常表

  • logging_event_property *表:

记录事件属性表

ConnectionSource

ConnectionSource接口提供了一种可插拔的方式,可以透明地获取需要使用java.sql.Connection的logback类的 JDBC 连接。 ConnectionSource当前有三种实现,即DataSourceConnectionSourceDriverManagerConnectionSourceJNDIConnectionSource

我们将审查的第一个示例是使用DriverManagerConnectionSource和 MySQL 数据库的配置。以下配置文件是需要的。

示例:DBAppender配置(logback-examples/src/main/resources/chapters/appenders/db/append-toMySQL-with-driverManager.xml)

观看为.groovy

必须声明正确的驱动程序。在这里,使用com.mysql.jdbc.Driver类。网址必须以* jdbc:mysql:// *开头。

DriverManagerConnectionSourceConnectionSource的实现,它基于连接 URL 以传统的 JDBC 方式获得连接。

请注意,此类将为对getConnection()的每次调用构建一个新的Connection。建议您使用本机支持连接池的 JDBC 驱动程序,或者创建自己的ConnectionSource实现,以利用您已经在使用的任何池化机制。如果您有权访问支持javax.sql.DataSource的 JNDI 实现,例如在 J2EE 应用程序服务器中,请参阅下面的JNDIConnectionSource

使用DataSource连接到数据库非常相似。现在,配置使用DataSourceConnectionSource,这是ConnectionSource的实现,该实现基于javax.sql.DataSource以推荐的 JDBC 方式获得Connection

示例:DBAppender配置(logback-examples/src/main/resources/chapters/appenders/db/append-with-datasource.xml)

观看为.groovy

请注意,在此配置示例中,我们大量使用了替换变量。当必须将连接详细信息集中在一个配置文件中并由 logback 和其他框架共享时,它们有时很方便。

JNDIConnectionSource

JNDIConnectionSource是另一种ConnectionSource的实现,以 logback 提供。顾名思义,它从 JNDI 检索javax.sql.DataSource,然后利用它获得java.sql.Connection实例。 JNDIConnectionSource主要设计用于 J2EE 应用程序服务器内部或由应用程序服务器 Client 端使用,前提是应用程序服务器支持javax.sql.DataSource的远程访问。因此,可以利用连接池和应用程序服务器提供的其他任何优点。更重要的是,您的应用程序将是dryer,因为不再需要在* logback.xml *中定义DataSource

例如,这是 Tomcat 的配置代码段。尽管所有受支持的数据库系统(上面列出)都可以使用,但它假定 PostgreSQL 为数据库。

在 J2EE 服务器中定义DataSource后,您的 logback 配置文件可以轻松地引用它,如下面的示例所示。

示例:通过JNDIConnectionSource进行DBAppender配置(logback-examples/src/main/resources/chapters/appenders/db/append-via-jndi.xml)

观看为.groovy

请注意,此类将使用无参数构造函数获得javax.naming.InitialContext。在 J2EE 环境中执行时,这通常会起作用。在 J2EE 环境之外时,请确保提供 JNDI 提供程序的文档所述的* jndi.properties *文件。

Connection pooling

日志事件可以以相当快的速度创建。为了跟上必须插入数据库的事件流,建议对DBAppender使用连接池。

实验表明,将连接池与DBAppender一起使用可显着提高性能。使用以下配置文件,日志记录事件将被发送到 MySQL 数据库,而不会进行任何池化。

示例:DBAppender不带缓冲的配置(logback-examples/src/main/resources/chapters/appenders/db/append-toMySQL-with-datasource.xml)

观看为.groovy

使用此配置文件,将 500 个日志记录事件发送到 MySQL 数据库需要 5 秒钟,即每个请求 10 毫秒。当处理大型应用程序时,此数字是不可接受的。

要使用带有DBAppender的连接池,必须有专用的外部库。下一个示例使用c3p0。为了能够使用 c3p0,必须下载它并将* c3p0-VERSION.jar *放在 Classpath 中。

示例:DBAppender具有缓冲的配置(logback-examples/src/main/resources/chapters/appenders/db/append-toMySQL-with-datasource-and-pooling.xml)

观看为.groovy

使用这种新配置,将 500 个日志记录请求发送到上述 MySQL 数据库大约需要 0.5 秒,平均每个请求 1 毫秒,这使性能提高了十倍。

SyslogAppender

syslog 协议是一个非常简单的协议:syslog 发送方向 syslog 接收方发送一条小消息。接收器通常称为* syslog 守护程序 syslog 服务器*。 Logback 可以将消息发送到远程 syslog 守护程序。这是通过使用SyslogAppender实现的。

这是您可以传递给 SyslogAppender 的属性。

Property NameTypeDescription
syslogHostStringsyslog 服务器的主机名。
portStringsyslog 服务器上要连接的端口号。通常,人们不希望更改默认值* 514 *。
facilityString该功能旨在识别消息的来源。


该工具选项必须设置为以下字符串之一:* KERN,USER,MAIL,DAEMON,AUTH,SYSLOG,LPR,NEWS,UUCP,CRON,AUTHPRIV,FTP,NTP,AUDIT,ALERT,CLOCK,LOCAL0,LOCAL1,LOCAL2, LOCAL3,LOCAL4,LOCAL5,LOCAL6,LOCAL7 。大小写并不重要。
| suffixPattern | String | suffixPattern 选项指定发送到 syslog 服务器的消息的非标准化部分的格式。默认情况下,其值为
[%thread]%logger%msg *。 PatternLayout可以使用的任何值都是正确的 suffixPattern 值。
| stackTracePattern | String | stackTracePattern 属性允许自定义出现在每个堆栈跟踪行之前的字符串。此属性的默认值为“\t”,即制表符。 PatternLayout接受的任何值都是 stackTracePattern 的有效值。
| throwableExcluded | boolean |将 throwableExcluded 设置为true将导致与 Throwable 关联的堆栈跟踪数据被忽略。默认情况下,throwableExcluded 设置为false,以便将堆栈跟踪数据发送到 syslog 服务器。 |

日志事件的系统日志严重性是从日志事件的级别转换而来的。 * DEBUG 级别转换为 7 INFO 转换为 6 WARN 转换为 4 ERROR 转换为 3 *。

由于 syslog 请求的格式遵循相当严格的规则,因此SyslogAppender不能使用任何布局。但是,使用 suffixPattern 选项可以使用户显示她希望的任何信息。

这是使用SyslogAppender的示例配置。

示例:SyslogAppender配置(logback-examples/src/main/resources/chapters/appenders/conf/logback-syslog.xml)

观看为.groovy

测试此配置时,应验证远程 syslog 守护程序是否接受来自外部源的请求。经验表明,默认情况下,syslog 守护程序通常会拒绝通过网络连接发出的请求。

SiftingAppender

顾名思义,SiftingAppender可用于根据给定的运行时属性来分离(或筛选)日志记录。例如,SiftingAppender可以根据用户会话将日志记录事件分开,以便将不同用户生成的日志放入不同的日志文件中,每个用户一个日志文件。

Property NameTypeDescription
timeoutDuration超时持续时间内未访问的嵌套追加器被认为是陈旧的。陈旧的附加程序已关闭,并且SiftingAppender未对其进行引用。超时的默认值为 30 分钟。
maxAppenderCountinteger可以创建和跟踪嵌套的追加程序SiftingAppender的最大数量。 maxAppenderCount 的默认值为 Integer.MAX_VALUE。

SiftingAppender通过动态创建嵌套的追加程序来实现这一壮举。嵌套的附加程序是根据SiftingAppender本身的配置(包含在<sift>元素内,请参见下面的示例)中指定的模板创建的。 SiftingAppender负责 Management 子追加程序的生命周期。例如,SiftingAppender将自动关闭并删除所有过时的附加程序。如果没有超过 timeout 参数指定的持续时间,则嵌套的附加程序将被视为过时的。

处理日志记录事件时,SiftingAppender将选择一个子附加程序委托给它。选择标准是在运行时由鉴别器计算的。用户可以在Discriminator的帮助下指定选择标准。现在让我们研究一个例子。

Example

SiftExample应用程序记录一条消息,指出该应用程序已启动。然后将 MDC 密钥“ userid”设置为“ Alice”并记录一条消息。这是明显的代码:

logger.debug(“应用程序已启动”); MDC.put(“ userid”,“ Alice”); logger.debug(“爱丽丝问好”);

配置文件的模板说明了SiftingAppender的用法。

示例:SiftingAppender配置(logback-examples/src/main/resources/chapters/appenders/sift/byUserid.xml)

观看为.groovy

在没有 class 属性的情况下,假定鉴别器类型为MDCBasedDiscriminator。区别值是与 key 属性给定的 key 相关联的 MDC 值。但是,如果该 MDC 值为 null,则将 defaultValue 用作区分值。

SiftingAppender在引用和配置子附加程序方面具有独特的功能。在上面的示例中,SiftingAppender将创建多个FileAppender实例,每个FileAppender实例由与“ userid” MDC 密钥关联的值标识。只要为“用户 ID” MDC 密钥分配了新值,就会从头开始构建新的FileAppender实例。 SiftingAppender跟踪其创建的附加程序。未使用 30 分钟的 Appender 将自动关闭并丢弃。

变量导出拥有不同的追加器实例是不够的。每个实例必须输出到不同的目标资源。为了进行这种区分,在附加程序模板内,导出了传递给鉴别符的密钥,即上例中的“ userid”,并成为variable。因此,此变量可用于区分给定子附加器使用的实际资源。

使用上面显示的“ byUserid.xml”配置文件运行SiftExample应用程序,将产生两个不同的日志文件,即“ unknown.log”和“ Alice.log”。

局部作用域变量从版本 1.0.12 开始,配置文件中本地作用域中定义的属性将可用于嵌套的追加程序。此外,您可以<sift>元素内的define variablesdynamically compute变量。还支持将<sift>元素外部和内部定义的部分中的变量组合在一起。

正确设置超时时间

对于某些类型的应用程序,可能很难正确设置超时参数。如果超时时间太短,则可能会删除嵌套的附加程序,而仅在几秒钟后重新创建。这种现象称为* trashing *。如果超时时间太长,并且快速连续创建了附加程序,则可能会耗尽资源。同样,将 maxAppenderCount 设置得太低也可能导致垃圾回收。

在许多情况下,在代码中精确定位某个位置(在此之后不再需要嵌套的附加程序)可能会更容易。如果存在这样的位置(甚至近似存在),请使用FINALIZE_SESSION标记从该位置记录。只要 SiftingAppender 看到记录为FINALIZE_SESSION的日志记录事件,它将终止关联的嵌套追加器的寿命。到达使用寿命终止时,嵌套的附加程序将停留几秒钟以处理任何即将发生的事件(如果有),然后将其关闭。

AsyncAppender

AsyncAppender 异步记录ILoggingEvent。它仅充当事件分发程序,因此必须引用另一个追加程序才能执行任何有用的操作。

如果 80%的 AsyncAppender 完整缓冲BlockingQueue中的事件,则默认情况下有损。由AsyncAppender创建的工作线程从队列的开头获取事件,并将其分派到AsyncAppender附加的单个追加程序。请注意,默认情况下,如果AsyncAppender的队列已满 80%,它将删除级别 TRACE,DEBUG 和 INFO 的事件。该策略以事件丢失为代价,对性能产生了惊人的有利影响。

应用程序停止/重新部署在应用程序关闭或重新部署后,必须停止AsyncAppender才能停止并回收工作线程并从队列中清除日志记录事件。这可以通过停止 LoggerContext来完成,它将关闭所有附加程序,包括任何AsyncAppender实例。 AsyncAppender将 await 工作线程刷新到 maxFlushTime 中指定的超时。如果您发现LoggerContext关闭期间已丢弃排队的事件,则可能需要增加超时时间。将 maxFlushTime 指定为 0 值将强制AsyncAppender在从 stop 方法返回之前 await 刷新所有排队的事件。

关闭后清理取决于 JVM 关闭的模式,处理排队事件的工作线程可能会中断,从而使事件滞留在队列中。当LoggerContext没有干净地停止或 JVM 在典型控制流之外终止时,通常会发生这种情况。为了避免在这些情况下中断工作线程,可以在启动 JVM 关闭之后将关闭钩子插入正确停止 LoggerContext的 JVM 运行时。当其他关闭钩子尝试记录事件时,关闭钩子也可能是干净关闭 Logback 的首选方法。

这是AsyncAppender:允许的属性列表

Property NameTypeDescription
queueSizeint阻塞队列的最大容量。默认情况下,queueSize 设置为 256.
discardingThresholdint默认情况下,当阻塞队列的剩余容量为 20%时,它将丢弃 TRACE,DEBUG 和 INFO 级别的事件,仅保留 WARN 和 ERROR 级别的事件。要保留所有事件,请将 discardingThreshold 设置为 0.
includeCallerDataboolean提取呼叫者数据可能会非常昂贵。为了提高性能,默认情况下,将事件添加到事件队列时,不会提取与事件关联的呼叫者数据。默认情况下,仅复制“便宜”数据(例如线程名和MDC)。您可以通过将 includeCallerData 属性设置为 true 来指示此附加程序包括调用方数据。
maxFlushTimeint取决于队列深度和到引用的附加程序的延迟,AsyncAppender可能要花费不可接受的时间来完全刷新队列。 LoggerContext停止时,AsyncAppender stop方法 await 此超时,直到工作线程完成。使用 maxFlushTime 指定最大队列刷新超时(以毫秒为单位)。无法在此窗口中处理的事件将被丢弃。此值的语义与Thread.join(long)相同。
neverBlockboolean如果为false(默认设置),则附加程序将在附加到完整队列时阻止,而不是丢失消息。设置为true,附加程序将仅丢弃该消息,并且不会阻止您的应用程序。

默认情况下,事件队列配置的最大容量为 256 个事件。如果队列已满,则将阻止应用程序线程记录新事件,直到工作线程有机会分派一个或多个事件。当队列不再达到最大容量时,应用程序线程能够再次开始记录事件。因此,当追加程序以其事件缓冲区的容量或接近其事件缓冲区的容量进行操作时,异步日志记录将变为伪同步。这不一定是一件坏事。附加程序旨在允许应用程序 continue 运行,尽管花费更多时间记录事件,直到减轻附加程序缓冲区的压力。

为了最大程度地提高应用程序吞吐量,最佳地调整 appender 事件队列的大小取决于几个因素。以下任何一个或所有因素都可能导致显示伪同步行为:

  • 大量的应用程序线程

  • 每个应用程序调用都有大量日志事件

  • 每个日志记录事件有大量数据

  • child 追加器的高延迟

为了保持运行状态,增加队列大小通常会有所帮助,但会浪费应用程序可用的堆空间。

有损行为根据上面的讨论,并且为了减少阻塞,默认情况下,当剩余的队列容量不到 20%时,AsyncAppender将丢弃级别 TRACE,DEBUG 和 INFO 的事件,仅保留级别 WARN 和 ERROR 的事件。当队列的容量不足 20%时,此策略可确保以 TRACE,DEBUG 和 INFO 级别的成本损失事件来无阻塞地处理日志事件(因此具有出色的性能)。通过将 discardingThreshold 属性设置为 0(零),可以防止事件丢失。

示例:AsyncAppender配置(logback-examples/src/main/resources/chapters/appenders/conc/logback-async.xml)

观看为.groovy

编写自己的 Appender

您可以通过子类化AppenderBase来轻松编写您的附加程序。它处理对大多数附加程序共享的过滤器,状态消息和其他功能的支持。派生类仅需要实现一种方法,即append(Object eventObject)

接下来列出的CountingConsoleAppender将有限数量的传入事件追加到控制台上。达到限制后它将关闭。它使用PatternLayoutEncoder格式化事件并接受名为limit的参数。因此,除了append(Object eventObject)外,还需要其他一些方法。如下所示,这些参数是由 logback 的各种配置机制自动处理的。

示例 4.:CountingConsoleAppender(logback-examples/src/main/java/chapters/appenders/CountingConsoleAppender.java)

start()方法检查PatternLayoutEncoder的存在。如果未设置编码器,则附加器无法启动并发出错误消息。

此自定义附加程序说明了两点:

  • 遵循 setter/getter JavaBeans 约定的所有属性均由 logback 配置器透明处理。 start()方法在logback配置期间会自动调用,它负责验证是否设置了附加程序的各种属性并使其一致。

  • AppenderBase.doAppend()方法调用其派生类的 append()方法。实际的输出操作以append()方法发生。特别是,在此方法中,附加程序通过调用事件的布局来格式化事件。

CountingConsoleAppender可以像其他任何附加程序一样进行配置。有关示例,请参阅 samples 配置文件* logback-examples/src/main/resources/chapters/appenders/countingConsole.xml *。

Logback Access

在 logback-classic 中发现的大多数附加程序在 logback-access 中具有相同的功能。这些工作原理与经典的 logback 工作原理相同。在下一节中,我们将介绍它们的用法。

SocketAppender 和 SSLSocketAppender

SocketAppender旨在通过在线传输序列化的AccessEvent对象来logback到远程实体。就访问事件而言,远程日志记录是非侵入式的。在反序列化后的接收端,可以记录该事件,就好像它是本地生成的一样。

SSLSocketAppender扩展了基本SocketAppender,从而允许通过安全套接字层(SSL)logback到远程实体。

access'SocketAppender的属性与经典SocketAppender可用的属性相同。

ServerSocketAppender 和 SSLServerSocketAppender

SocketAppender一样,ServerSocketAppender旨在通过在线传输序列化的AccessEvent对象来logback到远程实体。但是,使用ServerSocketAppender时,附加程序充当服务器,被动侦听 TCP 套接字,以 await 感兴趣的 Client 端的入站连接。传递给附加程序的日志事件将分发给所有连接的 Client 端。

SSLSocketAppender扩展了基本ServerSocketAppender,从而允许通过安全套接字层(SSL)logback到远程实体。

access'ServerSocketAppender的属性与经典ServerSocketAppender可用的属性相同。

SMTPAppender

Access'SMTPAppender的工作方式与经典版本相同。但是,评估者选项却大不相同。默认情况下,SMTPAppender使用URLEvaluator对象。该评估器包含一个 URL 列表,这些 URL 将根据当前请求的 URL 进行检查。当请求提供给URLEvaluator的页面之一时,SMTPAppender发送电子邮件。

这是访问环境中SMTPAppender的示例配置。

示例:SMTPAppender配置(logback-examples/src/main/resources/chapters/appenders/conf/access/logback-smtp.xml)

例如,这种触发电子邮件的方式使用户可以选择在特定过程中是重要步骤的页面。当访问此类页面时,将与先前访问的页面以及用户希望包含在电子邮件中的所有信息一起发送电子邮件。

DBAppender

DBAppender用于将访问事件插入数据库。

DBAppender使用两个表:* access_event access_event_header 。它们都必须存在,才能使用DBAppender。 Logback 附带将创建表的 SQL 脚本。它们可以在 logback-access/src/main/java/ch/qos/logback/access/db/script *目录中找到。每个最受欢迎的数据库系统都有一个特定的脚本。如果缺少针对您特定类型的数据库系统的脚本,那么以现有脚本之一为例,应该很容易编写一个脚本。鼓励您将缺少的脚本贡献给项目。

  • access_event *表的字段如下所述:
FieldTypeDescription
timestampbig int在创建访问事件时有效的时间戳。
requestURIvarchar请求的 URI。
requestURLvarchar所请求的 URL。这是一个由请求方法,请求 URI 和请求协议组成的字符串。
remoteHostvarchar远程主机的名称。
remoteUservarchar远程用户的名称。
remoteAddrvarchar远端 IP 地址。
protocolvarchar请求协议,例如* HTTP HTTPS *。
methodvarchar请求方法,通常是* GET POST *。
serverNamevarchar发出请求的服务器的名称。
event_idint访问事件的数据库 ID。
  • access_event_header *表包含每个请求的 Headers。该信息的组织如下所示:
FieldTypeDescription
event_idint相应访问事件的数据库标识。
header_keyvarcharHeaders 名称,例如* User-Agent *。
header_valuevarcharHeaders 值,例如* Mozilla/5.0(Windows; U; Windows NT 5.1; fr; rv:1.8.1)Gecko/20061010 Firefox/2.0 *

在访问权限的DBAppender中可以使用经典DBAppender的所有属性。后者提供了另一个选项,如下所述。

Property NameTypeDescription
insertHeadersboolean告诉DBAppender使用所有传入请求的 Headers 信息填充数据库。

这是使用DBAppender的示例配置。

示例:DBAppender 配置*(logback-examples/src/main/resources/chapters/appenders/conf/access/logback-DB.xml)*

SiftingAppender

logback-access 中的 SiftingAppender 与 logback-classic 相当。主要区别在于,在 logback-access 中,默认标识符AccessEventDiscriminator不是基于 MDC 的。顾名思义,AccessEventDiscriminator 使用 AccessEvent 中的指定字段作为选择嵌套追加程序的基础。如果指定字段的值为 null,则使用 defaultValue 属性中指定的值。

指定的 AccessEvent 字段可以是 COOKIE,REQUEST_ATTRIBUTE,SESSION_ATTRIBUTE,REMOTE_ADDRESS,LOCAL_PORT 和 REQUEST_URI 之一。请注意,前三个字段要求还必须指定 AdditionalKey 属性。

以下是示例配置文件。

示例:SiftingAppender 配置(logback-examples/src/main/resources/chapters/appenders/conf/sift/access-siftingFile.xml)

在上面的配置文件中,SiftingAppender嵌套FileAppender实例。键“ id”被指定为变量,嵌套FileAppender实例可以使用。默认区分符AccessEventDiscriminator将在每个AccessEvent中搜索“用户名”会话属性。如果没有此类属性可用,则将使用默认值“ NA”。因此,假设名为“ username”的会话属性包含每个已logback用户的用户名,则(当前文件夹的)* byUser/*文件夹下将存在一个日志文件,该文件以包含该用户访问日志的每个用户的名字命名。