开源轮子 - Logback 和 Slf4j
spring boot内置:Logback
文章目录
- spring boot内置:Logback
- 一:Logback强在哪?
- 二:简单使用
- 三:把 log4j 转成 logback
- 四:日志门面SLF4J
- 1:什么是SLF4J
- 2:SLF4J 解决了什么痛点
- 3:SLF4J 比 Log4J 强在哪
一:Logback强在哪?
- 非常自然地实现了 SLF4J,不需要像 Log4j 和 JUL 那样加一个适配层
- 是Spring Boot默认的[一旦某款工具库成为了默认选项,那就说明这款工具已经超过了其他竞品]
- 支持自动重新加载配置文件,不需要另外创建扫描线程来监视
- 性能大大的提升
logback手册:https://github.com/itwanger/logback-chinese-manual
二:简单使用
<dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>1.2.3</version>
</dependency>
Maven 会自动导入另外两个依赖:
package org.example.open_source.log;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;/*** <p>* 功能描述:logback demo test* </p>** @author cui haida* @date 2024/04/05/21:02*/
public class LogbackDemo {static Logger logger = LoggerFactory.getLogger(LogbackDemo.class);public static void main(String[] args) {logger.info("info");logger.debug("debug");logger.error("error");logger.warn("warn");}
}
Logger 和 LoggerFactory 都来自 SLF4J,所以如果项目是从 Log4j + SLF4J 切换到 Logback 的话,此时的代码是零改动的。
在没有配置文件的情况下,一切都是默认的,Logback 的日志信息会输出到控制台。
可以通过 StatusPrinter 来打印 Logback 的内部信息:
LoggerContext lc = (LoggerContext)LoggerFactory.getILoggerFactory();
StatusPrinter.print(lc);
一般来说,我们会在本地环境中配置 logback-test.xml,在生产环境下配置 logback.xml。
<configuration debug="true"><appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"><!-- encoder将日志变成字节数组并转到输出流 --><encoder><!-- pattern指定格式,各个参数的意义见下图 --><pattern>%d{HH:mm:ss.SSS} %relative [%thread] %-5level %logger{36} - %msg%n</pattern></encoder></appender><root level="debug"><appender-ref ref="STDOUT" /></root>
</configuration>
Logback 的配置文件非常灵活
最基本的结构为 <configuration>
元素,包含 0 或多个 <appender>
元素,其后跟 0 或多个 <logger>
元素,其后再跟最多只能存在一个的 <root>
元素。
appender
root
只支持一个属性——level,值可以为:TRACE、DEBUG、INFO、WARN、ERROR、ALL、OFF。
appender-ref 用来指定具体的 appender
查看内部状态信息
可以在代码中通过 StatusPrinter 来打印 Logback 内部状态信息
也可以通过在 configuration 上开启 debug 来打印内部状态信息
自动重载配置
之前提到 Logback 很强的一个功能就是支持自动重载配置,那想要启用这个功能也非常简单,只需要在 configuration 元素上添加 scan=true
即可。
<configuration scan="true">//...
</configuration>
默认情况下,扫描的时间间隔是一分钟一次。
如果想要调整时间间隔,可以通过 scanPeriod 属性进行调整,单位可以是毫秒(milliseconds)、秒(seconds)、分钟(minutes)或者小时(hours)。
下面这个示例指定的时间间隔是 30 秒:
<configuration scan="true" scanPeriod="30 seconds">...
</configuration>
注意:如果指定了时间间隔,没有指定时间单位,默认的时间单位为毫秒。
当设置 scan=true
后,Logback 会起一个 ReconfigureOnChangeTask
的任务来监视配置文件的变化。
三:把 log4j 转成 logback
如果你的项目以前用的 Log4j,那么可以通过下面这个网址把 log4j.properties 转成 logback-test.xml:
http://logback.qos.ch/translator/
将之前的那个log4j.peoperties拿到之后,将会转成下面的xml
<?xml version="1.0" encoding="UTF-8"?><!-- Built in 2024-04-05 01:26 by logback-translator -->
<!-- -->
<!-- For sponsoring SLF4J/logback/reload4j projects see -->
<!-- https://github.com/sponsors/qos-ch -->
<!-- -->
<!-- Contact sales(at)qos.ch about licensing this tool or -->
<!-- custom development.-->
<configuration><appender name="stdout" class="ch.qos.logback.core.ConsoleAppender"><Target>System.out</Target><encoder><!-- 问题1:Logback 中没有 %l --><pattern>[%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n</pattern></encoder></appender><!-- 问题2,滚动策略? --><appender name="D" class="ch.qos.logback.core.rolling.RollingFileAppender"><!--See http://logback.qos.ch/manual/appenders.html#RollingFileAppender--><!--and http://logback.qos.ch/manual/appenders.html#TimeBasedRollingPolicy--><!--for further documentation--><Append>true</Append><File>debug.log</File><encoder><pattern>%d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n</pattern></encoder><filter class="ch.qos.logback.classic.filter.ThresholdFilter"><level>DEBUG</level></filter></appender><appender name="E" class="ch.qos.logback.core.rolling.RollingFileAppender"><!--See http://logback.qos.ch/manual/appenders.html#RollingFileAppender--><!--and http://logback.qos.ch/manual/appenders.html#TimeBasedRollingPolicy--><!--for further documentation--><Append>true</Append><File>error.log</File><encoder><pattern>%d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n</pattern></encoder><filter class="ch.qos.logback.classic.filter.ThresholdFilter"><level>ERROR</level></filter></appender><root level="debug"><appender-ref ref="stdout"/><appender-ref ref="D"/><appender-ref ref="E"/></root>
</configuration>
来看下面这个 RollingFileAppender 配置:
<appender name="D" class="ch.qos.logback.core.rolling.RollingFileAppender"><file>debug.log</file><rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><!-- 按天滚动 --><fileNamePattern>debug.%d{yyyy-MM-dd}.log</fileNamePattern><!-- 保存 30 天的历史记录,最大大小为 30GB --><maxHistory>30</maxHistory><totalSizeCap>3GB</totalSizeCap></rollingPolicy><encoder><pattern>%relative [%thread] %level %logger{35} - %msg%n</pattern></encoder>
</appender>
基于按天滚动的文件策略,最多保留 30 天,最大大小为 30G。
SizeAndTimeBasedRollingPolicy
比 TimeBasedRollingPolicy
多了一个日志文件大小设定的属性:maxFileSize
,其他完全一样。
基于我们对 RollingPolicy 的了解,可以把 logback-test.xml 的内容调整为以下内容:
<configuration><appender name="stdout" class="ch.qos.logback.core.ConsoleAppender"><Target>System.out</Target><encoder><pattern>%d{HH:mm:ss.SSS} [%thread] %level %logger{36} - %msg%n</pattern></encoder></appender><appender name="D" class="ch.qos.logback.core.rolling.RollingFileAppender"><Append>true</Append><File>debug.log</File><rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><!-- 按天轮转 --><fileNamePattern>debug.%d{yyyy-MM-dd}.log</fileNamePattern><!-- 保存 30 天的历史记录,最大大小为 30GB --><maxHistory>30</maxHistory><totalSizeCap>3GB</totalSizeCap></rollingPolicy><encoder><pattern>%relative [%thread] %-5level %logger{35} - %msg%n</pattern></encoder></appender><appender name="E" class="ch.qos.logback.core.rolling.RollingFileAppender"><File>error.log</File><rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><!-- 按天轮转 --><fileNamePattern>error.%d{yyyy-MM-dd}.log</fileNamePattern><!-- 保存 30 天的历史记录,最大大小为 30GB --><maxHistory>30</maxHistory><totalSizeCap>3GB</totalSizeCap></rollingPolicy><encoder><pattern>%d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n</pattern></encoder><filter class="ch.qos.logback.classic.filter.ThresholdFilter"><level>ERROR</level></filter></appender><root level="debug"><appender-ref ref="stdout"/><appender-ref ref="D"/><appender-ref ref="E"/></root>
</configuration>
四:日志门面SLF4J
1:什么是SLF4J
SLF4J 是 Simple Logging Facade for Java 的缩写(for≈4),也就是简易的日志门面
以外观模式(Facade pattern,一种设计模式,为子系统中的一组接口提供一个统一的高层接口,使得子系统更容易使用)实现
支持 java.util.logging、Log4J 和 Logback。
SLF4J 的作者就是 Log4J 和 Logback 的作者
2:SLF4J 解决了什么痛点
春秋战国的时候,每个国家都有自己的货币,用别国的货币也不合适,对吧?那在发生贸易的时候就比较麻烦了,货币不统一,就没法直接交易,因为货币可能不等价。
那秦始皇统一六国后,就推出了新的货币政策,全国都用一种货币,那之前的问题就解决掉了。
你看,同样的道理,日志系统有 JUL、JCL,Ceki Gulcu 自己又写了 2 种,Log4j 和 Logback
各有各的优缺点,再加上使用者千千万,萝卜白菜各有所爱,这就导致不同的应用可能会用不同的日志系统。
假设我们正在开发一套系统,打算用 SLF4J 作为门面,Log4j 作为日志系统
我们在项目中使用了 A 框架,而 A 框架的门面是 JCL,日志系统是 JUL,那就相等于要维护两套日志系统,对吧?
这就难受了!
Ceki Gulcu 想到了这个问题,并且帮我们解决了!来看 SLF4J 官网给出的解决方案。
- 使用
jcl-over-slf4j.jar
替换 commons-logging.jar - 引入
jul-to-slf4j.jar
3:SLF4J 比 Log4J 强在哪
SLF4J 除了解决掉以上的痛点,帮助我们的应用程序独立于任何特定的日志系统,还有一个非常牛逼的功能,那就是 SLF4J 在打印日志的时候使用了占位符 {}
,
它有点类似于 String 类的 format()
方法(使用 %s
等填充参数),但更加便捷,这在很大程度上提高了程序的性能。
众所周知,字符串是不可变的,字符串拼接会创建很多不必要的字符串对象,极大的消耗了内存空间。但 Log4J 在打印带参数的日志时,只能使用字符串拼接的方式:
String name = "张三";
int age = 18;
logger.debug(name + ",年纪:" + age + ",hello world");
非常笨重,但加入了 SLF4J 后,这个问题迎刃而解。我们来看一下在 Log4j 项目中加入 SLF4J 的详细的步骤。
第一步,把 log4j 的依赖替换为 slf4j-log4j12
(Maven 会自动引入 slf4j-api.jar 和 log4j.jar):
<dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId><version>1.7.25</version>
</dependency>
第二步,在 resources 目录下创建 log4j.properties 文件
# config rootLogger
log4j.rootLogger = debug,stdout,D,E# config logger stdout
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n# config logger debug
# if the log level is debug, the log will be output to debug.log
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = debug.log
log4j.appender.D.Append = true
log4j.appender.D.Threshold = DEBUG
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern = %d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n# config logger error
# if the log level is error, the log will be output to error.log
log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
log4j.appender.E.File =error.log
log4j.appender.E.Append = true
log4j.appender.E.Threshold = ERROR
log4j.appender.E.layout = org.apache.log4j.PatternLayout
log4j.appender.E.layout.ConversionPattern = %d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
第三步,新建测试类:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;/*** @author cuihaida*/
public class Log4jSLF4JDemo {private static final Logger logger = LoggerFactory.getLogger(Log4jSLF4JDemo.class);public static void main(String[] args) {logger.debug("{},hello world","张三");}
}
看到了吧,使用占位符要比“+”操作符方便的多。并且此时不再需要 isDebugEnabled()
先进行判断,debug()
方法会在字符串拼接之前执行。
如果只是 Log4J 的话,会先进行字符串拼接,再执行 debug()
方法
这也就意味着,如果日志系统的级别不是 DEBUG,就会多执行了字符串拼接的操作,白白浪费了性能。
相关文章:

开源轮子 - Logback 和 Slf4j
spring boot内置:Logback 文章目录 spring boot内置:Logback一:Logback强在哪?二:简单使用三:把 log4j 转成 logback四:日志门面SLF4J1:什么是SLF4J2:SLF4J 解决了什么痛…...

内部知识库的未来展望:技术融合与用户体验的双重升级
在当今数字化飞速发展的时代,企业内部知识库作为知识管理的关键载体,正站在变革的十字路口,即将迎来技术融合与用户体验双重升级的崭新时代,这一系列变化将深度重塑企业知识管理的格局。 一、技术融合:开启知识管理新…...

【Linux系列】Shell 命令:`echo ““ > img.sh`及其应用
💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…...

【RAG实战】语言模型基础
语言模型赋予了计算机理解和生成人类语言的能力。它结合了统计学原理和深度神经网络技术,通过对大量的样本数据进行复杂的概率分布分析来学习语言结构的内在模式和相关性。具体地,语言模型可根据上下文中已出现的词序列,使用概率推断来预测接…...

【MySQL】7.0 入门学习(七)——MySQL基本指令:帮助、清除输入、查询等
1.0 help ? 帮助指令,查询某个指令的解释、用法、说明等。详情参考博文: 【数据库】6.0 MySQL入门学习(六)——MySQL启动与停止、官方手册、文档查询 https://www.cnblogs.com/xiaofu007/p/10301005.html 2.0 在cmd命…...

我的 2024 年终总结
2024 年,我离开了待了两年的互联网公司,来到了一家聚焦教育机器人和激光切割机的公司,没错,是一家硬件公司,从未接触过的领域,但这还不是我今年最重要的里程碑事件 5 月份的时候,正式提出了离职…...

STM32CUBEMX+STM32H743ZIT6+IAP+UART在线升级初始化和代码解析
1、STM32H7带的ITCM,DTCM,AXI SRAM,SRAM1,SRAM2,SRAM3,SRAM4和备份SRAM五块。 其中, ①TCM区包括ITCM和DTCM,这两个是直连CPU的。 速率与CPU一致,最高能到480MHz。 DTCM地…...

半连接转内连接 | OceanBase SQL 查询改写
查询优化器是关系型数据库系统的核心模块,是数据库内核开发的重点和难点,也是衡量整个数据库系统成熟度的“试金石”。为了帮助大家更好地理解 OceanBase 查询优化器,我们撰写了查询改写系列文章,带大家更好地掌握查询改写的精髓&…...

Git使用经历
目录 1、先创建文件夹 2、仓库初始化 3、配置gitee用户名和密码 4、克隆指定仓库的中指定分支到本地仓库 5、查看当前所在分支、切换分支 6、查看状态,判断是否有修改 7、把更新的内容添加到缓存区 8、把缓存区的数据提交 9、把数据推送到远程仓库 10、把…...

永磁同步电机控制算法-自适应带宽LADRC转速控制器
一、原理介绍 设计了自适应带宽 LADRC 控制方法,继承了 LADRC 优点的同时,加入自适应带宽控制,提出运用 Softsign 函数设计带宽自适应函数,根据电机转速自动调节控制带宽,解决了永磁同步电机在复杂且多变的环境下受到…...

基于springboot+vue实现的博物馆游客预约系统 (源码+L文+ppt)4-127
摘 要 旅游行业的快速发展使得博物馆游客预约系统成为了一个必不可少的工具。基于Java的博物馆游客预约系统旨在提供高效、准确和便捷的适用博物馆游客预约服务。本文讲述了基于java语言开发,后台数据库选择MySQL进行数据的存储。该软件的主要功能是进行博物馆游客…...

LeetCode 1705.吃苹果的最大数目:贪心(优先队列) - 清晰题解
【LetMeFly】1705.吃苹果的最大数目:贪心(优先队列) - 清晰题解 力扣题目链接:https://leetcode.cn/problems/maximum-number-of-eaten-apples/ 有一棵特殊的苹果树,一连 n 天,每天都可以长出若干个苹果。在第 i 天,…...

vim多窗格
vim打开文件分为三个阶段:buffer、window与tab buffer就是在同一个界面打开的文件window就是使用水平分割与垂直分割的窗口tab则是可以是上述两者的总集合 buffer :e filename在已打开文件的界面中再打开一个新文件,显示这个新文件,原文件被隐…...

ubuntu paddle ocr 部署bug问题解决
ubuntu paddle ocr 部署会出现异常报错。 尝试安装以下版本: pip install paddlepaddle2.5.2 -i https://pypi.tuna.tsinghua.edu.cn/simpl 助力快速掌握数据集的信息和使用方式。 数据可以如此美好!...

OpenFeign快速入门 示例:黑马商城
使用起因 之前我们利用了Nacos实现了服务的治理,利用RestTemplate实现了服务的远程调用。这样一来购物车虽然通过远程调用实现了调用商品服务的方法,但是远程调用的代码太复杂了: 解决方法 并且这种调用方式比较复杂,一会儿远程调用,一会儿本地调用。 因…...

【C++】ceil 和 floor 函数的实现与分析
博客主页: [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C 文章目录 💯前言💯ceil 和 floor 函数的基础介绍1. ceil 函数定义与功能示例代码输出结果功能分析使用场景 2. floor 函数定义与功能示例代码输出结果功能分析使用场景 💯自行实现…...

zabbix监控山石系列Hillstone配置模版(适用于zabbix6及以上)
监控项: 触发器: 监控数据:...

在瑞芯微RK3588平台上使用RKNN部署YOLOv8Pose模型的C++实战指南
在人工智能和计算机视觉领域,人体姿态估计是一项极具挑战性的任务,它对于理解人类行为、增强人机交互等方面具有重要意义。YOLOv8Pose作为YOLO系列中的新成员,以其高效和准确性在人体姿态估计任务中脱颖而出。本文将详细介绍如何在瑞芯微RK3588平台上,使用RKNN(Rockchip N…...

CTFHub disable_functions通关
LD_PRELOAD 来到首页发现有一句话直接就可以用蚁剑连接 根目录里有/flag但是不能看;命令也被ban了就需要绕过了 绕过工具在插件市场就可以下载 如果进不去的话 项目地址: #本地仓库;插件存放 antSword\antData\plugins 绕过选择 上传后我们点进去可以看到多了一个绕过的文件;…...

Chromium GN 目标指南 - view_example 计数器示例 (七)
1. 引言 在前面的文章中,我们学习了如何在 views_examples 中添加自定义 Button 示例。在本篇文章中,我们将继续探索 Views 框架的应用,创建一个简单的计数器示例,以学习如何使用 Label 和 Button 控件进行交互,以及如…...

一步一步写线程之十六线程的安全退出之二例程
一、说明 在一篇分析了多线程的安全退出的相关机制和方式,那么本篇就针对前一篇的相关的分析进行举例分析。因为有些方法实现的方法类似,可能就不一一重复列举了,相关的例程主要以在Linux上的运行为主。 二、实例 线程间的同步,…...

【Linux系列】Shell 脚本中的条件判断:`[ ]`与`[[ ]]`的比较
💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…...

ArcGIS+MIKE21 洪水淹没分析、溃坝分析,洪水淹没动态效果
洪水淹没分析过程: 一、所需数据: 1.分析区域DEM数据 二、ArcGIS软件 1.提取分析区域DEM(水库坝下区域) 2.DEM栅格转点 3.计算转换后几何点的x和y坐标值(精度20、小数位3) 4.导出属性表,形式…...

Git 的基本概念和使用
Git是一个分布式版本控制系统,它可以帮助开发人员追踪和管理代码的修改。下面是Git的基本概念和使用方式的解释: 仓库(Repository):Git使用仓库来存储代码和版本历史记录。仓库可以位于本地计算机上,也可以…...

*【每日一题 基础题】 [蓝桥杯 2024 省 B] 好数
[蓝桥杯 2024 省 B] 好数 好数 一个整数如果按从低位到高位的顺序,奇数位(个位、百位、万位……)上的数字是奇数,偶数位(十位、千位、十万位……)上的数字是偶数,我们就称之为“好数”。 给定一…...

对中文汉字排序的方法总结
写在前面 在各个系统中,都随处可见根据某个字段进行升序(ASC)或降序(DESC)进行排序展示。但进行中文汉字排序和查找的时候,对中文汉字的排序和查找结果往往都是错误的。 为了尽量提供全面的解决方法,本文会从各个层面出发告知有需要的人对应…...

【解决报错】AttributeError: ‘NoneType‘ object has no attribute ‘group‘
学习爬虫时,遇到如下报错: 报错原因: 正则表达式的 search 或 finditer 方法没有找到任何匹配项,可能是换行符处理不当等。 解决方法如下: 在正则表达式末尾加上re.S即可,re.S是一个编译标志,…...

数据结构经典算法总复习(上卷)
第一章:数据结构导论 无重要考点,仅需了解时间复杂度。 第二章:线性表 1.获得线性表第i个元素 void GetElem_sq(SqList L, int i, ElemType &e) {if (i<1 || i>L.length) ErrorMsg("Invalid i value"); //注意错误监…...

JS获取URL中参数值的4种方法
方法1:现代浏览器都支持 URL 和 URLSearchParams 对象,可以很方便地从URL中提取参数 // 假设当前URL为 "https://example.com/?nameJohn&age30" const url new URL(window.location.href); // 或者你可以直接传入一个URL字符串 const …...

【面经】2024年软件测试面试题,精选100 道(附答案)
测试技术面试题 1、我现在有个程序,发现在 Windows 上运行得很慢,怎么判别是程序存在问题还是软硬件系统存在问题? 2、什么是兼容性测试?兼容性测试侧重哪些方面? 3、测试的策略有哪些? 4、正交表测试用…...