Logback学习笔记1

Logback介绍

Logback 分为三个模块:CoreClassic AccessCore模块是其他两个模块的基础。 Classic模块扩展了core模块。 Classic模块相当于log4j的显著改进版。Logback-classic 直接实现了 SLF4J API

要引入logback,由于Logback-classic依赖slf4j-api.jarlogback-core.jar,所以要把slf4j-api.jarlogback-core.jarlogback-classic.jar添加到要引入Logbac日志管理的项目的class path.

 

Logback的配置

LoggerAppender Layout

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

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

 

Logger context

各个logger 都被关联到一个 LoggerContextLoggerContext负责制造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 可以被分配级别。级别包括:TRACEDEBUGINFOWARN 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

 

LoggerAppenderslayouts的关系

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

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

Logger 的叠加性默认为 true。如果希望定制输出格式。这时为 appender 关联一个 layout 即可。Layout 负责根据用户意愿对记录请求进行格式化,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 进行定义。尽管如此,可以这样描述配置文件的基本结构:以<configuration>开头,后面有零个或多个<appender>元素,有零个或多个<logger>元素,有最多一个<root>元素。

 

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

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

package com.ttpod.chapters.configuration;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

publicclass MyApp1 {

finalstatic Logger logger = LoggerFactory.getLogger(MyApp1.class);

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

publicclass Foo {

staticfinal Logger logger = LoggerFactory.getLogger(Foo.class);

publicvoid doIt() {

logger.debug("Did it again!");    //定义一个debug级别的日志输出

}

    …………

}

 

自动打印警告和错误消息

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

finalstatic Logger logger = LoggerFactory.getLogger(MyApp2.class);

publicstaticvoid main(String[] args) {

// 在当前环境中假设 SLF4J 已经被绑定到logback

LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();

// 打印logback的内部状态

StatusPrinter.print(lc);

…………

}

}

对应的配置文件:

<?xmlversion="1.0"encoding="UTF-8"?>

<configuration>

<!--定义一个名为STDOUTappender,并将其关联到ch.qos.logback.core.ConsoleAppender-->

<appendername="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>

<rootlevel="debug">    <!-- root logger,定义级别为debug-->

<appender-refref="STDOUT"/>    <!--将名为STDOUTappender添加到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 属性的值大小写无关,其值为下面其中一个字符串:TRACEDEBUGINFOWARNERRORALL OFF。注意不能设置为"INHERITED" "NULL" <logger>元素可以包含零个或多个<appender-ref>元素。<logger>元素类似,声明<root>元素后,会先关闭然后移除全部当前 appender,只引用声明了的 appender。如果 root 元素没有引用任何 appender,就会失去所有 appender

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

<?xmlversion="1.0"encoding="UTF-8"?>

<configuration>

<appendername="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 loggerdebug级别 -->

    <loggername="chapters.configuration"level="INFO"/>

    <!-- 严格来说, root logger level属性没有必要设置,因为 -->

    <!-- root logger的级别被默认设置为DEBUG -->

    <rootlevel="DEBUG">

        <!--

         root标签内没有引入chapters.configuration,所有在此包下不会

        显示任何组件的任何 DEBUG 信息

        -->

        <appender-refref="STDOUT"/>    <!-- appender引入到root logger -->

    </root>

</configuration>

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

配置 Appenders

Appender <appender>元素配置,该元素必要属性 name class name 属性指定 appender 的名称,class 属性指定 appender 类的全限定名。 <appender>元素可以包含零个或多个<layout>元素、零个或多个<encoder>元素和零个或多个<filter>元素。除了这三个常用元素之外,还可以包含 appender 类的任意数量的 javabean

属性。下图演示了常用结构,注意对 javabean 属性的支持在图中不可见。

 

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

<configuration>

    <appendername="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>

 

    <appendername="STDOUT"class="ch.qos.logback.core.ConsoleAppender">

<encoder>

<pattern>%msg%n</pattern>

</encoder>

    </appender>

 

    <rootlevel="debug">

        <appender-refref="FILE"/>

        <appender-refref="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 都有自己的 encoderEncoder 通常不能被多个 appender 共享,layout也是。所以,logback 的配置文件里没有共享 encoder layout 的语法。

Appender累积

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

<configuration>

    <appendername="STDOUT"

        class="ch.qos.logback.core.ConsoleAppender">

        <encoder>

            <pattern>

                %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n

            </pattern>

</encoder>

    </appender>

    <loggername="chapters.configuration">

        <appender-refref="STDOUT"/>

    </logger>

    <rootlevel="debug">

        <appender-refref="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>

    …………

    <loggername="com.ttpod.chapters.configuration.Foo"additivity="false">

        <appender-refref="FILE"/>

    </logger>

    <rootlevel="debug">

        <appender-refref="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。下面是配置文件:

