Java-Logback学习笔记

Logback介绍

目前,logback 分为三个模块:Core、Classic 和 Access。Core模块是其他两个模块的基础。 Classic模块扩展了core模块。 Classic模块相当于log4j的显著改进版。Logback-classic 直接实现了 SLF4J API,因此你可以在 logback 与其他记录系统如 log4j和 java.util.logging (JUL)之间轻松互相切换。Access 模块与 Servlet 容器集成,提供 HTTP 访问记录功能。

引入logback的必要条件
Logback-classic依赖slf4j-api.jar和logback-core.jar,并把它们添加到class path. 简单示例1.1:Basic template for logging (logback-examples/src/main/java/chapters/introduction/HelloWorld1.java)

package com.ttpod.chapters.introduction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HelloWorld1 {
  public static void main(String[] args) {
    //调用LoggerFactory 类的静态方法getLogger取得一个Logger实例,
//这个logger被命名为以chapters.introduction.HelloWorld1
    Logger logger = LoggerFactory.getLogger("chapters.introduction.HelloWorld1");
    //定义一个级别为DEBUG的、包含Hello world消息的记录语句
logger.debug("Hello world.");
  }
}

运行结果:18:20:42.125 [main] DEBUG chapters.introduction.HelloWorld1 - Hello world.
HelloWorld1类导入了org.slf4j包里的Logger类和LoggerFactory类。

Logback 可以通过内置的状态系统来报告其内部状态。通过 StatusManager 组件可以访问 logback 生命期内发生的重要事件。目前,我们调用 StatusPrinter 类的 print()方法来打印 logback 的内部状态。

示例1.2:Printing Logger Status (logback-examples/src/main/java/chapters/introduction/HelloWorld2.java)

package com.ttpod.chapters.introduction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.core.util.StatusPrinter;
public class HelloWorld2 {
    public static void main(String[] args) {
        Logger logger = LoggerFactory.getLogger("chapters.introduction.HelloWorld2");
        logger.debug("Hello world.");
//通过getILoggerFactory()方法得到logger上下文件环境(logger的内部状态)
        LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
        StatusPrinter.print(lc);        //打印内部状态
    }
}

Appender 包含许多不同类型的目的地,包括控制台、文件、Syslog、TCP 套接字、JMS 和其他,当发生错误时,logback 将自动在控制台上打印其内部状态。
An Appender is a class that can be seen as an output destination. 一个Appender是一个类,可以被看作是一个输出目的地。

在应程序里启用记录的三个必需步骤如下:

1.  配置 logback 环境。
2.  在每个需要执行记录的类里,调用 org.slf4j.LoggerFactory 类的 getLogger()方法获
取一个 Logger 实例,以当前类名或类本身作为参数。 
3.  调用取得的 logger 实例的打印方法,即 debug()、info()、warn()和 error(),把记录
输出到配置里的各 appender。

Logback的配置

Logger、Appender和 Layout

Logback建立于三个主要类之上:Logger、Appender 和 Layout。Logger类是logback-classic模块的一部分,而Appender和Layout接口来自logback-core。作为一个多用途模块,logback-core 不包含任何 logger。

Logger作为日志的记录器,把它关联到应用的对应的context上后,主要用于存放日志对象,也可以定义日志类型、级别。Appender主要用于指定日志输出的目的地,目的地可以是控制台、文件、远程套接字服务器、 MySQL、 PostreSQL、 Oracle和其他数据库、 JMS和远程UNIX Syslog守护进程等。Layout 负责把事件转换成字符串,格式化的日志信息的输出。

Logger context

各个logger 都被关联到一个 LoggerContext,LoggerContext负责制造logger,也负责以树结构排列各 logger。

如果 logger的名称带上一个点号后是另外一个 logger的名称的前缀,那么,前者就被称为后者的祖先。如果 logger与其后代 logger之间没有其他祖先,那么,前者就被称为子logger 之父。比如,名为 “com.foo”“的 logger 是名为”com.foo.Bar”之父。root logger 位于 logger 等级的最顶端,root logger 可以通过其名称取得,如下所示:

Logger rootLogger = LoggerFactory.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME);

其他所有logger也通过org.slf4j.LoggerFactory 类的静态方法getLogger取得。 getLogger方法以 logger 名称为参数。用同一名字调用LoggerFactory.getLogger 方法所得到的永远都是同一个logger对象的引用。

有效级别与级别继承

Logger 可以被分配级别。级别包括:TRACE、DEBUG、INFO、WARN 和 ERROR,定义于 ch.qos.logback.classic.Level类。如果 logger没有被分配级别,那么它将从有被分配级别的最近的祖先那里继承级别。root logger 默认级别是 DEBUG。

打印方法与基本选择规则

打印方法决定记录请求的级别。例如,如果 L 是一个 logger 实例,那么,语句 L.info(“..”)是一条级别为 INFO 的记录语句。记录请求的级别在高于或等于其 logger 的有效级别时被称为被启用,否则,称为被禁用。

记录请求级别为 p,其 logger的有效级别为 q, 只有则当 p>=q时, 该请求才会被执行。 该规则是 logback 的核心。级别排序为: TRACE < DEBUG < INFO < WARN < ERROR。

Logger、Appenders及layouts的关系

一个 logger 可以被关联多个 appender。 方法 addAppender() 为指定的 logger 添加一个 appender。 对于 logger 的每个启用了的记录请求,都将被发送到 logger 里的全部 appender 及更高等级的 appender。换句话说,appender叠加性地继承了 logger 的层次等级。

configuration结构图
configuration结构图

Logger L的记录语句的输出会发送给 L及其祖先的全部 appender。如果 logger L的某个祖先 P设置叠加性标识为 false,那么,L的输出会发送给L 与 P之间(含P)的所有 appender,但不会发送给P的任何祖先的appender。

Logger 的叠加性默认为 true。如果希望定制输出格式。这时为 appender 关联一个 layout 即可。Layout 负责根据用户意愿对记录请求进行格式化,appender 负责将格式化化后的输出发送到目的地。

Appender结构图
Appender结构图

