将日志记录中的应用程序日志与log4j中的Spark日志分开

sbr*_*non 10 logging scala jar maven apache-spark

我有一个使用Spark的Scala Maven项目,我正在尝试使用Logback实现日志记录.我正在将我的应用程序编译到jar,并部署到安装了Spark发行版的EC2实例.我的pom.xml包含Spark和Logback的依赖项,如下所示:

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.1.7</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>log4j-over-slf4j</artifactId>
            <version>1.7.7</version>
        </dependency>
        <dependency>
            <groupId>org.apache.spark</groupId>
            <artifactId>spark-core_${scala.binary.version}</artifactId>
            <version>${spark.version}</version>
            <exclusions>
                <exclusion>
                    <groupId>org.slf4j</groupId>
                    <artifactId>slf4j-log4j12</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>log4j</groupId>
                    <artifactId>log4j</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
Run Code Online (Sandbox Code Playgroud)

提交我的Spark应用程序时,我会在命令行上打印出slf4j绑定.如果我使用java执行jar代码,则绑定是Logback.但是,如果我使用Spark(即spark-submit),则绑定到log4j.

  val logger: Logger = LoggerFactory.getLogger(this.getClass)
  val sc: SparkContext = new SparkContext()
  val rdd = sc.textFile("myFile.txt")

  val slb: StaticLoggerBinder = StaticLoggerBinder.getSingleton
  System.out.println("Logger Instance: " + slb.getLoggerFactory)
  System.out.println("Logger Class Type: " + slb.getLoggerFactoryClassStr)
Run Code Online (Sandbox Code Playgroud)

产量

Logger Instance: org.slf4j.impl.Log4jLoggerFactory@a64e035
Logger Class Type: org.slf4j.impl.Log4jLoggerFactory
Run Code Online (Sandbox Code Playgroud)

据我了解,双方log4j-1.2.17.jarslf4j-log4j12-1.7.16.jar都在/ usr /本地/火花/罐,而火花,尽管在我的pom.xml排除最有可能引用这些罐子,因为如果我删除,我给在运行时一个ClassNotFoundException火花提交.

我的问题是:有没有办法使用Logback在我的应用程序中实现本机日志记录,同时保留Spark的内部日志记录功能.理想情况下,我想将Logback应用程序日志写入文件,并允许Spark日志仍显示在STDOUT.

Ata*_*ais 10

我遇到了非常类似的问题。

我们的构建类似于您的构建(但我们使用sbt),并在此处进行了详细说明:https : //stackoverflow.com/a/45479379/1549135

在本地运行此解决方案效果很好,但随后spark-submit忽略所有排除项和新的日志记录框架(logback),因为spark的类路径优先于已部署的jar。而且由于它包含log4j 1.2.xx它,因此只需加载它,而忽略我们的设置。

我已经使用了几种来源。但引用Spark 1.6.1文档(同样适用于Spark最新版本/ 2.2.0):

spark.driver.extraClassPath

额外的类路径条目,以前置于驱动程序的类路径。注意:在客户端模式下,不得直接在应用程序中通过SparkConf设置此配置,因为此时驱动程序JVM已经启动。相反,请通过--driver-class-path命令行选项或在默认属性文件中进行设置。

spark.executor.extraClassPath

额外的类路径条目,以附加到执行者的类路径。主要是为了与旧版本的Spark向后兼容。用户通常不需要设置此选项。

此处未写的是,extraClassPath 它优先于默认Spark的类路径!

因此,现在的解决方案应该非常明显。

1.下载这些罐子:

- log4j-over-slf4j-1.7.25.jar
- logback-classic-1.2.3.jar
- logback-core-1.2.3.jar
Run Code Online (Sandbox Code Playgroud)

2.运行spark-submit

libs="/absolute/path/to/libs/*"

spark-submit \
  ...
  --master yarn \
  --conf "spark.driver.extraClassPath=$libs" \
  --conf "spark.executor.extraClassPath=$libs" \
  ...
  /my/application/application-fat.jar \
  param1 param2
Run Code Online (Sandbox Code Playgroud)

我还不确定是否可以将这些罐子放在HDFS上。我们将它们放在应用程序jar的本地。

userClassPathFirst

奇怪的是,使用Spark 1.6.1docs我也在文档中找到了这个选项:

spark.driver.userClassPathFirstspark.executor.userClassPathFirst

(实验性的)在驱动程序中加载类时,是否使用户添加的jar优先于Spark自己的jar。此功能可用于缓解Spark依赖项和用户依赖项之间的冲突。目前,这是一项实验功能。仅在群集模式下使用。

但只需设置:

--conf "spark.driver.userClassPathFirst=true" \
--conf "spark.executor.userClassPathFirst=true" \
Run Code Online (Sandbox Code Playgroud)

没有为我工作。所以我很高兴使用extraClassPath

干杯!


载入中 logback.xml

如果您在加载logback.xml到Spark时遇到任何问题,我在这里的问题可能会帮助您:将 系统属性传递给spark-submit并从类路径或自定义路径读取文件


Sam*_*awi 3

我遇到了同样的问题:我试图使用 logback 配置文件。我尝试了很多排列,但没有成功。

我使用以下 SBT 依赖项通过 grizzled-slf4j 访问 logback:

"org.clapper" %% "grizzled-slf4j" % "1.3.0",
Run Code Online (Sandbox Code Playgroud)

添加 log4j 配置文件后:

src/main/resources/log4j.properties/log4j.properties files.
Run Code Online (Sandbox Code Playgroud)

我的日志记录工作正常。