<configurationdebug="true">

<appendername="STDOUT"class="ch.qos.logback.core.ConsoleAppender">

<encoderclass="ch.qos.logback.core.encoder.LayoutWrappingEncoder">

     <!—自定义的格式化输出处理类-->

<layoutclass="com.ttpod.chapters.layouts.MySampleLayout"/>

</encoder>

</appender>

<rootlevel="DEBUG">

<appender-refref="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\nlog4j推荐使用这个转换符,而不是\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 依赖JoranJoran logback-core 的一部分,是个配置类库。Logback 的默认配置机制是调用JoranConfiguratorclasspath上的默认配置文件进行处理。不管出于什么理由,如果你想重新实现 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的内部状态

publicclass MyApp1 {

finalstatic Logger logger = LoggerFactory.getLogger(MyApp1.class);    //定义一个全局的记录器,通过LoggerFactory获取

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

publicclass Foo {

staticfinal Logger logger = LoggerFactory.getLogger(Foo.class);

publicvoid doIt() {

logger.debug("test logger in other class!");

}

publicvoid createLoggingRequest() {

     subMethodToCreateRequest();

     }

     //这个方法执行后创建一条异常信息

privatevoid subMethodToCreateRequest() {

logger.error("error-level request", new Exception("test exception"));

}

}

此程序通过参数传配置文件的名字,对程序的日志输出配置,本例如下:

(com/ttpod/file/ MyApp1Config.xml)

<configuration>

<!-- 指定属性文件路径 -->

<propertyfile="src/com/ttpod/file/variables.properties"/>

 

<!-- 指定日志输出到文件-->

<appendername="FILE"class="ch.qos.logback.core.FileAppender">

<file>${destination}</file>

<encoder>

<!-- %msg表示日志信息,%n表示换行 -->

<pattern>%msg%n</pattern>

</encoder>

</appender>

 

<rootlevel="debug">

<appender-refref="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 Agumentssrc/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;

publicclass MyApp2 {

    static Timer t;

    publicstaticvoid main(String[] args) {

        // 调用LoggerFactory 类的静态方法getLogger取得一个Logger实例,

        final Logger logOut = LoggerFactory.getLogger("SystemOut"); // 定义一个名为SystemOutlogger

        final Logger logErr = LoggerFactory.getLogger("SystemErr"); // 定义一个名为SystemErrlogger

        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

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

<?xmlversion="1.0"encoding="UTF-8"?>

<!DOCTYPE configuration>

<configuration>

<jmxConfigurator />

<!-- 配置文件路径 -->

<propertyfile="src/com/ttpod/file/variables.properties"/>

<!--logback的版本必须是0.9.21以上才支持-->

<timestampkey="byDay"datePattern="yyyyMMdd"/>

<!-- 控制台输出日志 -->

<appendername="STDOUT"class="ch.qos.logback.core.ConsoleAppender">

<layoutclass="ch.qos.logback.classic.PatternLayout">

<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>

</layout>

</appender>

<!-- 文件输出日志 (文件大小策略进行文件输出,超过指定大小对文件压缩(.zip)备份)-->

<appendername="FILE"class="ch.qos.logback.core.rolling.RollingFileAppender">

    <!-- 文件的路径及文件名 -->

<File>${USER_HOME}/SystemOut.log</File>

<!-- 定义窗口滚动策略 -->

<rollingPolicyclass="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">

    <!-- 每触发一次,自动压缩日志文件,%i1-3之间循环变化 -->

<FileNamePattern>${USER_HOME}/SystemOut_%i.log.zip</FileNamePattern>

<MinIndex>1</MinIndex><!-- %i的最小值为1-->

<MaxIndex>3</MaxIndex><!-- %i的最大值为3-->

</rollingPolicy>

<!-- 触发策略,通常rollingPolicytriggeringPolicy联合使用 -->

<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)备份) -->

<appendername="FILE-ERROR"class="ch.qos.logback.core.rolling.RollingFileAppender">

<filterclass="ch.qos.logback.classic.filter.LevelFilter">

<level>ERROR</level><!-- 指定要对级别为ERROR日志信息过滤 -->

<OnMismatch>DENY</OnMismatch>     <!-- 如果不匹配,则拒绝处理 -->

<OnMatch>ACCEPT</OnMatch>         <!-- 如果匹配,则立即处理 -->

</filter>

<File>${USER_HOME}/SystemErr.log</File><!-- 文件名即路径 -->

<rollingPolicyclass="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">

<FileNamePattern>${USER_HOME}/SystemErr_%i.log.zip</FileNamePattern>

<MinIndex>1</MinIndex>

<MaxIndex>3</MaxIndex>

</rollingPolicy>

<triggeringPolicyclass="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设置日志级别做铺垫 -->

<!-- 分别将STDOUTFILE appender都添加到自定义的logger中,否则将不会输出到appender指定的目的地-->

<loggername="SystemOut"level="INFO">

<appender-refref="STDOUT"/>

<appender-refref="FILE"/>

</logger>

<loggername="SystemErr"level="INFO">

<appender-refref="STDOUT"/>

<appender-refref="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;;

 

publicclass MyApp3 {

publicstaticvoid 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},可以输出MDCtest对应的值

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>

<!-- 指定属性文件路径 -->

<propertyfile="src/com/ttpod/file/variables.properties"/>

<appendername="FILE"class="ch.qos.logback.core.rolling.RollingFileAppender">

<file>${USER_HOME}/testFile.log</file>

<!--滚动策略-->

<rollingPolicyclass="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">

<!—自动压缩备份-->

<fileNamePattern>${USER_HOME}/testFile.%i.log.zip</fileNamePattern>

<minIndex>1</minIndex>

<maxIndex>3</maxIndex><!--%i1-3之间循环变化-->

</rollingPolicy>

<!—触发策略-->

<triggeringPolicyclass="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">

<!--日志文件大小限制在5kB以内,否则就触发滚动-->

<maxFileSize>5kB</maxFileSize>

</triggeringPolicy>

<encoder><!--格式化输出-->

<pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>

</encoder>

</appender>

<rootlevel="DEBUG">

<appender-refref="FILE"/>

</root>

</configuration>

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

 

(com/ttpod/file/MyApp3-RollingTimeBased.xml)

<configuration>

<!-- 指定属性文件路径 -->

<propertyfile="src/com/ttpod/file/variables.properties"/>

 

<!-- 基于时间的滚动策略 -->

<appendername="FILE"class="ch.qos.logback.core.rolling.RollingFileAppender">

<file>${USER_HOME}/logFile.log</file>

<rollingPolicyclass="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>

 

<rootlevel="DEBUG">

<appender-refref="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>

<!-- 基于时间与大小的归档 -->

<statusListenerclass="ch.qos.logback.core.status.OnConsoleStatusListener"/>

 

<!-- 指定属性文件路径 -->

<propertyfile="src/com/ttpod/file/variables.properties"/>

 

<!-- 基于时间与大小的归档 -->

<appendername="ROLLING"class="ch.qos.logback.core.rolling.RollingFileAppender">

<file>${USER_HOME}/mylog.txt</file>

<rollingPolicyclass="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>

<timeBasedFileNamingAndTriggeringPolicyclass="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">

<!-- 当文件大小超过5kB时触发滚动,这里设置5kb只是便于测试 -->

<maxFileSize>5kB</maxFileSize>

</timeBasedFileNamingAndTriggeringPolicy>

</rollingPolicy>

<encoder>

<pattern>%msg%n</pattern>

</encoder>

</appender>

 

<rootlevel="debug">

<appender-refref="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;

 

publicclass HtmlTest1 {

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

<!-- 指定属性文件路径 -->

<propertyfile="src/com/ttpod/html/variables.properties"/>

 

<!-- 指定日志输出到文件-->

<appendername="FILE"class="ch.qos.logback.core.FileAppender">

<encoderclass="ch.qos.logback.core.encoder.LayoutWrappingEncoder">

<layoutclass="ch.qos.logback.classic.html.HTMLLayout">

<pattern>%relative%thread%mdc%level%logger%msg</pattern>

</layout>

</encoder>

<file>${destination}</file>

</appender>

 

<rootlevel="DEBUG">

<appender-refref="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;

publicclass EMail {

staticpublicvoid 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);

}

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

<!-- 指定属性文件的位置 -->

<propertyfile="src/com/ttpod/mail/gmailSSL.properties"/>

 

<!-- 目的指定向emailappender -->

<appendername="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><!-- 一般采用这种方式格式化输出 -->

    <layoutclass="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>

 

<!-- 输出到控制台,以便将日志也打印到控制台-->

<appendername="STDOUT"class="ch.qos.logback.core.ConsoleAppender">

    <encoder>

<pattern>

%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n

     </pattern>

</encoder>

</appender>

 

<!-- 输出到文件,将日志记录到本地文件-->

<appendername="FILE"class="ch.qos.logback.core.FileAppender">

<file>./log/mailtest.log</file>

<encoder>

<!-- %msg表示日志信息,%n表示换行 -->

<pattern>%msg%n</pattern>

</encoder>

</appender>

 

<rootlevel="debug">

<appender-refref="EMAIL"/>

<appender-refref="STDOUT"/>

<appender-refref="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 被默认分配一个 OnErrorEveluatorch.qos.logback.classic.boolex.OnErrorEvaluator)实例,当遇到级别为 ERROR 或更高级别

的事件后,触发 email 传输。此处最后一条消息是一个error级别的记录,触发了邮件的发送。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值