Chapter 4: Appenders

OutputStreamAppender

ConsoleAppender

三个可配置属性:

encoderOutputStreamAppender的一个属性,用来设置日志格式

target:  System.out or System.err,default is System.out

withJansi: ANSI color(在win7 64bit上无法正常工作)

 

 

<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

The FileAppender, a subclass of OutputStreamAppender, appends log  events into a file.

可配置属性

append: 是否追加,默认为true

encoder:OutputStreamAppender的一个属性,用于设置日志格式

file: 指定存放日志的文件,如果不存在,将自动创建(mkdirs)。

   文件路径:c:/test.log 或 c:\\test.log。文件属性没有默认值

prudent: true/false, default false. 确保在多JVM环境下的日志安全处理的机制(文件锁)。

   该机制如果被设置为true,则append属性将自动设置为true

   该机制会影响到日志写入效率!

 

<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设置唯一的日志文件名

取配置文件被解析时的时间作为当前时间

<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="yyyy年MM月dd日HH时mm分ss秒"/>

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

 

使用系统的contextBirth 设置时间

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

  

 

RollingFileAppender

滚动日志

两个重要的组件:

   RollingPolicy     负责日志滚动-how

   TriggeringPolicy  负责触发日志回滚动作的执行-when

RollingFileAppender 必须配置RollingPolicy 和   TriggeringPolicy

不过,RollingPolicy 已经对TriggeringPolicy 进行了实现,因此,只需要配置RollingPolicy 即可!

 

RollingFileAppender可配置属性:

file:记录日志的文件,该属性可选。如果没有设置,logback将自动进行文件命名。

如logFile.2014-03-07.log。

但是,通过file属性指定文件,可以实现已记录日志与正在记录日志文件的解耦。

append:是否追加,默认true

encoder:OutputStreamAppender的一个属性,用于设置日志格式

rollingPolicy:负责日志滚动时的具体行为

triggeringPolicy:告诉fileAppender何时激活日志的滚动行为

prudent:FixedWindowRollingPolicy 不支持

TimeBasedRollingPolicy 进行联合使用,不支持也不允许文件压缩,file属性不能设置,必须为blank

 

 

TimeBasedRollingPolicy

TimeBasedTriggeringPolicy 实现了RollingPolicy和TriggeringPolicy

TimeBasedRollingPolicy具有1个强制属性和几个可选属性:

fileNamePattern 强制属性,指定日志文件的名称样式(actived,已记录完日志的文件)

%d{pattern} SimpleDateFormat格式,默认为yyyy-MM-dd

注意:"/" 或者 "\",logback将其解析为路径分隔符

maxHistory int类型 指定最大保留多少个文件,将自动删除超出保留个数的日志文件

cleanHistoryOnStart boolean类型 在appender启动的时候移除已有日志文件?

 

fileNamePattern详细配置  

/wombat/foo.%d   每天自动滚动[daily rollover at midnight]

没有设置file属性

第1天的日志名为/wombat/foo.2006-11-23

第2天的日志名为/wombat/foo.2006-11-24

设置了file属性,即指定了file名称

                设置了日志文件名称为/wombat/foo.txt

到午夜,foo.txt将被重命名为/wombat/foo.2006-11-23

然后,logback将创建1个新的foo.txt日志文件(保证当天记录日志的文件名始终都是foo.txt)

 

/wombat/%d{yyyy/MM}/foo.txt  每个月初进行滚动

file property not set:

当月:    /wombat/2006/10/foo.txt

 下个月:/wombat/2006/11/foo.txt.         

file property set to /wombat/foo.txt:

  在2006年10月份,日志名称始终是 /wombat/foo.txt

  在2006年11月份,日志名称将被重命名为 /wombat/2006/10/foo.txt

  而且,1个新的日志文件被创建,名称仍未指定的文件名/wombat/foo.txt

 到在2006年12月份,又被重命名为/wombat/2006/11/foo.txt

然后再创建1个新的/wombat/foo.txt

 

/wombat/foo.%d{yyyy-ww}.log  每周滚动1次

 

/wombat/foo%d{yyyy-MM-dd_HH-mm}.log  每分钟滚动1次

 

