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端打包加编译没有任何问题,一切还是那么的美好(毕竟花了一天时间)

其他

相关推荐
拓端研究室1 小时前
专题:2025AI时代的医疗保健业:应用与行业趋势研究报告|附130+份报告PDF、数据、可视化模板汇总下载
大数据·人工智能
小泊客3 小时前
使用讯飞星火 Spark X1-32K 打造本地知识助手
大数据·分布式·spark·大模型应用·本地知识助手
wangqiaowq4 小时前
StarRocks 3.5.7 安装部署
大数据
PPT百科4 小时前
PPT插入的音乐怎么让它播放到某一页就停?
大数据·职场和发展·powerpoint·职场·ppt模板
码上地球4 小时前
大数据成矿预测系列(八) | 从定性到概率:逻辑回归——地质统计学派的“集大成者”
大数据·逻辑回归
拓端研究室4 小时前
专题:2025中国医疗器械出海现状与趋势创新发展研究报告|附160+份报告PDF、数据、可视化模板汇总下载
大数据·人工智能·pdf
zskj_zhyl5 小时前
科技向暖,银发无忧:十五五规划中智慧养老的温度革命
大数据·人工智能·科技·物联网·生活
muxue1786 小时前
Hadoop集群搭建(上):centos 7为例(已将将安装所需压缩包统一放在了/opt/software目录下)
大数据·hadoop·centos
阿里云大数据AI技术6 小时前
【跨国数仓迁移最佳实践11】基于 MaxCompute Resource & Quota策略优化实现资源管理性能与成本最优平衡
大数据
Elastic 中国社区官方博客7 小时前
Elasticsearch 的结构化文档配置 - 递归分块实践
大数据·人工智能·elasticsearch·搜索引擎·ai·全文检索·jenkins