Spark升级中对log4j中的一些思考

背景

最近在做Spark版本的升级(由spark3.1升级到spark3.5),其实单纯从spark升级涉及到的log4j来说,并没有什么能够记录的,

但是由于公司内部做了Spark的serveless,把spring和spark混在了一起,所以导致了不可预见的问题

分析

我们Spring用的是5.2.6.RELEASE版本,由于spark用的是logback作为日志的具体实现,而Spark在3.1和spark 3.5是采用了不同的日志具体实现:

在 spark3.1中采用的是log4j1 (log4j + slf4j-log4j2),spark 3.5中采用的是log42(log4j-core + log4j-api + log4j-slf4j2-impl),

再加上由于其他log包引入,比如说:

1. "org.apache.logging.log4j" % "log4j-1.2-api"

2. "org.apache.logging.log4j" % "log4j-to-slf4j"

3. "org.slf4j" % "slf4j-log4j12"

4. "org.slf4j" % "slf4j-api"

5. "org.slf4j" % "jcl-over-slf4j"

6. "org.slf4j" % "jul-to-slf4j"

7. "commons-logging" % "commons-logging"

8. "ch.qos.logback" % "logback-classic"

9. "ch.qos.logback" % "logback-core"

这真是太酸爽了,一时间几乎日志系统都齐全了,出现的错误也是千奇百怪:

1. Getting Exception org.apache.logging.slf4j.SLF4JLoggerContext cannot be cast to org.apache.logging.log4j.core.LoggerContext

2. java.lang.StackOverflowError at org.apache.logging.log4j.util.StackLocator.getCallerClass

3. Slf4j: Found slf4j-api dependency but no providers were found

4. java.lang.AssertionError: unsafe symbol Level (child of package log4j) in runtime reflection universe
        at scala.reflect.internal.Symbols$Symbol.<init>(Symbols.scala:224)
        at scala.reflect.internal.Symbols$TypeSymbol.<init>(Symbols.scala:3070)
        at scala.reflect.internal.Symbols$ClassSymbol.<init>(Symbols.scala:3261)
        at scala.reflect.internal.Symbols$StubClassSymbol.<init>(Symbols.scala:3539)

这些问题一度让我认为是Spark scala版本升级导致的(当然也是我在其中排除了各种乱七八糟的log包导致的问题),以上问题在google中也能搜寻到,

但是最后反思了一下:还是对log sl4j logback理解的不够:

  1. slf4j 原理及使用原则,可以参考slf4j 原理及使用原则
    这里面讲述了slf4j的一些原理以及关系

  2. 常用日志框架(Log4j,Slf4j,Logback)之间到底有啥区别 可以参考 常用日志框架(Log4j,Slf4j,Logback)之间到底有啥区别
    这里面讲了logback与其中的关系

  3. Difference between slf4j-log4j12 and log4j-slf4j-impl,可以参考Difference between slf4j-log4j12 and log4j-slf4j-impl
    这里讲了slf4j1.x slf4j2.x与Log4j 2.x Log4j 1.2的jar包的关系

  4. 秒懂log4j1与log4j2的区别,参考秒懂log4j1与log4j2的区别
    这里最为关键:

     slf4j的成功在于他的高屋建瓴,俯视一切。slf4j是日志门面(像:java的接口,没有提供任何实现),通过提供各种桥接器,适配各种日志框架(log4j1,logback等)。log4j1并没有这样的高度,于是log4j2就借鉴了slf4j的设计,log4f2有两部分组成:log4j-api、log4j-core。log4j-api和slf4j是相同的,都是日志门面,log4j-core是对log4j-api的实现,和log4j1、logback是相同的, 并且通过桥接器log4j-api还可以适配其他的日志系统(logback等)。这样log4j2就成了一个文堪比slf4,武可斗logback的双优生
    

    这里说明可以用log4j-api 适配logback ,再加上极客时间的讨论

     Geek_58afe9 问:
      
     "其实,我们只是换成了 Log4j2 API,真正的日志记录还是走的 Logback 框架。没错,这就是 SLF4J 适配的一个好处。". Log4j2 和 LogBack 不是同质化产品吗, Log4j2 api 怎么会走到Logback?
     作者回复: log4j2 API,并不是log4j 你在ch.qos.logback.classic.Logger.buildLoggingEventAndAppend设一个断点看一下整个过程就知道了,或者直接访问 https://github.com/JosephZhu1983/java-common-mistakes/blob/master/src/main/java/org/geekbang/time/commonmistakes/logging/placeholder/log4j2api_to_slf4j_to_logack.jpg 查看```
    

从以上我们知道 log4j2 不仅仅可以和slf4j适配,也可以和logback适配,这提供了另一条思路:不要只考虑slf4j和log4的爱恨情仇,也得考虑log4j和logback的亲密关系

解决

最终我们只留下了log4j2 (log4j-core + log4j-api) + logback (logback-classic + logback-core) ,其他的都排除掉,web端打包加编译没有任何问题,一切还是那么的美好(毕竟花了一天时间)

其他

相关推荐
拓端研究室TRL2 小时前
【梯度提升专题】XGBoost、Adaboost、CatBoost预测合集:抗乳腺癌药物优化、信贷风控、比特币应用|附数据代码...
大数据
黄焖鸡能干四碗2 小时前
信息化运维方案,实施方案,开发方案,信息中心安全运维资料(软件资料word)
大数据·人工智能·软件需求·设计规范·规格说明书
编码小袁2 小时前
探索数据科学与大数据技术专业本科生的广阔就业前景
大数据
WeeJot嵌入式3 小时前
大数据治理:确保数据的可持续性和价值
大数据
zmd-zk4 小时前
kafka+zookeeper的搭建
大数据·分布式·zookeeper·中间件·kafka
激流丶4 小时前
【Kafka 实战】如何解决Kafka Topic数量过多带来的性能问题?
java·大数据·kafka·topic
测试界的酸菜鱼4 小时前
Python 大数据展示屏实例
大数据·开发语言·python
时差9534 小时前
【面试题】Hive 查询:如何查找用户连续三天登录的记录
大数据·数据库·hive·sql·面试·database
Mephisto.java4 小时前
【大数据学习 | kafka高级部分】kafka中的选举机制
大数据·学习·kafka
Mephisto.java4 小时前
【大数据学习 | kafka高级部分】kafka的优化参数整理
大数据·sql·oracle·kafka·json·database