LogBack入门实践

一、简介

LogBack是一个日志框架,它是Log4j作者Ceki的又一个日志组件。

LogBack,Slf4j,Log4j之间的关系

    slf4j是The Simple Logging Facade for Java的简称,是一个简单日志门面抽象框架,它本身只提供了日志Facade API和一个简单的日志类实现,一般常配合Log4j,LogBack,java.util.logging使用。Slf4j作为应用层的Log接入时,程序可以根据实际应用场景动态调整底层的日志实现框架(Log4j/LogBack/JdkLog...);

    LogBack和Log4j都是开源日记工具库,LogBack是Log4j的改良版本,比Log4j拥有更多的特性,同时也带来很大性能提升。

    LogBack官方建议配合Slf4j使用,这样可以灵活地替换底层日志框架。

LogBack的结构

LogBack分为3个组件,logback-core, logback-classic 和 logback-access。

其中logback-core提供了LogBack的核心功能,是另外两个组件的基础。

logback-classic则实现了Slf4j的API,所以当想配合Slf4j使用时,则需要引入这个包。

logback-access是为了集成Servlet环境而准备的,可提供HTTP-access的日志接口。

Log的行为级别

OFF、

FATAL、

ERROR、

WARN、

INFO、

DEBUG、

ALL

从下向上,当选择了其中一个级别,则该级别向下的行为是不会被打印出来。

举个例子,当选择了INFO级别,则INFO以下的行为则不会被打印出来。

二、slf4j与logback结合使用原理

我们从java代码最简单的获取logger开始

Logger logger = LoggerFactory.getLogger(xxx.class.getName());

LoggerFactory是slf4j的日志工厂,获取logger方法就来自这里。

1public static Logger getLogger(String name) { 2    ILoggerFactory iLoggerFactory = getILoggerFactory(); 3    return iLoggerFactory.getLogger(name); 4}

这个方法里面有分为两个过程。

第一个过程是获取ILoggerFactory,就是真正的日志工厂。

第二个过程就是从真正的日志工厂中获取logger。

第一个过程又分为三个部分。

第一个部分加载org/slf4j/impl/StaticLoggerBinder.class文件

paths = ClassLoader.getSystemResources(STATIC_LOGGER_BINDER_PATH);//STATIC_LOGGER_BINDER_PATH = "org/slf4j/impl/StaticLoggerBinder.class"

第二部分随机选取一个StaticLoggerBinder.class来创建一个单例

当项目中存在多个StaticLoggerBinder.class文件时,运行项目会出现以下日志:

1SLF4J: Class path contains multiple SLF4J bindings. 2SLF4J: Found binding in [jar:file:/C:/Users/zhangheng5/.m2/repository/ch/qos/logback/logback-classic/1.1.3/logback-classic-1.1.3.jar!/org/slf4j/impl/StaticLoggerBinder.class] 3SLF4J: Found binding in [jar:file:/C:/Users/zhangheng5/.m2/repository/org/slf4j/slf4j-log4j12/1.7.12/slf4j-log4j12-1.7.12.jar!/org/slf4j/impl/StaticLoggerBinder.class] 4SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation. 5SLF4J: Actual binding is of type [ch.qos.logback.classic.util.ContextSelectorStaticBinder]

最后会随机选择一个StaticLoggerBinder.class来创建一个单例

StaticLoggerBinder.getSingleton()

第三部分返回一个ILoggerFactory实例

StaticLoggerBinder.getSingleton().getLoggerFactory();

所以slf4j与其他实际的日志框架的集成jar包中,都会含有这样的一个org/slf4j/impl/StaticLoggerBinder.class类文件,并且提供一个ILoggerFactory的实现。

第二个过程就是每一个和slf4j集成的日志框架中实现ILoggerFactory方法getLogger()的实例所做的事了。

三、slf4j与logback结合使用实践

第一步引入jar包

slf4j-api

logback-core

logback-classic(含有对slf4j的集成包)

1<!-- slf4j-api --> 2<dependency> 3    <groupId>org.slf4j</groupId> 4    <artifactId>slf4j-api</artifactId> 5    <version>1.7.12</version> 6</dependency> 7<!-- logback --> 8<dependency>  9    <groupId>ch.qos.logback</groupId>  10    <artifactId>logback-core</artifactId>  11    <version>1.1.3</version>  12</dependency>  13<dependency>  14    <groupId>ch.qos.logback</groupId>  15    <artifactId>logback-classic</artifactId>  16    <version>1.1.3</version>  17</dependency>

第二步编写简单的logback配置文件

1<?xml version="1.0" encoding="UTF-8"?> 2<configuration> 3  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> 4    <encoder> 5      <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> 6    </encoder> 7  </appender> 8  <root level="DEBUG">           9    <appender-ref ref="STDOUT" /> 10  </root>   11</configuration>

文件位置位于src/main/resources下,名字默认为logback.xml

当然,logback也支持groovy格式的配置文件,如果你会用那更好。

接下来,自己随便写一个类调用一下logger

