Spark 1.5.2和SLF4J StaticLoggerBinder

10
尽管这不会影响我的代码运行,但我为什么会收到这个警告而感到很疯狂。我正在使用Scala 2.11.7、ScalaIDE和SBT 0.13.9。
尽管这不影响代码的功能,但我试图理解为什么会出现这个警告,感到非常疯狂。 我使用的是Scala 2.11.7、ScalaIDE和SBT 0.13.9。
15/11/20 12:17:05 INFO akka.event.slf4j.Slf4jLogger: Slf4jLogger started
15/11/20 12:17:06 INFO Remoting: Starting remoting
15/11/20 12:17:06 INFO Remoting: Remoting started; listening on addresses :[akka.tcp://sparkDriver@0.0.0.0:36509]
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.

[Stage 0:=======================================================> (31 + 1) / 32]
[Stage 0:=========================================================(32 + 0) / 32]
现在我通常理解为什么会出现这种错误,但问题是我完全没有改过Spark的日志记录。如果我将slf4j-simple添加到我的项目中,它会抱怨多个SLF4j绑定,但不是这个警告。我无论如何都想不出如何使这两个东西都能很好地运行。我的代码本身使用log4j 2.4进行自己的日志记录。我尝试过以下几种方法,但无济于事:
1. 排除Spark的日志记录并包括自己的日志记录。 2. 使用log4j2将SLF4j调用路由到log4j2并排除Spark的SLF4j。 3. 包括几乎所有的SLF4j绑定,以尝试让其中一个接受它。 4. 向我的类路径、Spark的驱动程序和执行器类路径添加SLF4j jars。
如果我尝试排除Spark日志记录,我将会从Spark得到ClassNotFoundException问题,但我想不出到底是什么在做这件事。更多细节:我正在使用Spark,但我正在排除和包括我的版本Hadoop(2.7.1)。
这里是我认为根据系统类加载器提供的相关jar文件。
~/.ivy2/cache/org.slf4j/slf4j-api/jars/slf4j-api-1.7.10.jar
~/.ivy2/cache/org.slf4j/slf4j-log4j12/jars/slf4j-log4j12-1.7.10.jar
~/.ivy2/cache/log4j/log4j/bundles/log4j-1.2.17.jar
~/.ivy2/cache/org.slf4j/jul-to-slf4j/jars/jul-to-slf4j-1.7.10.jar
~/.ivy2/cache/org.slf4j/jcl-over-slf4j/jars/jcl-over-slf4j-1.7.10.jar
~/.ivy2/cache/com.typesafe.akka/akka-slf4j_2.11/jars/akka-slf4j_2.11-2.3.11.jar
~/.ivy2/cache/org.apache.logging.log4j/log4j-api/jars/log4j-api-2.4.1.jar
~/.ivy2/cache/org.apache.logging.log4j/log4j-core/jars/log4j-core-2.4.1.jar
~/.ivy2/cache/com.typesafe.akka/akka-slf4j_2.11/jars/akka-slf4j_2.11-2.4.0.jar

有人能对此提供任何见解吗?我会非常感激。

log4j: Trying to find [log4j.xml] using context classloader sun.misc.Launcher$AppClassLoader@42a57993.
log4j: Trying to find [log4j.xml] using sun.misc.Launcher$AppClassLoader@42a57993 class loader.
log4j: Trying to find [log4j.xml] using ClassLoader.getSystemResource().
log4j: Trying to find [log4j.properties] using context classloader sun.misc.Launcher$AppClassLoader@42a57993.
log4j: Using URL [file:/home/scarman/workspace-scala/Ingestions/ingestion/bin/log4j.properties] for automatic log4j configuration.
log4j: Reading configuration from URL file:/home/scarman/workspace-scala/Ingestions/ingestion/bin/log4j.properties
log4j: Parsing for [root] with value=[INFO, console].
log4j: Level token is [INFO].
log4j: Category root set to INFO
log4j: Parsing appender named "console".
log4j: Parsing layout options for "console".
log4j: Setting property [conversionPattern] to [%d{yy/MM/dd HH:mm:ss} %p %c: %m%n].
log4j: End of parsing for "console".
log4j: Setting property [target] to [System.err].
log4j: Parsed "console" options.
log4j: Parsing for [org.spark-project.jetty] with value=[WARN].
log4j: Level token is [WARN].
log4j: Category org.spark-project.jetty set to WARN
log4j: Handling log4j.additivity.org.spark-project.jetty=[null]
log4j: Parsing for [org.spark-project.jetty.util.component.AbstractLifeCycle] with value=[ERROR].
log4j: Level token is [ERROR].
log4j: Category org.spark-project.jetty.util.component.AbstractLifeCycle set to ERROR
log4j: Handling log4j.additivity.org.spark-project.jetty.util.component.AbstractLifeCycle=[null]
log4j: Parsing for [org.apache.spark] with value=[WARN].
log4j: Level token is [WARN].
log4j: Category org.apache.spark set to WARN
log4j: Handling log4j.additivity.org.apache.spark=[null]
log4j: Parsing for [org.apache.hadoop.hive.metastore.RetryingHMSHandler] with value=[FATAL].
log4j: Level token is [FATAL].
log4j: Category org.apache.hadoop.hive.metastore.RetryingHMSHandler set to FATAL
log4j: Handling log4j.additivity.org.apache.hadoop.hive.metastore.RetryingHMSHandler=[null]
log4j: Parsing for [parquet] with value=[INFO].
log4j: Level token is [INFO].
log4j: Category parquet set to INFO
log4j: Handling log4j.additivity.parquet=[null]
log4j: Parsing for [org.apache.hadoop] with value=[WARN].
log4j: Level token is [WARN].
log4j: Category org.apache.hadoop set to WARN
log4j: Handling log4j.additivity.org.apache.hadoop=[null]
log4j: Parsing for [org.apache.spark.repl.SparkILoop$SparkILoopInterpreter] with value=[INFO].
log4j: Level token is [INFO].
log4j: Category org.apache.spark.repl.SparkILoop$SparkILoopInterpreter set to INFO
log4j: Handling log4j.additivity.org.apache.spark.repl.SparkILoop$SparkILoopInterpreter=[null]
log4j: Parsing for [org.apache.spark.repl.SparkIMain$exprTyper] with value=[INFO].
log4j: Level token is [INFO].
log4j: Category org.apache.spark.repl.SparkIMain$exprTyper set to INFO
log4j: Handling log4j.additivity.org.apache.spark.repl.SparkIMain$exprTyper=[null]
log4j: Parsing for [org.apache.parquet] with value=[ERROR].
log4j: Level token is [ERROR].
log4j: Category org.apache.parquet set to ERROR
log4j: Handling log4j.additivity.org.apache.parquet=[null]
log4j: Parsing for [org.apache.hadoop.hive.ql.exec.FunctionRegistry] with value=[ERROR].
log4j: Level token is [ERROR].
log4j: Category org.apache.hadoop.hive.ql.exec.FunctionRegistry set to ERROR
log4j: Handling log4j.additivity.org.apache.hadoop.hive.ql.exec.FunctionRegistry=[null]
log4j: Finished configuring

将我的类绑定添加到slf4j在加载时定位的位置...

jar:file:/home/scarman/.ivy2/cache/org.slf4j/slf4j-log4j12/jars/slf4j-log4j12-1.7.10.jar!/org/slf4j/impl/Log4jLoggerFactory.class
org.slf4j.impl.Log4jLoggerFactory@7cef4e59
org.slf4j.impl.Log4jLoggerFactory

你在 src/main/resources 目录下有一个 log4j.properties 文件吗? - Marius Soutier
@MariusSoutier 是的先生,我会。 - Stephen Carman
我还应该注意到,Spark日志记录似乎完美地工作,我通常将日志记录设置为WARN,但如果我提高日志记录级别,所有Spark的消息都能正常传递。 - Stephen Carman
你可以将log4j绑定添加到classpath中,并使用JVM参数-Dlog4j.debug=true运行并发布输出吗? - Jem Tucker
抱歉,我重新阅读了您的帖子,发现您已经尝试过那个方法了... - Jem Tucker
显示剩余4条评论
2个回答

7
更新:这仍然适用于Spark 1.6.1。
关于这个问题的跟进和答案,我想补充一下。我注意到这个警告只会在使用Spark的parquet接口时发生。我进行了测试以确认这一点,并发现有人已经在SPARK-10057中写过这个问题。那个问题的问题是其他开发人员无法复制它,但公正地说,最初的报告人在描述问题时相当模糊。
无论如何,我决定追踪它,没有别的原因,只是为了满足我的强迫症。
所以我测试了在S3和本地磁盘上使用两个文件。文本和JSON文件不会触发此警告,但是parquet使用会触发此警告,无论文件是本地还是在S3中。这适用于读取和写入parquet文件。查看ParquetRelation.scala,我们可以看到唯一与SLF4j相关的引用。
  // Parquet initializes its own JUL logger in a static block which always prints to stdout.  Here
  // we redirect the JUL logger via SLF4J JUL bridge handler.
  val redirectParquetLogsViaSLF4J: Unit = {
    def redirect(logger: JLogger): Unit = {
      logger.getHandlers.foreach(logger.removeHandler)
      logger.setUseParentHandlers(false)
      logger.addHandler(new SLF4JBridgeHandler)
    }

我认为断言Parquet的JUL日志记录器和SLF4j桥梁之间的连接导致出现了此警告是合理的。我想它会初始化桥梁,然后发生某些事情,导致无法加载正确的静态日志记录器绑定器。我需要深入挖掘Spark的代码并进行测试才能找出原因,但至少这就是引起问题的原因。如果时间允许,我将尝试解决这个问题。

最后,这里有一个本地复制警告的代码示例。

scala> sc.setLogLevel("WARN")

scala> val d = sc.parallelize(Array[Int](1,2,3,4,5))
d: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[0] at parallelize at <console>:21

scala> val ddf = d.toDF()
ddf: org.apache.spark.sql.DataFrame = [_1: int]

scala> ddf.write.parquet("/home/scarman/data/test.parquet")
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.

0

很可能,您的项目依赖中缺少org.slf4j.slf4j-simple


2
请阅读帖子,我已经添加了它。 - Stephen Carman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接