日志通关4:logback

插: AI时代,程序员或多或少要了解些人工智能,前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家(前言 – 人工智能教程 )

坚持不懈,越努力越幸运,大家一起学习鸭~~~

一、配置入口

Logback支持XML、Groovy的配置方式,以XML来说,它会默认查找resources目录下的logback-test.xml(用于测试)/logback.xml文件。

而如果你使用的Spring Boot,那么你还可以使用logback-spring.xml文件进行配置。这两者的区别是:

  • logback-spring.xml是由 Spring Boot 找到,插入自己的上下文信息[1]并做进一步处理后再传递给Logback的,你可以在其中使用<springProfile>区分环境配置,也可以使用<springProperty>拿到Spring上下文信息(比如spring.application.name)。
  • logback.xml是由Logback自己找到的,自然不会有Spring Boot相关的能力。

二、配置文件介绍

接下来我们以logback-spring.xml为例进行介绍。一个Logback配置文件主要有以下几个标签:

  • confinuration:最外层的父标签,其中有几个属性配置,但项目中较少使用,就不啰嗦了;
  • property:定义变量;
  • appender:负责日志输出(一般是写到文件),我们可以通过它设置输出方案;
  • logger:用来设置某个LoggerName的打印级别;
  • root:logger的兜底配置,从而我们不必配置每个LoggerName;
  • conversionRule:定义转换规则,参考【四、Java API】;

2.1 springProperty 和 property

前文提到<springProperty>用来插入Spring上下文,那<property>就是 Logback 自己定义变量的标签。直接看示例:

<springProperty scope="context" name="APP_NAME" source="spring.application.name"/><property name="LOG_PATH" value="${user.home}/${APP_NAME}/logs"/>
<property name="APP_LOG_FILE" value="${LOG_PATH}/application.log"/>
<property name="APP_LOG_PATTERN"value="%date{yyyy-MM-dd HH:mm:ss.SSS}|%-5level|%X{trace_id}|%thread|%logger{20}|%message%n%exception"/>

我们首先用<springProperty>插入APP_NAME这个变量来表示应用名,随后用它拼出LOG_PATH变量。示例中还用到了${user.home}这个Logback内建支持的上下文变量[2]。APP_LOG_FILE是log文件路径;APP_LOG_PATTERN是日志格式(请参考【三、占位符】节)。

2.2 appender

这一节涉及到的知识点很多,但一码胜千言,先直接给出示例:

<appender name="APPLICATION" class="ch.qos.logback.core.rolling.RollingFileAppender"><file>${APP_LOG_FILE}</file><encoder><pattern>${APP_LOG_PATTERN}</pattern></encoder><rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"><fileNamePattern>${APP_LOG_FILE}.%d{yyyy-MM-dd}.%i</fileNamePattern><maxHistory>30</maxHistory><maxFileSize>200MB</maxFileSize><totalSizeCap>10GB</totalSizeCap></rollingPolicy>
</appender>
<appender name="APPLICATION-async" class="ch.qos.logback.classic.AsyncAppender"><queueSize>256</queueSize><discardingThreshold>0</discardingThreshold><neverBlock>true</neverBlock><appender-ref ref="APPLICATION"/>
</appender>

示例中涉及的变量在上一节已经提到,这里不啰嗦了。需要关注的是以下几个点:

  • ch.qos.logback.core.rolling.RollingFileAppender负责将日志滚动打印,避免单文件体积过大。具体的滚动策略都在<rollingPolicy>中指定,各配置项都还算好理解。
  • ch.qos.logback.classic.AsyncAppender负责将日志异步打印,避免大量打印日志时阻塞线程。

除了上边这两个,还有如ch.qos.logback.core.ConsoleAppender是用来将日志输出到控制台,如果你用到了,建议参考【下一篇九、不要将日志输出至Console】节。

更多Appender和RollingPolicy相关的介绍,可以参考官方文档Chapter 4: Appenders[3]。

