Spark Yarn模式下自定义本地日志文件为空的问题排查
你的sparkU.log为空,但控制台和HDFS日志正常,说明Driver和Executor的基础日志流程没问题,问题出在自定义Logger的配置传递或权限上,主要有这几个可能:
- Executor节点路径权限不足:YARN的Executor运行在各个NodeManager节点上,你指定的
/mypath/sparkU.log要么在某个NodeManager节点上不存在,要么Executor进程(Cloudera环境下通常是yarn用户)没有读写权限,导致日志写不进去。 - Log4j配置没传到Executor:Spark on YARN模式下,Driver和Executor是独立的进程,如果你只修改了Driver端的log4j配置,Executor根本没拿到这个自定义配置,自然不会往指定文件写日志。
- 日志级别不匹配:如果你的
myLogger级别设置得比ERROR高(比如FATAL),那代码里的ERROR级日志就会被过滤掉,不会写入文件。
接下来一步步修复这个问题:
1. 修正Log4j配置文件
先确保你的log4j.properties配置正确,示例如下:
# 定义自定义Logger myLogger,级别设为ERROR,绑定自定义Appender log4j.logger.myLogger=ERROR, myAppender # 关闭日志追加到rootLogger,避免重复输出 log4j.additivity.myLogger=false # 配置DailyRollingFileAppender log4j.appender.myAppender=org.apache.log4j.DailyRollingFileAppender # 日志文件路径(每个Executor节点的本地路径) log4j.appender.myAppender.File=/mypath/sparkU.log # 按日期滚动切割日志 log4j.appender.myAppender.DatePattern='.'yyyy-MM-dd # 日志格式 log4j.appender.myAppender.layout=org.apache.log4j.PatternLayout log4j.appender.myAppender.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
2. 确保所有Executor节点的路径权限
因为Executor运行在各个NodeManager节点上,所以必须在每一台NodeManager机器上执行以下命令,创建目录并设置权限:
# 创建日志目录 sudo mkdir -p /mypath # 把目录权限交给yarn用户(Cloudera环境下Executor默认以yarn用户运行) sudo chown yarn:yarn /mypath # 设置读写权限 sudo chmod 755 /mypath
3. 将Log4j配置分发到所有Executor
Spark on YARN模式下,必须把自定义的log4j配置传递给所有Executor,有两种常用方式:
方式1:提交作业时临时传递(适合测试)
用spark-submit的--files参数把配置文件分发到所有节点,同时通过spark.executor.extraJavaOptions让Executor加载这个配置:
spark-submit \ --master yarn \ --deploy-mode cluster \ --files /本地路径/custom-log4j.properties \ --conf spark.executor.extraJavaOptions="-Dlog4j.configuration=custom-log4j.properties" \ --conf spark.driver.extraJavaOptions="-Dlog4j.configuration=custom-log4j.properties" \ 你的Python作业.py
注意:如果是
client部署模式,Driver在本地,spark.driver.extraJavaOptions可以不用,但cluster模式下Driver也在YARN容器里,所以必须设置。
方式2:集群全局配置(适合长期使用)
如果你需要这个自定义日志配置长期生效,可以通过Cloudera Manager设置:
- 进入Spark服务的配置页面
- 搜索
Spark Client Advanced Configuration Snippet (Safety Valve) for spark-conf/spark-defaults.conf - 添加以下配置:
spark.executor.extraJavaOptions=-Dlog4j.configuration=file:/opt/cloudera/spark-conf/custom-log4j.properties spark.driver.extraJavaOptions=-Dlog4j.configuration=file:/opt/cloudera/spark-conf/custom-log4j.properties - 把你的
custom-log4j.properties放到所有节点的/opt/cloudera/spark-conf/路径下 - 重启Spark服务
4. Python代码中正确获取自定义Logger
确保代码里获取的是你定义的myLogger,而不是默认的日志实例:
from pyspark import SparkContext if __name__ == "__main__": sc = SparkContext(appName="CustomLoggerTest") # 获取Log4j的Java实例,创建自定义Logger log4j_instance = sc._jvm.org.apache.log4j.Logger my_logger = log4j_instance.getLogger("myLogger") # 输出ERROR级日志,测试是否写入文件 my_logger.error("这是一条来自Executor的测试错误日志") # 这里写你的业务逻辑代码... sc.stop()
如果还是没解决,去YARN UI里找到你的Application,进入对应的Executor页面,查看stdout或stderr日志,里面可能会有Log4j的报错信息,比如FileNotFoundException(路径不存在)或Permission denied(权限不足),这些能直接帮你定位问题。
内容的提问来源于stack exchange,提问作者Michail N

