记录层次结构并将 Spark log4j 记录器附加到它

Posted

技术标签:

【中文标题】记录层次结构并将 Spark log4j 记录器附加到它【英文标题】:Logging hierarchy and appending the Spark log4j Logger to it 【发布时间】:2016-12-01 16:49:43 【问题描述】:

我在 python 中有一个主脚本和其他模块文件,目前它们都在一个文件夹中。 我现在正在尝试在任何地方注入日志消息,但我并不真正了解日志层次结构 python,尽管我一直在阅读它。

    所以只是检查一下,因为这是我的测试中发生的: 如果我在我的主模块上配置一个记录器,我导入到这个主模块的模块的日志记录会自动附加到它,只要我用logging.getLogger(__name__) 调用记录器,对吗?所以导入的模块不必在子文件夹什么的?

    我在脚本中使用 PySpark,因此我按照 Spark > 2.0 中的建议创建了一个 Spark 会话,并在我的模块中使用它。但是,我希望 Spark 记录器像我的脚本记录器一样配置,并将其消息与我的模块记录器一起输出到文件或我配置的任何处理程序中。

直到现在我才发现我可以通过 Spark 记录器

log4jLogger = sc._jvm.org.apache.log4j
LOGGER = log4jLogger.LogManager.getLogger(__name__)

但我不想使用 log4j 进行日志记录,但恰恰相反。我希望将 Spark 的记录器附加到我的记录器,这将是父记录器。

此外,即使我确实使用了 Spark 的 log4j,我也不想通过使用 conf 目录中的静态 log4j.properties 文件来更改整个 Spark 的日志记录配置,但我想根据调用脚本进行日志记录.

有没有办法做到这一点?如果不是,那么将这两个记录器组合成一个配置和输出的最佳方法是什么?

【问题讨论】:

欢迎来到 Stack Overflow!你的帖子很好,所以没有必要在你的帖子开始时为成为初学者而道歉(我已经为你编辑了)。祝你好运找到答案! 【参考方案1】:

无法配置 spark 将日志转发到 python 记录器 - python 和 spark jvm 是独立的进程。

但是,正如您所注意到的,您可以使用 py4j 网关将事件从 pyspark 记录到 log4j(仅在驱动程序上)。您的 log4j 配置不需要对所有脚本都是静态的,您可以创建许多 log4j 配置并在运行时加载它们:

./bin/spark-submit --driver-java-options \
     '-Dlog4j.configuration=file:/tmp/custom_logging.properties' script.py

如果您在 YARN 中使用 yarn-cluster 运行应用程序,请记住使用 --files 发送配置文件,例如:

./bin/spark-submit --master yarn --deploy-mode cluster \
    --driver-java-options '-Dlog4j.configuration=file:logging.properties' \
    --files /tmp/logging.properties script.py

【讨论】:

我明白了,谢谢。只是为了从措辞中确定:我知道配置 spark 本身以转发日志是不可能的,但这是否也意味着也无法配置属性文件并捕获这些消息来自 python通过py4j网关?此外,如果我使用 Spark 的 py4j,如果我通过getLogger(__name__) 调用每个模块的记录器,它是否也与 python 的层次结构相同?最后,我可以在模块的开头获取记录器还是需要先创建一个 SparkContext? 啊,是的,还有一个问题:如果我导入在顶部也导入记录器的模块,py4j 是否也会禁用现有记录器,然后从主模块获取根记录器?或者调用 spark-submit 时从一开始就完成了配置,这无关紧要?更重要的是,如果上下文在主模块中,我如何在子模块中导入 py4j 记录器? 好的,所以我尝试使用 log4j Logger 来记录我的消息。我将配置文件添加到提交参数中,它确实找到了它。我使用了来自 spark 的默认属性模板 rootCategory=INFO,但是每次运行脚本时,我都会在开头收到消息 Setting default log level to "WARN".。如果我从此自定义属性文件的详细部分更改格式或其他选项,例如log4j.logger.org.spark_project.jetty=INFO,他们出现了,但是 rootLogger 仍然在 WARN,我看不到我的自定义 INFO 消息。 无法从 python 日志模块捕获日志消息到 log4j,在驱动程序上您可以通过 py4j 调用 log4j。如果您在主应用程序模块中触发上下文,请获取 log4j 记录器对象并将其传递给子模块,记录应该可以工作。此Setting default log level to "WARN" 消息来自pyspark-shell,使用spark-submit 完全加载请求的log4j.properties。 好的,再次非常感谢。我还没有在集群上尝试过,因为它还没有准备好。目前我只能在 Windows 上使用 Eclipse 环境。所以我将--master local[*] --queue PyDevSpark2.0.1 --driver-java-options "-Dlog4j.configuration=file:C:/log4j.properties" pyspark-shell 添加到PYSPARK_SUBMIT_ARGS 环境变量中,我得到了第一条消息。如果我将pyspark-shell 更改为spark-submit,或者完全删除它,我会得到一个异常:Java gateway process exited before sending the driver its port number。你会碰巧知道我怎样才能让它在这里工作吗?

以上是关于记录层次结构并将 Spark log4j 记录器附加到它的主要内容,如果未能解决你的问题,请参考以下文章

log4j 日志记录层次结构顺序

从 spark 数据框或 sql 中选择具有偏好层次结构的多个记录

log4j详解及log4j.properties配置

Log4J2 详细介绍

Log4j日志在java项目中的使用(附工程源码)

以编程方式配置 Log4j 记录器