2.3 logger和root

<logger>用来设置某个LoggerName的打印级别。比如:

<logger level="INFO" additivity="false" name="com.foo.bar"><appender-ref ref="APPLICATION-async"/>
</logger>
<root level="INFO"><appender-ref ref="APPLICATION-async"/>
</root>

上面的配置指定所有LoggerName为com.foo.bar的日志以INFO级别进行打印(TRACE和DEBUG级别将不会输出),此配置绑定的输出器(appender)为APPLICATION-async。

其中LoggerName会以 . 为分隔符逐级向上匹配,比如实际LoggerName为com.foo.bar.service.ExampleService,那么它的查找过程依次为:

  1. com.foo.bar.service.ExampleService
  2. com.foo.bar.service
  3. com.foo.bar(此时命中了我们示例中的<logger>,另外因为配置了additivity="false" 所以停止继续向下查找)
  4. com.foo
  5. com
  6. <root>

而 <root>就是兜底配置了,当LoggerName没匹配到任何一项<logger> 时,就会使用 <root>,所以它是没有additivity和name属性的。

一般实际业务场景中,所有<logger>都建议加上additivity="false" ,否则日志就会因查找到多个<logger>(或<root>)而打印多份。

2.4 springProfile

Spring还提供了<springProfile>标签,用来根据Spring Profiles[4](即 spring.profiles.active的值)动态调整日志信息,比如我们希望线上环境使用INFO级别,而预发、日常使用TRACE级别:

<springProfile name="production"><root level="INFO"><appender-ref ref="APPLICATION-async"/></root>
</springProfile>
<springProfile name="staging,testing"><root level="TRACE"><appender-ref ref="APPLICATION-async"/></root>
</springProfile>

三、占位符

3.1 Conversion Word

Logback提供了大量有用的占位符给大家使用,官方文档在Conversion Word[5]。

比如一些常用的占位符(大部分占位符都有缩写形式,比如%logger可以简写为%c,我不在这里一一列举了,具体可以查看上边给出的官方文档):

占位符

说明

%logger

输出LoggerName(参考【第三篇:1.1 工厂函数】节)

%message

输出你实际要打印的日志信息(参考【第三篇:3.1 info方法】节)

%exception

输出异常堆栈,对应通过Slf4j传入的异常(参考【第三篇:3.1 info方法】节)

%level

输出日志级别,即TRACE/DEBUG/INFO/WARN/ERROR/FATAL。

注意这里有别于Slf4j(参考【第三篇:二、日志级别】),多了个FATAL级别,这是为了适配Log4j而存在的。

%xException

输出异常堆栈,同时包含每行堆栈所归属的JAR包名

%marker

输出通过Marker(参考【第三篇:四、Marker】节)传入的字符串

%mdc

输出MDC(参考【第三篇:五、MDC】节)中对应的值

%kvp

输出通过addKeyValue(参考【第三篇:六、Fluent API (链式调用)】节)传入的KV对

%date

输出时间,可以添加符合ISO 8601[6]的参数指定输出格式,比如我们常用的yyyy-MM-dd HH:mm:ss

%thread

输出打印日志方法所在的线程名

%n

输出一个换行符

%replace(p){r, t}

将p中的r替换为t,r为正则。请参考【第五篇:七、将堆栈合并为一行】节

%nopex

忽略传入的堆栈,不打印。请参考【第五篇:七、将堆栈合并为一行】节

Logback会判断你的日志pattern,如果没有输出堆栈,会默认追加%exception,以保证传入的异常信息不会丢。这个占位符就是明确要求不做追加。

另外,针对%logger额外做一下补充。%logger的参数中可以传一个正整数,用于指定输出长度,当LoggerName长度超过限制时,Logback会以 . 为分隔智能缩短。假设LoggerName是com.example.foo.bar.ExampleService(这个字符串长度为34),那么:

配置

输出结果

说明