1package log.test; 2import org.slf4j.Logger; 3import org.slf4j.LoggerFactory; 4/** 5 * @author jiangmitiao 6 * @date 2016/3/24 7 * @description TODO 8 */ 9public class Foo { 10    public static void doIt(){ 11        Logger logger = LoggerFactory.getLogger(Foo.class.getName()); 12        logger.debug("let`s do it"); 13    } 14} 15 16package log.test; 17import org.slf4j.Logger; 18import org.slf4j.LoggerFactory; 19/** 20 * @author jiangmitiao 21 * @date 2016/3/24 22 * @description TODO 23 */ 24public class MyApp1 { 25    public static void main(String[] args) { 26        Logger logger = LoggerFactory.getLogger(MyApp1.class.getName()); 27        logger.info("before"); 28        Foo.doIt(); 29        logger.info("after"); 30        try { 31            int i = 10 / 0; 32        } catch (Exception e) { 33            logger.error("errorTest",e); 34        } 35    } 36}

最后的结果是:

116:22:13.459 [main] INFO  log.test.MyApp1 - before 216:22:13.463 [main] DEBUG log.test.Foo - let`s do it 316:22:13.463 [main] INFO  log.test.MyApp1 - after 416:22:13.466 [main] ERROR log.test.MyApp1 - errorTest 5java.lang.ArithmeticException: / by zero 6at log.test.MyApp1.main(MyApp1.java:19) ~[classes/:na] 7at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.6.0_25] 8at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) ~[na:1.6.0_25] 9at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) ~[na:1.6.0_25] 10at java.lang.reflect.Method.invoke(Method.java:597) ~[na:1.6.0_25] 11at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140) [idea_rt.jar:na]

配置规则简述

上边这么简单的配置当然是没有用的,下面这个就能够说明logback配置文件的编写规则了。

1<!-- scan的意思是是否扫描  seconds是说多长时间扫描一次 --> 2<configuration scan="true" scanPeriod="30 seconds" debug="false" packagingData="true"> 3    <!-- 项目名称 --> 4    <contextName>myApp1 contextName</contextName> 5    <!-- 属性 --> 6    <property name="USER_HOME" value="./log"/> 7    <!-- Insert the current time formatted as "yyyyMMdd'T'HHmmss" under 8       the key "bySecond" into the logger context. This value will be 9       available to all subsequent configuration elements. --> 10    <timestamp key="bySecond" datePattern="yyyyMMdd" timeReference="contextBirth"/> 11    <!-- appender很重要,一个配置文件会有多个appender --> 12    <!-- ConsoleApperder意思是从console中打印出来 --> 13    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> 14        <!-- 过滤器,一个appender可以有多个 --> 15        <!-- 阈值过滤,就是log行为级别过滤,debug及debug以上的信息会被打印出来 --> 16        <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> 17            <level>debug</level> 18        </filter> 19        <!-- encoders are assigned the type 20             ch.qos.logback.classic.encoder.PatternLayoutEncoder by default --> 21        <!-- encoder编码规则 --> 22        <encoder> 23            <!--<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>--> 24            <!--<pattern>%%contextName %msg%n</pattern>--> 25            <!-- pattern模式 %d时间 %thread 线程名 %level行为级别 %logger logger名称 %method 方法名称 %message 调用方法的入参消息 --> 26            <pattern>%-4d [%thread] %highlight%-5level %cyan%logger.%-10method - %message%n</pattern> 27        </encoder> 28    </appender> 29    <!-- FileAppender 输出到文件 --> 30    <appender name="FILE" class="ch.qos.logback.core.FileAppender"> 31        <!-- 文件存放位置 %{xxx} 就是之前定义的属性xxx --> 32        <file>${USER_HOME}/myApp1log-${bySecond}.log</file> 33        <encoder> 34            <!-- %date和%d是一个意思 %file是所在文件 %line是所在行 --> 35            <pattern>%date %level [%thread] %logger{30} [%file:%line] %msg%n</pattern> 36        </encoder> 37    </appender> 38    <!-- 输出到HTML格式的文件 --> 39    <appender name="HTMLFILE" class="ch.qos.logback.core.FileAppender"> 40        <!-- 过滤器,这个过滤器是行为过滤器,直接过滤掉了除debug外所有的行为信息 --> 41        <filter class="ch.qos.logback.classic.filter.LevelFilter"> 42            <level>debug</level> 43            <onMatch>ACCEPT</onMatch> 44            <onMismatch>DENY</onMismatch> 45        </filter> 46        <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder"> 47            <!-- HTML输出格式 可以和上边差不多 --> 48            <layout class="ch.qos.logback.classic.html.HTMLLayout"> 49                <pattern>%relative%thread%mdc%level%logger%msg</pattern> 50            </layout> 51        </encoder> 52        <file>${USER_HOME}/test.html</file> 53    </appender> 54    <!-- 滚动日志文件,这个比较常用 --> 55    <appender name="ROLLINGFILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> 56        <!-- 当project等于true的时候file就不会起效果--> 57        <prudent>true</prudent> 58        <!--<file>${USER_HOME}/logFile.log</file>--> 59        <!-- 按天新建log日志 --> 60        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> 61            <!-- daily rollover --> 62            <fileNamePattern>${USER_HOME}/logFile.%d{yyyy-MM-dd}_%i.log</fileNamePattern> 63            <!-- 保留30天的历史日志 --> 64            <maxHistory>30</maxHistory> 65            <!-- 基于大小和时间,这个可以有,可以没有 --> 66            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> 67                <!-- or whenever the file size reaches 100MB --> 68                <!-- 当一个日志大小大于10KB,则换一个新的日志。日志名的%i从0开始,自动递增 --> 69                <maxFileSize>10KB</maxFileSize> 70            </timeBasedFileNamingAndTriggeringPolicy> 71        </rollingPolicy> 72        <encoder> 73        <!-- %ex就是指抛出的异常,full是显示全部,如果在{}中写入数字,则表示展示多少行 --> 74            <pattern>%-4date [%thread] %-5level %logger{35} - %msg%n%ex{full, DISPLAY_EX_EVAL}</pattern> 75        </encoder> 76    </appender> 77    <!-- 重点来了,上边都是appender输出源。这里开始就是looger了 --> 78    <!-- name意思是这个logger管的哪一片,像下面这个管的就是log/test包下的所有文件 level是只展示什么行为信息级别以上的,类似阈值过滤器 additivity表示是否再抛出事件,就是说如果有一个logger的name是log,如果这个属性是true,另一个logger就会在这个logger处理完后接着继续处理 --> 79    <logger name="log.test" level="INFO" additivity="false"> 80        <!-- 连接输出源,也就是上边那几个输出源,你可以随便选几个appender --> 81        <appender-ref ref="STDOUT"/> 82        <appender-ref ref="ROLLINGFILE"/> 83        <appender-ref ref="HTMLFILE"/> 84    </logger> 85    <!-- 这个logger详细到了类 --> 86    <logger name="log.test.Foo" level="debug" additivity="false"> 87        <appender-ref ref="STDOUT"/> 88        <appender-ref ref="ROLLINGFILE"/> 89        <appender-ref ref="HTMLFILE"/> 90    </logger> 91    <!-- Strictly speaking, the level attribute is not necessary since --> 92    <!-- the level of the root level is set to DEBUG by default.       --> 93    <!-- 这就是上边logger没有管到的情况下 root默认接管所有logger --> 94    <root level="debug"> 95        <appender-ref ref="STDOUT"/> 96    </root> 97</configuration>

四、过滤器的一些疑问

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

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

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

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

写一个简单的过滤器大家就明白了。

1package log.test; 2import ch.qos.logback.classic.spi.ILoggingEvent; 3import ch.qos.logback.core.filter.Filter; 4import ch.qos.logback.core.spi.FilterReply; 5public class SampleFilter extends Filter<ILoggingEvent> { 6  @Override 7  public FilterReply decide(ILoggingEvent event) {     8    if (event.getMessage().contains("let")) { 9      return FilterReply.ACCEPT; 10    } else { 11      return FilterReply.DENY; 12    } 13  } 14}

可以选择任意几个输出源加入这个filter

<filter class="log.test.SampleFilter" />

最后的结果是,加入该filter的输出源只能输出Foo.doIt()中的日志了。

五、总结

logback配置比较简单,官网手册也是比较容易看懂的。除上边几种输出源之外,logback还支持输出到远程套接字服务器、 MySQL、 PostreSQL、Oracle和其他数据库、 JMS和远程UNIX Syslog守护进程等等。

第一次学习log方面的知识,如有错误,请不吝赐教。

相关资源:

http://logback.qos.ch/manual/index.html

http://www.cnblogs.com/mailingfeng/p/3499436.html

http://yuri-liuyu.iteye.com/blog/954038

http://www.cnblogs.com/yongze103/archive/2012/05/05/2484753.html

http://blog.csdn.net/haidage/article/details/6794509

更多文章:http://blog.gavinzh.com

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

springmvc+logback项目日志配置

  最近在做项目的时候用到logback作为项目日志,而抛弃了log4j。具体为什么用logback,我总结了以下几点:  1.log4j和logback的创作者是同一个人,logback是log4j的升级版,是对log4j核心的一个封装。  2.性能提升,在某些特定场景上执行速度提升10倍以上,同时初始化内存更小  3.扩展文档,丰富的并且详细

Spring Boot(十)Logback和Log4j2集成与日志发展史

一、简介Java知名的日志有很多,比如:JUL、Log4j、JCL、SLF4J、Logback、Log4j2,那么这些日志框架之间有着怎样的关系?诞生的原因又是解决什么问题?下面一起来看。<!more1.1JULJava有自己的日志框架JUL(JavaUtilLogging)在java.util.lo

Java日志体系(八)最佳实践

java常用日志框架关系Log4j2与Log4j1发生了很大的变化,Log4j2不兼容Log4j1。Logback必须配合Slf4j使用。由于Logback和Slf4j是同一个作者,其兼容性不言而喻。比较常用的组合使用方式是Slf4j与Logback组合使用,Commons