SLF4J简介与使用(整合log4j)

SLF4J简介与使用(整合log4j)

一、概念

SLF4J的全称是Simple Logging Facade for Java,即简单日志门面。SLF4J并不是具体的日志框架,而是作为一个简单门面服务于各类日志框架,如java.util.logging, logback和log4j。

SLF4J提供了统一的记录日志的接口,对不同日志系统的具体实现进行了抽象化,只要按照其提供的方法记录即可,最终日志的格式、记录级别、输出方式等通过绑定具体的日志系统来实现。

使用SLF4J的好处在于,你只需要按统一的方式写记录日志的代码,如:

public class LoggerTest {private static final Logger logger = LoggerFactory.getLogger(Tester.class);public static void main(String[] args) {logger.info("Current Time: {}", System.currentTimeMillis());}
}

SLF4J支持{}作为占位符,等价于C语言中的%s,而不必再进行字符串的拼接,效率有显著的提升(见后面运行结果)。

而无需关心日志是通过哪个日志系统,以什么风格输出的。因为它们取决于部署项目时绑定的日志系统。
例如,在项目中使用了SLF4J记录日志,并且绑定了log4j,则日志会以log4j的风格输出;后期需要改为以logback的风格输出日志,只需要将log4j替换成logback即可,不用修改项目中的代码。

二、依赖

SLF4J绑定各类日志框架的原理图:

SLF4J绑定各类日志框架的原理图

由上图可知,使用SLF4J依赖于slf4j-api-1.8.0-alpha2.jar,部署时还依赖于要绑定的日志系统的jar包和相应的适配器jar包。

以绑定log4j为例,需要导入以下包:

  • slf4j-api-1.8.0-alpha2.jar
  • log4j-1.2.17.jar
  • slf4j-log4j12-1.8.0-alpha2.jar

如果使用Maven,则只需添加适配器jar包依赖即可

三、使用示例

这里以SLF4J + log4j为例。

1.在pom.xml中添加依赖(或者手动导入上述3个jar包)

<dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId><version>1.8.0-alpha2</version>
</dependency>

2.配置log4j

在类路径下创建log4j.properties配置文件,这样log4j会自动加载配置文件。

# rootLogger参数分别为:根Logger级别,输出器stdout,输出器log
log4j.rootLogger = info,stdout,log# 输出信息到控制台
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = %d [%-5p] %l %rms: %m%n# 输出DEBUG级别以上的日志到D://logs/debug.log
log4j.appender.log = org.apache.log4j.DailyRollingFileAppender
log4j.appender.log.DatePattern = '.'yyyy-MM-dd
log4j.appender.log.File = D://debug.log
log4j.appender.log.Encoding = UTF-8
#log4j.appender.log.Threshold = INFO
log4j.appender.log.layout = org.apache.log4j.PatternLayout
log4j.appender.log.layout.ConversionPattern = %d [%-5p] (%c.%t): %m%n

将log4j.properties放在类路径下是最简单的做法,当然也可以通过PropertyConfigurator在代码中加载或者通过web.xml加载。

3.测试代码

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;public class LoggerTest {private static final Logger logger = LoggerFactory.getLogger(LoggerTest.class);public static void main(String[] args) {logger.info("Current Time: {}", System.currentTimeMillis());logger.info("Current Time: " + System.currentTimeMillis());logger.info("Current Time: {}", System.currentTimeMillis());logger.trace("trace log");logger.warn("warn log");logger.debug("debug log");logger.info("info log");logger.error("error log");}
}

4.运行结果

2018-09-01 23:14:32,690 [INFO ] com.lun.helloslf4j.LoggerTest.main(LoggerTest.java:11) 2ms: Current Time: 1535814872683
2018-09-01 23:14:32,700 [INFO ] com.lun.helloslf4j.LoggerTest.main(LoggerTest.java:12) 12ms: Current Time: 1535814872700
2018-09-01 23:14:32,701 [INFO ] com.lun.helloslf4j.LoggerTest.main(LoggerTest.java:13) 13ms: Current Time: 1535814872701
2018-09-01 23:14:32,701 [WARN ] com.lun.helloslf4j.LoggerTest.main(LoggerTest.java:15) 13ms: warn log
2018-09-01 23:14:32,701 [INFO ] com.lun.helloslf4j.LoggerTest.main(LoggerTest.java:17) 13ms: info log
2018-09-01 23:14:32,701 [ERROR] com.lun.helloslf4j.LoggerTest.main(LoggerTest.java:18) 13ms: error log

在这里插入图片描述

通常输出日志开销非常大,从上述结果可见,SLF4J通过{}作为占位符的方式输出字符串,相比字符串拼接的方式,效率有显著的提升。

5.更换日志系统

看到这里,你可能会有疑问:既然都用了log4j,为什么还要用SLF4J来写记录日志的代码呢,不是多此一举吗?