[%logger]

[com.example.foo.bar.ExampleService]

原样输出

[%logger{32}]

[c.example.foo.bar.ExampleService]

实际长度32,与限制值一致

[%logger{30}]

[c.e.foo.bar.ExampleService]

实际长度26,比限制值小。因为每一级 package要么保留原样,要么只取第一个字符

[%logger{10}]

[c.e.f.b.ExampleService]

实际长度20,比限制值大。因为每一级 package至少会保留一个字符,且最后一级不会被缩短

[%logger{0}]

[ExampleService]

0比较特殊,表示只保留最后一级,且不会被缩短

3.2 Format modifiers

从前边我们可以看到,占位符的基本使用方式是:%占位符{参数},但其实还有一个用于控制格式的可选配置,可以放在%与占位符之间,叫作Format modifiers[7]。一个完整的格式配置包含五个部分,比如:-10.-20,我们分别解释:

  • -:第一个-表示不足最小长度时在右侧填充空格,即输出内容左对齐(默认是在左侧填充空格,即右对齐);
  • 10:第一个数字表示输出最小长度,不足的补空格;
  • .:与后边两项配置的分隔符,本身没有含义;
  • -:第二个-表示超过最大长度时先裁剪右侧,即保留左侧字符(默认先裁剪左侧,即保留右侧字符);
  • 20:第二个数字表示输出最大长度,超出部分会做裁剪;

举个几个例子:

配置

文本

输出结果

说明

[%5level]

INFO

[ INFO]

最小5个字符,右对齐

[%-5level]

INFO

[INFO ]

最小5个字符,左对齐

[%.-1level]

INFO

[I]

最大1个字符,优先保留左侧字符

[%-5,-10logger]

com.foo.bar.Service

[com.foo.ba]

最大10个字符,优先保留左侧字符

[%-5,10logger]

com.foo.bar.Service

[ar.Service]

最大10个字符,优先保留右侧字符

四、Java API

除了使用XML配置文件外,Logback还提供了大量的Java API[8]以支持更复杂的业务诉求。我们通过三个非常实用的场景来简单介绍一下。

  1. 场景一:使用log.info("obj={}", obj) 时,如何将obj统一转JSON String后输出;
  2. 场景二:日志中涉及到的手机号、身份证号,如何脱敏后再记录日志;
  3. 场景三:Logback配置基于XML,如何不改代码不发布,也可以动态修改日志级别;

其中前两个问题都可以通过MessageConverter[9]实现,因为篇幅原因,具体介绍可关注后续文章。

第三个问题可以借助LoggerContext[10]及Logger[11],同样因为篇幅原因,具体介绍可关注后续文章。

五、MDC 中的 traceId

单独拿出一节讲这个,是因为我发现有很多同学会手动记录traceId,比如:

log.info("traceId={}, blah blah blah", Span.current().getSpanContext().getTraceId());

其实OpenTelemetry[12]已经自动将traceId加到了MDC,对应的Key是trace_id,使用%mdc{trace_id}(参考【第三篇五、MDC】节)即可打印出traceId。比如我们在【2.1 springProperty和property】一节的示例中,就使用了这个Key。

六、后记

以上只是简单介绍了Logback的常用功能,如需进一步了解可以参考官方文档Logback documentation[13]。特别是其中很多例子是结合Slf4j一起介绍的,非常易懂。

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

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

相关文章

Nginx学习笔记(十)如何配置HTTPS协议?(公网)

目录 一、简介二、SSL 证书类型介绍三、公网 SSL 证书3.1 证书管理工具3.2 下载安装 acme.sh3.3 申请并下载证书报错1&#xff1a;没有指定账号报错2&#xff1a;DNS无法解析的域名报错3&#xff1a;无效的响应 404 3.4 配置 Nginx3.5 证书过期刷新 四、补充4.1 同一域名的不同…

硬盘危机:磁盘损坏无法打开的应对策略