/foo/%d{yyyy-MM,aux}/%d.log  带文件夹的每天滚动1次 【aux 辅助标记】

日志将被放在1个以年和月命名的文件夹下,而且日志名称采用年月日的方式命名

由于%d没有aux修饰,将被作为日志的命名规则

这样,日志名称按%d进行命名,同时,文件夹将以年和月进行命名

如,folder :   /foo/2006-11/

日志路径则为: /foo/2006-11/2006-11-14.log

 好处:非常方便的将日志文件放在不同文件夹下进行管理!

 

/wombat/foo.%d.gz  在日志滚动的时候,将对历史日志文件进行压缩

如果,fileNamePattern以".gz"或者".zip"结尾,日志压缩功能将被开启

 

<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模式,支持多JVM环境往同一个日志文件写入日志

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

 

SizeAndTimeBasedFNATP

基于时间和文件大小的配置

当文件达到指定大小时,将通过额外的index参数(自增,从0开始)附加在日志文件上

已归档的日志:

mylog-2014-03-08.0.txt

mylog-2014-03-08.1.txt

mylog-2014-03-08.2.txt

当前日志:

mylog.txt

<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>10MB</maxFileSize>
      </timeBasedFileNamingAndTriggeringPolicy>
    </rollingPolicy>
    <encoder>
      <pattern>%msg%n</pattern>
    </encoder>
  </appender>


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

</configuration>

 

  

SizeBasedTriggeringPolicy

当日志文件达到指定大小时,logback对日志进行滚动

SizeBasedTriggeringPolicy 只支持1个属性

maxFileSize:default value of 10MB

maxFileSize可以指定的值:KB,MB ,  GB (5000KB, 5MB and 2GB)

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

 

===============================================================================  

 

 

SocketAppender and SSLSocketAppender

SocketAppender被设计成可在网络上传输序列化的ILoggingEvent实例对象,在远程日志服务器上进行日志记录

SocketAppender  以明文方式进行传输

SSLSocketAppender 以密文方式进行传输

LoggingEventVO 实现了ILoggingEvent   接口

当反序列话完成之后,在远程日志服务器上将对日志进行记录,就像在本地记录日志一样

在接收端反序列化日志对象后,该事件可以像本地一样的进行日志记录

在不同的机器上运行多个SocketAppender实例,他们的日志输出定向到一个中央日志服务器,其格式是固定的,因为网路上传输日志是没有Layout可言的

SocketAppender利用传输控制协议(TCP)层进行数据传输,TCP提供了一个可靠的,有序的,流控制的端到端的字节流

如果远程日志服务器连接正常,则日志将被正确传输过去

如果远程日志服务器关机或不可达,则日志将被丢弃

当远程服务器恢复可连接状态时,日志传输任务将透明的被恢复,这个透明的重连接是通过一个"connector thread"周期性尝试与远程服务器进行连接实现的【底层源码如何实现的?】

 

需要注意:即使SocketAppender 没有注册到任何logger上,它也不会被JVM垃圾回收

当且仅当远程服务器关机,导致连接失败时,"connector thread"才会自动结束

为了避免垃圾收集文件,当不需要远程日志记录时,应该明确关闭  SocketAppender

如果1个应用处于长时间运行,又进行远程日志记录,就需要注意这个问题了

在应用退出之前,为了防止管道流中仍有未传输完成的日志数据,应该调用   SocketAppender 的close()或者LoggerContext's stop(),将数据都传输完成再关闭应用。

 

可配置属性如下

includeCallerData

default:false
true ,调用者的相关信息将提供给远程主机
false,  调用方的相关信息不提供给远程主机

reconnectionDelay

指定连接服务器失败后,再次尝试连接的等待时间,如10 seconds
Default value of this option is 30 seconds.
默认值30秒
Setting this option to zero turns off reconnection capability
设置为0则关闭重连接
如果连接成功,则没有"connector thread"存在(该线程仅当连接失败时才有存在的必要)

queueSize

通过1个非负的整数描述该队列需要保留多少logging event
当队列长度为0时,将以同步方式进行数据传输
当队列长度大于0时,logging event 将被加入到队列中(队列未满)

