LogBack 入门实践

一、简介

前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到教程。

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

LogBack,Slf4j,Log4j之间的关系

slf4j是The Simple Logging Facade for Java的简称,是一个简单日志门面抽象框架,它本身只提供了日志Facade API和一个简单的日志类实现,一般常配合Log4jLogBackjava.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方法就来自这里。

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

这个方法里面有分为两个过程。第一个过程是获取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文件时,运行项目会出现以下日志:

SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/C:/Users/jiangmitiao/.m2/repository/ch/qos/logback/logback-classic/1.1.3/logback-classic-1.1.3.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/C:/Users/jiangmitiao/.m2/repository/org/slf4j/slf4j-log4j12/1.7.12/slf4j-log4j12-1.7.12.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: 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的集成包)

<!-- slf4j-api -->
<dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>1.7.12</version>
</dependency>
<!-- logback -->
<dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> <version>1.1.3</version> 
</dependency> 
<dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.1.3</version> 
</dependency>

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

<?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><root level="DEBUG">          <appender-ref ref="STDOUT" /></root>  
</configuration>

文件位置位于src/main/resources下,名字默认为logback.xml
当然,logback也支持groovy格式的配置文件,如果你会用那更好。
接下来,自己随便写一个类调用一下logger

package log.test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/*** @author jiangmitiao* @date 2016/3/24* @description TODO*/
public class Foo {public static void doIt(){Logger logger = LoggerFactory.getLogger(Foo.class.getName());logger.debug("let`s do it");}
}package log.test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/*** @author jiangmitiao* @date 2016/3/24* @description TODO*/
public class MyApp1 {public static void main(String[] args) {Logger logger = LoggerFactory.getLogger(MyApp1.class.getName());logger.info("before");Foo.doIt();logger.info("after");try {int i = 10 / 0;} catch (Exception e) {logger.error("errorTest",e);}}
}

最后的结果是:

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

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