答案是否定的。假设我们不再需要log4j,而是希望改为使用java自带logging记录日志,我们需要做的仅仅是将pom.xml的依赖项slf4j-log4j12改为slf4j-jdk14即可,无需对上述测试代码做任何修改。

<dependency><groupId>org.slf4j</groupId><artifactId>slf4j-jdk14</artifactId><version>1.8.0-alpha2</version>
</dependency>

是的,就是这么简单。再次运行测试代码:

九月 01, 2018 11:25:35 下午 com.lun.helloslf4j.LoggerTest main
信息: Current Time: 1535815535309
九月 01, 2018 11:25:35 下午 com.lun.helloslf4j.LoggerTest main
信息: Current Time: 1535815535475
九月 01, 2018 11:25:35 下午 com.lun.helloslf4j.LoggerTest main
信息: Current Time: 1535815535477
九月 01, 2018 11:25:35 下午 com.lun.helloslf4j.LoggerTest main
警告: warn log
九月 01, 2018 11:25:35 下午 com.lun.helloslf4j.LoggerTest main
信息: info log
九月 01, 2018 11:25:35 下午 com.lun.helloslf4j.LoggerTest main
严重: error log

我们发现,此时日志已经变为以logging的方式输出。

四、总结

SLF4J的使用非常简单,甚至连官网上都说鉴于它太轻量,文档篇幅不长。

Given the small size of SLF4J, its documentation is not very lengthy.

在《阿里巴巴Java开发手册(正式版)》中,日志规约一项第一条就强制要求使用SLF4J:

【强制】应用中不可直接使用日志系统(Log4j、Logback)中的API,而应依赖使用日志框架SLF4J中的API,使用门面模式的日志框架,有利于维护和各个类的日志处理方式统一。

所以从现在开始使用SLF4J吧!

引用

来源处

官方文档

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

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

相关文章

multism中ui和uo应该怎么表示_王者荣耀:梦泪直播时谈到体验服大改动,表示装备的改动很关键...

王者荣耀的主播梦泪&#xff0c;大家都很熟了&#xff0c;也是一个很强的主播&#xff0c;他对于王者荣耀的理解&#xff0c;还是非常深刻的&#xff0c;而最近王者荣耀的体验服&#xff0c;进行了大改动&#xff0c;也是改变了很多的东西。对此&#xff0c;网友们也是非常的在…

怎么关闭或者卸载ivanti_电脑软件卸载不了怎么办,教您解决电脑软件无法卸载方法技巧...

我们在使用电脑的过程中&#xff0c;肯定会安装各种软件&#xff0c;但是一些软件在使用完之后就不会再使用了&#xff0c;但又无法卸载。下面由小编分享一下电脑安装的软件无法卸载解决方法&#xff0c;如果你在某卸载软件的时候出现无法卸载的情况&#xff0c;不妨通过以下方…

解决Github图片加载失败

问题描述 浏览自己Github某仓库的README.md内时&#xff0c;发现文档的图片始终加载不出&#xff0c;打开浏览器后台&#xff0c;冒出一片红&#xff0c;Failed to load resource: net::ERR_CONNECTION_RESET&#xff0c;如下图所示&#xff1a; 问题分析 可能造成这问题的原…

FFmpeg源代码简单分析-通用-结构体分析-关键结构体之间的关系

参考链接 FFMPEG中最关键的结构体之间的关系_雷霄骅的博客-CSDN博客_ffmpeg 结构体关系 最关键的结构体可以分成以下几类&#xff1a; 解协议&#xff08;http,rtsp,rtmp,mms&#xff09; AVIOContext&#xff0c;URLProtocol&#xff0c;URLContext主要存储视音频使用的协…

用Python下载文件

前提条件 需要事先安装requests模块&#xff1a; pip install requests 放码过来 import requestsurl XXX #文件下载来源URL filename #下载到本地后新文件名 r requests.get(url) with open(filename, "wb") as code:code.write(r.content)实战演习 从目标…

FFmpeg源代码简单分析-通用-常见结构体的初始化和销毁(AVFormatContext,AVFrame等)

参考链接 FFmpeg源代码简单分析&#xff1a;常见结构体的初始化和销毁&#xff08;AVFormatContext&#xff0c;AVFrame等&#xff09;_雷霄骅的博客-CSDN博客 结构体 AVFormatContext&#xff1a;统领全局的基本结构体。主要用于处理封装格式&#xff08;FLV/MKV/RMVB等&…

FFmpeg源代码简单分析-通用-avio_open2()

参考链接 FFmpeg源代码简单分析&#xff1a;avio_open2()_雷霄骅的博客-CSDN博客_avio_open avio_open2() 该函数用于打开FFmpeg的输入输出文件avio_open2()的声明位于libavformat\avio.h文件中&#xff0c;如下所示。 /*** Create and initialize a AVIOContext for accessi…

用Tomcat构建一个简单图片服务器

前提条件 Tomcat 7.0.90 方法一&#xff1a;修改配置文件 在TOMCAT_HOME/conf/server.xml配置文件内的<Host>内添加一子标签&#xff1a; <Context docBase"C:\exambase\" path"/img"/>方法二&#xff1a;添加Servlet 新建一应用&#xf…

