如何防止Java库污染STDOUT

时间:2019-05-20 15:07:06

标签: python-3.x pyspark py4j

我正在编写一个使用pyspark进行计算的python 3.6程序。我正在编写它,以便它可以像正常的UNIX程序一样工作,接受来自STDIN的输入并将输出发送到STDOUT。

未安装Java,并且在给定足够高的日志严重性的情况下,默认的语言是注销到STDOUT。 pyspark对此并不陌生。

在导入任何py4j库之前,我是否需要手动弄乱我的文件描述符,还是有某种方法可以从Python端处理Java端的事情,以便所有日志记录都进入STDERR?

我曾希望工作但基本上没有参加的kludge是this

import contextlib
import sys

@contextlib.contextmanager
def impolite_library_wrapper():
    real_out = sys.stdout
    sys.stdout = sys.stderr
    yield
    sys.stdout = real_out

with impolite_library_wrapper():
    import pyspark.sql
    spark_builder = pyspark.sql.SparkSession.builder.enableHiveSupport()
    spark = spark_builder.getOrCreate()

print("pls")

...我可以在这样的最小环境中运行:

$ bash
$ mkdir /tmp/pls
$ cd /tmp/pls
$ pipenv install pyspark==2.3
$ env -i "PATH=$PATH" pipenv run python wtf.py 2>/dev/null
2019-05-20 17:10:54 WARN  Utils:66 - Your hostname, <redacted> resolves to a loopback address...
2019-05-20 17:10:54 WARN  Utils:66 - Set SPARK_LOCAL_IP if you need to bind to another address
2019-05-20 17:10:55 WARN  NativeCodeLoader:62 - Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
pls

我希望这会输出pls,并且只输出pls

我看到pyspark将在Spark 3.0中使用SPARK-21094专门解决此问题;我可以接受针对pyspark的答案,但是我目前的目标是Spark 2.3。

1 个答案:

答案 0 :(得分:1)

我讨厌其中的每一个部分,但似乎有效:

import contextlib
import sys
import subprocess

class StderrOnlyPopen(subprocess.Popen):
    def __init__(self, args, bufsize=-1, executable=None,
                 stdin=None, stdout=sys.stderr, *more, **kwmore):
        super().__init__(args, bufsize, executable,
                         stdin, stdout, *more, **kwmore)

@contextlib.contextmanager
def impolite_library_wrapper():
    real_Popen = subprocess.Popen
    subprocess.Popen = StderrOnlyPopen
    yield
    subprocess.Popen = real_Popen

with impolite_library_wrapper():
    import pyspark.sql

spark_builder = pyspark.sql.SparkSession.builder.enableHiveSupport()
spark = spark_builder.getOrCreate()