<!-- scan 是否定期扫描xml文件, scanPeriod是说扫描周期是30秒-->
<configuration scan="true" scanPeriod="30 seconds" debug="false" packagingData="true"><!-- 项目名称 --><contextName>myApp1 contextName</contextName><!-- 属性 --><property name="USER_HOME" value="./log"/><!-- Insert the current time formatted as "yyyyMMdd'T'HHmmss" underthe key "bySecond" into the logger context. This value will beavailable to all subsequent configuration elements. --><timestamp key="bySecond" datePattern="yyyyMMdd" timeReference="contextBirth"/><!-- appender很重要,一个配置文件会有多个appender --><!-- ConsoleApperder意思是从console中打印出来 --><appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"><!-- 过滤器,一个appender可以有多个 --><!-- 阈值过滤,就是log行为级别过滤,debug及debug以上的信息会被打印出来 --><filter class="ch.qos.logback.classic.filter.ThresholdFilter"><level>debug</level></filter><!-- encoders are assigned the typech.qos.logback.classic.encoder.PatternLayoutEncoder by default --><!-- encoder编码规则 --><encoder><!--<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>--><!--<pattern>%d %contextName %msg%n</pattern>--><!-- pattern模式 %d时间 %thread 线程名 %level行为级别 %logger logger名称 %method 方法名称 %message 调用方法的入参消息 --><pattern>%-4d [%thread] %highlight%-5level %cyan%logger.%-10method - %message%n</pattern></encoder></appender><!-- FileAppender 输出到文件 --><appender name="FILE" class="ch.qos.logback.core.FileAppender"><!-- 文件存放位置 %{xxx} 就是之前定义的属性xxx --><file>${USER_HOME}/myApp1log-${bySecond}.log</file><encoder><!-- %date和%d是一个意思 %file是所在文件 %line是所在行 --><pattern>%date %level [%thread] %logger{30} [%file:%line] %msg%n</pattern></encoder></appender><!-- 输出到HTML格式的文件 --><appender name="HTMLFILE" class="ch.qos.logback.core.FileAppender"><!-- 过滤器,这个过滤器是行为过滤器,直接过滤掉了除debug外所有的行为信息 --><filter class="ch.qos.logback.classic.filter.LevelFilter"><level>debug</level><onMatch>ACCEPT</onMatch><onMismatch>DENY</onMismatch></filter><encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder"><!-- HTML输出格式 可以和上边差不多 --><layout class="ch.qos.logback.classic.html.HTMLLayout"><pattern>%relative%thread%mdc%level%logger%msg</pattern></layout></encoder><file>${USER_HOME}/test.html</file></appender><!-- 滚动日志文件,这个比较常用 --><appender name="ROLLINGFILE" class="ch.qos.logback.core.rolling.RollingFileAppender"><!-- 当project等于true的时候file就不会起效果--><prudent>true</prudent><!--<file>${USER_HOME}/logFile.log</file>--><!-- 按天新建log日志 --><rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><!-- daily rollover --><fileNamePattern>${USER_HOME}/logFile.%d{yyyy-MM-dd}_%i.log</fileNamePattern><!-- 保留30天的历史日志 --><maxHistory>30</maxHistory><!-- 基于大小和时间,这个可以有,可以没有 --><timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"><!-- or whenever the file size reaches 100MB --><!-- 当一个日志大小大于10KB,则换一个新的日志。日志名的%i从0开始,自动递增 --><maxFileSize>10KB</maxFileSize></timeBasedFileNamingAndTriggeringPolicy></rollingPolicy><encoder><!-- %ex就是指抛出的异常,full是显示全部,如果在{}中写入数字,则表示展示多少行 --><pattern>%-4date [%thread] %-5level %logger{35} - %msg%n%ex{full, DISPLAY_EX_EVAL}</pattern></encoder></appender><!-- 重点来了,上边都是appender输出源。这里开始就是looger了 --><!-- name意思是这个logger管的哪一片,像下面这个管的就是log/test包下的所有文件 level是只展示什么行为信息级别以上的,类似阈值过滤器 additivity表示是否再抛出事件,就是说如果有一个logger的name是log,如果这个属性是true,另一个logger就会在这个logger处理完后接着继续处理 --><logger name="log.test" level="INFO" additivity="false"><!-- 连接输出源,也就是上边那几个输出源 ,你可以随便选几个appender--><appender-ref ref="STDOUT"/><appender-ref ref="ROLLINGFILE"/><appender-ref ref="HTMLFILE"/></logger><!-- 这个logger详细到了类 --><logger name="log.test.Foo" level="debug" additivity="false"><appender-ref ref="STDOUT"/><appender-ref ref="ROLLINGFILE"/><appender-ref ref="HTMLFILE"/></logger><!-- Strictly speaking, the level attribute is not necessary since --><!-- the level of the root level is set to DEBUG by default.       --><!-- 这就是上边logger没有管到的情况下 root默认接管所有logger --><root level="debug"><appender-ref ref="STDOUT"/></root>
</configuration>

四、过滤器的一些疑问

Logback的过滤器基于三值逻辑,允许把它们组装或成链,从而组成任意的复合过滤策略。过滤器很大程度上受到Linux的iptables启发。这里的所谓三值逻辑是说,过滤器的返回值只能是ACCEPT、DENY和NEUTRAL的其中一个。
如果返回DENY,那么记录事件立即被抛弃,不再经过剩余过滤器;
如果返回NEUTRAL,那么有序列表里的下一个过滤器会接着处理记录事件;
如果返回ACCEPT,那么记录事件被立即处理,不再经过剩余过滤器。
写一个简单的过滤器大家就明白了。

package log.test;import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.filter.Filter;
import ch.qos.logback.core.spi.FilterReply;public class SampleFilter extends Filter<ILoggingEvent> {@Overridepublic FilterReply decide(ILoggingEvent event) {    if (event.getMessage().contains("let")) {return FilterReply.ACCEPT;} else {return FilterReply.DENY;}}
}

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

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

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

