009_logback本地Appender

一. Appender接口

1. 什么是Appender?

1.1. Appender是负责写记录事件的组件。Appender必须实现接口"ch.qos.logback.core.Appender"。

2. Appender接口的重要方法

3. Appender接口里的多数方法都是getter和setting。值得注意的是doAppend()方法, 它唯一的参数是类型E的对象。类型E的实际类型视logback模块的不同而不同。在logback-classic模块里, E可能是"ILoggingEvent"类型; 在logback-access模块里, E可能是"AccessEvent"类型。doAppend()方法也许是logback框架里最重要的方法, 它负责以适当的格式将记录事件输出到合适的设备。

4. Appender接口扩展了FilterAttachable接口, 因此appender实例可被关联一个或多个过滤器。

5. FilterAttachable接口的实现类FilterAttachableImpl

6. Appender是最终负责输出记录事件的组件。然而, 它们可以把实际格式化的任务委托给Layout或Encoder对象。每个layout/encoder都关联到一个且仅一个appender。有些appender有内置的或固定的事件格式, 因此它们不需要也没有layout/encoder。例如: SocketAppender在发送记录事件之前只是简单地对其进行序列化。

二. AppenderBase抽象类

1. 类ch.qos.logback.core.AppenderBase是实现了Appender接口的抽象类。AppenderBase提供所有appender共享的基本功能, 比如设置/获取名字的方法, 其活动状态和过滤器。AppenderBase是loback里继承自appender的一个超类。尽管是抽象类, AppenderBase实际上实现了Appender接口的doAppend()方法。

2. AppenderBase抽象类doAppend方法实现

3. 这里的doAppend()方法的实现是同步的(synchronized), 确保不同线程对同一个appender的记录是线程安全的。这里进行的同步并不总是合适的, logback带了与AppenderBase非常相似的类ch.qos.logback.core.UnsynchronizedAppenderBase, 之后会讨论它。

4. doAppend()方法做的第一件事就是检查"guard"是否为true。如果是, 则立即退出方法。如果未设置"guard", 紧接下来的语句就把它设为true。"guard"确保doAppend()方法不会递归/重复调用自己。

5. 之后的语句里, 我们检查"started"字段是否为true。如果不是, doAppend()会发出一条警告信息然后返回。换句话说, appender一旦关闭后, 就无法再向它写入。Appender对象实现LifeCycle接口, 意味着它们实现了start()、stop()和isStarted()方法。对appender的所有属性都设值后, Joran调用start()方法让appender激活自己的属性。

6. LifeCycle接口

7. 如果appender不能启动或者已经被停止, 则会通过logback的内部状态管理系统发出一条警告消息。尝试几次后, 为了避免内部状态系统被同一条警告消息所淹没, doAppend()方法将停止发出这些警告消息。

8. 接着的if语句检查关联的过滤器的结果。根据过滤器链的判断结果, 事件被拒绝或接受。如果过滤器链没有结果, 则事件被默认接受。

9. doAppend()方法然后调用派生类的append()方法, 此方法真正把事件增加到合适的设备。

10. 最后, 释放guard, 允许下一个doAppend()调用。

三. UnsynchronizedAppenderBase抽象类

1. UnsynchronizedAppenderBase抽象类和AppenderBase抽象类最大的区别就是doAppend方法不是同步的

四. OutputStreamAppender类

1. OutputStreamAppender把事件添加到java.io.OutputStream。该类提供其他appender所需的基本服务。用户通常不直接实例化OutputStreamAppender对象。由于java.io.OutputStream一般无法被方便地映射到字符串, 所以无法在配置文件里指定目标OutputStream对象。简而言之, 你不能在配置文件里配置OutputStreamAppender。但这不是说OutputStreamAppender没有配置属性。它的属性如下。

2. OutputStreamAppender是另外三个appender的超类: ConsoleAppender、FileAppender及其直接子类RollingFileAppender。下图演示了OutputStreamAppender和其子类的类图。

五. ConsoleAppender类 

1. ConsoleAppender把事件添加到控制台, 更准确地说是System.out或System.err, 默认为前者。

2. System.out和System.err都是java.io.PrintStream类型, 因此, 它们被包裹在有缓冲I/O操作的OutputStreamWriter里。

3. ConsoleAppender配置

<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
	<layout class="ch.qos.logback.classic.PatternLayout">
		<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
	</layout>
</appender>

六. FileAppender类

1. FileAppender是OutputStreamAppender的子类, 把记录事件添加到文件。目标文件通过File选项指定。如果文件已经存在, 则根据Append属性追加或清空文件。

2. FileAppender配置

<appender name="file" class="ch.qos.logback.core.FileAppender">
	<file>log/my.log</file>
	<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
		<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
	</encoder>
</appender>

七. RollingFileAppender类 

1. RollingFileAppender继承FileAppender, 能够滚动记录文件。例如: RollingFileAppender能先记录到文件"log.txt", 然后当符合某个条件时, 变成记录到其他文件。

2. RollingFileAppender有两个与之互动的重要子组件。第一个是RollingPolicy负责滚动, 第二个是TriggeringPolicy决定是否以及何时进行滚动。所以RollingPolicy负责"什么", TriggeringPolicy负责"何时"。