例如,转换模式”%-4relative [%thread] %-5level %logger{32} - %msg%n”在 PatternLayout里会输出形如:

176 [main] DEBUG manual.architecture.HelloWorld2 - Hello world.

第一个字段是自程序启动以来的逝去时间,单位是毫秒。 第二个地段发出记录请求的线程。 第三个字段是记录请求的级别。 第四个字段是与记录请求关联的 logger 的名称。 “-“之后是请求的消息文字。

Logback的默认配置

如果配置文件 logback-test.xml 和 logback.xml 都不存在,那么 logback 默认地会调用BasicConfigurator ,创建一个最小化配置。最小化配置由一个关联到根 logger 的ConsoleAppender 组成。输出用模式为%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 的 PatternLayoutEncoder 进行格式化。root logger 默认级别是 DEBUG。

logback配置文件

Logback 配置文件的语法非常灵活。正因为灵活,所以无法用 DTD 或 XML schema 进行定义。尽管如此,可以这样描述配置文件的基本结构:以开头,后面有零个或多个元素,有零个或多个元素,有最多一个元素。

Logback默认配置的采用的步骤

  1. 尝试在 classpath 下查找文件 logback-test.xml;
  2. 如果文件不存在,则查找文件 logback.xml;
  3. 如果两个文件都不存在,logback 用 Bas icConfigurator 自动对自己进行配置,这会导致记录输出到控制台。

假设配置文件 logback-test.xml 和 logback.xml 都不存在,那么 logback 默认地会调用BasicConfigurator ,创建一个最小化配置。最小化配置由一个关联到根 logger 的ConsoleAppender 组成。输出用模式为%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 的 PatternLayoutEncoder 进行格式化。还有,根 logger 默认级别是 DEBUG。

最简单的配置方法就是使用默认配置。 以下是logback用BasicConfigurator 配置的简单例子:

package com.ttpod.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) {
        logger.info("Entering application.");    //进行另一个application中
        Foo foo = new Foo();
        foo.doIt();        //执行其它中的日志输出方法
        logger.info("Exiting application.");    //退出另一个application
    }
}

该类定义了一个静态变量 logger,然后实例化一个 Foo 对象。Foo 类如下

package com.ttpod.chapters.configuration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Foo {
    static final Logger logger = LoggerFactory.getLogger(Foo.class);
    public void doIt() {
        logger.debug("Did it again!");    //定义一个debug级别的日志输出
    }
    …………
}

自动打印警告和错误消息

当解析配置文件有警告或出错时,logback 会在控制台上自动打印状态数据。如果没有警告或错误,还是想检查 logback 的内部状态的话, 可以调用 StatusPrinter 的 print()方法。示例如下:

final static Logger logger = LoggerFactory.getLogger(MyApp2.class);
public static void main(String[] args) {
// 在当前环境中假设 SLF4J 已经被绑定到logback
        LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
// 打印logback的内部状态
        StatusPrinter.print(lc);
        …………
        }
}

对应的配置文件:

<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
<!--定义一个名为STDOUT的appender,并将其关联到ch.qos.logback.core.ConsoleAppender-->
<appender name="STDOUT"
class="ch.qos.logback.core.ConsoleAppender">
<!-- encoders 作用是将logger事件转换成字节数组,并将字节数组写入到输出流-->
<encoder>
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度
        %msg:日志消息,%n是换行符-->
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<root level="debug">    <!-- root logger,定义级别为debug-->
<appender-ref ref="STDOUT" />    <!--将名为STDOUT的appender添加到root logger下-->
</root>
</configuration>

控制台输出结果如下:

…………
20:12:33,359 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Could NOT find resource [logback.groovy]
20:12:33,359 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Could NOT find resource [logback-test.xml]
20:12:33,359 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Found resource [logback.xml] at [file:/D:/Workspaces/MyEclipse%208.5/logback_test/WebRoot/WEB-INF/classes/logback.xml]
20:12:33,484 |-INFO in ch.qos.logback.core.joran.action.AppenderAction - About to instantiate appender of type [ch.qos.logback.core.ConsoleAppender]
20:12:33,484 |-INFO in ch.qos.logback.core.joran.action.AppenderAction - Naming appender as [STDOUT]
20:12:33,500 |-INFO in ch.qos.logback.core.joran.action.NestedComplexPropertyIA - Assuming default type [ch.qos.logback.classic.encoder.PatternLayoutEncoder] for [encoder] property
20:12:33,593 |-INFO in ch.qos.logback.classic.joran.action.RootLoggerAction - Setting level of ROOT logger to DEBUG
20:12:33,593 |-INFO in ch.qos.logback.core.joran.action.AppenderRefAction - Attaching appender named [STDOUT] to Logger[ROOT]
20:12:33,593 |-INFO in ch.qos.logback.classic.joran.action.ConfigurationAction - End of configuration.
20:12:33,593 |-INFO in ch.qos.logback.classic.joran.JoranConfigurator@cb6009 - Registering current configuration as safe fallback point
…………

Logback自定义配置

配置root logger

<root>元素配置根 logger。该元素有一个 level属性。没有 name 属性,因为已经被命名为"ROOT"。   
Level 属性的值大小写无关,其值为下面其中一个字符串:TRACE、DEBUG、INFO、WARN、ERROR、ALL和 OFF。    
注意不能设置为"INHERITED" 或"NULL"。   
<logger>元素可以包含零个或多个<appender-ref>元素。    
与<logger>元素类似,声明<root>元素后,会先关闭然后移除全部当前 appender,只引用声明了的 appender。    
如果 root 元素没有引用任何 appender,就会失去所有 appender。   

假设我们不想看到”com.ttpod.file”包里的任何组件的任何 DEBUG 信息,可以设置如下:

<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
    <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>
    <!-- 设置configuration下的logger的级别为INFO,默认是继承root logger的debug级别 -->
    <logger name="chapters.configuration" level="INFO" />
    <!-- 严格来说, root logger 的level属性没有必要设置,因为 -->
    <!-- root logger的级别被默认设置为DEBUG -->
    <root level="DEBUG">
        <!--
         在root标签内没有引入chapters.configuration,所有在此包下不会
        显示任何组件的任何 DEBUG 信息
        -->
        <appender-ref ref="STDOUT" />    <!-- 将appender引入到root logger -->
    </root>