在数字化时代&#xff0c;磁盘作为数据存储和传输的核心设备&#xff0c;其稳定性和安全性至关重要。然而&#xff0c;在日常使用过程中&#xff0c;我们时常会面临磁盘损坏无法打开的困境。这不仅会影响我们的工作效率&#xff0c;还可能造成重要数据的丢失。本文将深入探讨磁…

2024年,计算机相关专业还值得选择吗?

问&#xff1a;随着2024年高考落幕&#xff0c;数百万高三学生又将面临人生中的重要抉择&#xff1a;选择大学专业。在这个关键节点&#xff0c;计算机相关专业是否仍是“万金油”的选择&#xff1f;在过去很长一段时间里&#xff0c;计算机科学与技术、人工智能、网络安全、软…

抖音 根据sec uid获取个人详细信息(性别、年龄、属地、关注数、粉丝数、简介等)

本文带来用户的secuid获取用户信息以及其他基本信息&#xff1a; 话不多说看效果&#xff1a; 第一步输入用户sec_uid 根据secuid获取到用户基本信息&#xff1a; 可以支持接口批量转换&#xff0c;欢迎咨询

从信息泄露到登录后台

信息收集 上谷歌用谷歌语法&#xff0c;经过漫长的翻找发现一处PDF&#xff1a; 是某大学的某系统帮助文档&#xff0c;其中泄露了人员的工号和sfz 尝试登陆 此时&#xff0c;虽然获取了工号和sfz&#xff0c;众所周知&#xff0c;现在很多统一身份认证都是学号/工号sfz后六位…

玩转ChatGPT:最全学术论文提示词分享【下】

学境思源&#xff0c;一键生成论文初稿&#xff1a; AcademicIdeas - 学境思源AI论文写作 本篇文章&#xff0c;是系列文章「最全学术论文提示词」的完结篇。前两篇的内容请到文末链接处跳转&#x1f447;&#x1f3fb; 11.提交和发布 prompt 1&#xff1a;根据[期刊/会议]指…

深入探讨Java压缩利器:net.lingala.zip4j.ZipFile的应用与实践

在现代软件开发中&#xff0c;数据压缩是一个常见且重要的任务。无论是减小文件大小以节省存储空间&#xff0c;还是将多个文件打包在一起以便于传输和分发&#xff0c;压缩技术都是不可或缺的。在Java世界中&#xff0c;net.lingala.zip4j.ZipFile库因其强大的功能和易用性&am…

如何系统学习vue框架

前言 在软件开发的浩渺星海中&#xff0c;编程规范如同航海的罗盘&#xff0c;为我们指引方向&#xff0c;确保我们的代码之旅能够顺利、高效地到达目的地。无论是个人开发者还是大型团队&#xff0c;编程规范都是提升代码质量、保障项目成功不可或缺的一环。 因此&#xff0c…

人工智能模型对有争议的话题持相反的观点

人工智能模型对有争议的话题持相反的观点 并非所有生成式人工智能模型都是平等的&#xff0c;特别是当涉及到它们如何处理两极分化的主题时。 在2024年ACM公平、问责和透明度(FAccT)会议上发表的一项最新研究中&#xff0c;卡内基梅隆大学、阿姆斯特丹大学和人工智能初创公司h…

【设计模式】结构型-代理模式

在静谧的林间舞台上&#xff0c;代理轻舞着对象的梦想&#xff0c;掌控访问&#xff0c;引领旋律&#xff0c;真实与虚幻间&#xff0c;交织出灵动的诗篇。 文章目录 一、数据库操作的问题二、代理模式三、代理模式的核心组成四、运用代理模式五、代理模式的应用场景六、小结推…

nginx脚本原理(复杂变量)详解

