logback 使用说明

为啥有logback?
Logback为取代log4j而生。
Logback由log4j的创立者Ceki Gülcü设计。以十多年设计工业级记录系统的经验为基础,所创建的logback比现有任何记录系统更快、占用资源更少,有时差距非常大

0. 需要添加的 JAR 包
logback-core.jar – logback 核心包,必备
slf4j-api.jar – 通用日志接口包,可以在logback与其他记录系统如log4j和java.util.logging (JUL)之间轻松互相切换
Logback-classic – 实现了 SLF4J API,扩展了core模块

1. 系统启动,默认家在classpath下的logback.xml 或者 logback-test.xml。 这里可以把默认配置文件的位置作为系统属性进行指定
java -Dlogback.configurationFile=/path/to/config.xml chapters.configuration.MyApp1

2. 在根元素configuration中配置属性scan=”true”后,当配置文件修改后自动重新加载,默认每分钟扫描一次。
configuration元素的 scanPeriod 属性控制扫描周期,其值可以带时间单位,包括:milliseconds、seconds、minutes和hours。
如果没写明时间单位,则默认为毫秒。示例:

<configuration debug="true" scan="true" scanPeriod="30 minutes">
</configuration>

 为提高性能,不会在每个logger被调用时去检查是否需要扫描,而是每隔16次记录操作进行一次检查。
简言之,当配置文件改变后,它会被延时重新加载,延时时间由扫描间隔时间和一些logger调用所决定
debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。

3. Logback-classic带了一个叫ViewStatusMessagesServlet的Servlet,它以HTML表格的格式打印与当前LoggerContext关联的StatusManager的内容

<servlet> 
        <servlet-name>ViewStatusMessages</servlet-name>
        <servlet-class>ch.qos.logback.classic.ViewStatusMessagesServlet</servlet-class>
</servlet>
<servlet-mapping> 
        <servlet-name>ViewStatusMessages</servlet-name>
        <url-pattern>/lbClassicStatus</url-pattern>
</servlet-mapping>

 访问地址是http://host/yourWebapp/lbClassicStatus。

4. 可以这样描述配置文件的基本结构:
以<configuration>开头,后面有零个或多个<appender>元素,有零个或多个<logger>元素,有最多一个<root>元素

a. Logger是用<logger>元素配置的。<logger>元素有且仅有一个name属性、一个可选的level属性和一个可选的additivity属性。
Logger: Level属性的值大小写无关,其值为下面其中一个字符串:TRACE、DEBUG、INFO、WARN、ERROR、ALL和OFF。
还可以是一个特殊的字符串“INHERITED”或其同义词“NULL”,表示强制继承上级的级别
<logger>元素可以包含零个或多个<appender-ref ref=”logger的name” >元素,表示这个appender会被添加到该logger。强调一下,每个用<logger>元素声明的logger,首先会移除所有appender,然后才添加引用了的appender,所以如果logger没有引用任何appender,就会失去所有appender。

b. <root>元素配置根logger。该元素有一个level属性。没有name属性,因为已经被命名为“ROOT”。
ROOT: Level属性的值大小写无关,其值为下面其中一个字符串:TRACE、DEBUG、INFO、WARN、ERROR、ALL和OFF。注意不能设置为“INHERITED” 或“NULL”。

c. 配置Appender:
Appender用 <appender>元素配置,该元素必要属性name和class。name属性指定appender的名称,class属性指定appender类的全限定名。
<appender>元素可以包含零个或多个<layout>元素、零个或多个<encoder>元素和零个或多个<filter>元素。
<layout>元素的class属性是必要的,表示将被实例化的layout类的全限定名。因为太常用了,所以当当layout是PatternLayout时,可以省略class属性。
<encoder>元素class属性是必要的,表示将被实例化的encoder类的全限定名。因为太常用了,所以当当encoder是PatternLayoutEncoder时,可以省略class属性。

注意每个appender都有自己的encoder。Encoder通常不能被多个appender共享,layout也是。所以,logback的配置文件里没有共享encoder或layout的语法。

5.常用Appender(负责写记录事件的组件):
a. ConsoleAppender, FileAppender, RollingFileAppender, FixedWindowRollingPolicy
ConsoleAppender把事件添加到控制台,更准确地说是System.out或System.err,默认为前者。ConsoleAppender按照用户指定的encoder对事件进行格式化。System.out和System.err都是java.io.PrintStream类型,因此,它们被包裹在有缓冲I/O操作的OutputStreamWriter里