</configuration>

注意:由名为”chapters.configuration.Foo”的 logger 生成的 DEBUG 级别的信息都被屏蔽了.同样,也可以为任意数量的 logger 设置级别。

配置 Appenders

Appender 用元素配置,该元素必要属性 name 和 class。 name 属性指定 appender 的名称,class 属性指定 appender 类的全限定名。 元素可以包含零个或多个元素、零个或多个元素和零个或多个元素。除了这三个常用元素之外,还可以包含 appender 类的任意数量的 javabean 属性。下图演示了常用结构,注意对 javabean 属性的支持在图中不可见。

Appender类层次图
Appender类层次图

记录输出到多个 appender 很简单,先定义各种 appender,然后在 logger 里进行引用,就行了。如下面的配置文件所示:

<configuration>
    <appender name="FILE" class="ch.qos.logback.core.FileAppender">
        <file>myApp.log</file>
        <!-- encoders are assigned by default the type
        ch.qos.logback.classic.encoder.PatternLayoutEncoder -->
        <encoder>
            <pattern>%date %level [%thread] %logger{10} [%file:%line] %msg%n</pattern>
        </encoder>
    </appender>
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%msg%n</pattern>
        </encoder>
    </appender>
    <root level="debug">
        <appender-ref ref="FILE" />
        <appender-ref ref="STDOUT" />
    </root>
</configuration>

该配置文件定义了两个 appender,分别是”FILE”和”STDOUT”。 “FILE” 这个 appender 把记录输 出到文件 “myapp.log “ ,它的 encoder 是PatternLayoutEncoder,输出了日期、级别、线程名、logger 名、文件名及记录请求的行号、消息和行分隔符。 “STDOUT”这个 appender 把记录输出到控制台,它的 encoder 只是输出消息和行分隔符。 myApp.log文件内容如下:

2011-12-25 16:56:48,593 INFO [main] c.t.c.c.MyApp3 [MyApp3.java:48] Entering application.
2011-12-25 16:56:48,593 DEBUG [main] c.t.c.c.Foo [Foo.java:24] Did it again!
2011-12-25 16:56:48,593 INFO [main] c.t.c.c.MyApp3 [MyApp3.java:52] Exiting application.

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

Appender累积

默认情况下,appender 是可累积的:logger 会把记录输出到它自身的 appender 和它所有祖先的 appender。因此,把同一 appender 关联到多个 logger 会导致重复输出,如下面的配置文件会导致重复的输出:

<configuration>
    <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>
    <logger name="chapters.configuration">
        <appender-ref ref="STDOUT" />
    </logger>
    <root level="debug">
        <appender-ref ref="STDOUT" /> <!—这会导致重复输出-->
    </root>
</configuration>

输出结果如下:

20:53:29.328 [main] INFO c.t.chapters.configuration.MyApp2 - Entering application.
20:53:29.328 [main] INFO c.t.chapters.configuration.MyApp2 - Entering application.
20:53:29.328 [main] DEBUG com.ttpod.chapters.configuration.Foo - Did it again!
20:53:29.328 [main] DEBUG com.ttpod.chapters.configuration.Foo - Did it again!
20:53:29.328 [main] INFO c.t.chapters.configuration.MyApp2 - Exiting application.
20:53:29.328 [main] INFO c.t.chapters.configuration.MyApp2 - Exiting application.

覆盖默认的累积行为

如果你觉得默认的累积行为不合适,可以设置叠加性标识为 false 以关闭它。 这样的话,logger 树里的某个分支可以输出到与其他 logger 不同的 appender。 示例:叠加性标识

<configuration>
    …………
    <logger name="com.ttpod.chapters.configuration.Foo" additivity="false">
        <appender-ref ref="FILE" />
    </logger>
    <root level="debug">
        <appender-ref ref="STDOUT" />
    </root>
</configuration>

输出结果:

Entering application.
Exiting application.

此例中,logger”chapters.configuration.Foo”关联 appender”FILE”,它的叠加性标记为false,这样它的记录输出仅会被发送到 appender”FILE”,不会被发送到更高 logger 等级关联的 appender。其他 logger 不受此影响。 用 additivityFlag.xml 配置 MyApp3 , 运 行 后 , 控 制 台 上 由 输 出 由”chapters.configuration.MyApp3”产生的记录。而 logger” chapters.configuration.Foo”将且仅仅将输出到文件 foo.log。

Layout格式化输出日志

配置自定义 layout 配置自定义layout与配置其他layout是一样的。 FileAppender和其子类需要一个encoder。如链接中的例子:http://logback.qos.ch/xref/chapters/layouts/MySampleLayout.html

此类中定义了一个处理格式的输出类,为了满足自定义的格式化的输出,把包裹了 MySampleLayout 的 LayoutWrappingEncoder 实例传递给FileAppender。下面是配置文件:

<configuration debug="true">
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
            <!—自定义的格式化输出处理类-->
            <layout class="com.ttpod.chapters.layouts.MySampleLayout" />
        </encoder>
    </appender>
    <root level="DEBUG">
        <appender-ref ref="STDOUT" />
    </root>
</configuration>

输出结果如下:

250 DEBUG [main] com.ttpod.chapters.introduction.HelloWorld1 - Hello world.

layout转换符

它和C语言的printf方法非常类似。格式转换由普通字符和转换字符组合而成。转换字符由%开始,紧跟着的是可选的格式修饰符和转换字符标示。使用%前缀的表示符号将被转换到实际的内容。如name, level, date, thread name.可用的转换符有:

转换符 描述
c 调用日志事件的所在记录器的名字,如一个logger的名字是my.test.bbb.ccc,调用的是WARN级别的日志输出,那么输出的是输出my.test.bbb.ccc,可以在其右边指定了精度,如%c{2}那么输出的是bbb.ccc
C 调用日志事件的所在的类名,和c转换符一样,可以在右边指定宽度,如%C{2}输出%C{2}
d 日志调用所发生的时间,日期格式在其后跟着的大括号内的格式指定如%d{yyyy-MM-dd HH:mm:ss},我现在输出的结果是2011-07-11 21:05:22,推荐使用的是log4j本身提供的日期格式,如%d{ISO8601},%d{ABSOLUTE},%d{DATE}
F 所处所在文件名,如上面说C转换符的例子,输出结果是LayoutTest.java
l 是的日志事件发生的位置信息,这个和虚拟机的实现有点关系,一般境况下能得到类,方法,行数源文件等信息,
L 只是输出触发日志事件代码所在的行号,性能损耗会小很多。
m 显示应用给日志提供的其他信息,如消息。logger.warn(“Message 2”);那么%m将得到的是Message 2
M 输出调用者所在的方法名
n 换行,和\r \r\n有相同功能,能识别系统的换行符,自动转换成\r或者\r\n,log4j推荐使用这个转换符,而不是\r或者\r\n
p 输出调用的日志的级别,如我是调用logger.debug方法,那么级别就是debug
r 输出自应用启动后第一次调用logger的日志输出方法,到输出该log信息耗费的毫秒数
t 输出所在线程的名字
x 输出产生的日志事件的线程的NDC(嵌套诊断上下文)
X 输出与生成的日志事件的线程关联的MDC(映射诊断上下文)。X转换符括号之间放置了一个key,就像在%X {clientNumber}中的clientNumberkey 一样。在MDC correspondingvalue将被输出。
% 写上%%后将直接输出一个%符号

layout格式修饰符

如给定的一个格式:%-5p [%t]: %m%n中,并没有明确的分隔转换字符和普通文本的字符存在。PatternLayout能自己区分普通文本和转换字符。其中%-5p是日志的调用级别。事件是左对齐的,5个字符宽度。

格式修饰符,放在%和转换符之间。 第一个可选的格式修饰符是左对齐(-);第二个可选的格式修饰符是字段最小宽度。一个整数。表示输出的最小字符数。如果数据未达到指定最小大小,那么它将以左填充(默认)或者右填充方式(左对齐情况下只能使用右填充了)。用空格填充,直到达到最小宽度。如果大于指定最小宽度,不会被截断 。当然可以指定最大字符数,使用.符号加数字表示最大字符数。如果大于指定长度,多余的字符会被删除。它是从前面删除,而不是从后面删除的。如最大字符是8个,数据有10个字符,那么前面两个字符会被删除。

%20c 右对齐,最少20字符,没有左边用空格填充 
%-20c 左对齐,最少20字符,没有右边用空格填充 
%.30c 右对齐,最多30字符,超过左边的截取掉 
%20.30c 右对齐,最少20字符,最多30字符,填充或截取规则略
%-20.30c 左对齐,最少20字符,最多30字符,填充或截取规则略 

在程序里启用logback记录

三个必须步骤:

  1. 配置 logback 环境。
  2. 在每个需要执行记录的类里,调用 org.slf4j.LoggerFactory 类的 getLogger()方法获取一个 Logger 实例,以当前类名或类本身作为参数。
  3. 调用取得的 logger 实例的打印方法,即 debug()、info()、warn()和 error(),把记录输出到配置里的各 appender。

直接调用JoranConfigurator

Logback 依赖Joran,Joran是 logback-core 的一部分,是个配置类库。Logback 的默认配置机制是调用JoranConfigurator对classpath上的默认配置文件进行处理。 不管出于什么理由,如果你想重新实现 logback 的默认配置机制的话,你可以直接调用 JoranConfigurator。下面程序 MyApp1 就调用了 JoranConfigurator 对作为参数传入的配置文件进行处理。

示例1(com/ttpod/file/ MyApp1.java)

package com.ttpod.file;
import org.slf4j.Logger;                //用于声明Logger
import org.slf4j.LoggerFactory;     //用于获取Logger以及LoggerContext
import ch.qos.logback.classic.LoggerContext;         //用于声明LoggerContext
import ch.qos.logback.classic.joran.JoranConfigurator; //用于定义Logback的配置机制
import ch.qos.logback.core.joran.spi.JoranException; //用于定义JoranException
import ch.qos.logback.core.util.StatusPrinter; //用于打印logback的内部状态
public class MyApp1 {
    final static Logger logger = LoggerFactory.getLogger(MyApp1.class);    //定义一个全局的记录器,通过LoggerFactory获取
    public static void main(String[] args) {
        //通过getILoggerFactory()方法得到logger上下文件环境,logback默认获得当前应用的logger context
        LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();    //得到当前应用中logger上下文
        try {
            JoranConfigurator configurator = new JoranConfigurator();    //定义一个(JoranConfigurator)配置器
            configurator.setContext(context);    //将当前应用的logger context的关联到到configurator对象
            context.reset();                        //清除以前的配置器中的所有内容
//configurator.doConfigure(args[0]);    //接收从命令行传入的参数,加载配置文件,并设置到配置器
            configurator.doConfigure("src/com/ttpod/file/MyApp1Config.xml");
//配置文件的路径:src/com/ttpod/file/MyApp1Config.xml
        } catch (JoranException je) {
            logger.error("JoranException occur at:"+je.getMessage());    //将此处异常也记录到日志
            je.printStackTrace();    //在控制打印出异常跟踪信息
        }
//打印出logger context中的error和供气ing,在此处作用相当于catch中的je.printStackTrace();
        StatusPrinter.printInCaseOfErrorsOrWarnings(context);
//流程进入有日志生成的类中
        logger.info("Entering application.demo class Foo >>>");
        Foo foo = new Foo();
        foo.doIt();    //执行foo中的一个生成了日志的方法,输出日志
        logger.info("Exiting application. demo class Foo <<<");
    }
}

其它类Foo类,代码如下:(com/ttpod/file/ Foo.java)

