LogBack学习记录(四)appender(输出源)的使用

来源:互联网 发布:湄公河惨案 知乎 编辑:程序博客网 时间:2024/05/17 20:32

logback将把日志事件向组件进行输出的过程称为appender,中文意义是输出源,个人感觉这么翻译有点不恰当,后面还是以appender进行称呼。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接口里面大部分都是getter和setter方法,需要注意的是doAppend()方法用一个泛型对象作为其唯一的参数。泛型的具体类型将有调用的logback模型决定。在logback-classic中,泛型的类型将会是IloggingEvent的子类,而在logback-access中,将会是AccessEvent 的子类。doAppend在logback的体系中是非常重要的,它负责将日志事件以合适的格式发送到指定的输出目标中。

Appender的实现类能够通过配置文件进行实例化,并且可以通过name属性进行引用,appender继承了filterAttachable接口。也就是说一个appender示例可以绑定一到多个filter。

appender 的最终目的是用于输出日志事件。实际上,appender是将日志事件转化为layout或者encoder对象来实现的。每个layout或者encoder都必须并且只能与一个appender进行关联。而对于appender来说,部分的appender实现类在内部实现了日志事件的转换,所以对于appender而言,并不一定要求包含layout或者encoder。比如说,socketAppender就是将日志事件进行序列化,然后通过网络进行传输,其内部就不包含layout或者encoder。

AppenderBase

ch.qos.logback.core.AppenderBase 是实现appender接口的一个抽象类。它提供了部分基本的实现功能已被所有的appender的子类来继承。这是logback中所有appender实现类的父类。尽管只是一个抽象类,但是他还是实现了appender接口的doappend方法。具体的实现代码参见如下:

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同样提供了一个类:ch.qos.logback.core.UnsynchronizedAppenderBase ,这个类除了不是线程外,其他的都与appenderbase很类似,为了简便起见,下面我们将对UnsynchronizedAppenderBase 进行详细的介绍:

在doappend方法中,第一件事就是判断guard是否为true,如果为true,立即退出。如果guard 没有赋值,则会给其赋值为true。guard变量就是用来确定doappend方法不会被其自身递归的调用。想象一下,在一个组件中在不同的通过调用append()方法去记录日志。然而实际上确实调用同一个appender来实现,这样就有可能倒是无限的迭代循环的出现,最终出现堆栈溢出。

然后将会判断started属性是否为true。如果不为true,doappend将会发送一个警告信息并退出。也就是说,一旦一个appender关闭了,将不可能在进行日志的输出。appender对象实现了lifecycle接口,在该接口总定义了start(),stop()和isStarted()方法。在完成appender的属性的注入后,logback的配置系统将会调用start方法来激活appender。部分appender的实现类可能会由于缺少某些属性注入而启动失败。如fileappender就必须明确了truncation mode才能进行初始化。明确的启动步骤确保了appender各项属性的准确注入。

如果appender无法启动或者已经停止。警告信息会通过logback的内部状态信息进行输出。在进行多次的重试启动,为了避免相同警告信息的重复输出,logback会关闭重复警告信息的输出。

完成启动后,将会检查appender关联的filter。取决于filter的判定,日志事件可能被接受或者拒绝。没有被filer处理的日志事件,默认会被接受。

然后doappend方法会调用实现类的具体的doappend方法。这个实现类的方法最终将会实现日志的输出工作。

最后,guard将会被释放,以允许后续的方法来调用doappend方法。

Logback-core

Logback-core作为其他logback模块的基础。因此,logback-core必须精简并且可以进行定制扩展。下面对一些appender的实现类进行讨论。

OutputStreamAppender

outputstreamAppender 将日志事件转换为java 的io流。这个类为其他appender实现类提供了基础的方法。用户一般并不直接使用outputstreamAppender,因为无法在配置文件中对其进行配置(很难对输出的目标进行配置)。outputstreamappender 也有配置属性,如下:

Property NameTypeDescriptionencoderEncoderDetermines the manner in which an event is written to the underlying OutputStreamAppender. Encoders are described in a dedicated chapter.
用以确定事件转化为流的方式。outputstreamappender是consoleappender,fileappender,rollingfileappender的父类。关系如下图所示。



A UML diagram showing OutputStreamAppender and sub-classes

consoleAppender

正如名字所显示的,console是将日志事件输出到console中或者更加精确的说是system.out 或者systm.err的目标,前者是默认的consoleappender的输出对象。由于system.out和system.err都是java的printStream的子类。因此将他们都封住在outputstreamwriter中以进行I/O操作。

consoleappender的属性配置如下:

Property NameTypeDescriptionencoderEncoderSee OutputStreamAppender properties.,用于配置encodertargetStringOne of the String values System.out or System.err. The default target is System.out.
System.out 或者System.err两者之一,默认是前者withJansibooleanBy the default withJansi property is set to false. Setting withJansi to true activates the Jansi library which provides support for ANSI color codes on Windows machines. On a Windows host, if this property is set to true, then you should put "org.fusesource.jansi:jansi:${jansi.version}" on the class path. Note that Unix-based operating systems such as Linux and Mac OS X support ANSI color codes by default.

Under the Eclipse IDE, you might want to try the ANSI in Eclipse Console plugin.

默认为false,当设置为true时,可以采用ansi的颜色编码,但是需要导入jansi的库,个人感觉没用。

下面是一个简单的例子,和前面说过的一样:

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


FileAppender

fileappender是outputstreamappender的子类,用于将日志事件存进文件中。目标文件通过file属性进行设置。如果该文件已经存在,是直接进行添加还是清空原文件再添加取决于append属性的设置。fileappender的属性设置如下所示:
Property NameTypeDescriptionappendbooleanIf true, events are appended at the end of an existing file. Otherwise, if append is false, any existing file is truncated. The append option is set to true by default.
如果设置为true,将会把日志添加到文件结尾处,否则将源文件内容删除,然后进行添加。默认为true。encoderEncoderSee OutputStreamAppender properties. encoder的配置fileStringThe name of the file to write to. If the file does not exist, it is created. On the MS Windows platform users frequently forget to escape back slashes. For example, the value c:\temp\test.log is not likely to be interpreted properly as '\t' is an escape sequence interpreted as a single tab character (\u0009). Correct values can be specified as c:/temp/test.log or alternatively as c:\\temp\\test.log. The File option has no default value.

If the parent directory of the file does not exist, FileAppender will automatically create it, including any necessary but nonexistent parent directories.

指定文件名。如果文件不存在,则创建。在windows系统中,用户经常会忘记对反斜杠进行处理。比如c:\temp\test.log的配置就是不真确的。因为‘“\t”会作为转义字符被视为(\u0009)。正确的方法应该是c:\\temp\\test.log.file属性没有默认值。需要注意的是,如果指定文件的父级文件目录没有创建的话,也会自动进行创建。

prudentbooleanIn prudent mode, FileAppender will safely write to the specified file, even in the presence of other FileAppender instances running in different JVMs, potentially running on different hosts. The default value for prudent mode is false.
在prudent模式下,fileappender将会安全向指定文件写入日志,甚至在对线程的情况下也可以安全的写入。默认值是false。

Prudent mode can be used in conjunction with RollingFileAppender although some restrictions apply.

prudent模式可以和rollingfileappender结合起来使用,当然有一些限制。

Prudent mode implies that append property is automatically set to true.

在prudent模式下,append属性将自动设置为true。

Produdent more relies on exclusive file locks. Experiments show that file locks approximately triple (x3) the cost of writing a logging event. On an "average" PC writing to a file located on a local hard disk, when prudent mode is off, it takes about 10 microseconds to write a single logging event. When prudent mode is on, it takes approximately 30 microseconds to output a single logging event. This translates to logging throughput of 100'000 events per second when prudent mode is off and approximately 33'000 events per second in prudent mode.