eventDelayLimit

对queueSize的附加配置
当远程日志服务器处理效率慢,而导致本地日志队列已满时,指定等待进入队列的logging Event被丢弃的时间
该属性的默认值为100 milliseconds,可以指定为10 seconds或其它
当100milliseconds后,队列中有空余空间,则加入,否则,丢弃等待进入队列的event

remoteHost

远程主机地址

 

port

远程主机端口

ssl

是否使用安全套接字进行传输

 

[远程记录日志以后再弄....]

 

 

 

=============================================================================== 

 

SMTPAppender

发送邮件的日志记录器

SMTPAppender 的属性配置:

 

smtpHost:   SMTP server,如smtp.126.com

 

smtpPort:    default 25

 

to:                 接收方邮件地址,多人接收则使用commas分割

 

from:            发送方的邮件地址

 

subject:        邮件主题

 

username:    连接SMTP SERVER的用户名

 

password:    连接SMTP SERVER的密码

 

discriminator: 使用默认提供的discriminator,它始终返回同一个值,这样,所有的event都使用同一个日志缓冲区;通过配置Discriminator,SMTPAppender 可以根据返回值的不同,将发生的event缓存到不同的buffer中。这样,可以实现不同event发送到不同的地方。【不同event进入不同buffer】

 

evaluator: 默认提供OnErrorEvaluator ,当发生error级别的日志时将触发邮件的发送。

logback提供了其它类型的触发机制:

通过标记来触发:OnMarkerEvaluatorJaninoEventEvaluator,GEventEvaluator.          

 

cyclicBufferTracker: 如果没有指定该属性,logback将提供1个默认的实现CyclicBufferTrackerImpl ,它将保持缓冲区大小为256条日志.缓冲区大小可以进行配置,通过设置CyclicBufferTrackerImplbufferSize属性即可。

256条日志:缓冲区最多保留256条日志。

 

STARTTLS: 默认false. 如果设置为true,appender将发出一个STARTTLS 命令给服务器,将连接切换为SSL传输

 

SSL: 默认false. 如果设置为true,则使用SSL 方式与服务器进行连接

 

charsetEncoding: 默认使用UTF-8编码

 

localhost: 客户端主机名称

 

asynchronousSending: 邮件传输是否采用异步方式。

 

includeCallerData: 默认为false.如果配置了asynchronousSending=true,希望包含调用者信息,可设置为true.

 

sessionViaJNDI: SMTPAppender 是依靠javax.mail.Session进行邮件发送的。

默认情况下,sessionViaJNDI 是设置为false的,因此javax.mail.Session是由SMTPAppender自己

创建的(通过读取用户配置的邮件服务器配置)。如果sessionViaJNDI 设置为true,则javax.mail.Session

将通过JNDI进行获取(JNDI服务在应用服务器/容器中进行配置)。

注意:如果使用JNDI获取javax.mail.Session,确保删除WEB-INF/lib中mail.jar、activation.jar 

 

jndiLocation: 配置javax.mail.Session的JNDI位置,默认"java:comp/env/mail/Session"

 

 

The SMTPAppender keeps only the last 256 logging events in its cyclic buffer, throwing away older events when its buffer becomes full. Thus, the number of logging events delivered in any e-mail sent by SMTPAppender is upper-bounded by 256. 

 SMTPAppender 的缓冲区仅仅保留最近的256条日志记录,当缓冲区满了,将从缓冲区中清除最旧的日志。这样,任何被传输的email最多包含256条日志。默认在发生error时触发邮件进行发送。

 

SMTPAppender 依赖 JavaMail API。因此,需要提供mail.jar 和 activation.jar到classpath中

 

<configuration debug="true">   
  <appender name="EMAIL" class="ch.qos.logback.classic.net.SMTPAppender">
    <smtpHost>smtp.126.com</smtpHost>
    <smtpPort>25</smtpPort>
    <username>[email protected]</username>
    <password>******</password>
    <to>[email protected]</to>
    <from>[email protected]</from>
    <subject>TESTING: %logger{20} - %m</subject>
    <includeCallerData>false</includeCallerData>
    <!-- 自定义样式 -->
    <layout class="ch.qos.logback.classic.PatternLayout">
      <pattern>%date %-5level %logger{35} - %message%n</pattern>
    </layout>       
  </appender>

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

 