b. 通过时间戳保证唯一文件名(比如对于不断启动的短生命周期的程序):

   <timestamp key="bySecond" datePattern="yyyyMMdd'T'HHmmss" />
   <appender name="logfile" class="ch.qos.logback.core.FileAppender">
      <file>logfile-${bySecond}.log</file>
      <append>false</append>
      <encoder>
        <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
      </encoder>
  </appender>

 timestamp元素有两个属性:key和datePattern。属性key是变量名,对余下的配置元素可用。属性datePattern表示把当前时间(解析配置文件的时间)转换成字符串时使用的日期模式,遵从java.text.SimpleDateFormat里的约定。

c. RollingFileAppender继承FileAppender,能够滚动记录文件。例如,RollingFileAppender能先记录到文件“log.txt”,然后当符合某个条件时,变成记录到其他文件。
RollingFileAppender有两个与之互动的重要子组件。第一个是RollingPolicy,负责滚动。第二个是TriggeringPolicy,决定是否以及何时进行滚动。所以,RollingPolicy负责“什么”, TriggeringPolicy负责“何时”。要想RollingFileAppender起作用,必须同时设置RollingPolicy和TriggeringPolicy。不过,如果RollingPolicy也实现了TriggeringPolicy接口,那么只需要设置RollingPolicy

<appender name="logfile" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <File>${log.base}.log</File>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <FileNamePattern>${log.base}.%d{yyyy-MM-dd}.log.zip</FileNamePattern>
        </rollingPolicy>
        <layout class="ch.qos.logback.classic.PatternLayout">
            <pattern>%date [%thread] %-5level %logger{80} - %msg%n</pattern>
        </layout>
</appender>

 同样也可以指定 maxHistory 属性,控制被保留的归档文件的最大数量,超出数量就删除旧文件

6. Encoder负责两件事,一是把事件转换为字节数组,二是把字节数组写入输出流。encoder不但可以完全控制待写出的字节的格式,而且可以控制字节何时及是否被写出。 在logback 0.9.19版之前没有encoder。
Layout,只负责把事件转换为字符串。此外,因为layout不能控制事件何时被写出,所以不能成批地聚集事件。相比之下,encoder不但可以完全控制待写出的字节的格式,而且可以控制字节何时及是否被写出。目前,PatternLayoutEncoder是唯一有用的encoder,它基本上是封装了PatternLayout,让PatternLayout负责大多数工作

注意:在之前的版本里,多数appender依靠layout来把事件转换成字符串并用java.io.Writer把字符串输出。在之前的版本里,用户需要在FileAppender里嵌入一个PatternLayout。

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

而从0.9.19版开始,FileAppender和其子类使用encoder,不接受layout。 如

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

 对于console 同样no longer admits a layout as a sub-component, set an encoder instead.

对于这个变化总的来说:既然PatternLayout是最常用的layout,logback便提供了PatternLayoutEncoder,它扩展了LayoutWrappingEncoder,且仅使用PatternLayout。从logback 0.9.19版起,FileAppender或其子类在只要用到PattternLayout时,都必须换成PatternLayoutEncoder。

7. Layout负责把事件转换成字符串。Layout接口的format()方法的参数是代表任何类型的事件,返回字符串

8. 附上几段appender的配置

<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
        <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
    </encoder>
</appender>
 
<appender name="logfile2" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <File>${bySecond}.log</File>
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
        <FileNamePattern>%d{yyyy-MM-dd-HH-mm-ss}.log</FileNamePattern>
    </rollingPolicy>
    <encoder>
        <pattern>%date [%thread] %-5level %logger{80} - %msg%n</pattern>
    </encoder>
</appender>

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

Logback浅析

1、Logback 为取代log4j 而生

     Logback是由 log4j创始人Ceki Gülcü 设计的又一个开源日志组件。logback当前分成三个模块:logback-core,logback- classic和logback-access。

2、Logback的核心对象:Logger、Appender、Layout

     Logback主要 建立于 Logger Appender   Layout 这三个类之上。

     Logger:日志的记录器,把它关联到应用的对应的 context 上后,主要用于存放日志对象,也可以定义日志类型、级别。Logger对象一般多定义为静态常量,如:

package com.logs;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 public class MyApp {
     final static Logger logger = LoggerFactory.getLogger("MyApp.class");
     public static void main(String[] args) {
         
         logger.trace("trace");
         logger.debug("debug str");
         logger.info("info str");
         logger.warn("warn");
         logger.error("error");
     }
 }
 

     Appender:用于指定日志输出的目的地,目的地可以是控制台、文件、远程套接字服务器、 MySQL、 PostreSQL、Oracle和其他数据库、 JMS和远程UNIX Syslog守护进程等。

     Layout: 负责把事件转换成字符串,格式化的日志信息的输出。具体的Layout通配符,可以直接查看帮助文档。

3、Level 有效级别

    Logger可以被分配级别。级别包括:TRACE、DEBUG、INFO、WARN和ERROR,定义于ch.qos.logback.classic.Level类。程序会打印高于或等于所设置级别的日志,设置的日志等级越高,打印出来的日志就越少。 如果设置级别为INFO,则优先级高于等于INFO级别(如:INFO、 WARN、ERROR)的日志信息将可以被输出,小于该级别的如DEBUG将不会被输出。 为确保所有logger都能够最终继承一个级别,根logger总是有级别,默认情况下,这个级别是DEBUG。

4、 三值逻辑

    Logback的过滤器基于三值逻辑(ternary logic),允许把它们组装或成链,从而组成任意的复合过滤策略。过滤器很大程度上受到Linux的iptables启发。这里的所谓三值逻辑是说,过滤器的返回值只能是ACCEPT、DENY和NEUTRAL的其中一个。

如果返回DENY,那么记录事件立即被抛弃,不再经过剩余过滤器;

如果返回NEUTRAL,那么有序列表里的下一个过滤器会接着处理记录事件;

如果返回ACCEPT,那么记录事件被立即处理,不再经过剩余过滤器。

5、Filter 过滤器

    Logback-classic提供两种类型的过滤器:常规过滤器和TuroboFilter过滤器。Logback整体流程:Logger 产生日志信息;Layout修饰这条msg的显示格式;Filter过滤显示的内容;Appender具体的显示,即保存这日志信息的地方。

6、具体使用案例

     Java项目中一般都会应用比如struts、spring、hibernate等开源框架,而这些框架很多是应用log4j记录日志的,所以我们考虑用log4j   +  slf4j   + logback 。这样我们需要导入log4j-over-slf4j-1.6.4.jar 、 logback-classic-1.0.1.jar 、 logback-core-1.0.1.jar 、 slf4j-api-1.6.4.jar ,如果你要用到EvaluatorFilter过滤器来过滤日志Msg中的特殊字符需要导入其依赖包 janino-2.3.2.jar 。其logback.xml

