日志系统学习与应用治理实践

标准——log4j

最开始出现的是log4j,也是应用最广泛的日志系统,它的出现使Java日志系统的标准基本确定了。

它提出的一些基本理念,一直沿用至今:

  • Appender: 实际的输出是通过Appender(输出源)。有许多可用的Appender,比如FileAppender、ConsoleAppender、SocketAppender、SyslogAppender、NTEventLogAppender,甚至SMTPAppender。多个Appender可以被关联到任何Logger上,所以可以到多个输出文件上记录相同的信息。
  • Logger:一个允许应用记录日志的对象。每个Logger相互独立,通过名字或标识符来区分
  • Level : 日志级别,通过配置不同的日志界别来打印不同的日志信息。

混乱——jul

在java1.4版本,SUN引入了一个新的API,叫java.util.logging,

规整—— commons-logging (jcl)

log4j与jul的共存,各个日志系统互相没有关联,没有统一和规整化API,开发使用严重依赖于具体实现,毫无扩展可言

为了解决这个问题,Apache弄出了一个commons-logging的框架。

commons-logging并非一个日志打印框架,而是一个API bridge, 它起到一个连接和沟通的作用,开发者可以使用它来兼容jul和log4j,第三方库可以使用commons-logging来做一个中间层,去灵活选择jul或者log4j,而不必强加依赖。

但jcl对jul和log4j的配置问题兼容得并不好,更糟糕的是,由于commons-logging使用动态绑定,可能会遇到类加载问题,导致NoClassDefFoundError的错误出现。因此又出现了slf4j

比如:子加载器加载 JCL 接口,JCL 接口使用当前或父类加载器加载接口实现,这就导致我们的子加载器的类不能访问 JCL 实现。而slf4j使用了编译时强绑定,只会加载依赖的一个实现,所有的 API 绑定都是在编译时完成的,slf4j-xxx.jar 或 logback-classic.jar 所有的依赖文件都打包在了一起

使用 Jakarta Commons Logging 时遇到的类加载器问题的分类 - 文章 - 代码饭 (daimafans.com)

发展期——slf4j,logback

slf4j

slf4j(Simple logging facade for Java)是log4j作者的又一力作,slf4j的设计相对较为精巧,作者将接口以及实现分开,其中slf4j-api中定义了接口,开发者需要关心的就是这个接口,无需再关心下层如何实现,同时各个是slf4j接口的实现者只要遵循这个接口,就能够做到日志系统间的无缝兼容。

SLF4J是简单的日志外观模式框架,抽象了各种日志框架例如Logback、Log4j、Commons-logging和JDK自带的logging实现接口

有各种桥接包,它使得用户可以在部署时使用自己想要的日志框架。

SLF4J是轻量级的,在性能方面几乎是零消耗的。虽然sl4j没有限定具体的日志实现方式,但作者更推荐logback,因为其具有更强大的功能与性能。

SFL4j在编译时静态绑定日志框架避免了JCL动态绑定带来的一系列问题,SLF4j+Logback在设计和性能上都优于Commons-logging+Log4j。

使用slf4j,要注意里面的几个概念

  • slf4j本身的api:slf4j-api 。
  • 绑定器:例如slf4j-#日志实现#-version.jar,通过绑定器绑定到真正的日志实现。一个应用中,只可以存在一个有效的绑定器和对应的日志实现。
  • 桥接器:例如#日志实现#-over-slf4j,通过桥接器,将原先的日志框架或实现代理到slf4j-api上。这样,应用无需修改原先的日志代码。

logback

Logback是由log4j创始人设计的又一个开源日志组件。

logback当前分成三个模块:logback-core,logback- classic和logback-access。Logback是Log4j的改进版本,而且原生支持SLF4J,性能也更好。

未来——log4j2?

Log4j1.x已经被广泛应用到各个系统及框架中。然后,1.x毕竟太古老,代码很久没有更新。目前,Log4j 1.x的代码已经很难维护,因为它依赖于很多Jdk老版本的api。

作为Log4j 1.x的替代品,SLF4J/Logback已经对日志系统做了很大的改进,主要是由于其异步输出性能优越,尤其是在分布式系统中,性能是logback的10倍以上,而且支持动态配置等。

常见的日志使用方式

commons-logging + log4j

应用中使用jcl接口编码(见代码片段1-4),实际输出使用log4j配置文件,这是大多数应用使用的方式,尤其是较老的一些应用。所需要的jar包比较简单
+ commons-logging
+ log4j

如果代码使用的jul日志系统,那么则只需要commons-logging这个jar即可。

