Spark 日志错误信息分析及解决方案:log4j、SLF4j

本文分析了Spark运行时遇到的log4j和SLF4J绑定错误,指出由于不同环境的jar包版本不一致导致的日志初始化失败问题。解决方案包括明确引入特定版本的slf4j-api、slf4j-log4j12和log4j包,排除冲突的jar,并调整提交作业时的配置选项。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Spark 日志错误信息
异常信息:( 解决了好久的问题 )
1、log4j错误类「org.apache.log4j.Appender」被加载,「org.apache.log4j.ConsoleAppender」不能分配给「org.apache.log4j.Appender」,导致sparkContext初始化失败
log4j:ERROR A "org.apache.log4j.ConsoleAppender" object is not assignable to a "org.apache.log4j.Appender" variable.
log4j:ERROR The class "org.apache.log4j.Appender" was loaded by
log4j:ERROR [sun.misc.Launcher$AppClassLoader@55f96302] whereas object of type
log4j:ERROR "org.apache.log4j.ConsoleAppender" was loaded by [org.apache.spark.util.ChildFirstURLClassLoader@687080dc].
log4j:ERROR Could not instantiate appender named "console".
log4j:ERROR A "org.apache.hadoop.log.metrics.EventCounter" object is not assignable to a "org.apache.log4j.Appender" variable.
log4j:ERROR The class "org.apache.log4j.Appender" was loaded by
log4j:ERROR [sun.misc.Launcher$AppClassLoader@55f96302] whereas object of type
log4j:ERROR "org.apache.hadoop.log.metrics.EventCounter" was loaded by [org.apache.spark.util.ChildFirstURLClassLoader@687080dc].
log4j:ERROR Could not instantiate appender named "EventCounter".
log4j:ERROR A "org.apache.log4j.ConsoleAppender" object is not assignable to a "org.apache.log4j.Appender" variable.
log4j:ERROR The class "org.apache.log4j.Appender" was loaded by
log4j:ERROR [sun.misc.Launcher$AppClassLoader@55f96302] whereas object of type
log4j:ERROR "org.apache.log4j.ConsoleAppender" was loaded by [org.apache.spark.util.ChildFirstURLClassLoader@687080dc].
log4j:ERROR Could not instantiate appender named "console".
log4j:ERROR A "org.apache.log4j.varia.NullAppender" object is not assignable to a "org.apache.log4j.Appender" variable.
log4j:ERROR The class "org.apache.log4j.Appender" was loaded by
log4j:ERROR [sun.misc.Launcher$AppClassLoader@55f96302] whereas object of type
log4j:ERROR "org.apache.log4j.varia.NullAppender" was loaded by [org.apache.spark.util.ChildFirstURLClassLoader@687080dc].
log4j:ERROR Could not instantiate appender named "NullAppender".
log4j:ERROR A "org.apache.log4j.ConsoleAppender" object is not assignable to a "org.apache.log4j.Appender" variable.
log4j:ERROR The class "org.apache.log4j.Appender" was loaded by
log4j:ERROR [sun.misc.Launcher$AppClassLoader@55f96302] whereas object of type
log4j:ERROR "org.apache.log4j.ConsoleAppender" was loaded by [org.apache.spark.util.ChildFirstURLClassLoader@687080dc].
log4j:ERROR Could not instantiate appender named "console".
<think>我们遇到了SLF4J的多个绑定问题。SLF4J(SimpleLoggingFacadeforJava)是一个日志门面,它允许用户在部署时绑定所需的日志框架(如Log4j,Logback,java.util.logging等)。但是,SLF4J要求类路径中只能有一个绑定。如果发现了多个绑定,它会在启动时给出警告,并选择一个绑定(具体选择哪个可能不确定,但这里显示实际绑定的是Log4jLoggerFactory)。根据错误信息,类路径中包含了两个绑定:1.log4j-slf4j-impl-2.11.2.jar(ApacheLog4j2的SLF4J绑定)2.slf4j-log4j12-1.7.30.jar(SLF4JLog4j1.x的绑定)这两个绑定不能同时存在。我们需要排除其中一个。解决方法:在项目的依赖中,我们需要排除掉其中一个不需要的绑定。通常,如果我们使用的是Log4j2,那么应该保留log4j-slf4j-impl,并排除掉slf4j-log4j12。反之,如果使用Log4j1.x,则保留后者。假设我们使用Maven,我们可以在pom.xml中排除依赖。情况1:排除slf4j-log4j12(如果我们想使用Log4j2)找到引入slf4j-log4j12的依赖,排除它。情况2:排除log4j-slf4j-impl(如果我们想使用Log4j1.x)找到引入log4j-slf4j-impl的依赖,排除它。例如,如果我们的项目中有一个依赖引入了slf4j-log4j12,我们可以这样排除:```xml<dependency><groupId>exampleGroupId</groupId><artifactId>exampleArtifactId</artifactId><version>exampleVersion</version><exclusions><exclusion><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId></exclusion></exclusions></dependency>```或者,如果我们想排除log4j-slf4j-impl,可以这样:```xml<dependency><groupId>exampleGroupId</groupId><artifactId>exampleArtifactId</artifactId><version>exampleVersion</version><exclusions><exclusion><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-slf4j-impl</artifactId></exclusion></exclusions></dependency>```但是,我们需要知道是哪个依赖传递引入了这些jar包。我们可以使用Maven命令来查看依赖树:```mvndependency:tree```然后根据依赖树找到引入冲突jar的依赖,进行排除。另外,需要注意的是,SLF4J的绑定与具体的日志实现版本也有关系。比如,log4j-slf4j-impl是用于Log4j2的,而slf4j-log4j12是用于Log4j1.x的。同时,它们对应的日志配置也不同。如果我们已经决定使用Log4j2,那么除了使用log4j-slf4j-impl绑定外,还需要包含log4j-core和log4j-api等依赖,并且配置log4j2.xml(或其他格式的Log4j2配置)。同时,确保没有其他SLF4J绑定存在。如果我们使用其他日志框架,比如Logback,那么我们应该使用slf4j与Logback的绑定(即引入logback-classic),并排除其他绑定。总结步骤:1.确定要使用的日志框架。2.在依赖树中找到并排除冲突的绑定(即不想要的绑定)。3.确保正确的绑定和日志实现依赖存在。4.配置相应的日志配置文件。现在,假设我们决定使用Log4j2,那么我们需要保留log4j-slf4j-impl,并排除slf4j-log4j12。示例:假设我们的项目中,一个依赖A引入了slf4j-log4j12,我们可以在依赖A中排除它:```xml<dependency><groupId>com.example</groupId><artifactId>projectA</artifactId><version>1.0</version><exclusions><exclusion><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId></exclusion></exclusions></dependency>```同时,我们确保引入了Log4j2的依赖:```xml<dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-api</artifactId><version>2.17.1</version></dependency><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-core</artifactId><version>2.17.1</version></dependency><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-slf4j-impl</artifactId><version>2.17.1</version></dependency>```注意:版本号应该根据实际需要选择。如果我们使用Logback,那么应该这样引入:```xml<dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>1.2.3</version></dependency>```并且排除其他所有的SLF4J绑定。最后,关于错误信息中提到的“Actualbindingisoftype[org.apache.logging.slf4j.Log4jLoggerFactory]”,这表示当前SLF4J实际绑定到了Log4j2(因为Log4jLoggerFactory是Log4j2的)。所以,如果我们希望使用Log4j2,那么可以忽略这个警告,因为我们实际绑定到了我们想要的。但是,为了避免潜在的问题(比如多个绑定可能会导致不可预料的行为),我们应该排除另一个绑定。但是,如果这不是我们期望的绑定,那么我们需要排除当前的绑定并引入我们想要的。因此,关键是根据我们期望的日志实现来排除冲突的绑定。如果不知道如何排除,或者项目依赖复杂,也可以使用Maven的dependency插件来分析依赖。另外,如果使用Gradle,排除依赖的方式类似:```groovydependencies{implementation('exampleGroupId:exampleArtifactId:exampleVersion'){excludegroup:'org.slf4j',module:'slf4j-log4j12'}}```或者排除log4j-slf4j-impl:```groovydependencies{implementation('exampleGroupId:exampleArtifactId:exampleVersion'){excludegroup:'org.apache.logging.log4j',module:'log4j-slf4j-impl'}}```总之,解决多个绑定的核心就是排除多余的绑定,只保留一个。注意:有时候,可能还有其他的传递依赖引入了其他的绑定,所以一定要仔细检查依赖树。下面是一个完整的Maven排除多个冲突绑定的例子:假设通过`mvndependency:tree`发现:```[INFO]+-org.springframework.boot:spring-boot-starter-log4j2:jar:2.1.6.RELEASE:compile[INFO]|+-org.apache.logging.log4j:log4j-slf4j-impl:jar:2.11.2:compile...[INFO]+-org.apache.spark:spark-core_2.12:jar:2.4.4:compile[INFO]|+-org.slf4j:slf4j-log4j12:jar:1.7.26:compile```我们想使用Log4j2,所以排除spark-core中的slf4j-log4j12:```xml<dependency><groupId>org.apache.spark</groupId><artifactId>spark-core_2.12</artifactId><version>2.4.4</version><exclusions><exclusion><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId></exclusion></exclusions></dependency>```这样,就只剩下log4j-slf4j-impl,问题解决。最后,如果问题仍然存在,检查是否有其他依赖引入了绑定,继续排除。</think> SLF4J 出现多个绑定的问题是因为类路径中存在多个日志实现绑定(此处为 Log4j2 和 Log4j1.x)。以下是详细的解决方案: ### 问题解决方案 1. **确定要保留的绑定**(推荐保留 Log4j2): ```xml <!-- 在 pom.xml 中排除不需要的绑定 --> <dependency> <groupId>your-project-group</groupId> <artifactId>your-project-artifact</artifactId> <version>1.0</version> <exclusions> <!-- 排除 Log4j 1.x 绑定 --> <exclusion> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> </exclusion> </exclusions> </dependency> ``` 2. **添加必要的 Log4j2 依赖**(如果尚未添加): ```xml <dependencies> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>2.19.0</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.19.0</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-slf4j2-impl</artifactId> <version>2.19.0</version> </dependency> </dependencies> ``` ### 依赖树检查方法 使用 Maven 命令检查依赖来源: ```bash mvn dependency:tree -Dincludes=org.slf4j:slf4j-log4j12,org.apache.logging.log4j:log4j-slf4j-impl ``` 输出示例: ``` [INFO] com.example:demo:jar:1.0 [INFO] +- org.springframework.boot:spring-boot-starter:jar:3.1.0 [INFO] | \- (org.slf4j:slf4j-log4j12:jar:1.7.36:runtime) [INFO] \- org.apache.spark:spark-core_2.12:jar:3.3.1 [INFO] \- (org.apache.logging.log4j:log4j-slf4j-impl:jar:2.18.0:compile) ``` ### 关键解释 1. **冲突原理**: - `log4j-slf4j-impl` 是 Log4j2 的绑定 - `slf4j-log4j12` 是 Log4j 1.x 的绑定 - SLF4J 不允许同时存在多个绑定 2. **排查重点**: - 使用 `mvn dependency:tree` 定位冲突依赖 - 优先排除旧版绑定(如 Log4j1.x) - 确保所有模块使用统一日志实现 3. **Gradle 排除方法**: ```groovy dependencies { implementation('org.apache.spark:spark-core_2.12') { exclude group: 'org.slf4j', module: 'slf4j-log4j12' } } ``` ### 验证修复 启动应用后应仅显示一条绑定信息: ``` SLF4J: Actual binding is of type [org.apache.logging.slf4j.Log4jLoggerFactory] ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值