<?xml version="1.0" encoding="UTF-8"?>
 <configuration>
 
     <!-- 控制台输出 -->
     <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
         <encoder>
             <pattern>%date [%thread] %-5level %logger{80} - %msg%n</pattern>
         </encoder>
     </appender>
 
     <!-- 时间滚动输出 level为 DEBUG 日志 -->
     <appender name="file—debug"
         class="ch.qos.logback.core.rolling.RollingFileAppender">
         <filter class="ch.qos.logback.classic.filter.LevelFilter">
             <level>DEBUG</level>
             <onMatch>ACCEPT</onMatch>
             <onMismatch>DENY </onMismatch>
         </filter>
         <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
             <FileNamePattern>D:/logs/debug.%d{yyyy-MM-dd}.log</FileNamePattern>
             <MaxHistory>30</MaxHistory>
         </rollingPolicy>
         <encoder>
             <pattern>%date [%thread] %-5level %logger{80} - %msg%n</pattern>
         </encoder>
     </appender>
 
     <!-- 时间滚动输出 level为 ERROR 日志 -->
     <appender name="file—error"
         class="ch.qos.logback.core.rolling.RollingFileAppender">
         <filter class="ch.qos.logback.classic.filter.LevelFilter">
             <level>ERROR</level>
             <onMatch>ACCEPT</onMatch>
             <onMismatch>DENY </onMismatch>
         </filter>
         <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
             <FileNamePattern>D:/logs/error.%d{yyyy-MM-dd}.log</FileNamePattern>
             <MaxHistory>30</MaxHistory>
         </rollingPolicy>
         <encoder>
             <pattern>%date [%thread] %-5level %logger{80} - %msg%n</pattern>
         </encoder>
     </appender>
 
     <!-- 特定过滤含有某字符串的日志 -->
     <appender name="file-str"
         class="ch.qos.logback.core.rolling.RollingFileAppender">
         <filter class="ch.qos.logback.core.filter.EvaluatorFilter">
             <evaluator>
                 <expression>message.contains("str")</expression>
             </evaluator>
             <onMatch>ACCEPT</onMatch>
             <onMismatch>DENY</onMismatch>
         </filter>
         <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
             <FileNamePattern>D:/logs/contains.%d{yyyy-MM-dd}.log
             </FileNamePattern>
             <MaxHistory>30</MaxHistory>
         </rollingPolicy>
         <encoder>
             <pattern>%date [%thread] %-5level %logger{80} - %msg%n</pattern>
         </encoder>
     </appender>
 
     <!-- 数据库输出 -->
     <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://host_name:3306/datebase_name</url>
             <user>username</user>
             <password>password</password>
         </connectionSource>
     </appender>
 
     <logger name="java.sql.Connection">
         <level value="DEBUG" />
     </logger>
     <logger name="java.sql.Statement">
         <level value="DEBUG" />
     </logger>
     <logger name="com.ibatis">
         <level value="DEBUG" />
     </logger>
     <logger name="com.ibatis.common.jdbc.SimpleDataSource">
         <level value="DEBUG" />
     </logger>
     <logger name="com.ibatis.common.jdbc.ScriptRunner">
         <level value="DEBUG" />
     </logger>
     <logger name="com.ibatis.sqlmap.engine.impl.SqlMapClientDelegate">
         <level value="DEBUG" />
     </logger>
     <logger name="com.danga.MemCached">
         <level value="INFO" />
     </logger>
     <logger name="org.springframework.test">
         <level value="DEBUG" />
     </logger>
     <logger name="org.apache.struts2">
         <level value="DEBUG" />
     </logger>
 
     <root level="DEBUG">
         <appender-ref ref="stdout" />
         <appender-ref ref="file—debug" />
         <appender-ref ref="file—error" />
         <appender-ref ref="file-str" />
         <appender-ref ref="db" />
     </root>
 
 </configuration>
 
========================================================================


首先介绍下logback的前世今生。

slf4j由log4j作者Ceki开发,逐步取代apahce commons logging。
logback由log4j作者Ceki开发,逐步取代log4j。
slf4j等于commons-logging,是各种日志实现的通用入口,会根据classpath中存在下面哪一个Jar来决定具体的日志实现库。
 
logback相比较log4j的优势
slf4j支持参数化的logger.error("帐号ID:{}不存在", userId);
告别了if(logger.isDebugEnable()) 时代。
另外logback的整体性能比log4j也较佳,hibernate等项目已经采用了slf4j。
 
slf4j和logback的使用
1.如果日志的参数超过3个,需要写成
Object[] params = {newVal, below, above};
logger.debug("Value {} was inserted between {} and {}.", params);
2.因为内部已优化,作者认为slf4j的logger不需要定义为static。
3.可设置缓存后批量写日志文件(但服务器如果重启,可能会丢失未写到磁盘的记录)
4.MDC,用Filter,将当前用户名等业务信息放入MDC中,在日志format定义中即可使用该变量。
5.JMS Appender用于告警, DB Appender用于业务日志等可以使用插件,如生成Log代码的Eclipse插件Log4E。
6.tomcat和glassfish中,设定日志路径为../logs/xxxx.log 都能将日志放入应用服务器本身的logs目录。
 
最后把最近完善的一个logback.xml贴上,毕竟实际项目中的文件最能说明问题。
<?xml version="1.0" encoding="UTF-8"?>