slf4j + logback

slf4j最佳的使用方式是用logback作为日志系统输出,应用中使用slf4j接口编码,所需要的包为
+ slf4j-api
+ logback-core
+ logback-classic(已含跟slf4j绑定的包

这只是最恰到的使用方式,实际情况由于应用的跨度比较长,可能老的代码或者依赖的二分库使用的jcl,log4j或者jul编码,而想升级到logback,则需要使用桥接包

slf4j+log4j

虽然使用slf4j的推荐日志系统是logback,但可能也会有些应用会采用log4j作为日志系统进行输出。
应用代码使用slf4j接口编码,使用log4j作为实际输出系统,需要引入如下jar包:
+ slf4j-api
+ slf4j-log4j12  将slf4j绑定到了log4j输出
+ log4j

jcl+slf4j+log4j

这种情况下,应用日志代码使用commons-logging和slf4j 混合编码,需要将jcl桥接到了slf4j上,并使用log4j作为日志输出。所需要的jar包如下:
+ jcl-over-slf4j
+ slf4j-api
+ slf4j-log4j12
+ log4j

桥接器允许有多个,绑定器(logback(logback-classic), slf4j-log4j12, slf4j-jdk14三种只能存在其一只能有一个

依赖空包的原理

maven在解析依赖的时候,有两个原则:

  • 第一原则是路径最短有限原则,例如A-->B-->C-1.0(A依赖B,B依赖C的1.0版本),同时A-->D-->E-->C-2.0,那么从A来看,最终会依赖C的1.0版本进来,因为路径最短,最可信,这个例子也推翻了“高版本覆盖低版本”的错误言论。
  • 第二原则是优先声明原则(pom中的声明顺序),这是对第一原则的补充,就是路径长度相同(第一原则好无力)的情况下,第二原则开始决策微调。

尽量使用dependencyManagement:

  • 它表示子项目 不强制依赖(关联)里面的依赖包。
  • 在父项目里可以这么用引入依赖,在具体实现的子项目里用这个没有意义,因为它不去关联jar,这里面的jar不会被关联和打包,子项目的依赖不指定版本默认会找他的版本

依赖空包:

  • 可以实现全局排掉这个包

排除jcl的影响:如果应用程序使用slf4j,但是依赖的组件引入jcl,如何排除组件使用jcl的影响?

  • 依赖jcl的一个空包。
  • 依赖jcl桥接到slf4j的包 jcl-over-slf4j。
  • 原理:桥接包jcl-over-slf4j的类路径和jcl里面的保持一致,但是逻辑是让slf4j来做具体的日志代理。

排除系统间接引入具体的日志实现造成的影响:如果应用程序使用slf4j+logback,但是依赖的组件直接使用log4j。

  • 依赖log4j的一个空包。
  • 依赖log4j桥接到slf4j的包 log4j-over-slf4j。防止应用使用log4j的方式

jcl +log4j 替换成slf4j+logback实践

若要将老的应用的日志系统从 jcl + log4j,替换成slf4j+logback,主要是依赖的jar包需要修改,再配置logback的配置文件。

  • 依赖slf-api和具体的日志实现logback-core。
  • 去除 jcl,log4j的依赖:将其依赖版本修改为一个空包,避免其他jar包间接引入。
  • 添加 jcl和log4j 到 slf4j的连接器:log4j-over-slf4j,jcl-over-slf4j。

具体jar包依赖如下:

<!--for log start-->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.2</version>
</dependency>

<!--强制使用 logback的绑定-->
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-core</artifactId>
    <version>1.1.2</version>
</dependency>
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.1.2</version>
</dependency>

<!--slf4j 的桥接器,将第三方类库对 log4j 的调用 delegate 到 slf api 上-->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>log4j-over-slf4j</artifactId>
    <version>1.7.13</version>
</dependency>

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>jcl-over-slf4j</artifactId>
    <version>1.7.13</version>
</dependency>
<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>jul-to-slf4j</artifactId>
  <version>1.7.25</version>
</dependency>
<!--桥接器end -->

<!--强制排除 log4j 的依赖,全部 delegate 到 log4j-over-slf4j 上-->
<!--连接器只能有一个:slf4j-log4j12与logback-basic不能共存 -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>99.0-does-not-exist</version>
</dependency>
<!--强制使用 logback的绑定,这里去除对log4j 的绑定-->
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>99.0-does-not-exist</version>
</dependency>

<dependency>
    <groupId>apache-log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>999-not-exist</version>
</dependency>
<!-- 使用slf4j框架,就要排除jcl框架-->
<dependency>
    <groupId>commons-logging</groupId>
    <artifactId>commons-logging</artifactId>
    <version>99.0-does-not-exist</version>
</dependency>
<!--for log end-->

系统应用日志治理

目前状况

  • 应用两个门面使用混乱包含JCL和slf4j,具体实现只有log4j,但是没有预防其他包在不知情状况下引入另外的实现logback,导致应用打不出来日志且没有日志文件。
  • 之前通过手动排除logback包,日志已经恢复,但未来完全不可控。

目标

  • 保证日志系统持续稳定运行。

处理方案

  • 日志实现使用log4j,按步不动。
  • 门面全部桥接到slf4j,因为JCL本身兼容性不好会出很多问题。
  • 避免其他jar包间接引入 其他日志实现包 导致日志系统崩溃。

具体实现

  • 1,依赖门面slf4j、jcl 和 具体的日志实现log4j。
  • 2,去除 logback 的依赖,不能去除JCL的依赖(目前线上部分在用):将其依赖版本修改为一个空包,避免其他jar包间接引入。
  • 3,添加jcl和jul 到 slf4j的桥接器:jul-over-slf4j,jcl-over-slf4j。
<!--for log start-->
<!--依赖门面slf4j、jcl-->
<dependency>
	<groupId>org.slf4j</groupId>
	<artifactId>slf4j-api</artifactId>
	<version>1.7.26</version>
</dependency>
<dependency>
    <groupId>commons-logging</groupId>
    <artifactId>commons-logging</artifactId>
    <version>1.2</version>
</dependency>

<!--强制使用 log4j的绑定-->
<dependency>
	<groupId>org.slf4j</groupId>
	<artifactId>slf4j-log4j12</artifactId>
	<version>1.7.5</version>
</dependency>
<dependency>
	<groupId>log4j</groupId>
	<artifactId>log4j</artifactId>
	<version>1.2.17</version>
</dependency>

<!--slf4j 的桥接器-->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>jcl-over-slf4j</artifactId>
    <version>1.7.5</version>
</dependency>
<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>jul-to-slf4j</artifactId>
  <version>1.7.25</version>
</dependency>
<!--桥接器end -->

<!--强制排除 logback 的依赖-->
<!--连接器只能有一个:slf4j-log4j12与logback-basic不能共存 -->
<dependency>
	<groupId>ch.qos.logback</groupId>
	<artifactId>logback-classic</artifactId>
	<version>999-not-exist</version>
</dependency>
<dependency>
	<groupId>ch.qos.logback</groupId>
	<artifactId>logback-core</artifactId>
	<version>999-not-exist-v1</version>
</dependency>
<!--for log end--

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
对于建立一个数据分析系统学习线路图,可以考虑以下步骤: 1. 学习基础数据分析概念:了解数据分析的基本概念、方法和技术,包括数据收集、清洗、转换、可视化和解释。 2. 学习统计学知识:熟悉统计学基本概念,例如概率、假设检验、回归分析等,这些知识对于数据分析至关重要。 3. 学习数据收集和清洗:了解不同类型的数据收集方法,例如问卷调查、日志记录、传感器数据等,并学习如何对数据进行清洗和预处理,以确保数据质量。 4. 学习数据分析工具和编程语言:掌握常用的数据分析工具和编程语言,例如Python、R、SQL等。这些工具可以帮助你进行数据处理、可视化和建模。 5. 学习数据可视化技术:了解如何使用图表、图形和仪表板等工具将数据可视化,以便更好地理解和传达分析结果。 6. 学习机器学习和预测建模:了解机器学习的基本原理和常见算法,例如线性回归、决策树、随机森林等。这些技术可以帮助你进行预测建模和数据驱动决策。 7. 学习数据仓库和数据挖掘技术:了解数据仓库的概念和设计原则,学习如何使用数据挖掘技术从大规模数据集中发现有用的信息和模式。 8. 学习数据隐私和安全:了解数据隐私和安全的基本原则,学习如何处理敏感数据并保护用户隐私。 9. 学习实践案例和项目:通过实践案例和项目来应用所学知识,例如分析真实世界的数据集或解决实际业务问题。这将帮助你巩固理论知识并提升实际应用能力。 10. 持续学习和跟进最新趋势:数据分析领域不断发展,新技术和方法层出不穷。因此,持续学习和跟进最新趋势是建立一个成功的数据分析系统的关键。 以上是一个大致的学习线路图,你可以根据自己的兴趣和实际需求进行调整和深入学习。祝你学习顺利!
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值