网页样式

<configuration debug="true">   
  <appender name="EMAIL" class="ch.qos.logback.classic.net.SMTPAppender">
    <smtpHost>smtp.126.com</smtpHost>
    <smtpPort>25</smtpPort>
    <username>[email protected]</username>
    <password>******</password>
    <to>[email protected]</to>
    <from>[email protected]</from>
    <subject>TESTING: %logger{20} - %m</subject>
    <includeCallerData>false</includeCallerData>
    <!-- HTML样式 -->
    <layout class="ch.qos.logback.classic.html.HTMLLayout"/>
  </appender>

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

 

 

 

Custom buffer size

指定缓冲区大小,比如,设置为10,则只保留error发生前的9条log

<configuration debug="true">   
  <appender name="EMAIL" class="ch.qos.logback.classic.net.SMTPAppender">
    <smtpHost>smtp.126.com</smtpHost>
    <smtpPort>25</smtpPort>
    <username>[email protected]</username>
    <password>*****</password>
    <to>[email protected]</to>
    <from>[email protected]</from>
    <subject>TESTING: %logger{20} - %m</subject>
    <includeCallerData>false</includeCallerData>
    
	<!-- 缓冲区大小 -->
    <cyclicBufferTracker class="ch.qos.logback.core.spi.CyclicBufferTracker">
      <bufferSize>10</bufferSize>
    </cyclicBufferTracker>

    <!-- HTML样式 -->
    <layout class="ch.qos.logback.classic.html.HTMLLayout"/>
  </appender>

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

  

Triggering event

【自定义触发机制】

当日志累积到多少条时发送有邮件,覆盖默认的OnErrorEvaluator,不再由Error所触发了!

 

package chapters.configuration;

import ch.qos.logback.core.boolex.EvaluationException;
import ch.qos.logback.core.boolex.EventEvaluator;
import ch.qos.logback.core.spi.ContextAwareBase;

