如何为Intellij内部运行的Spark程序配置log4j?

时间:2017-03-30 21:40:38

标签: apache-spark intellij-idea spark-dataframe

我已经在谷歌上尝试了所有可能的建议,但我仍然得到带有INFO级别的火花日志,这太冗长了。

import org.apache.log4j.{Level, LogManager, Logger}
import org.apache.spark.sql.SparkSession

object  tmp {

  def main(args: Array[String]): Unit = {
    val spark =  SparkSession.builder()
      .master("local[*]")
      .getOrCreate()

    spark.sparkContext.setLogLevel("ERROR")

    LogManager.getRootLogger.setLevel(Level.ERROR)
    val rootLogger = Logger.getRootLogger()
    rootLogger.setLevel(Level.ERROR)

    Logger.getLogger("org").setLevel(Level.OFF)
    Logger.getLogger("akka").setLevel(Level.OFF)

    spark.read.json("/home/white/wk/tmp/people.json").show
  }
}

6 个答案:

答案 0 :(得分:1)

这是您可能想要使用的private double[] performAnalysis (double[] rrIntervals) { ArrayList<Double> splineRRIntervals = SlplineInterpolator.interpolate(rrIntervals); ArrayList<Double> downSampledData = new ArrayList<>(); for (float i = 0; i < splineRRIntervals.size(); i = i + 1000f / (float) sampleRate) { downSampledData.add(splineRRIntervals.get((int) i)); } FileIO fileIO = new FileIO(); //fileIO.writeDoubleArrayToFile("interpolation_down.txt", convertDoubles(downSampledData)); double[] iirFiltered = new double[downSampledData.size()]; for(int i=0;i< iirFiltered.length ;i++){ if(i==0){ iirFiltered[i] = IIR.iirHpf1ecg(downSampledData.get(i),0,0); } else if(i==1){ iirFiltered[i] = IIR.iirHpf1ecg(downSampledData.get(i),downSampledData.get(i-1),0); } else{ iirFiltered[i] = IIR.iirHpf1ecg(downSampledData.get(i),downSampledData.get(i-1),downSampledData.get(i-2)); } } /*double[] iirFiltered = new double[splineRRIntervals.size()]; for(int i=0;i< iirFiltered.length ;i++){ if(i==0){ iirFiltered[i] = IIR.iirHpf1ecg(splineRRIntervals.get(i),0,0); } else if(i==1){ iirFiltered[i] = IIR.iirHpf1ecg(splineRRIntervals.get(i),splineRRIntervals.get(i-1),0); } else{ iirFiltered[i] = IIR.iirHpf1ecg(splineRRIntervals.get(i),splineRRIntervals.get(i-1),splineRRIntervals.get(i-2)); } }*/ //added for IIR filter iirFilteredForPlot = new double[iirFiltered.length]; for (int i = 0; i < iirFiltered.length; i++){ iirFilteredForPlot[i] = iirFiltered[i]; } //end for graph double[] fft = getFFT(iirFiltered); // logLFHF(); // added this new return fft; } 文件:

log4j.properties

它将# # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy tpInputOf the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # Set everything to be logged to the console log4j.rootCategory=WARN, console log4j.appender.console=org.apache.log4j.ConsoleAppender log4j.appender.console.target=System.err log4j.appender.console.layout=org.apache.log4j.PatternLayout log4j.appender.console.layout.ConversionPattern=%d{yy/MM/dd HH:mm:ss} %p %c{1}: %m%n # Set the default spark-shell log level to WARN. When running the spark-shell, the # log level for this class is used to overwrite the root logger's log level, so that # the user can have different defaults for the shell and regular Spark apps. log4j.logger.org.apache.spark.repl.Main=WARN # Settings to quiet third party logs that are too verbose log4j.logger.org.spark_project.jetty=WARN log4j.logger.org.spark_project.jetty.util.component.AbstractLifeCycle=ERROR log4j.logger.org.apache.spark.repl.SparkIMain$exprTyper=INFO log4j.logger.org.apache.spark.repl.SparkILoop$SparkILoopInterpreter=INFO log4j.logger.org.apache.parquet=ERROR log4j.logger.parquet=ERROR # SPARK-9183: Settings to avoid annoying messages when looking up nonexistent UDFs in SparkSQL with Hive support log4j.logger.org.apache.hadoop.hive.metastore.RetryingHMSHandler=FATAL log4j.logger.org.apache.hadoop.hive.ql.exec.FunctionRegistry=ERROR 设置为log4j.rootCategory。如果您想要更少的消息,可以使用WARN。将此文件放在类路径的根目录中。如果你有一个Maven项目,那就是ERROR

答案 1 :(得分:1)

您可以尝试在SparkContext上设置日志级别

sc.setLogLevel(&#34; ERROR&#34)

答案 2 :(得分:0)

rootLogger文件添加到类路径中,FATAL级别设置为OFFnow = DateTime.now if (now.hour >= 5) now = now.advance(days: 1) end now.change(hour: 5)

答案 3 :(得分:0)

专门针对Intellij的位置为${project.home}/src/test/resources/log4j.properties。我们可以看到Intellij将其复制到test-classes目录:

$find /git/forecast-ml/ -name log4j.properties
/git/forecast-ml.yuan//src/test/resources/log4j.properties
/git/forecast-ml.yuan/target/scala-2.11/test-classes/log4j.properties

答案 4 :(得分:0)

任何应用程序的重要组成部分是我们集成到其中的底层日志系统。日志不仅用于调试和可追溯性,还用于商业智能。在我们的应用程序中构建强大的日志记录系统可以用作对我们正在解决的业务问题的深入了解。

Apache Spark中的Log4j Spark使用log4j作为其自己的日志记录的标准库。 Spark内部发生的所有事件都会记录到Shell控制台和已配置的基础存储中。 Spark还为应用程序编写者提供了一个模板,因此我们可以使用same_log4j_库将所需的任何消息添加到Spark中现有和就地的日志实现中。

配置Log4j 在_SPARK_HOME / conf_文件夹下,有is_log4j.properties.template_文件,它是我们自己的日志记录系统的起点。

基于此文件,我们创建了log4j.properties文件并将其放置在同一目录下。

log4j.properties looks like follows:

log4j.appender.myConsoleAppender=org.apache.log4j.ConsoleAppender
log4j.appender.myConsoleAppender.layout=org.apache.log4j.PatternLayout
log4j.appender.myConsoleAppender.layout.ConversionPattern=%d [%t] %-5p %c - %m%n

log4j.appender.RollingAppender=org.apache.log4j.DailyRollingFileAppender
log4j.appender.RollingAppender.File=/var/log/spark.log
log4j.appender.RollingAppender.DatePattern='.'yyyy-MM-dd
log4j.appender.RollingAppender.layout=org.apache.log4j.PatternLayout
log4j.appender.RollingAppender.layout.ConversionPattern=[%p] %d %c %M - %m%n

log4j.appender.RollingAppenderU=org.apache.log4j.DailyRollingFileAppender
log4j.appender.RollingAppenderU.File=/var/log/sparkU.log
log4j.appender.RollingAppenderU.DatePattern='.'yyyy-MM-dd
log4j.appender.RollingAppenderU.layout=org.apache.log4j.PatternLayout
log4j.appender.RollingAppenderU.layout.ConversionPattern=[%p] %d %c %M - %m%n

默认情况下,所有内容都进入控制台和文件

log4j.rootLogger=INFO, RollingAppender, myConsoleAppender

我的自定义日志记录转到另一个文件

log4j.logger.myLogger=INFO, RollingAppenderU

嘈杂的火花日志仅进入文件

log4j.logger.spark.storage=INFO, RollingAppender
log4j.additivity.spark.storage=false
log4j.logger.spark.scheduler=INFO, RollingAppender
log4j.additivity.spark.scheduler=false
log4j.logger.spark.CacheTracker=INFO, RollingAppender
log4j.additivity.spark.CacheTracker=false
log4j.logger.spark.CacheTrackerActor=INFO, RollingAppender
log4j.additivity.spark.CacheTrackerActor=false
log4j.logger.spark.MapOutputTrackerActor=INFO, RollingAppender
log4j.additivity.spark.MapOutputTrackerActor=false
log4j.logger.spark.MapOutputTracker=INFO, RollingAppender
log4j.additivty.spark.MapOutputTracker=false

基本上,我们想隐藏Spark生成的所有日志,因此我们不必在shell中处理它们。我们将它们重定向以记录在文件系统中。另一方面,我们希望将自己的日志记录在Shell中并记录在单独的文件中,以免它们与Spark中的记录混淆。从这里,我们将把Splunk指向我们自己的日志所在的文件,在这种情况下,它们是_ / var / log / sparkU.log。_

该(log4j.properties)文件在应用程序启动时由Spark拾取,因此除了将其放置在上述位置外,我们无需做任何其他事情。

编写我们自己的日志 现在我们已经配置了Spark管理日志所需的组件,我们只需要开始在应用程序中编写日志即可。

为了展示如何做到这一点,让我们编写一个小应用程序来帮助我们进行演示。

我们的应用程序:

object app {
def main(args: Array[String]) {
val log = LogManager.getRootLogger
log.setLevel(Level.WARN)

val conf = new SparkConf().setAppName("demo-app")
val sc = new SparkContext(conf)

log.warn("Hello demo")

val data = sc.parallelize(1 to 100000)

log.warn("I am done")
}
}

运行此Spark应用程序将证明我们的日志系统有效。我们将能够看到_Hello演示_,并且消息已经记录在外壳程序和文件系统中,而Spark日志只会进入文件系统。

到目前为止,一切似乎都很容易,但是有一个我们没有提到的问题。

org.apache.log4j.Logger类不可序列化,这意味着在对Spark API的某些部分进行操作时,不能在闭包内部使用它。

例如,如果我们在应用程序中这样做:

val log = LogManager.getRootLogger
val data = sc.parallelize(1 to 100000)

data.map { value =>
log.info(value)
value.toString
}

在Spark上运行时将失败。 Spark抱怨the_log_对象不可序列化,因此无法通过网络发送给Spark工作者。

这个问题实际上很容易解决。让我们创建一个类,该类在进行大量日志记录的同时对我们的数据集有所帮助。

class Mapper(n: Int) extends Serializable{
@transient lazy val log = org.apache.log4j.LogManager.getLogger("myLogger")

def doSomeMappingOnDataSetAndLogIt(rdd: RDD[Int]): RDD[String] =
rdd.map{ i =>
log.warn("mapping: " + i)
(i + n).toString
}
}

映射器收到_RDD [Int] _并返回RDD [String],并且还记录正在映射的值。在这种情况下,请注意如何将_log_对象标记为@transient,这允许序列化系统忽略日志对象。现在,正在将Mapper序列化并发送给每个工作程序,但是在工作程序中需要它时,正在解决日志对象,从而解决了我们的问题。

另一种解决方案是将日志对象包装到_object_construct中并在各处使用它。我们宁愿在要使用它的类中有一个日志,但是替代方法也是有效的。

此时,我们的整个应用程序如下所示:

import org.apache.log4j.{Level, LogManager, PropertyConfigurator}
import org.apache.spark._
import org.apache.spark.rdd.RDD

class Mapper(n: Int) extends Serializable{
@transient lazy val log = org.apache.log4j.LogManager.getLogger("myLogger")
def doSomeMappingOnDataSetAndLogIt(rdd: RDD[Int]): RDD[String] =
rdd.map{ i =>
log.warn("mapping: " + i)
(i + n).toString
}
}
object Mapper {
def apply(n: Int): Mapper = new Mapper(n)
}
object app {
def main(args: Array[String]) {
val log = LogManager.getRootLogger
log.setLevel(Level.WARN)
val conf = new SparkConf().setAppName("demo-app")
val sc = new SparkContext(conf)

log.warn("Hello demo")

val data = sc.parallelize(1 to 100000)
val mapper = Mapper(1)
val other = mapper.doSomeMappingOnDataSetAndLogIt(data)
other.collect()

log.warn("I am done")
}
}

结论 现在,我们的日志显示在外壳中,并且也存储在它们自己的文件中。 Spark日志从Shell隐藏,并记录到其自己的文件中。我们还解决了尝试登录其他工作程序时出现的序列化问题。

我们现在可以像今天使用的其他非分布式系统和应用程序一样,基于自己的Spark日志构建更强大的BI系统。商业智能对我们来说是非常重要的,拥有正确的见解总是很高兴。

答案 5 :(得分:0)

如果您在应用程序中使用slf4j,则可以使用此XML限制所有日志

<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>

    <root level="ERROR">
        <appender-ref ref="STDOUT"/>
    </root>

    <logger name="com.ning.http.client" level="ERROR"/>
</configuration>