Java 日志体系概述与应用

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: Java 日志体系概述与应用

JAVA常用的日志打印组件

名称

描述

log4j

提供Async Append异步实现,稳定

logback

异步下,速度快

log4j2

log4j2是log4j 1.x 的升级版

基于LMAX Disruptor库,实现了一个高性能的异步记录器。在异步方面比logback和log4j都快

 

 

java.util.looging

jdk内置日志

假设Spring 框架要打印日志,应该选择中其中哪一个组件?

发现哪个都不能选,只能基于应用实际使用的日志组件来。不然就会日志打印会多份。

怎么找到应用实际使用的日志组件 Apache Commons Loging 解决了这个问题

Apache Commons Loging (JCL)

Commons Loging 本身只提供日志接口,具体实现在运行时动态寻找对应组件?比如:log4j、jdk14looger 等。但这种动态绑定的方式当系统特别庞大的时候会出现绑定失败的问题。现在比较流行的slf4j 基于静态绑定的方式解决了这个问题?

Slf4j

log4j的作者觉得jcl不好用,自己又写了一个新的接口api,那么就是slf4j。关于slf4j的集成图如下所示

 

sl4j 本身也只提供日志接口,应用调了sl4j-api,即日志门面接口。日志门面接口本身通常并没有实际的日志输出能力,它底层还是需要去调用具体的日志框架API的,也就是实际上它需要跟具体的日志框架结合使用。由于具体日志框架比较多,而且互相也大都不兼容,日志门面接口要想实现与任意日志框架结合可能需要对应的桥接器,上图红框中的组件即是对应的各种桥接器!

与commons loging 不同的是其采用在classPath 加入以下jar包来表示具体采用哪种实现 :

  • slfj-log4j12.jar (表示指定 log4j)
  • slf4j-jdk14.jar(表示指定jdk Looging)
  • slf4j-jcl.jar(表示指定jcl)
  • log4j-slf4j-impl(表示指定log4j2)
  • logback-classic(表示指定logback)

 

 假设你们系统当中之前在用 JCL 打印日志,但这时想加入slf4j来打印日志,就会出现两类日志输出如何解决?

加入如下等JAR包jcl-over-slf4j、log4j-over-sl4j、jul-over-sl4j ,即可在使用原API的情况下,又统一至slf4j 的实现进行输出了。 .

 

JAVA日志体系结构图

日志级别

Java的日志框架一般会提供以下日志级别,缺省打开info级别,也就是debug,trace级别的日志在生产环境不会输出,在开发和测试环境可以通过不同的日志配置文件打开debug级别。

  1. fatal - 严重的,造成服务中断的错误;
  2. error - 其他错误运行期错误;
  3. warn - 警告信息,如程序调用了一个即将作废的接口,接口的不当使用,运行状态不是期望的但仍可继续处理等;
  4. info - 有意义的事件信息,如程序启动,关闭事件,收到请求事件等;
  5. debug - 调试信息,可记录详细的业务处理到哪一步了,以及当前的变量状态;
  6. trace - 更详细的跟踪信息;

上面数字越小级别越高,只有超越项目所设置的日志级别的日志才有希望"脱颖而出"打印出来

打印规则

必须使用参数化信息的方式:

logger.debug("Processing trade with id:[{}] and symbol : [{}] ", id, symbol);

对于debug日志,必须判断是否为debug级别后,才进行使用

原因如下:https://blog.csdn.net/weixin_44593504/article/details/107950828

 

if (logger.isDebugEnabled()) {
   logger.debug("Processing trade with id: " +id + " symbol: " + symbol);
}

不要进行字符串拼接,那样会产生很多String对象,占用空间,影响性能。

反例(不要这么做):

logger.debug("Processing trade with id: " + id + " symbol: " + symbol);

使用[]进行参数变量隔离

如有参数变量,应该写成如下写法:

logger.debug("Processing trade with id:[{}] and symbol : [{}] ", id, symbol);

这样的格式写法,可读性更好,对于排查问题更有帮助。

 

 

循环依赖

假设,我们在应用中调用了sl4j-api,但是呢,你引了四个jar包,slf4j-api-xx.jar,slf4j-log4j12-xx.jar,log4j-xx.jar,log4j-over-slf4j-xx.jar,于是你就会出现如下尴尬的场面

如上图所示,在这种情况下,你调用了slf4j-api,就会陷入死循环中!slf4j-api去调了slf4j-log4j12,slf4j-log4j12又去调用了log4j,log4j去调用了log4j-over-slf4j。最终,log4j-over-slf4j又调了slf4j-api,陷入死循环!

 

 

项目实战

案例一

一个项目,一个模块用log4j,另一个模块用slf4j+log4j2,如何统一输出?

其实在某些中小型公司,这种情况很常见。我曾经见过某公司的项目,因为研发不懂底层的日志原理,日志文件里头既有log4j.properties,又有log4j2.xml,各种API混用,惨不忍睹!

还有人用着jul的API,然后拿着log4j.properties,跑来问我,为什么配置不生效!简直是一言难尽!

OK,回到我们的问题,如何统一输出!OK,这里就要用上slf4j的适配器,slf4j提供了各种各样的适配器,用来将某种日志框架委托给slf4j。其最明显的集成工作方式有如下:

 