package com.ttpod.file;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Foo {
    static final Logger logger = LoggerFactory.getLogger(Foo.class);
    public void doIt() {
        logger.debug("test logger in other class!");
    }
    public void createLoggingRequest() {
        subMethodToCreateRequest();
    }
    //这个方法执行后创建一条异常信息
    private void subMethodToCreateRequest() {
        logger.error("error-level request", new Exception("test exception"));
    }
}

此程序通过参数传配置文件的名字,对程序的日志输出配置,本例如下:(com/ttpod/file/ MyApp1Config.xml)

<configuration>
    <!-- 指定属性文件路径 -->
    <property file="src/com/ttpod/file/variables.properties" />
    <!-- 指定日志输出到文件-->
    <appender name="FILE" class="ch.qos.logback.core.FileAppender">
        <file>${destination}</file>
        <encoder>
            <!-- %msg表示日志信息,%n表示换行 -->
            <pattern>%msg%n</pattern>
        </encoder>
    </appender>
    <root level="debug">
        <appender-ref ref="FILE" /><!—添加到根logger-->
    </root>
</configuration>

对应的properties文件,嵌套的设置了日志文件的输出路径及文件名,如下:(com/ttpod/file/ variables.properties)

#指定USER_HOME目录
USER_HOME=./log
#指定日志文件名
fileName=myApp.log
#生成日志文件的目的地
destination=${USER_HOME}/${fileName}

配置好后,右键MyApp3 -> run as… -> run configurations -> 选择MyApp3,及arguments -> 配置program Aguments:src/com/ttpod/MyApp1Config.xml,以指定配置文件,然后运行即可,即可在当前就应用的/log文件夹下生成myApp.log ,输出如下:

Entering application.demo class Foo >>>
test logger in other class!
Exiting application. demo class Foo <<<

运用滚动策略与触发策略

RollingFileAppender 继承 FileAppender,能够滚动记录文件。例如,RollingFileAppender能先记录到文件”log.txt”,然后当符合某个条件时,变成记录到其他文件。 RollingFileAppender 有两个与之互动的重要子组件。第一个是RollingPolicy,负责滚动。第二个是 TriggeringPolicy,决定是否以及何时进行滚动。所以,RollingPolicy 负责”什么”, TriggeringPolicy 负责”何时”。

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

示例2

如下测试程序应用滚动与触发策略,来处理日志文件。(com/ttpod/file/MyApp2.java)

package com.ttpod.file;
import java.util.Date;
public class MyApp2 {
    static Timer t;
    public static void main(String[] args) {
        // 调用LoggerFactory 类的静态方法getLogger取得一个Logger实例,
        final Logger logOut = LoggerFactory.getLogger("SystemOut"); // 定义一个名为SystemOut的logger
        final Logger logErr = LoggerFactory.getLogger("SystemErr"); // 定义一个名为SystemErr的logger
        LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
        try {
            JoranConfigurator configurator = new JoranConfigurator();
            configurator.setContext(lc);
            lc.reset();
            //configurator.doConfigure(args[0]);
            configurator.doConfigure("src/com/ttpod/file/logback.xml");
        } catch (JoranException je) {
            je.printStackTrace();
        }
        // 打印logback的内部状态
        StatusPrinter.print(lc);    //固定部分
        t = new Timer(); // 定义一个定时器
        TimerTask tt = new TimerTask() { // 用定义器执行计划(schedule),并定义一个继承了TimerTask的匿名内部类
            @Override
            public void run() {
                for (int i = 100; i > 0; i--) {
                    // Timer t=null;
                    MyApp2.t.cancel();
                    logOut.info("测试Logback日志的使用"); // 定义了一个info级别的日志消息
                    logErr.error("发生错误"); // 定义了一个error级别的日志消息
                }
                System.out.println("~~~~~~~~~~~~~ ");
            }
        };
        t.schedule(tt, new Date(), 50); // 从当前系统时间开始,每50毫秒执行一次计划
    }
}
// 没有自定义它的logback所需的配置文件,程序启动时会自动加载classpath目录下的查找
// logback-test.xml;如果没找到则logback-test.xml,则继续在classpath下查找lobback.xml。

此测试类,在定时器中定义了一个执行计划,按照执行计划生成日志文件。在file包中添加相的logback配置文件,如下:(com/ttpod/file/logback.xml)

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration>
<configuration>
    <jmxConfigurator />
    <!-- 配置文件路径 -->
    <property file="src/com/ttpod/file/variables.properties" />
    <!--logback的版本必须是0.9.21以上才支持-->
    <timestamp key="byDay" datePattern="yyyyMMdd"/>
    <!-- 控制台输出日志 -->
    <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>
    <!-- 文件输出日志 (文件大小策略进行文件输出,超过指定大小对文件压缩(.zip)备份)-->
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 文件的路径及文件名 -->
        <File>${USER_HOME}/SystemOut.log</File>
        <!-- 定义窗口滚动策略 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
            <!-- 每触发一次,自动压缩日志文件,%i在1-3之间循环变化 -->
            <FileNamePattern>${USER_HOME}/SystemOut_%i.log.zip</FileNamePattern>
            <MinIndex>1</MinIndex> <!-- %i的最小值为1-->
            <MaxIndex>3</MaxIndex> <!-- %i的最大值为3-->
        </rollingPolicy>
        <!-- 触发策略,通常rollingPolicy与triggeringPolicy联合使用 -->
        <triggeringPolicy
                class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
            <MaxFileSize>10KB</MaxFileSize>
        </triggeringPolicy>
        <!-- 格式化输出 -->
        <!-- %d表示日期,格式为:yyyy-MM-dd HH:mm:ss.SSS ;%thread:线程名;
            %-5level:从左边以5个字符的宽度显示级别; %logger:显示logger名;%msg:日志消息;%n:换行 
        <layout class="ch.qos.logback.classic.PatternLayout">
        <Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</Pattern>
        </layout>
        -->
        <!-- 或者用下面的形式格式(推荐)-->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS}%relative%thread%mdc%level%logger%msg</pattern>
        </encoder>
        <!-- 以html文件输出 -->
        <!--
        <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
            <layout class="ch.qos.logback.classic.html.HTMLLayout">
                    <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS}%relative%thread%mdc%level%logger%msg</pattern>
                </layout>
                </encoder>
        -->
    </appender>
    <!-- 输出ERROR级别的日志到文件(同样采用文件大小策略进行文件输出,超过指定大小对文件压缩(.zip)备份) -->
    <appender name="FILE-ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level> <!-- 指定要对级别为ERROR日志信息过滤 -->
            <OnMismatch>DENY</OnMismatch>     <!-- 如果不匹配,则拒绝处理 -->
            <OnMatch>ACCEPT</OnMatch>         <!-- 如果匹配,则立即处理 -->
        </filter>
        <File>${USER_HOME}/SystemErr.log</File> <!-- 文件名即路径 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
            <FileNamePattern>${USER_HOME}/SystemErr_%i.log.zip</FileNamePattern>
            <MinIndex>1</MinIndex>
            <MaxIndex>3</MaxIndex>
        </rollingPolicy>
        <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
            <MaxFileSize>10KB</MaxFileSize>
        </triggeringPolicy>
        <!-- 格式化输出 -->
        <!--
        <layout class="ch.qos.logback.classic.PatternLayout">
        <Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</Pattern>
        </layout>
        -->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS}%relative%thread%mdc%level%logger%msg</pattern>
        </encoder>
    </appender>
    <!--这里指定logger name 是为jmx设置日志级别做铺垫 -->
    <!-- 分别将STDOUT与FILE appender都添加到自定义的logger中,否则将不会输出到appender指定的 目的地-->
    <logger name="SystemOut" level="INFO">
        <appender-ref ref="STDOUT" />
        <appender-ref ref="FILE" />
    </logger>
    <logger name="SystemErr" level="INFO">
        <appender-ref ref="STDOUT" />
        <appender-ref ref="FILE-ERROR" />
    </logger>