本文将结合实际的源码来探讨nginx的脚本实现原理,并会在最后对此进行总结。本次只展示复杂变量,对于其if等指令后续文章再来探讨。 nginx的脚本支持使其具备了强大的灵活性,我们可以使用简单的脚本指令配置,进行灵活的功能定制。欲了解此功能,必先了解其变量的实现原理.(…

Web前端可以开发哪些:探索无尽的可能性

Web前端可以开发哪些&#xff1a;探索无尽的可能性 在数字化时代的浪潮中&#xff0c;Web前端技术以其独特的魅力和广泛的应用领域&#xff0c;吸引了越来越多的开发者投入其中。那么&#xff0c;Web前端究竟可以开发哪些内容呢&#xff1f;本文将从四个方面、五个方面、六个方…

网工请自查,这十个技术问题还不会就out了

号主&#xff1a;老杨丨11年资深网络工程师&#xff0c;更多网工提升干货&#xff0c;请关注公众号&#xff1a;网络工程师俱乐部 下午好&#xff0c;我的网工朋友。 今天我想和大家聊聊几个与我们日常工作紧密相关的技术问题&#xff0c;它们都多多少少地影响了咱们的工作效率…

服务器如何有效解决源IP暴露问题

在现代互联网环境中&#xff0c;服务器的安全性至关重要。源IP暴露不仅增加了服务器遭受DDoS攻击、恶意扫描和数据泄露的风险&#xff0c;还可能影响业务的正常运行。本文将探讨如何利用技术手段&#xff0c;尤其是CDN和防火墙策略&#xff0c;来有效地解决服务器源IP暴露的问题…

C#面:Server.UrlEncode、HttpUtility.UrlDecode的区别

C#中的Server.UrlEncode和HttpUtility.UrlDecode都是用于处理URL编码和解码的方法&#xff0c;它们的区别如下&#xff1a; Server.UrlEncode&#xff1a; Server.UrlEncode是一个静态方法&#xff0c;属于System.Web命名空间。它用于将字符串进行URL编码&#xff0c;将特殊字…

JS常用HOOK脚本

Hook定义 Hook 技术又叫做钩子函数&#xff0c;在系统没有调用该函数之前&#xff0c;钩子程序就先捕获该消息&#xff0c;钩子函数先得到控制权 这时钩子函数既可以加工处理&#xff08;改变&#xff09;该函数的执行行为&#xff0c;还可以强制结束消息的传递 简单来说&am…

数字人贴牌哪家好?需要关注的核心优势有哪些?

随着人工智能时代的发展&#xff0c;数字人蕴含着的广泛的应用场景和庞大的市场需求也逐渐展现在了人们的眼前。在此背景下&#xff0c;数字人成为了一众创业赛道中的大热门&#xff0c;数字人贴牌模式也因此走红。 所谓的数字人贴牌&#xff0c;又称为数字人源码部署和数字人O…

04. fastLED像素参考(颜色设置详解)

fastLED像素参考 原文 Overview 概述 There’s two main pixel types in the library - the CRGB class and the CHSV class. CHSV objects have to be converted to CRGB objects before they can be written out. You can also write CHSV objects into the CRGB array an…

我们离成功有多远呢?只要能完成自己阶段性的目标就算是一次成功

做起一个账号&#xff0c;带好一个团队&#xff0c;经营好一家公司&#xff0c;似乎这些都能叫成功&#xff0c;成功的定义可大可小&#xff0c;而我认为只要能完成自己阶段性的目标就算是一次成功&#xff0c;毕竟每个人学历、背景、阅历、资源、认知都不同&#xff0c;很难同…

重磅!最新JCR分区、中科院分区、影响因子大汇总!

【欧亚科睿学术】 期 刊 影响因子及JCR分区 2023年JCR 2023年6月&#xff0c;科睿唯安(Clarivate Analytics)发布了最新年度期刊引证报告(JCR)。 JCR 变化盘点 ① ESCI和AHCI期刊首次获得影响因子。 据最新数据显示(截止至2023年6月28日)&#xff0c;目前共有SCIE期刊95…