进行选择填空,将我们的案例里的条件填入,根据题意应该选log4j-over-slf4j适配器,于是就变成下面这张图

就可以实现日志统一为log4j2来输出!

ps:根据适配器工作原理的不同,被适配的日志框架并不是一定要删除!以上图为例,log4j这个日志框架删不删都可以,你只要能保证log4j的加载顺序在log4j-over-slf4j后即可。因为log4j-over-slf4j这个适配器的工作原理是,内部提供了和log4j一模一样的api接口,因此你在程序中调用log4j的api的时候,你必须想办法让其走适配器的api。如果你删了log4j这个框架,那你程序里肯定是走log4j-over-slf4j这个组件里的api。如果不删log4j,只要保证其在classpth里的顺序比log4j前即可!

 

案例二

如何让spring以log4j2的形式输出?

spring默认使用的是jcl输出日志,由于你此时并没有引入Log4j的日志框架,jcl会以jul做为日志框架。此时集成图如下

而你的应用中,采用了slf4j+log4j-core,即log4j2进行日志记录,那么此时集成图如下

那我们现在需要让spring以log4j2的形式输出?怎么办?

OK,第一种方案,走jcl-over-slf4j适配器,此时集成图就变成下面这样了

 

在这种方案下,spring框架中遇到日志输出的语句,就会如上图红线流程一样,最终以log4J2的形式输出!

OK,有第二种方案么?

有,走jul-to-slf4j适配器,此时集成图如下

 

ps:这种情况下,记得在代码中执行

SLF4JBridgeHandler.removeHandlersForRootLogger();

SLF4JBridgeHandler.install();

这样jul-to-slf4j适配器才能正常工作,详情可以查询该适配器工作原理。


相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
10天前
|
JSON Java Apache
非常实用的Http应用框架,杜绝Java Http 接口对接繁琐编程
UniHttp 是一个声明式的 HTTP 接口对接框架,帮助开发者快速对接第三方 HTTP 接口。通过 @HttpApi 注解定义接口,使用 @GetHttpInterface 和 @PostHttpInterface 等注解配置请求方法和参数。支持自定义代理逻辑、全局请求参数、错误处理和连接池配置,提高代码的内聚性和可读性。
|
19天前
|
人工智能 前端开发 Java
基于开源框架Spring AI Alibaba快速构建Java应用
本文旨在帮助开发者快速掌握并应用 Spring AI Alibaba,提升基于 Java 的大模型应用开发效率和安全性。
基于开源框架Spring AI Alibaba快速构建Java应用
|
15天前
|
存储 SQL 监控
|
15天前
|
自然语言处理 监控 数据可视化
|
13天前
|
SQL Java 数据库连接
从理论到实践:Hibernate与JPA在Java项目中的实际应用
本文介绍了Java持久层框架Hibernate和JPA的基本概念及其在具体项目中的应用。通过一个在线书店系统的实例,展示了如何使用@Entity注解定义实体类、通过Spring Data JPA定义仓库接口、在服务层调用方法进行数据库操作,以及使用JPQL编写自定义查询和管理事务。这些技术不仅简化了数据库操作,还显著提升了开发效率。
27 3
|
23天前
|
SQL 监控 Java
技术前沿:Java连接池技术的最新发展与应用
本文探讨了Java连接池技术的最新发展与应用,包括高性能与低延迟、智能化管理和监控、扩展性与兼容性等方面。同时,结合最佳实践,介绍了如何选择合适的连接池库、合理配置参数、使用监控工具及优化数据库操作,为开发者提供了一份详尽的技术指南。
30 7
|
20天前
|
SQL Java 数据库连接
在Java应用中,数据库访问常成为性能瓶颈。连接池技术通过预建立并复用数据库连接,有效减少连接开销,提升访问效率
在Java应用中,数据库访问常成为性能瓶颈。连接池技术通过预建立并复用数据库连接,有效减少连接开销,提升访问效率。本文介绍了连接池的工作原理、优势及实现方法,并提供了HikariCP的示例代码。
34 3
|
20天前
|
存储 Java 关系型数据库
在Java开发中,数据库连接是应用与数据交互的关键环节。本文通过案例分析,深入探讨Java连接池的原理与最佳实践
在Java开发中,数据库连接是应用与数据交互的关键环节。本文通过案例分析,深入探讨Java连接池的原理与最佳实践,包括连接创建、分配、复用和释放等操作,并通过电商应用实例展示了如何选择合适的连接池库(如HikariCP)和配置参数,实现高效、稳定的数据库连接管理。
39 2
|
22天前
|
缓存 Java 数据库连接
Hibernate:Java持久层框架的高效应用
通过上述步骤,可以在Java项目中高效应用Hibernate框架,实现对关系数据库的透明持久化管理。Hibernate提供的强大功能和灵活配置,使得开发者能够专注于业务逻辑的实现,而不必过多关注底层数据库操作。
12 1
|
25天前
|
移动开发 前端开发 JavaScript
java家政系统成品源码的关键特点和技术应用
家政系统成品源码是已开发完成的家政服务管理软件,支持用户注册、登录、管理个人资料,家政人员信息管理,服务项目分类,订单与预约管理,支付集成,评价与反馈,地图定位等功能。适用于各种规模的家政服务公司,采用uniapp、SpringBoot、MySQL等技术栈,确保高效管理和优质用户体验。
下一篇
无影云桌面