3. 要想RollingFileAppender起作用, 必须同时设置RollingPolicy和TriggeringPolicy。不过, 如果RollingPolicy也实现了TriggeringPolicy接口, 那么只需要设置RollingPolicy。

4. 下面是RollingFileAppender的可用属性

5. 滚动策略概述

5.1. RollingPolicy负责滚动步骤, 涉及文件移动和重命名。

5.2. RollingPolicy接口如下

5.3. rollover方法完成对当前记录文件的归档工作。

5.4. getActiveFileName()方法计算当前记录文件(写实时记录的地方)的文件名。

5.5. getCompressionMode()方法名所示, RollingPolicy也负责决定压缩模式。

5.6. 最后, RollingPolicy通过setParent()方法得到一个对其父的引用。

6. FixedWindowRollingPolicy类

6.1. 当发生滚动时, FixedWindowRollingPolicy根据固定窗口算法重命名文件。

6.2. 选项"fileNamePattern"代表归档(滚动)记录文件的文件名模式。该选项是必需的, 且必需在模式的某处包含标志"%i"。

6.3. 下面是FixedWindowRollingPolicy的可用属性

6.4. 由于固定窗口滚动策略需要的文件重命名操作与窗口大小一样多, 所以强烈建议不要使用太大的窗口大小。当用户指定过大的窗口大小时, 当前的代码会自动将窗口大小设为12。

让我们来看固定窗口滚动策略的一个更具体的例子。假设"minIndex"是1, "maxIndex"是3, "fileNamePatter"是"foo%i.log"。

6.5. 使用FixedWindowRollingPolicy的RollingFileAppender的示例配置

<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> 
	<file>log/my.log</file>   
	<rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">    
		<fileNamePattern>log/my.%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>

6.6. 例子

6.6.1. 新建一个名为LocalFwrp的Java项目, 同时添加相关jar包

6.6.2. 编辑Myfwrp.java

