2014-12-02 114 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文件。