<configuration>
	<substitutionProperty name="log.base" value="d:\\logback\\logback" />
	<jmxConfigurator />
	<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
		<filter class="ch.qos.logback.core.filter.EvaluatorFilter">
			<evaluator name="myEval">
				<expression>message.contains("dao")</expression>
			</evaluator>
			<onMatch>ACCEPT</onMatch>
			<onMismatch>DENY</onMismatch>
		</filter>
		<layout class="ch.qos.logback.classic.PatternLayout">
			<pattern>%date [%thread] %-5level %logger{80} - %msg%n</pattern>
		</layout>
	</appender>
	<appender name="logfile-dao"
		class="ch.qos.logback.core.rolling.RollingFileAppender">
		<filter class="ch.qos.logback.core.filter.EvaluatorFilter">
			<evaluator name="myEval_dao">
				<expression>message.contains("dao")</expression>
			</evaluator>
			<onMatch>ACCEPT</onMatch>
			<onMismatch>DENY</onMismatch>
		</filter>
		<Encoding>UTF-8</Encoding>
		<File>${log.base}_dao.log</File>
		<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
			<FileNamePattern>${log.base}.%d{yyyy-MM-dd}_dao.log.zip
			</FileNamePattern>
		</rollingPolicy>
		<layout class="ch.qos.logback.classic.PatternLayout">
			<pattern>%date [%thread] %-5level %logger{80} - %msg%n</pattern>
		</layout>
	</appender>
	<appender name="logfile-service"
		class="ch.qos.logback.core.rolling.RollingFileAppender">
		<filter class="ch.qos.logback.core.filter.EvaluatorFilter">
			<evaluator name="myEval_service">
				<expression>message.contains("service.impl")</expression>
			</evaluator>
			<onMatch>ACCEPT</onMatch>
			<onMismatch>DENY</onMismatch>
		</filter>
		<Encoding>UTF-8</Encoding>
		<File>${log.base}_service.log</File>
		<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
			<FileNamePattern>${log.base}.%d{yyyy-MM-dd}_service.log.zip
			</FileNamePattern>
		</rollingPolicy>
		<layout class="ch.qos.logback.classic.PatternLayout">
			<pattern>%date [%thread] %-5level %logger{80} - %msg%n</pattern>
		</layout>
	</appender>
	<appender name="jms_dao" class="ch.qos.logback.classic.net.JMSQueueAppender">
		<InitialContextFactoryName>
			org.apache.activemq.jndi.ActiveMQInitialContextFactory
		</InitialContextFactoryName>
		<ProviderURL>tcp://192.168.1.120:61616</ProviderURL>
		<filter class="ch.qos.logback.core.filter.EvaluatorFilter">
			<evaluator name="myEval_service">
				<expression>message.contains("dao")</expression>
			</evaluator>
			<onMatch>ACCEPT</onMatch>
			<onMismatch>DENY</onMismatch>
		</filter>
		<QueueConnectionFactoryBindingName>ConnectionFactory
		</QueueConnectionFactoryBindingName>
		<QueueBindingName>cms_dao_log</QueueBindingName>
	</appender>
	<appender name="jms_service" class="ch.qos.logback.classic.net.JMSQueueAppender">
		<InitialContextFactoryName>
			org.apache.activemq.jndi.ActiveMQInitialContextFactory
		</InitialContextFactoryName>
		<ProviderURL>tcp://192.168.1.120:61616</ProviderURL>
		<filter class="ch.qos.logback.core.filter.EvaluatorFilter">
			<evaluator name="myEval_service">
				<expression>message.contains("service.impl")</expression>
			</evaluator>
			<onMatch>ACCEPT</onMatch>
			<onMismatch>DENY</onMismatch>
		</filter>
		<QueueConnectionFactoryBindingName>ConnectionFactory
		</QueueConnectionFactoryBindingName>
		<QueueBindingName>cms_service_log</QueueBindingName>
	</appender>
	<logger name="com.cms5.cmsservice.jms">
		<level value="DEBUG" />
	</logger>
	<logger name="java.sql.PreparedStatement">
		<level value="DEBUG" />
	</logger>
	<logger name="java.sql.Connection">
		<level value="DEBUG" />
	</logger>
	<logger name="java.sql.Statement">
		<level value="DEBUG" />
	</logger>
	<logger name="com.ibatis">
		<level value="DEBUG" />
	</logger>
	<logger name="com.ibatis.common.jdbc.SimpleDataSource">
		<level value="DEBUG" />
	</logger>
	<logger name="com.ibatis.common.jdbc.ScriptRunner">
		<level value="DEBUG" />
	</logger>
	<logger name="com.ibatis.sqlmap.engine.impl.SqlMapClientDelegate">
		<level value="DEBUG" />
	</logger>
	<logger name="com.danga.MemCached">
		<level value="INFO" />
	</logger>
	<logger name="org.springframework.test">
		<level value="DEBUG" />
	</logger>
	<logger name="org.apache.struts2">
		<level value="DEBUG" />
	</logger>
	<root>
		<level value="INFO" />
		<!--<appender-ref ref="stdout" />
		-->
		<appender-ref ref="logfile-dao" />
		<appender-ref ref="logfile-service" />
		<appender-ref ref="jms_dao" />
		<appender-ref ref="jms_service" />
	</root>
</configuration>
 

猜你喜欢

转载自wb8206656.iteye.com/blog/1613153