2014-12-02 115 views
19

所以感谢容易googleable博客我想:如何在单元测试中抑制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 = 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 

回答

32

添加以下代码到log4j.properties文件src/test/resources目录内,创建文件/目录。如果不存在

# 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),我只接收WARN级别的日志,换句话说就是不再使用INFO级别的日志(虽然它们在调试时可能有用)。

我希望这会有所帮助。晚

+0

适用于SBT,specs2 – samthebest 2014-12-10 10:36:52

+1

谢谢@Emre。它在intelliJ的想法中像java一样的魅力。 – 2017-01-21 06:46:28

2

您可以使用一个单独的logback配置测试。根据您的环境,您可能只需创建隐藏日志的东西即可创建conf/logback-test.xml。我认为这应该这样做:

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

据我了解,这捕获所有日志(水平debug及更高版本)和没有记录分配给他们,因此他们被丢弃。一个更好的选择是为它们配置一个文件记录器,所以如果你愿意,你仍然可以访问日志。

请参阅http://logback.qos.ch/manual/configuration.html的详细文档。

+0

感谢您的回答,所以我尝试在您所提供的内容中添加一个名为“logback-test.xml”的“src/test/resources/conf”文件(尝试级别“警告”),但它已经没有效果:( – samthebest 2014-12-02 17:17:40

+0

我真的不确定所有这些,对不起。但是我们的项目在测试期间将日志导向文件,所以我们只需要弄清楚它是如何设置的:)。 'logback-test.xml'在这里位于'/conf'中。该文件在我们的源代码中没有提及,因此它可能是一个神奇的默认位置。我没有看到其他任何东西......如果我删除文件,我会在测试过程中开始获取日志输出(从'warn'开始)。我们使用Scalatest。 – 2014-12-03 10:10:21

+1

我试着把它放在'proj-root/conf /'不行。我有点困惑,因为文件名或内容引用会引发火花,所以它会如何获得选择。在此期间,我使用了一个非常冒险的脚本,它使用正则表达式来执行'grep -v',它可以删除火花日志。 – samthebest 2014-12-03 16:22:48

3

一个小党,但我发现这个在spark example code

def setStreamingLogLevels() { 
    val log4jInitialized = Logger.getRootLogger.getAllAppenders.hasMoreElements 
    if (!log4jInitialized) { 
     // We first log something to initialize Spark's default logging, then we override the 
     // logging level. 
     logInfo("Setting log level to [WARN] for streaming example." + 
     " To override add a custom log4j.properties to the classpath.") 
     Logger.getRootLogger.setLevel(Level.WARN) 
    } 
} 

我还发现,你的代码,如果你调用setLogLevels喜欢它下面切出很多了把我的。

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

后星火日志输出挣扎,以及一段时间,我发现了一个blog post与我特别喜欢的解决方案。

如果使用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> 

注意可能,以确保是有它在依赖列表的开头重要的是,给定的实现被用来代替那些可能与其他软件包一起提供的软件(为了保持你的课程路径整洁并避免意外冲突,你可以考虑排除它们)。

+1

这是唯一对我有用的东西 – Kratos 2016-12-25 13:37:02

2

在我的情况下,我自己的一个库为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文件。