</configuration>

执行以上程序,在控制台也会不断的输出以下日志信息:

14:42:34.875 [Timer-0] INFO SystemOut - 测试Logback日志的使用
14:42:34.875 [Timer-0] ERROR SystemErr - 发生错误
14:42:34.937 [Timer-0] INFO SystemOut - 测试Logback日志的使用
14:42:34.937 [Timer-0] ERROR SystemErr - 发生错误
14:42:35.000 [Timer-0] INFO SystemOut - 测试Logback日志的使用
14:42:35.000 [Timer-0] ERROR SystemErr - 发生错误
14:42:35.062 [Timer-0] INFO SystemOut - 测试Logback日志的使用
14:42:35.062 [Timer-0] ERROR SystemErr - 发生错误

FixedWindowRollingPolicy当发生滚动时,FixedWindowRollingPolicy 根据如下固定窗口(window)算法重命名文件。 选项”fileNamePattern”代表归档(滚动)记录文件的文件名模式。该选项是必需的,且必需在模式的某处包含标志”%i”。如示例3中的MyApp3-RollingFixedWindow.xml 。

TimeBasedRollingPolicy 或许是最受流行的滚动策略。它根据时间来制定滚动策略,例如根据日或月。TimeBasedRollingPolicy 既负责滚动也负责触发滚动。实际上,TimeBasedRollingPolicy 同时实现了 RollingPolicy 接口和 TriggeringPolicy 接口。和 FixedWindowRollingPolicy一样,TimeBasedRollingPolicy 也支持自动压缩文件。如果”fileNamePattern”选项以”.gz”或”.zip”结尾,就表示需要压缩。如示例3中的MyApp3-RollingTimeBased.xml 。

SizeAndTimeBasedFNATP按照日期进行归档的同时限制每个记录文件的大小,特别是当后处理工具对记录文件大小有限制时。Logback 为此提供了 SizeAndTimeBasedFNATP ,它是TimeBasedRollingPolicy 的子组件,FNATP 代表”FNATP stands for File Naming And Triggering Policy”。 下面的例子MyApp3-sizeAndTime.xml演示了基于大小和时间的记录文件归档。

示例3(com/ttpod/file/MyApp3.java)

package com.ttpod.file;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.joran.JoranConfigurator;
import ch.qos.logback.core.joran.spi.JoranException;
import ch.qos.logback.core.util.StatusPrinter;
import com.ttpod.file.Foo;;
public class MyApp3 {
    public static void main(String[] args) throws InterruptedException {
        Logger logger = (Logger) LoggerFactory.getLogger(MyApp3.class);
        LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
        try {
            JoranConfigurator configurator = new JoranConfigurator();
            configurator.setContext(lc);
            lc.reset();
            configurator.doConfigure(args[0]);
        } catch (JoranException je) {
            je.printStackTrace();
        }    //固定部分
//打印logback的内部状态
        StatusPrinter.print(lc);
        logger.debug("**Hello {}", new Foo());
//客户端的每个记录请求添加唯一戳(uniquely stamp),运用MDC(Mapped Diagnostic Context)
//在分布式应用程序中,可以区分并处理不同客户端的记录输出,而不增加logger的开销
        MDC.put("testKey", "testValueFromMDC");        //在appender中用%X{testKey},可以输出MDC中test对应的值
        MDC.put("testKey2", "value2");
        for (int i = 0; i < 10; i++) {
            logger.debug("logging statement " + i);
            Thread.sleep(100);
        }
        Foo foo = new Foo();
        foo.createLoggingRequest();
    }
}

配置文件:(com/ttpod/file/MyApp3-RollingFixedWindow.xml)

<configuration>
    <!-- 指定属性文件路径 -->
    <property file="src/com/ttpod/file/variables.properties" />
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${USER_HOME}/testFile.log</file>
        <!--滚动策略-->
        <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
            <!—自动压缩备份-->
            <fileNamePattern>${USER_HOME}/testFile.%i.log.zip</fileNamePattern>
            <minIndex>1</minIndex>
            <maxIndex>3</maxIndex><!--%i在1-3之间循环变化-->
        </rollingPolicy>
        <!—触发策略-->
        <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
            <!--日志文件大小限制在5kB以内,否则就触发滚动-->
            <maxFileSize>5kB</maxFileSize>
        </triggeringPolicy>
        <encoder><!--格式化输出-->
            <pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
        </encoder>
    </appender>
    <root level="DEBUG">
        <appender-ref ref="FILE" />
    </root>