public class CounterBasedEvaluator extends ContextAwareBase implements
		EventEvaluator {
	
	/**每10条日志就触发邮件发送*/
	static int LIMIT = 10;
	int counter = 0;
	String name;

	public boolean evaluate(Object event) throws NullPointerException,
			EvaluationException {
		//计数器
		counter++;

		if (counter == LIMIT) {
			counter = 0;

			return true;
		} else {
			return false;
		}
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
	
	//====================================
	public void start() {}

	public void stop() {}

	public boolean isStarted() {
		return false;
	}
}

 

此时,定义的BufferSize最好与LIMIT一致

<configuration debug="true">   
  <appender name="EMAIL" class="ch.qos.logback.classic.net.SMTPAppender">
	
	<evaluator class="chapters.configuration.CounterBasedEvaluator" />
	
    <smtpHost>smtp.126.com</smtpHost>
    <smtpPort>25</smtpPort>
    <username>[email protected]</username>
    <password>*****</password>
    <to>[email protected]</to>
    <from>[email protected]</from>
    <subject>TESTING: %logger{20} - %m</subject>
    <includeCallerData>false</includeCallerData>
    
	<!-- 缓冲区大小与LIMIT保持一致 -->
    <cyclicBufferTracker class="ch.qos.logback.core.spi.CyclicBufferTracker">
      <bufferSize>10</bufferSize>
    </cyclicBufferTracker>

    <!-- HTML样式 -->
    <layout class="ch.qos.logback.classic.html.HTMLLayout"/>
  </appender>

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

 

Marker based triggering

基于标记进行触发

当具有特定标记的日志被记录时,触发邮件发送

不一定非得发送ERROR时才发送邮件,可以在某个感兴趣的事件发生时发送邮件

比如,用户付款成功后,即发送邮件进行通知

 

logback.xml

<configuration debug="true">   
  <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>smtp.126.com</smtpHost>
    <smtpPort>25</smtpPort>
    <username>[email protected]</username>
    <password>*****</password>
    <to>[email protected]</to>
    <from>[email protected]</from>
    <subject>TESTING: %logger{20} - %m</subject>
    <includeCallerData>false</includeCallerData>

    <!-- HTML样式 -->
    <layout class="ch.qos.logback.classic.html.HTMLLayout"/>
  </appender>

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

 

记录日志的时候,使用Marker

package chapters.configuration;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.Marker;
import org.slf4j.MarkerFactory;

public class MyApp1 {
	  final static Logger logger = LoggerFactory.getLogger(MyApp1.class);

	  public static void main(String[] args) {
		  logger.info("some one coming to shopping");
		  String name = "张三";
		  int howmuch = 1000000;
		  Marker notifyAdmin = MarkerFactory.getMarker("NOTIFY_ADMIN");
		  logger.info(notifyAdmin,"name = {}, paid money: {}", name, howmuch);
	  }

}

  



 

 

Marker-based triggering with JaninoEventEvaluator

另一种Marker的使用方式: JaninoEventEvaluator

<configuration>
  <appender name="EMAIL" class="ch.qos.logback.classic.net.SMTPAppender">
    <evaluator class="ch.qos.logback.classic.boolex.JaninoEventEvaluator">
      <expression>
        (marker != null) &&
        (marker.contains("NOTIFY_ADMIN") || marker.contains("TRANSACTION_FAILURE"))
      </expression>
    </evaluator>    
    ... same as above
  </appender>
</configuration>

  

Marker-based triggering with GEventEvaluator

 另一种Marker的使用方式:GEventEvaluator

 

<configuration>
  <appender name="EMAIL" class="ch.qos.logback.classic.net.SMTPAppender">
    <evaluator class="ch.qos.logback.classic.boolex.GEventEvaluator">
      <expression>
        e.marker?.contains("NOTIFY_ADMIN") || e.marker?.contains("TRANSACTION_FAILURE")
      </expression>
    </evaluator>    
    ... same as above
  </appender>
</configuration>

 

Authentication/STARTTLS/SSL

 In SSL mode, the connection is encrypted right from the start.    

 SSL模式,连接一开始就是进行加密传输的

 

 In STARTTLS, the connection is initially non-encrypted and only after the STARTTLS command is issued by the client does the connection switch to SSL.

STARTTLS模式在初始化连接时不是加密连接的,仅当客户端使用STARTTLS 命令后,连接才被切换到SSL连接(前提是服务器支持模式切换)

 

<configuration>
  <appender name="EMAIL" class="ch.qos.logback.classic.net.SMTPAppender">
    <smtpHost>smtp.126.com</smtpHost>
    <smtpPort>25</smtpPort>
    <SSL>true</SSL>
    <username>[email protected]</username>
    <password>****</password>

    <to>[email protected]</to>
    <to>[email protected]</to> <!-- additional destinations are possible -->
    <from>[email protected]</from>
    <subject>TESTING: %logger{20} - %m</subject>
    <layout class="ch.qos.logback.classic.PatternLayout">
      <pattern>%date %-5level %logger{35} - %message%n</pattern>
    </layout>       
  </appender>

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

 

 STARTTLS protocol

<configuration>   
  <appender name="EMAIL" class="ch.qos.logback.classic.net.SMTPAppender">
    <smtpHost>smtp.gmail.com</smtpHost>
    <smtpPort>587</smtpPort>
    <STARTTLS>true</STARTTLS>
    <username>[email protected]</username>
    <password>YOUR_GMAIL_xPASSWORD</password>
    
    <to>EMAIL-DESTINATION</to>
    <to>ANOTHER_EMAIL_DESTINATION</to> <!-- additional destinations are possible -->
    <from>[email protected]</from>
    <subject>TESTING: %logger{20} - %m</subject>
    <layout class="ch.qos.logback.classic.PatternLayout">
      <pattern>%date %-5level %logger - %message%n</pattern>
    </layout>       
  </appender>

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

===============================================================================

DBAppender

把日志往数据库中记录

three tables:

logging_event

logging_event_property

logging_event_exception.

 

The logging_event table contains the following fields:  

timestamp 记录日志时的时间戳

formatted_message  格式化之后的日志内容
logger_name 记录该日志的logger名称
level_string  logger的Level
reference_flag 标识日志事件所关联的属性( MDC or Context properties )
caller_filename logger所在的java类
caller_class   全路径类名
caller_method 日志记录时所在的方法名称

caller_line 日志记录时所在的行号

event_id  数据库id

 

The logging_event_property is used to store the keys and values contained in the MDC or the Context. It contains these fields:  

event_id  日志的数据库id

mapped_key  MDC的key

mapped_value MDC的key

 

The logging_event_exception table contains the following fields:  

event_id 日志的数据库id

堆栈跟踪的索引

trace_line  堆栈跟踪对应的行

 

Logback提供了创建3张表的脚本,MySql为例

 

# Logback: the reliable, generic, fast and flexible logging framework.
# Copyright (C) 1999-2010, QOS.ch. All rights reserved.
#
# See http://logback.qos.ch/license.html for the applicable licensing 
# conditions.

# This SQL script creates the required tables by ch.qos.logback.classic.db.DBAppender.
#
# It is intended for MySQL databases. It has been tested on MySQL 5.1.37 
# on Linux


BEGIN;
DROP TABLE IF EXISTS logging_event_property;
DROP TABLE IF EXISTS logging_event_exception;
DROP TABLE IF EXISTS logging_event;
COMMIT;


BEGIN;
CREATE TABLE logging_event 
  (
    timestmp         BIGINT NOT NULL,
    formatted_message  TEXT NOT NULL,
    logger_name       VARCHAR(254) NOT NULL,
    level_string      VARCHAR(254) NOT NULL,
    thread_name       VARCHAR(254),
    reference_flag    SMALLINT,
    arg0              VARCHAR(254),
    arg1              VARCHAR(254),
    arg2              VARCHAR(254),
    arg3              VARCHAR(254),
    caller_filename   VARCHAR(254) NOT NULL,
    caller_class      VARCHAR(254) NOT NULL,
    caller_method     VARCHAR(254) NOT NULL,
    caller_line       CHAR(4) NOT NULL,
    event_id          BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY
  );
COMMIT;

BEGIN;
CREATE TABLE logging_event_property
  (
    event_id	      BIGINT NOT NULL,
    mapped_key        VARCHAR(254) NOT NULL,
    mapped_value      TEXT,
    PRIMARY KEY(event_id, mapped_key),
    FOREIGN KEY (event_id) REFERENCES logging_event(event_id)
  );
COMMIT;

BEGIN;
CREATE TABLE logging_event_exception
  (
    event_id         BIGINT NOT NULL,
    i                SMALLINT NOT NULL,
    trace_line       VARCHAR(254) NOT NULL,
    PRIMARY KEY(event_id, i),
    FOREIGN KEY (event_id) REFERENCES logging_event(event_id)
  );
COMMIT;

 

 

 

ConnectionSource

 

据专家介绍,在"标准PC"上,往数据库插入1条记录大约需要10 milliseconds

如果使用了连接池技术,时间消耗将仅有1 millisecond

因此,与数据库打交道,数据库连接池显得非常重要

 

通过使用DBAppender 与数据库打交道可以有几种不同的方式:

关于DBAppender 最重要的配置- ConnectionSource 对象

logback通过ConnectionSource 接口提供可插拔的方式获取java.sql.Connection.

 

There are currently three implementations of ConnectionSource, namely DataSourceConnectionSource,

DriverManagerConnectionSource,

JNDIConnectionSource.    

 

<dependency>
	<groupId>mysql</groupId>
	<artifactId>mysql-connector-java</artifactId>
	<version>5.1.10</version>
</dependency>

 

 

 DriverManagerConnectionSource

Note that this class will establish a new Connection for each call to getConnection()

注意:DriverManagerConnectionSource每次都会创建1个新的连接,没有使用连接池技术

因此,需要自己实现一个连接池,通过implementation of ConnectionSource

 

没有使用连接池的配置,直接使用DriverManagerConnectionSource

每次都创建新的连接

logback.xml

<configuration>

  <appender name="DB" class="ch.qos.logback.classic.db.DBAppender">
    <connectionSource class="ch.qos.logback.core.db.DriverManagerConnectionSource">
      <driverClass>com.mysql.jdbc.Driver</driverClass>
      <url>jdbc:mysql://localhost:3306/logback</url>
      <user>root</user>
      <password>root</password>
    </connectionSource>
  </appender>
  
  <root level="DEBUG" >
    <appender-ref ref="DB" />
  </root>
</configuration>

 

测试类

package chapters.configuration;

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

public class MyApp1 {
	  final static Logger logger = LoggerFactory.getLogger(MyApp1.class);

	  public static void main(String[] args) {
		  long start = System.currentTimeMillis();
		  for(int i=0;i<500;i++)
		  logger.info("some one coming to shopping");
		  long total = System.currentTimeMillis()-start;
		  logger.info("500 records takes: {} mills ", total);
	  }

}

 

 

 

 

DataSourceConnectionSource

实现了ConnectionSource 接口,并且基于javax.sql.DataSource获取数据库连接

使用C3P0连接池

<dependency>
	<groupId>c3p0</groupId>
	<artifactId>c3p0</artifactId>
	<version>0.9.1.2</version>
</dependency>

 
Logback.xml

<configuration>

  <appender name="DB" class="ch.qos.logback.classic.db.DBAppender">
    <connectionSource
      class="ch.qos.logback.core.db.DataSourceConnectionSource">
      <dataSource
        class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <driverClass>com.mysql.jdbc.Driver</driverClass>
        <jdbcUrl>jdbc:mysql://localhost:3306/logback</jdbcUrl>
        <user>root</user>
        <password>root</password>
      </dataSource>
    </connectionSource>
  </appender>

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

 测试类

package chapters.configuration;

import java.util.Random;

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

public class MyApp1 {
	  final static Logger logger = LoggerFactory.getLogger(MyApp1.class);

	  public static void main(String[] args)throws Exception {
		  logger.info("some one coming to shopping");
		  Thread.sleep(new Random().nextInt(10000));
		  System.out.println("waking...");
		  long start = System.currentTimeMillis();
		  for(int i=0;i<500;i++)
		  logger.info("some one coming to shopping");
		  long total = System.currentTimeMillis()-start;
		  logger.info("500 records takes: {} mills ", total);
	  }

}

 



 

采用C3P0默认的设置,发现没快好多呢。。。

 

JNDIConnectionSource

在J2EE Sever中定义DataSource,以Tomcat为例

Context.xml 

<Context docBase="/path/to/app.war" path="/myapp">
  ...
  <Resource name="jdbc/logging"
               auth="Container"
               type="javax.sql.DataSource"
               username="..."
               password="..."
               driverClassName="org.postgresql.Driver"
               url="jdbc:postgresql://localhost/..."
               maxActive="8"
               maxIdle="4"/>
  ...
</Context>

 

logback.xml  通过JNDI从Tomcat容器中获取DataSource

<configuration debug="true">
  <appender name="DB" class="ch.qos.logback.classic.db.DBAppender">
    <connectionSource class="ch.qos.logback.core.db.JNDIConnectionSource">
      <!-- please note the "java:comp/env/" prefix -->
      <jndiLocation>java:comp/env/jdbc/logging</jndiLocation>
    </connectionSource>
  </appender>
  <root level="INFO">
    <appender-ref ref="DB" />
  </root>  
</configuration>

 

 POM.XML

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>logger</groupId>
	<artifactId>sl4j</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>sl4j</name>
	<url>http://maven.apache.org</url>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
	</properties>

	<dependencies>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.10</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>ch.qos.logback</groupId>
			<artifactId>logback-classic</artifactId>
			<version>1.0.13</version>
		</dependency>
		<dependency>
			<groupId>javax.mail</groupId>
			<artifactId>mail</artifactId>
			<version>1.4.7</version>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>5.1.10</version>
		</dependency>
		<dependency>
			<groupId>c3p0</groupId>
			<artifactId>c3p0</artifactId>
			<version>0.9.1.2</version>
		</dependency>

	</dependencies>
</project>

 

猜你喜欢

转载自schy-hqh.iteye.com/blog/2026859