Scala 如何抑制单元测试中的火花记录?

Scala 如何抑制单元测试中的火花记录?,scala,log4j,apache-spark,Scala,Log4j,Apache Spark,因此,多亏了易于搜索的博客,我尝试了: import org.specs2.mutable.Specification class SparkEngineSpecs extends Specification { sequential def setLogLevels(level: Level, loggers: Seq[String]): Map[String, Level] = loggers.map(loggerName => { val logger = Log

因此,多亏了易于搜索的博客,我尝试了:

import org.specs2.mutable.Specification

class SparkEngineSpecs extends Specification {
  sequential

  def setLogLevels(level: Level, loggers: Seq[String]): Map[String, Level] = loggers.map(loggerName => {
    val logger = Logger.getLogger(loggerName)
    val prevLevel = logger.getLevel
    logger.setLevel(level)
    loggerName -> prevLevel
  }).toMap

  setLogLevels(Level.WARN, Seq("spark", "org.eclipse.jetty", "akka"))

  val sc = new SparkContext(new SparkConf().setMaster("local").setAppName("Test Spark Engine"))

  // ... my unit tests
但不幸的是,它不工作,我仍然得到很多火花输出,例如:

14/12/02 12:01:56 INFO MemoryStore: Block broadcast_4 of size 4184 dropped from memory (free 583461216)
14/12/02 12:01:56 INFO ContextCleaner: Cleaned broadcast 4
14/12/02 12:01:56 INFO ContextCleaner: Cleaned shuffle 4
14/12/02 12:01:56 INFO ShuffleBlockManager: Deleted all files for shuffle 4

您可以为测试使用单独的Logback配置。根据您的环境,您可能只需要使用隐藏日志的内容创建
conf/logback test.xml
。我认为这应该做到:

<configuration>
  <root level="debug">
  </root>
</configuration>

据我所知,这会捕获所有日志(level
debug
及更高级别),并且不会为它们分配任何记录器,因此它们会被丢弃。一个更好的选择是为它们配置一个文件记录器,这样,如果需要,您仍然可以访问日志


有关详细文档,请参阅。

src/test/resources
目录中的
log4j.properties
文件中添加以下代码,如果不存在,请创建文件/dir

# Change this to set Spark log level
log4j.logger.org.apache.spark=WARN

# Silence akka remoting
log4j.logger.Remoting=WARN

# Ignore messages below warning level from Jetty, because it's a bit verbose
log4j.logger.org.eclipse.jetty=WARN
当我运行我的单元测试(我使用的是JUnit和Maven)时,我只收到警告级别的日志,换言之,不再与信息级别的日志混在一起(尽管它们有时对调试很有用)


我希望这能有所帮助。

晚会有点晚了,但我在:

我还发现,如果你像下面这样调用setLogLevels,你的代码会给我带来很多麻烦

setLogLevels(Level.WARN, Seq("spark", "org", "akka"))

在与Spark log输出进行了一段时间的斗争之后,我找到了一个我特别喜欢的解决方案

如果使用slf4j,只需交换底层日志实现即可。slf4j nop是测试范围内的一个很好的数据源,它认真地获取日志输出,并将其放在从未有阳光的地方

使用Maven时,可以将以下内容添加到依赖项列表的顶部:

<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-api</artifactId>
  <version>1.7.12</version>
  <scope>provided</scope>
</dependency>

<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-nop</artifactId>
  <version>1.7.12</version>
  <scope>test</scope>
</dependency>

org.slf4j
slf4j api
1.7.12
假如
org.slf4j
slf4j nop
1.7.12
测试

注意,在依赖列表的开头拥有它是重要的,以确保给定的实现被使用,而不是那些可能与其他包一起使用的(并且可以考虑排除,以保持类路径整齐并避免意外冲突)。.

在我的例子中,我自己的一个库将logback classic引入了混合。这体现在一开始的警告中:

SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/home/alex/.ivy2/cache/ch.qos.logback/logback-classic/jars/logback-classic-1.1.2.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/home/alex/.ivy2/cache/org.slf4j/slf4j-log4j12/jars/slf4j-log4j12-1.7.5.jar!/org/slf4j/impl/StaticLoggerBinder.class]
我通过将其从依赖项中排除来解决此问题:

"com.mystuff" % "mylib" % "1.0.0" exclude("ch.qos.logback", "logback-classic")

现在,我可以在
test/resources
中添加一个
log4j.properties
文件,Spark现在使用该文件。

最简单的解决方案是:

cp $SPARK_HOME/conf/log4j.properties.template $YOUR_PROJECT/src/test/resources/log4j.properties
sed -i -e 's/log4j.rootCategory=INFO/log4j.rootCategory=WARN/g' $YOUR_PROJECT/src/test/resources/log4j.properties

感谢您的回答,所以我尝试在“src/test/resources/conf”中添加一个名为“logback test.xml”的文件,其中包含您提供的内容(也尝试了“warn”级别),但没有效果:(对不起,我真的不确定这一切。但是我们的项目在测试期间将日志定向到一个文件,所以我们只需要弄清楚它是如何设置的:)在这里的
/conf
中。在我们的源代码中没有提到该文件,因此它可能是一个神奇的默认位置。我没有看到其他任何东西。。。如果我删除了该文件,我将在测试期间开始获得日志输出(从
warn
up)。我们使用Scalatest。我试着把它放在
proj root/conf/
没有运气。我有点困惑,既然文件名和内容都引用了spark,它怎么会被选出来放进去。与此同时,我正在使用一个非常粗糙的脚本,它使用一个正则表达式来执行
grep-v
,这个正则表达式可以删除spark日志。将它粘贴到
test/resources/logback.xml
。适用于SBT和Specs2Thank@Emre。它就像intelliJ idea中java的魅力一样。新版本使用log4j2.properties(特别是2.4.0)
cp $SPARK_HOME/conf/log4j.properties.template $YOUR_PROJECT/src/test/resources/log4j.properties
sed -i -e 's/log4j.rootCategory=INFO/log4j.rootCategory=WARN/g' $YOUR_PROJECT/src/test/resources/log4j.properties