</configuration>

多次运行MyApp3,logback配置参数传入MyApp3-RollingFixedWindow.xml,即可发现在当前应用的log目录下生成了如:testFile.1.log.zip、testFile.2.log.zip、testFile.3.log.zip,testFile.log文件。备份的压缩文件中的日志文件的文件名默认后缀跟了归档日期。 (com/ttpod/file/MyApp3-RollingTimeBased.xml)

<configuration>
    <!-- 指定属性文件路径 -->
    <property file="src/com/ttpod/file/variables.properties" />
    <!-- 基于时间的滚动策略 -->
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${USER_HOME}/logFile.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 每天滚动
            <fileNamePattern>logFile.%d{yyyy-MM-dd}.log</fileNamePattern>
            -->
            <!-- 每分钟滚动 -->
            <fileNamePattern>${USER_HOME}/logFile.%d{yyyy-MM-dd_HH-mm}.log</fileNamePattern>
            <!-- 限制文件最大保存时间为30天-->
            <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>
        <!--
        运行:
        java chapters.appenders.ConfigurationTester
        src/com/ttpod/chapters/appenders/conf/logback-RollingTimeBased.xml
        -->

多次运行MyApp3,logback配置参数传入MyApp3-RollingTimeBased.xml,若设置一个执行计谋,程序不停止,则每分钟可触发一次日志备份,即可发现在当前应用的log目录下生成了按配置的格式的文件,如:(com/ttpod/file/MyApp3-sizeAndTime.xml)

<configuration>
    <!-- 基于时间与大小的归档 -->
    <statusListener class="ch.qos.logback.core.status.OnConsoleStatusListener" />
    <!-- 指定属性文件路径 -->
    <property file="src/com/ttpod/file/variables.properties" />
    <!-- 基于时间与大小的归档 -->
    <appender name="ROLLING" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${USER_HOME}/mylog.txt</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 每天滚动
            <fileNamePattern>${USER_HOME}/mylog-%d{yyyy-MM-dd}.%i.txt</fileNamePattern>
            -->
            <minIndex>1</minIndex>
            <maxIndex>3</maxIndex>
            <!-- 每分钟滚动 -->
            <fileNamePattern>${USER_HOME}/mylog-%d{yyyy-MM-dd_HH-mm}.%i.txt</fileNamePattern>
            <!-- 限制文件最大保存时间为30天-->
            <maxHistory>30</maxHistory>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <!-- 当文件大小超过5kB时触发滚动,这里设置5kb只是便于测试 -->
                <maxFileSize>5kB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
        </rollingPolicy>
        <encoder>
            <pattern>%msg%n</pattern>
        </encoder>
    </appender>
    <root level="debug">
        <appender-ref ref="ROLLING" />
    </root>
</configuration>

运行时,logback配置参数传入src/com/ttpod/file/MyApp3-sizeAndTime.xml即可。当日志文件超过5kB时,或到另一天时,程序又被执行了,则会触发滚动,按照此前配置规则备原来的文件。

以网页形式输出日志文件

HTMLLayout 与 logback-classic 里的 HTMLLayout 相似。 默认情况下,PatternLayout 创建包含下列数据的表格:远程IP;日期;请求的URL;状态吗;Content Length 。

以下有个示例,演示以HTMLLayout格式化后,以htm文件输出日志。如下:示例4:(com/ttpod/html/HTMLTest1.java)

package com.ttpod.html;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.joran.JoranConfigurator;
import ch.qos.logback.core.joran.spi.JoranException;
import ch.qos.logback.core.util.StatusPrinter;
public class HtmlTest1 {
    public static void main(String[] args) throws InterruptedException {
        Logger logger = LoggerFactory.getLogger(HtmlTest1.class);
        LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
        try {
            JoranConfigurator configurator = new JoranConfigurator();
            configurator.setContext(lc);
            lc.reset();
            configurator.doConfigure(args[0]);
//configurator.doConfigure("./src/com/ttpod/html/htmlLayoutConfig1.xml");
        } catch (JoranException je) {
            je.printStackTrace();    //固定部分
        }
        StatusPrinter.printInCaseOfErrorsOrWarnings(lc);
        for (int i = 0; i < 6; i++) {
            if (i % 5 == 0) {
                logger.warn("a warning message " + i);    //声明一条warn级别的日志消息
                //logger.info("a warning message " + i);
            } else {
                logger.debug("hello world number" + i);
            }
        }
        logger.error("Finish off with fireworks", new Exception("Just testing"));
    }
}

用以下配置文件格式化输出到properties文件指向的目的地。(com/ttpod/html/htmlLayoutConfig1.xml)

<configuration>
    <!-- 指定属性文件路径 -->
    <property file="src/com/ttpod/html/variables.properties" />
    <!-- 指定日志输出到文件-->
    <appender name="FILE" class="ch.qos.logback.core.FileAppender">
        <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
            <layout class="ch.qos.logback.classic.html.HTMLLayout">
                <pattern>%relative%thread%mdc%level%logger%msg</pattern>
            </layout>
        </encoder>
        <file>${destination}</file>
    </appender>
    <root level="DEBUG">
        <appender-ref ref="FILE" />
    </root>
</configuration>
        <!-- 以以下方式运行
        java com.ttpod.html.HtmlTest1 src/com/ttpod/html/htmlLayoutConfig1.xml
        -->

属性文件内容如下:(com/ttpod/html/ variables.properties)

#指定USER_HOME目录
USER_HOME=./log
#指定日志文件名
fileName=htmlTest.htm
#生成日志文件的目的地
destination=${USER_HOME}/${fileName}

运行html/HTMLTest1,并传入配置参数:src/com/ttpod/html/htmlLayoutConfig1.xml,可以发现在在当前应用的/log目录下生成一个htmlTest.htm日志文件。