produdent模式依赖于对于文件的锁定。实验证明,向锁定的文档中记录日志信息要耗费三倍的时间。在一台一般配置的pc机上,向本地磁盘的一个文件中写入一条日志,一般需要10毫秒。当启动produent模式,将耗费30毫秒。也就是说,在普通模式下,一般每秒能够处理100000个,而在produent模式下就只能每秒处理33000个日志事件了。

Prudent mode effectively serializes I/O operations between all JVMs writing to the same file. Thus, as the number of JVMs competing to access a file increases so will the delay incurred by each I/O operation. As long as the total number of I/O operations is in the order of 20 log requests per second, the impact on performance should be negligible. Applications generating 100 or more I/O operations per second can see an impact on performance and should avoid using prudent mode.

prudent模式需要对所有的jvm对于日志文件的IO操作都进行线性化。因此,随着jvm抢夺操作文件的数量增多,IO的延迟也将加大。一般来说,如果每秒大约20个日志请求的话,这种延时是可以忽略的,如果每秒大于100的请求时,延迟则会比较严重,建议就不要采用prudent模式了。

NETWORKED FILE LOCKS When the log file is located on a networked file system, the cost of prudent mode is even greater. Just as importantly, file locks over a networked file system can be sometimes strongly biased such that the process currently owning the lock immediately re-obtains the lock upon its release. Thus, while one process hogs the lock for the log file, other processes starve waiting for the lock to the point of appearing deadlocked.

The impact of prudent mode is highly dependent on network speed as well as the OS implementation details. We provide an very small application called FileLockSimulator which can help you simulate the behavior of prudent mode in your environment.

如果文件位于网络上,则延时会更加严重,并且可能产生死锁问题。而且这种方式同时受到网速和操作系统的限制。因此我们提供一个小的应用FileLockSimulaor来实现网络文件的线程安全存储。


默认情况下,日志事件会立即转换为底层的输出流。当你直接关闭应用而没有关闭appender时,你的日志事件不会发生泄漏,这种默认的方式是安全的。然而,当日志数据过于庞大时,就应该考虑将Encoder中的immediateFlush属性设置为false.

下面是一个fileappender的配置样例:

<configuration>  <appender name="FILE" class="ch.qos.logback.core.FileAppender">    <file>testFile.log</file>    <append>true</append>    <!-- 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>


根据时间唯一命名日志文件Uniquely named files (by timestamp)

在应用的开发过程中或者在一些生命期比较短的应用中,比如批处理程序,要求能够在每次应用启动时建立一个新的日志文件。通过<timestamp>元素可以很容易的实现这一点。如下例所示:

注意中间的T就是一个表示符,可以没有或者换成任意其他符号。

View as .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属性是用以唯一标示这个timestamp以便后文使用的。datepattern属性用以将时间转换为字符串,转化的格式采用simpledateformat格式。timereference属性定义了具体的时间,默认采用的时间是配置文件解析的时间。然而在一些特定环境中,将采用上下文创建的时间。可以通过将timereference属性设置为contextbirth来实现。用法如下所示:

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

RollingFileAppender
rollingFileAppender继承自fileappender,能够滚动存储日志文件。例如,rollingfileappender能够将日志存储到一个名为log.txt的文件中,一旦满足了一定的条件就能自动改变输出对象为另外的文件。
rollingfileappender有两个重要的子组件:rollingpolicy,用于保证日志的滚动。Triggeringpolicy用于确定滚动是否已经发生。因此RollingPolicy是负责如果发生滚动而triggeringpolicy是负责何时发生滚动的。一个rollingFileappender必须同时创建了rollingpolicy和triggeringpolicy才能够使用。当然,如果rollingpolicy同时也实现了triggeringpolicy接口,则只用指定一个就行了。

rollingfileappender的属性如下:


Property NameTypeDescriptionfileStringSee FileAppender properties. 文件appendbooleanSee FileAppender properties. 参见前面的encoderEncoderSee OutputStreamAppender properties.参见前面的 rollingPolicyRollingPolicyThis option is the component that will dictate RollingFileAppender's behavior when rollover occurs. See more information below.triggeringPolicyTriggeringPolicyThis option is the component that will tell RollingFileAppender when to activate the rollover procedure. See more information below.prudentbooleanFixedWindowRollingPolicy is not supported in prudent mode.

RollingFileAppender supports the prudent mode in conjunction with TimeBasedRollingPolicy albeit with two restrictions.

  1. In prudent mode, file compression is not supported nor allowed. (We can't have one JVM writing to a file while another JVM is compressing it.)
  2. The file property of FileAppender cannot be set and must be left blank. Indeed, most operating systems do not allow renaming of a file while another process has it opened.
See also properties for FileAppender.
fixedwindowRollingPolicy不支持 prudent模式。
rollingfileappender支持prudent模式,但是需要用time八色rollingpolicy,并且有两个限制:
1,在prudent模式下,不能启动文件压缩
2,文件属性不能设置,必须为空

Overview of rolling policies

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 方法实现将当前的日志文件存档。getacticefilename 用于计算当前日志文件的名称。getCompressionMode用于决定压缩方式。最后RollingPolicy通过setparent方法给出一个其父类fileappender的引用。

TimeBasedRollingPolicy

timebasedRollingpolicy 几乎是最流行的滚动策略了。他采用时间作为触发条件,可以按照天,月等等。timebaserollingpolicy同时承担了滚动和触发的作用。实际上time八色rollingpolicy同时实现了rollingpolicy和triggeringpolicy接口。time八色rollingpolicy有一个必须属性“fileNamePattern”和多个可选属性:
Property NameTypeDescriptionfileNamePatternStringThe mandatory fileNamePattern property defines the name of the rolled-over (archived) log files. Its value should consist of the name of the file, plus a suitably placed %d conversion specifier. The %d conversion specifier may contain a date-and-time pattern as specified by the java.text.SimpleDateFormat class. If the date-and-time pattern is omitted, then the default patternyyyy-MM-dd is assumed. The rollover period is inferred from the value of fileNamePattern.
必须属性filenamepattern 定义了滚动日志文件的名称。这个名称必须包含文件的名称加上一个合适的变量。这个变量通过date-and-time模式可以用simpledateformat来构造。如果date-and-time被忽略了则采用默认的yyyy-MM--dd来设置。翻滚的周期由fileNamePattern来决定。

Note that the file property in RollingFileAppender (the parent of TimeBasedRollingPolicy) can be either set or omitted. By setting the file property of the containing FileAppender, you can decouple the location of the active log file and the location of the archived log files. The current logs will be always targeted at the file specified by the file property. It follows that the name of the currently active log file will not change over time. However, if you choose to omit the file property, then the active file will be computed anew for each period based on the value of fileNamePattern. The examples below should clarify this point.

需要注意的是file属性可以设置或者不设置。如果设置的话,可以将正在使用日志文件和归档的日志文件进行区分:正在使用的日志文件名将由file属性决定。然而,如果忽略了file属性的设置的话,正在使用的日志文件就是每次根据filenamepattern计算出来的最新的文件。后面的例子将会说明这一点。

The date-and-time pattern, as found within the accolades of %d{} follow java.text.SimpleDateFormat conventions. The forward slash '/' or backward slash '\' characters anywhere within the fileNamePattern property or within the date-and-time pattern will be interpreted as directory separators.

It is possible to specify multiple %d tokens but only one of which can be primary, i.e. used to infer the rollover period. All other tokens must be marked as auxiliary by passing the 'aux' parameter (see examples below).

date-and-time模式中(遵循了simpledateformat的模式),filenamepattern属性,data-andtime中任何位置的正斜杠或者反斜杠都会被解释为分隔符。

有可能指定了多个%d符号,但是只有一个是主要的,例如用来指定滚动间隔。其他的都是辅助作用的。参见后面的例子。

maxHistoryintThe optional maxHistory property controls the maximum number of archive files to keep, deleting older files. For example, if you specify monthly rollover, and set maxHistory to 6, then 6 months worth of archives files will be kept with files older than 6 months deleted. Note as old archived log files are removed, any folders which were created for the purpose of log file archiving will be removed as appropriate.
maxhistory属性用来控制存档文件的最大量,将删除过期的文件。例如,如果指定了按照每月滚动一次,并且将maxhistory设置为6.那么将只保存6个月日志文件,6个月以前的文件都将进行删除。注意,在日志文件删除的同时,为该日志文件存档所创建的相关文件也会删除。cleanHistoryOnStartboolean

If set to true, archive removal will be executed on appender start up. By default this property is set to false.

Archive removal is normally performed during roll over. However, some applications may not live long enough for roll over to be triggered. It follows that for such short-lived applications archive removal may never get a chance to execute. By settingcleanHistoryOnStart to true, archive removal is performed at appender start up.

如果设置为true,在appender启动时将执行文档的删除。默认设置为false。存档日志的删除一般发生在滚动过程中,但是部分应用可能无法运行太长的时间以触发滚动行为。比如一些小的短期应用根本没有机会触发滚动,则可以将这个属性设置为true,以便每次启动appender时清空历史日志。


对filenamepattern的介绍:

fileNamePatternRollover scheduleExample/wombat/foo.%dDaily rollover (at midnight). Due to the omission of the optional time and date pattern for the %d token specifier, the default pattern of yyyy-MM-dd is assumed, which corresponds to daily rollover.
每天进行滚动(午夜执行)。缺省time and date 的模式使用%d进行标记。默认的模式是yyyy-MM-dd,每天进行滚动

file property not set: During November 23rd, 2006, logging output will go to the file/wombat/foo.2006-11-23. At midnight and for the rest of the 24th, logging output will be directed to /wombat/foo.2006-11-24.

file property set to /wombat/foo.txt: During November 23rd, 2006, logging output will go to the file /wombat/foo.txt. At midnight, foo.txt will be renamed as /wombat/foo.2006-11-23. A new /wombat/foo.txt file will be created and for the rest of November 24th logging output will be directed to foo.txt.

file属性没有设置:2006年11月23日,日志将要输出到 file/wombat/foo.2006-11-23.在24号午夜,日志将会输出到/wombat/foo.2006-11-24.

file属性设置为 /wombat/foo.txt.在2006-11-23,日志将会输出到/wombat/foo.txt中。在午夜,foo.txt文件将会被重命名为/wombat/foo.2006-11-23.一个新的/wombat/foo.txt文件将会被创建,24号的日志将会被输出到这个文件。

/wombat/%d{yyyy/MM}/foo.txtRollover at the beginning of each month.
每个月滚动一次

file property not set: During the month of October 2006, logging output will go to/wombat/2006/10/foo.txt. After midnight of October 31st and for the rest of November, logging output will be directed to /wombat/2006/11/foo.txt.

file property set to /wombat/foo.txt: The active log file will always be /wombat/foo.txt. During the month of October 2006, logging output will go to /wombat/foo.txt. At midnight of October 31st, /wombat/foo.txt will be renamed as /wombat/2006/10/foo.txt. A new /wombat/foo.txt file will be created where logging output will go for the rest of November. At midnight of November 30th, /wombat/foo.txt will be renamed as/wombat/2006/11/foo.txt and so on.

file属性没有设置:在2006的10月,日志将会输出到wombat/2006/10/foo.txt.在十月31号的午夜,11月份的日志将会输出到wombat/2006/11/foo.txt中。

file的属性设置为/wombat/foot.txt.激活的日志文件一直是/wombat/foo.txt.在2006.10月,日志将输出到wombat/foot.txt文件中,在10月31的午夜,foo.txt文件将会重命名为/wombat/2006/10/foo.txt.一个新的foo.txt将会被创建。以后的日志将会输出到这个文件里面

/wombat/foo.%d{yyyy-ww}.logRollover at the first day of each week. Note that the first day of the week depends on the locale.
每周的第一天滚动。注意的是,每周的第一天取决于具体的地点。Similar to previous cases, except that rollover will occur at the beginning of every new week.
与前面类似,每周的开始触发/wombat/foo%d{yyyy-MM-dd_HH}.logRollover at the top of each hour.
每个小时触发 Similar to previous cases, except that rollover will occur at the top of every hour.
与前面相同,每个小时触发/wombat/foo%d{yyyy-MM-dd_HH-mm}.logRollover at the beginning of every minute.
每分钟触发Similar to previous cases, except that rollover will occur at the beginning of every minute.
与前面相同,每分钟触发/foo/%d{yyyy-MM,aux}/%d.logRollover daily. Archives located under a folder contaning year and month.
每天滚动。在一个文档中按照年和月进行存档。根据主变量进行日志文件的创建,根据辅助变量进行文件的存档。In this example, the first %d token is marked as auxiliary. The second %d token, with time and date pattern omitted, is then assumed to be primary. Thus, rollover will occur daily (default for %d) and the folder name will depend on the year and month. For example, during the month of November 2006, archived files will all placed under the /foo/2006-11/ folder, e.g /foo/2006-11/2006-11-14.log.
在这个例子中,第一个%d是辅助标记。第二个%d省略了time and date模式,被认为是主要标记,因此滚动将会每天触发,而日志文件的名称将会依据年月进行存档。比如,2006年11月,存档文件将会被放置在/foo/2006-11的文件夹下,如foo/2006-11/2006-11-14.log

Any forward or backward slash characters are interpreted as folder (directory) separators. Any required folder will be created as necessary. You can thus easily place your log files in separate folders.

任何正斜杠或者反斜杠都被视为文件切割符。相关的文件夹将会根据需要自动创建。

可以通过将filenamepattern属性的结尾设置为.gz或者.zip来启动日志文件的自动压缩功能,举例如下:

fileNamePatternRollover scheduleExample/wombat/foo.%d.gzDaily rollover (at midnight) with automatic GZIP compression of the archived files
按天滚动,并且自动将归档文件进行压缩。

file property not set: During November 23rd, 2009, logging output will go to the file /wombat/foo.2009-11-23. However, at midnight that file will be compressed to become /wombat/foo.2009-11-23.gz. For the 24th of November, logging output will be directed to /wombat/folder/foo.2009-11-24 until it's rolled over at the beginning of the next day.

文件属性没有设置:2009年11月23号的日志将会输出到wombat/foo.2009-11-23中,在午夜,该文件将会被压缩为2009-11-23.gz,24号的日志将会输出到2009-11-24的文件里面。

file property set to /wombat/foo.txt: During November 23rd, 2009, logging output will go to the file/wombat/foo.txt. At midnight that file will be compressed and renamed as /wombat/foo.2009-11-23.gz. A new/wombat/foo.txt file will be created where logging output will go for the rest of November 24rd. At midnight November 24th, /wombat/foo.txt will be compressed and renamed as /wombat/foo.2009-11-24.gz and so on.

如果文件属性设置了:foo.txt.则在23号日志将输出到这个文件中,在午夜这个文件将会被压缩并且重命名为2009-11-23.gz.一个新foo将会被创建并进行日志的记录。

filenamepattern有两个作用:第一计算滚动的频率第二计算每个日志文件的名称。需要注意的是可以采用两种不同模式来实现:yyyy-MM或者yyyy@MM都是按照月进行滚动。

通过设置file属性,能够将正在使用的日志文件和存档日志文件区分开。日志将会输出到file属性设置的文件中,也就是说正在使用的日志文件的名字是不变的。而如果选择忽略file属性,则真在使用的日志文件的名字是根据滚动自动生成的。选择忽略file属性有一个好处就是避免了当回滚时,进行文件改名操作时,有另外的程序正在对日志文件进行操作而造成异常。

maxhistory属性控制了存档的文件数,删除过期的日志文档。比如将maxhistory设置为6,就会保留6个月的数据,6个月前的数据会被删除。需要注意的是,当存档文件删除时,与其相关的附属文件也会被删除。

由于一些技术原因,滚动并不是由时间驱动的,而是由日志来进行驱动。比如,在按天滚动的模式下,正常情况下应该是午夜12:00触发滚动。但是如果午夜12:00的时候没有任何日志事件,而到了00:20分才有新的日志事件,那么滚动就将在00:20分触发。

下面是一个采用的TimeBaseRollingpolicy的rollingfileappender的配置文件的例子:

View as .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 -->      <maxHistory>30</maxHistory>    </rollingPolicy>    <encoder>      <pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>    </encoder>  </appender>   <root level="DEBUG">    <appender-ref ref="FILE" />  </root></configuration>

下面的例子中使用了prudent模式,个人建议没有必要使用这个模式,会大大降低日志的效率

View as .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>     </rollingPolicy>    <encoder>      <pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>    </encoder>  </appender>   <root level="DEBUG">    <appender-ref ref="FILE" />  </root></configuration>

FixedWindowRollingPolicy

当滚动发生时,fixedwindowRollingpolicy将会根据算法对日志文件进行重命名:

The fileNamePattern option represents the file name pattern for the archived (rolled over) log files. This option is required and must include an integer token%i somewhere within the pattern.

filenamepattern属性设置了存档文件名的模式,这个属性必须在其中包含一个数字标记i%。下面是他的一些属性:

Property NameTypeDescriptionminIndexint

This option represents the lower bound for the window's index.

最小值

maxIndexint

This option represents the upper bound for the window's index.

最大值

fileNamePatternString

This option represents the pattern that will be followed by the FixedWindowRollingPolicy when renaming the log files. It must contain the string %i, which will indicate the position where the value of the current window index will be inserted.

For example, using MyLogFile%i.log associated with minimum and maximum values of 1 and 3 will produce archive files namedMyLogFile1.logMyLogFile2.log and MyLogFile3.log.

Note that file compression is also specified via this property. For example, fileNamePattern set to MyLogFile%i.log.zip means that archived files must be compressed using the zip format; gz format is also supported.

这个属性设置了日志文件的命名方式,在其中必须包含一个变量值。比如采用 MyLogFile%i.log的方式,并且最小值为1,最大值为3,那么将生成MyLogFile1.log,MyLogFile2.log,MyLogFile3.log,这三个文件。同样可以将文件的结尾设置为.zip或者.gz的方式来启动文件的自动压缩。如mylog%i.log.zip

fixedWindowRollingPolicy需要对文件执行windowsize次的文件重命名操作,因此建议不要将这个值设置过大。当用户把这个值设置过大时,目前的实现机制,会将这个值自动设置为12.、

下面举一个例子,将民index设置为1,将maxindex 设置为3,file那么Pattern设置为foo%i.log并且file属性设置为foo.log(此处英文版应该有编写错误)

Number of rolloversActive output targetArchived log filesDescription0foo.log-No rollover has happened yet, logback logs into the initial file.
没有滚动发生,直接向foo.log中输出日志1foo.logfoo1.logFirst rollover. foo.log is renamed as foo1.log. A new foo.log file is created and becomes the active output target.
第一次滚动,foo.log更名为foo1.log,一个新的foo.log文件创建并进行日志记录。2foo.logfoo1.log, foo2.logSecond rollover. foo1.log is renamed as foo2.logfoo.log is renamed as foo1.log. A new foo.log file is created and becomes the active output target.
第二次滚动,foo1.log 更名为foo2.log,foo.log 更名为foo1.log,一个新的foo.log创建并记录日志。3foo.logfoo1.log, foo2.log, foo3.logThird rollover. foo2.log is renamed as foo3.logfoo1.log is renamed as foo2.logfoo.log is renamed as foo1.log. A new foo.logfile is created and becomes the active output target.
第三次滚动,foo2变为foo3,foo1变为foo2,foo变为foo1,新的foo创建并记录日志。4foo.logfoo1.log, foo2.log, foo3.logIn this and subsequent rounds, the rollover begins by deleting foo3.log. Other files are renamed by incrementing their index as shown in previous steps. In this and subsequent rollovers, there will be three archive logs and one active log file.
在后续的滚动中,最久的foo3文件将会被删除,然后重复前面的顺序。这样,自此之后将始终有一个激活的日志文件和三个存档的日志文件。

下面的例子说明了在rollingfileappender中使用fixedwindowrollingpolicy。需要注意的是,file 属性必须进行设置,即使在一些情况下,它的值可能可能和通过filename生成的一样。

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

Size and time based archiving

有的时候可能不仅要控制存档日志文件的时间还要控制其的大小,例如说一些日志处理工具对于日志文件的大小有限制。为了实现这一目标,logback为timebaserollingpolicy提供了一个组件sizeandtimebasedfnatp,用于创建日志文件名称和触发滚动。
下面是一个例子:
View as .groovy
<configuration>  <appender name="ROLLING" class="ch.qos.logback.core.rolling.RollingFileAppender">    <file>mylog.txt</file>    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">      <!-- rollover daily -->      <fileNamePattern>mylog-%d{yyyy-MM-dd}.%i.txt</fileNamePattern>      <timeBasedFileNamingAndTriggeringPolicy            class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">        <!-- or whenever the file size reaches 100MB -->        <maxFileSize>100MB</maxFileSize>      </timeBasedFileNamingAndTriggeringPolicy>    </rollingPolicy>    <encoder>      <pattern>%msg%n</pattern>    </encoder>  </appender>  <root level="DEBUG">    <appender-ref ref="ROLLING" />  </root></configuration>

需要注意的是,在之前的%d变量后面又添加了一个%i变量。每次当日志文件达到所设置的上限(maxfilesize属性设置),将会触发滚动进行存档,i%的起始值为0.

size and time base存档支持对过期日志文件的删除,需要对maxhistory的值进行设定。当系统应用重启是,日志将会在从真确位置进行记录。比如,在某个滚动阶段文档的i%值为最大的文档中进行日志记录。

Overview of triggering policies

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同样也是一种滚动策略。

SizeBasedTriggeringPolicy

sizebasedtriggeringpolicy 监控当前使用的日志文件的大小。当文件大于指定的大小时,将会通过rollingfileappender触发滚动事件。它只接受一个属性,maxfilesize。默认值是10MB。maxfilesize属性可以以KB,MB,GB作为单位,如5000000.5000KB,5MB ,5GB,前面三个值是相等的。举例如下,文件大小设置为5MB。
View as .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

尽管logging event在logback-core里面非常通用,但是在logback-class中,日志事件一般是IloggingEvent的实例。Logback-classic只是对日志事件做了一些特定的处理而已。

这些处理的方式包括:

SocketAppender and SSLSocketAppender

ServerSocketAppender and SSLServerSocketAppender

SMTPAppender

DBAppender

SyslogAppender

SiftingAppender

AsyncAppender

Logback Access

在logback-class中有的appender在logback-access中一般都有,本质上他们实现了相同的功能.

SocketAppender and SSLSocketAppender

ServerSocketAppender and SSLServerSocketAppender

SMTPAppender

DBAppender

SiftingAppender

最后的logback-classic和logback-access 目前在实际中完全没有用到,将包含的appender种类进行列出,基本上都能够看命知意。等到用到的时候再仔细研究吧。appender的学习暂时到此为止。