FFmpeg源代码简单分析-通用-av_find_decoder()和av_find_encoder()

参考链接 FFmpeg源代码简单分析&#xff1a;av_find_decoder()和av_find_encoder()_雷霄骅的博客-CSDN博客_avcodec_find_encoder avcodec_find_encoder avcodec_find_encoder()用于查找FFmpeg的编码器avcodec_find_encoder()的声明位于libavcodec\codec.h 版本差异avcode…

post方法就反回了一个string字符串前台怎么接_Golang Web入门(2):如何实现一个RESTful风格的路由...

摘要在上一篇文章中&#xff0c;我们聊了聊在Golang中怎么实现一个Http服务器。但是在最后我们可以发现&#xff0c;固然DefaultServeMux可以做路由分发的功能&#xff0c;但是他的功能同样是不完善的。由DefaultServeMux做路由分发&#xff0c;是不能实现RESTful风格的API的&a…

FFmpeg源代码简单分析-通用-avcodec_open2()

参考链接 FFmpeg源代码简单分析&#xff1a;avcodec_open2()_雷霄骅的博客-CSDN博客 avcodec_open2() 该函数用于初始化一个音视频编解码器的AVCodecContextavcodec_open2()的声明位于libavcodec\avcodec.h&#xff0c;如下所示。 /*** Initialize the AVCodecContext to use…

统计MySQL中某数据库硬盘占用量大小

放码过来 select TABLE_NAME, concat(truncate(data_length/1024/1024,2), MB) as data_size, concat(truncate(index_length/1024/1024,2), MB) as index_size from information_schema.tables where TABLE_SCHEMA your_db_name order by data_length desc;运行结果 参考…

FFmpeg源代码简单分析-解码-打开媒体的函数avformat_open_input

参考链接 图解FFMPEG打开媒体的函数avformat_open_input_雷霄骅的博客-CSDN博客_avformat_open_input 使用FFmpeg源代码简单分析&#xff1a;avformat_open_input()_雷霄骅的博客-CSDN博客_avformat_open_input() avformat_open_input FFmpeg打开媒体的的过程开始于avformat_…

redis session java获取attribute_面试题:给我说说你能想到几种分布式session实现?...

作者&#xff1a;yanglbme 来源&#xff1a;https://github.com/doocs/advanced-java/blob/master/docs/distributed-system/distributed-session.md# 面试官心理分析面试官问了你一堆 dubbo 是怎么玩儿的&#xff0c;你会玩儿 dubbo 就可以把单块系统弄成分布式系统&#xff0…

FFmpeg源代码简单分析-解码-avformat_find_stream_info()

参考链接 FFmpeg源代码简单分析&#xff1a;avformat_find_stream_info()_雷霄骅的博客-CSDN博客_avformat_find_stream_info avformat_find_stream_info() ​该函数可以读取一部分视音频数据并且获得一些相关的信息avformat_find_stream_info()的声明位于libavformat\avform…

Tail Recursion尾递归

什么是尾递归 Tail Recursion /teɪl rɪˈkɜːrʒn/ In traditional recursion, the typical model is that you perform your recursive calls first, and then you take the return value of the recursive call and calculate the result. In this manner, you don’t g…

FFmpeg源代码简单分析-解码-av_read_frame()

参考链接 ffmpeg 源代码简单分析 &#xff1a; av_read_frame()_雷霄骅的博客-CSDN博客_ffmpeg frame av_read_frame() ffmpeg中的av_read_frame()的作用是读取码流中的音频若干帧或者视频一帧。例如&#xff0c;解码视频的时候&#xff0c;每解码一个视频帧&#xff0c;需要…

FFmpeg源代码简单分析-解码-avformat_close_input()

参考链接 FFmpeg源代码简单分析&#xff1a;avformat_close_input()_雷霄骅的博客-CSDN博客_avformat_close_input avformat_close_input() 本文简单分析FFmpeg的avformat_close_input()函数。该函数用于关闭一个AVFormatContext&#xff0c;一般情况下是和avformat_open_inp…

FFmpeg源代码简单分析-编码-avformat_alloc_output_context2()

参考链接 FFmpeg源代码简单分析&#xff1a;avformat_alloc_output_context2()_雷霄骅的博客-CSDN博客_avformat_alloc_context avformat_alloc_output_context2() 在基于FFmpeg的视音频编码器程序中&#xff0c;该函数通常是第一个调用的函数&#xff08;除了组件注册函数av…

FFmpeg源代码简单分析-编码-avformat_write_header()

参考链接 FFmpeg源代码简单分析&#xff1a;avformat_write_header()_雷霄骅的博客-CSDN博客_avformat_write_header avformat_write_header() FFmpeg写文件用到的3个函数&#xff1a;avformat_write_header()&#xff0c;av_write_frame()以及av_write_trailer()其中av_writ…