以邮件形式输出日志
以邮件形式输出日志,依赖于SMTPAppender ,SMTPAppender在固定大小的缓冲里积累记录时间,当用户指定的事件发生后,就通过email发出这些事件。默认情况下,email发送是由级别为 ERROR 或更高级别的记录事件触发的。

下面的演示程序 chapters.appenders.mail.EMail,生成大量记录消息,然后生成一个错误消息。该程序有两个参数,第一个是需要生成的记录消息的数量,第二个是 logback 配置文件。该程序生成的最后一条记录事件,即 ERROR 级别的事件,将触发 email的发送。

示例5 (com/ttpod/mail/Email.java)

package com.ttpod.mail;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.joran.JoranConfigurator;
import ch.qos.logback.core.util.StatusPrinter;
public class EMail {
    static public void main(String[] args) throws Exception {
        if (args.length != 2) {
            usage("Wrong number of arguments.");
        }
        int runLength = Integer.parseInt(args[0]);
        String configFile = args[1];
        //int runLength = Integer.parseInt("300");
        //String configFile="src/com/ttpod/mail/gmailSSL.xml";
        //String configFile = "src/com/ttpod/mail/gmailSTARTTLS.xml";
        //自定义配置文件,得到日志固定格式
        LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
        JoranConfigurator configurator = new JoranConfigurator();
        lc.reset();
        configurator.setContext(lc);
        configurator.doConfigure(configFile);
        Logger logger = LoggerFactory.getLogger(EMail.class);
        for (int i = 1; i <= runLength; i++) {
            if ((i % 10) < 9) {
                logger.debug("This is a debug message. Message number: " + i);
            } else {
                logger.warn("This is a warning message. Message number: " + i);
            }
        }
        //定义一条error级别的日志输出
        logger.error("At last an error.", new Exception("Just testing"));
        //打印logger内部状态
        StatusPrinter.printInCaseOfErrorsOrWarnings(lc);
    }
    static void usage(String msg) {    //当参数传入错误时,提供的处理惯例
        System.err.println(msg);
        System.err.println("Usage: java " + EMail.class.getName() +
                " runLength configFile\n" +
                " runLength (integer) the number of logs to generate\n" +
                " configFile a logback configuration file in XML format." +
                " XML files must have a '.xml' extension.");
        System.exit(1);    //退出程序
    }
}

如下配置文件从属性文件中读取发送邮件定义的属性,配置由邮件输出日志,如下:

<configuration>
    <!-- 指定属性文件的位置 -->
    <property file="src/com/ttpod/mail/gmailSSL.properties" />
    <!-- 目的指定向email的appender -->
    <appender name="EMAIL" class="ch.qos.logback.classic.net.SMTPAppender">
        <SMTPHost>${SMTPHOST}</SMTPHost><!-- 邮件服务器地址 -->
        <SMTPPort>${SMTPPORT}</SMTPPort><!--SMTPPORT端口-->
        <SSL>true</SSL>
        <Username>${EMAIL_USERNAME}</Username><!-- 用户名 -->
        <Password>${EMAIL_PASSWORD}</Password><!-- 密码 -->
        <To>${EMAIL-DESTINATION}</To><!-- 目标接收人 -->
        <To>${ANOTHER_EMAIL_DESTINATION}</To> <!-- additional destinations are possible -->
        <From>${EMAIL_USERNAME}</From><!-- 发件人 -->
        <Subject>TESTING: %logger{20} - %m</Subject><!-- 主题 -->
        <encoder><!-- 一般采用这种方式格式化输出 -->
            <layout class="ch.qos.logback.classic.html.HTMLLayout">
                <!-- 采用什么渲染方式,这采取的是HTML方式 -->
                <Pattern>%date %-5level %logger - %message%n</Pattern>
            </layout>
        </encoder>
        <!--
        <layout class="ch.qos.logback.classic.PatternLayout">
        <Pattern>%date %-5level %logger - %message%n</Pattern>
        </layout>
        -->
    </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="FILE" class="ch.qos.logback.core.FileAppender">
        <file>./log/mailtest.log</file>
        <encoder>
            <!-- %msg表示日志信息,%n表示换行 -->
            <pattern>%msg%n</pattern>
        </encoder>
    </appender>
    <root level="debug">
        <appender-ref ref="EMAIL" />
        <appender-ref ref="STDOUT" />
        <appender-ref ref="FILE"></appender-ref>
    </root>
</configuration>

属性文件如下设置,以供自定的logback配置文件读取。

SMTPHOST=smtp.gmail.com
SMTPPORT=465
EMAIL_USERNAME = someone123@gmail.com
EMAIL_PASSWORD = password123
EMAIL-DESTINATION = someone456@ttpod.com
ANOTHER_EMAIL_DESTINATION = some456@126.com

传入配置文件参数,运行,当出现也error级别以及以上级别的日志时,就会触发日志发送到邮件,但目前此测试例子,可能由于本地tomcat服务器缓存邮件,以致邮件无法发送到外网服务器,所以在这里没给出具体发送成功的结果。但可以通过它生成对应的HTML文件,可以看到邮件内容。

如果未指定选项”Evaluator”,则 SMTPAppender 被默认分配一个 OnErrorEveluator(ch.qos.logback.classic.boolex.OnErrorEvaluator)实例,当遇到级别为 ERROR 或更高级别的事件后,触发 email 传输。此处最后一条消息是一个error级别的记录,触发了邮件的发送。

另外,还可以将日志写入数据库要把记录事件写入数据库,依赖于DBAppender ,DBAppender把记录事件写入数据库的三张表。三张表分别是 logging_event、logging_event_property 和 logging_event_exception。在使用 DBAppender 之前,这三张表必须已经被创建。关于将日志记录写入到数据库中,更多可参考logback手册中的DBAppender。

编写此文档参考了的以下的网站、博客。相关的chm api和参考文档上传在服务器\192.168.1.201上。

Logback官方网站:http://logback.qos.ch/ Slf4j官方网站:http://www.slf4j.org/

版权所有,转载请注明出处 luowei.github.io.