Grails环境下如何覆盖Spark Core_2.12 (v3.3.0)默认日志配置
问题背景
- 运行环境为Grails 2.5.4框架,需要通过SparkSession实例生成Parquet格式输出,已将Spark Core及关联依赖升级至v3.3.0版本。
- 调用
SparkSession.builder()初始化时,控制台输出大量冗余INFO、WARN级别日志,首行输出Using Spark's default log4j profile: org/apache/spark/log4j2-defaults.properties,确认Spark加载了内置默认日志配置。 - 初始化SparkSession前已通过编程方式批量设置各包路径日志级别为ERROR,代码如下:
Configurator.setLevel("org", Level.ERROR) Configurator.setLevel("org.apache.spark", Level.ERROR) Configurator.setLevel("akka", Level.ERROR) Configurator.setLevel("scala", Level.ERROR) Configurator.setLevel("java", Level.ERROR) Configurator.setLevel("org.slf4j", Level.ERROR) Configurator.setLevel("com", Level.ERROR) Configurator.setLevel("javax", Level.ERROR) Configurator.setLevel("jakarta", Level.ERROR) Configurator.setLevel("io", Level.ERROR) Configurator.setLevel("net", Level.ERROR)
- 上述配置未生效,需要可落地的Spark默认日志配置覆盖方案。
原因说明
编程配置不生效的本质原因是:Spark 3.3.0默认采用Log4j 2作为日志实现,内置的log4j2-defaults.properties在SparkContext初始化的最早期就会被加载,Configurator.setLevel的执行时机晚于Spark内置日志配置的初始化节点,因此启动阶段的日志无法被拦截。
可行解决方案
按稳定性从高到低排序:
方案1:JVM启动参数指定自定义Log4j2配置(推荐)
在应用启动的JVM参数中添加如下配置,直接跳过Spark内置默认配置的加载流程:
-Dlog4j2.configurationFile=file:/你的自定义log4j2配置文件绝对路径/log4j2.properties
自定义配置文件可直接将全局日志级别设为ERROR,示例配置:
status = error name = SparkCustomLogConfig appender.console.type = Console appender.console.name = STDOUT appender.console.layout.type = PatternLayout appender.console.layout.pattern = %d{yy/MM/dd HH:mm:ss} %p %c{1}: %m%n rootLogger.level = error rootLogger.appenderRef.stdout.ref = STDOUT
该配置在JVM启动阶段就会加载日志规则,执行时机早于所有Spark类的初始化,能完全屏蔽所有启动阶段的冗余日志。
方案2:构建阶段排除Spark内置日志配置文件
如果使用Gradle/Maven管理项目依赖,可以直接将Spark依赖中自带的默认配置文件从classpath中排除,避免其被自动加载。
以Gradle配置为例:
implementation('org.apache.spark:spark-core_2.12:3.3.0') { // 排除内置的默认log4j2配置 exclude 'org/apache/spark/log4j2-defaults.properties' }
排除后,存放在项目resources目录下的自定义Log4j2配置文件会被正常加载,不会被内置配置覆盖。
方案3:提前重置日志上下文(无法修改启动参数时使用)
如果没有权限修改JVM启动参数,需要将日志配置的执行时机提前到所有Spark相关类被加载之前,比如Grails项目中放在BootStrap.groovy最顶部,早于所有Bean初始化逻辑执行,执行前先重置Log4j2上下文,清除Spark提前加载的默认配置:
import org.apache.logging.log4j.core.config.Configurator import org.apache.logging.log4j.Level // 先重置日志上下文,清空默认配置 Configurator.shutdown() Configurator.reconfigure() // 再设置日志级别 Configurator.setRootLevel(Level.ERROR) Configurator.setLevel("org.apache.spark", Level.ERROR)
注意:该方案如果执行时机不够靠前,仍会漏出最开头的几行Spark启动日志,稳定性弱于前两种方案。
注意事项
- Spark 3.x不再兼容Log4j 1.x的配置格式,如果项目中仍在使用1.x版本的
log4j.properties,配置完全不会生效,必须替换为Log4j 2对应的配置格式。 - 日志中出现的
Unable to load native-hadoop library属于WARN级别,配置全局ERROR级别后会自动屏蔽,无需额外处理。 - 如果项目存在SLF4J绑定冲突,先排除多余的SLF4J绑定包,否则会出现日志配置不生效的问题。
内容的提问来源于stack exchange,提问作者dev-eloper
相关产品推荐
相关产品推荐

