如何管理PySpark作业中print语句的输出及文件重定向?
首先得明确:PySpark里的print()语句输出和Spark的log4j日志根本不是一回事儿——print()的内容是直接输出到驱动程序的标准输出(stdout),而log4j控制的是Spark框架本身的日志(包括Executor日志、Spark核心组件的INFO/WARN等日志),这就是为什么你改了conf/log4j.properties之后,只能看到INFO级别的框架日志,看不到print内容。
接下来分两种部署模式给你说解决方案:
1. Client部署模式(你例子里的--deploy-mode client)
这种模式下,驱动程序是在你提交任务的本地机器上运行的,所以print的内容默认会打到本地的终端stdout里。
最直接的方式就是你提到的shell重定向:
用>或者>>把整个spark-submit命令的stdout重定向到文件,还可以加上2>&1把错误输出也一起定向,方便排查问题:/usr/bin/spark-submit --master yarn --deploy-mode client --queue default /home/hadoop/app.py > /home/hadoop/output 2>&1也可以在代码里手动重定向stdout:
如果不想用shell命令的方式,也可以在PySpark代码开头修改sys.stdout的指向,比如:import sys # 用追加模式打开文件,后续所有print都会写入这里 sys.stdout = open('/home/hadoop/output', 'a') print("这条print内容会直接写到指定文件里")不过这种方式要注意:如果代码里有多线程操作,可能会出现输出混乱的问题;而且一旦修改了stdout,所有依赖stdout的输出都会进这个文件,包括PySpark本身的一些驱动端输出。
2. Cluster部署模式(--deploy-mode cluster)
如果是Cluster模式,驱动程序是运行在YARN集群的某个节点上的,这时候本地的shell重定向完全没用,因为stdout不在你的本地机器上。
查看YARN应用日志:
用YARN的日志命令就能拿到驱动程序的stdout内容,包括print的输出,还可以把输出重定向到本地文件:# 先获取应用ID,再导出日志 yarn logs -applicationId application_xxxxxx_xxxx > /home/hadoop/output改用Spark日志API替代print:
如果想让这些输出和log4j的日志整合到一起,建议把print()替换成Spark的日志工具,比如用Python的logging模块配合Spark的日志配置:import logging # 获取Spark的日志实例 logger = logging.getLogger("pyspark") logger.setLevel(logging.INFO) logger.info("这条内容会被log4j捕获,写入你配置的日志文件")这样只要你的
log4j.properties配置正确,这些日志就会和Spark的INFO级日志一起写到指定文件里,不用再单独处理print的输出。
总结
回到你的问题:是不是必须用shell重定向?
- 在Client模式下,shell重定向是最简单、最稳妥的方式,当然也可以用代码重定向stdout;
- 在Cluster模式下,shell重定向无效,得通过YARN日志查看或者改用日志API来整合到log4j中。
内容的提问来源于stack exchange,提问作者simplycoding