五、总结

LogBack配置比较简单,官网手册也是比较容易看懂的。除上边几种输出源之外,logback还支持输出到远程套接字服务器、 MySQL、 PostreSQL、Oracle和其他数据库、 JMS和远程UNIX Syslog守护进程等等。
第一次学习log方面的知识,如有错误,请不吝赐教。
相关资源:
官方手册
LogBack简易教程
实际的xml配置
Logback浅析
logback 配置详解(一)

转自:https://segmentfault.com/a/1190000004693427

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/448750.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

20个公司绝对不会告诉你的潜规则

1.入职时的工资高低不重要&#xff0c;只要你努力工作你会得到相应待遇的    我估计几乎找过工作的人都听过这句话&#xff0c;当我们确定被聘用跟公司谈工资时&#xff0c;他们都会说“如果以后你业绩突出、努力工作&#xff0c;你的报酬也会相应增加的”&#xff0c;特别是…

java 复制文件

2019独角兽企业重金招聘Python工程师标准>>> public class copyFIle { public static void main(String[] args) throws IOException { File source new File("d:/test/1.xml");File des new File("d:/test/ma.txt");InputStream input null;…

Quartz学习资料地址记录 、Quartz 学习的博客地址记录

Quartz专栏系列 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 1.Quartz学习——Quartz大致介绍&#xff08;一&#xff09; 2.Quartz学习——Quartz简单入门Demo&#xff08;二&#…

民间75个不传之密 ,医院都不知道的秘密

1、头痛&#xff08;各种头痛均可&#xff09;&#xff1a; 生白萝卜汁&#xff0c;每次滴鼻孔两滴(两鼻孔都滴)&#xff0c;一日两次&#xff0c;连用4-5天&#xff0c;可除根。忌吃花椒、胡椒。 2、头晕&#xff08;头昏眼花、晕眩&#xff09;&#xff1a; 鸭蛋一个、赤豆2…

Docker最全教程之MySQL容器化 (二十四)

Docker最全教程之MySQL容器化 &#xff08;二十四&#xff09; 原文:Docker最全教程之MySQL容器化 &#xff08;二十四&#xff09;前言 MySQL是目前最流行的开源的关系型数据库&#xff0c;MySQL的容器化之前有朋友投稿并且写过此块&#xff0c;本篇仅从笔者角…

CODING 受邀参加《腾讯全球数字生态大会》

近日&#xff0c;腾讯全年最重要的一场活动——《腾讯全球数字生态大会》于昆明滇池国际会展中心正式举办。此次全球数字生态大会是腾讯战略升级后&#xff0c;整合互联网数字经济峰会、云未来峰会、腾讯全球合作伙伴三大行业大会&#xff0c;全新升级打造的行业创新大会。大会…

解决 dockerfile 构建镜像报错: [WARNING]: Empty continuation lines will become errors in a future release.

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 1. 只是想自己写个 dockerfile 用 docker 来部署 rocketmq 的服务。 dockerfile 中要运行多行命令 于是我写成 RUN 命令a \&&…

第二章:08运算符[比较运算符]

①比较运算符②实例/* 运算符之三&#xff1a;比较运算符 ! > < > < instanceof 结论&#xff1a; 1.比较运算符的结果是boolean类型 2.区分 和 */ class CompareTest { public static void main(String[] args) { int i 10; int j 20; System.out.pr…

Apache版本兼容性问题

Apache 版本2.2.31 版本对于谷歌浏览器不兼容、IE8版本可以正常使用 当使用了Apache 高版本的话就解决了 出现以下现象 转载于:https://www.cnblogs.com/tzhyy/p/10931084.html

王淮经验谈:我的码农原则

摘要&#xff1a;王淮是Facebook第二位中国籍工程师&#xff0c;也是第一位中国籍研发经理&#xff0c;他一手开创了Facebook的支付安全和客服工具领域。2011年他离开Facebook&#xff0c;回国成为天使投资人。本文是王淮以前写代码和做代码审查时候的一些原则&#xff0c;供大…

centos uwsgi自动调用python2环境,指定uwsgi调用版本

将自己开发好的django项目用uwsgi部署到Linux服务器、当运行uwsgi时出现了uwsgi选择python版本的问题。因为本机器是在原来的机器上安装了python3环境和pip3&#xff0c; 使用命令安装uwsgi: pip3 install uwsgi 一点问题也没有&#xff0c;使用uwsgi部署项目时 uwsgi --http :…

docker build Dockfile ---- RUN 中 cd 切换路径失败 的原因、解决

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 1. 我只是想 直接切换到对应目录下 执行后续命令。 ​​​​​写法如下&#xff1a; FROM openjdk:8-jre-alpineMAINTAINER JiangYuRU…

米尔电子Zynq UltraScale MPSoC核心板资料介绍

米尔Zynq UltraScale MPSoC核心板&#xff08;MYC-CZU3EG&#xff09;是采用Xilinx新一代Zynq处理器。该核心板是业界最小尺寸Zynq UltraScale 核心板&#xff0c;采用16纳米制程&#xff0c;相比Znyq7000系列每瓦性能提升5倍&#xff0c;且单芯片融合4核心Cortex-A53&#xff…

幸福秘诀 男女必须要看哦

女人说&#xff1a;这一辈子最大的成功是什么?我认为是找到一个真正疼自己的老公,有了老公的支持才可以把事业做得有声有色,有一个幸福的家和一个可爱的宝宝。 男人说&#xff1a;我的成功是在我的人生之中&#xff0c;是妻子和我形影相随&#xff0c;朝夕相伴。她是我身边…

解决:If the number of processors is expected to increase from one, then you should configure the numbe

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 1. 按官方说明用 docker 部署 rocketmq ,启动 broker 报错&#xff1a; OpenJDK 64-Bit Server VM warning: If the number of processo…

JAVA-缓存机制

本地缓存 继承AbstractBaseLocalCache&#xff0c;并实现相应的抽象方法&#xff1b;适用于单实例项目或不会经常变化的数据&#xff1b;代码示例&#xff1a;/*** 仓库信息缓存类*/ Service public class WarehouseCache extends AbstractBaseLocalCache<Long, Warehouse&g…

腾讯QQ团队开源分布式后台毫秒服务引擎全解析:引擎架构、RPC、灰度……

腾讯QQ团队将于12月4日开源一个服务开发运营框架&#xff0c;叫做毫秒服务引擎&#xff08;Mass Service Engine in Cluster&#xff0c;MSEC&#xff09;&#xff0c;它集RPC、名字发现服务、负载均衡、业务监控、灰度发布、容量管理、日志管理、Key-Value存储于一体&#xff…

古代隐士如何忙衣食

三岁娃儿都晓得&#xff0c;吃饭穿衣是维持生命的基本条件&#xff0c;想潇洒地“旧山归隐浪摇青&#xff0c;绿鬓山童一帙经”&#xff0c;就得准备足够的柴米油盐。 所谓隐士&#xff0c;须得强调是“士”&#xff0c;即读书人。手无缚鸡之力&#xff0c;不仕就无俸禄&…

一个秘密

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 这是一个秘密&#xff0c; 一个不想说出来&#xff0c;却真实的秘密&#xff1a; --- --- 本来我不想说&#xff0c; 可是最近的一切…

程序员如何在大公司做管理

本文被记录的最大初衷在于从创业公司的CEO转变成阿里巴巴的一名开发专家&#xff0c;打心底触动了心灵最深处的一次学习经历&#xff0c;无论成长、挫折、困难、收获都烙在心里。 写文章的思路&#xff1a; 背景&#xff08;认清现状&#xff09;管理&#xff08;阐述自己的理解…