package com.zr.fwrp;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Myfwrp {
	private static final Logger logger = LoggerFactory.getLogger(Myfwrp.class);
	
	public static void main(String[] args) {
		for(int i = 0; i < 100; i++) {
			logger.trace("我是一个跟踪信息: " + i);
			logger.debug("我是一个测试信息: " + i);
			logger.info("我是一个日志信息: " + i);
			logger.warn("我是一个警告信息: " + i);
			logger.error("我是一个错误信息: " + i);
			try {
				Thread.sleep(300);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}

6.6.3. 在src目录下编辑logback.xml

<configuration debug="true">

	<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
		<layout class="ch.qos.logback.classic.PatternLayout">
			<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
		</layout>
	</appender>

	<appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender">
		<file>log/my.log</file>   
		<rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">    
			<fileNamePattern>log/my.%i.log.zip</fileNamePattern>    
			<minIndex>1</minIndex>    
			<maxIndex>12</maxIndex>   
		</rollingPolicy> 
		<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">    
			<maxFileSize>10240</maxFileSize>   
		</triggeringPolicy>
		<encoder>    
			<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> 
		</encoder> 
	</appender>

	<root level="debug">
		<appender-ref ref="file" />
		<appender-ref ref="stdout" />
	</root>

</configuration>

6.6.4. 运行项目, 生成了日志文件和压缩包

7. TimeBasedRollingPolicy类 

7.1. TimeBasedRollingPolicy或许是最受流行的滚动策略。它根据时间来制定滚动策略, 例如根据日或月。TimeBasedRollingPolicy既负责滚动也负责触发滚动。实际上, TimeBasedRollingPolicy同时实现了RollingPolicy接口和TriggeringPolicy接口。 

7.2. TimeBasedRollingPolicy有两个属性: 必需的"fileNamePattern"和可选的"maxHistory"。

7.3. 下面是fileNamePattern的部分值及其作用

7.4. TimeBasedRollingPolicy支持自动压缩文件。如果"fileNamePattern"选项以".gz"或".zip"结尾, 就表示需要压缩。

7.5. 属性"fileNamePattern"有两个目的。一是, logback计算滚动周期; 二是, 计算每个归档文件的名称。注意, 可以为两种不同的模式指定同一个周期。模式yyyy-MM和yyyy@MM都表示每月滚动, 但它们的归档文件名不同。

7.6. 通过设置"file"属性, 你可以为活动记录文件和归档记录文件指定不同的位置。记录输出会被指向"file"属性指定的文件, 所以活动文件的名字不会改变。然而, 如果没有"file"属性, 则活动文件的名字会根据"fileNamePattern"的值每隔一段时间就重新计算一次。

7.7. 属性"maxHistory"控制被保留的归档文件的最大数量, 超出数量就删除旧文件。例如, 假设每月滚动, 且maxHistory是6, 则只保留最近6个月的归档文件, 删除之前的文件。注意当删除旧归档文件时, 那些为了归档而创建的目录也会被删除。

7.8. 出于某些技术原因, 滚动不是时钟驱动, 而是按照记录事件的到达时间。比如, 在2002年3月8日, 假设"fileNamePattern"是"yyyy-MM-dd"(每日滚动), 则午夜过后的第一个 记录事件会触发滚动。如果, 比如说直到0点23分47秒之前都没有记录事件, 那么滚动发生的实际时间是3月9日0点23分47秒, 而不是0点0分。因此, 根据事件到达的频率, 滚动或许会被延时触发。不过, 在某个时期内产生的所有记录事件都被输出到划分该时期的正确的文件, 从这个角度看, 虽然有延迟, 滚动算法仍然是正确的。

7.9. 下面是RollingFileAppender和TimeBasedRollingPolicy合作的例子

<appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender">   
	<file>log/my.log</file>   
	<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
		<fileNamePattern>log/my.%d{yyyy-MM-dd}.log</fileNamePattern> 
		<maxHistory>30</maxHistory>   
	</rollingPolicy>  
  	<encoder>    
  		<pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>   
  	</encoder>  
</appender>

7.10. 下面是在prudent模式下, 使用TimeBasedRollingPolicy的RollingFileAppender的配置例子

<appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender">   
	<prudent>true</prudent>    
	<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
		<fileNamePattern>my.%d{yyyy-MM-dd}.log</fileNamePattern> 
		<maxHistory>30</maxHistory>   
	</rollingPolicy>  
  	<encoder>    
  		<pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>   
  	</encoder>  
</appender>

7.11. 例子

7.11.1. 新建一个名为LocalTbrp的Java项目, 同时添加相关jar包

7.11.2. 编辑Mytbrp.java

package com.zr.fwrp;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Mytbrp {
	private static final Logger logger = LoggerFactory.getLogger(Mytbrp.class);
	
	public static void main(String[] args) {
		for(int i = 0; i < 5; i++) {
			logger.trace("我是一个跟踪信息: " + i);
			logger.debug("我是一个测试信息: " + i);
			logger.info("我是一个日志信息: " + i);
			logger.warn("我是一个警告信息: " + i);
			logger.error("我是一个错误信息: " + i);
			try {
				Thread.sleep(10000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}

7.11.3. 在src目录下编辑logback.xml

<configuration debug="true">

	<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
		<layout class="ch.qos.logback.classic.PatternLayout">
			<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
		</layout>
	</appender>

	<appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender">
		<file>log/my.log</file>   
		<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
			<fileNamePattern>log/my.%d{yyyy-MM-dd}.log</fileNamePattern> 
			<maxHistory>30</maxHistory>   
		</rollingPolicy>  
		<encoder>    
			<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> 
		</encoder> 
	</appender>

	<root level="debug">
		<appender-ref ref="file" />
		<appender-ref ref="stdout" />
	</root>

</configuration>

7.11.4. 运行项目, 同时调整系统时间

8. 基于大小和时间的归档

8.1. 有时你也许想按照日期进行归档的同时限制每个记录文件的大小, 特别是当后处理工具对记录文件大小有限制时。Logback为此提供了SizeAndTimeBasedFNATP, 它是TimeBasedRollingPolicy的子组件, FNATP代表"文件命名和触发策略"。

8.2. 下面的例子演示了基于大小和时间的记录文件归档

<appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender">   
	<file>log/my.log</file>     
	<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
		<fileNamePattern>log/my.%d{yyyy-MM-dd}.%i.log</fileNamePattern> 
		<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> 
			<maxFileSize>100MB</maxFileSize> 
		</timeBasedFileNamingAndTriggeringPolicy>    
	</rollingPolicy>  
  	<encoder>    
  		<pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>   
  	</encoder>  
</appender>

8.3. 注意"%d"后面的"%i"。在当前时间周期结束之前, 每当当前记录文件达到"maxFileSize"时, 就会用递增索引归档, 索引从0开始。

8.4. 基于大小和时间的归档支持删除旧归档文件。你需要用"maxHistory"属性指定要保留的周期的数量。当程序停止并重启时, 记录会从正确的位置继续, 即当前周期的最大索引。

9. 触发策略概述

9.1. TriggeringPolicy负责指示RollingFileAppender在什么时候滚动。

9.2. TriggeringPolicy接口只有一个方法

9.3. isTriggeringEvent()方法有两个参数, 一个是归档文件, 一个是当前正被处理的记录事件。该方法的具体实现根据这两个参数来决定是否进行滚动。

10. SizeBasedTriggeringPolicy类

10.1. 查看当前活动文件的大小。如果超过指定大小SizeBasedTriggeringPolicy会告诉RollingFileAppender去触发当前活动文件的滚动。

10.2. SizeBasedTriggeringPolicy只有一个参数maxFileSize, 默认值是10MB。

10.3. 根据数字后面不同的后缀, "maxFileSize"可以是bytes、KB、MB或GB。比如: 5000000, 5000KB、5MB和2GB都是合法值, 且前三个等价(为bytes的时候不要带单位)

10.4. 下面是RollingFileAppender与SizeBasedTriggeringPolicy合作的配置例子, 当记录文件的大小超过5MB后, 会触发滚动。

<appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender">   
	<file>my.log</file>     
	<rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
		<fileNamePattern>my.%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>

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值