apache spark_如何登录Apache Spark

apache spark

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

Apache Spark中的Log4j

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

配置Log4j

SPARK_HOME / conf文件夹下,有log4j.properties.template文件,它是我们自己的日志记录系统的起点。

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

log4j.properties如下所示:

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


# By default, everything goes to console and file
log4j.rootLogger=INFO, RollingAppender, myConsoleAppender

# My custom logging goes to another file
log4j.logger.myLogger=INFO, RollingAppenderU

# The noisier spark logs go to file only
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中处理它们。 我们将它们重定向以记录在文件系统中。 另一方面,我们希望将自己的日志记录在外壳程序中,并记录在一个单独的文件中,以免它们与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抱怨该日志对象不可序列化,因此无法通过网络发送给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] ,并且还记录其映射的值。 在这种情况下,请注意如何将日志对象标记为@transient ,这允许序列化系统忽略日志对象。 现在,正在将Mapper序列化并发送给每个工作程序,但是在工作程序中需要它时,正在解决日志对象,从而解决了我们的问题。

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

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

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日志从外壳中隐藏,并记录到其自己的文件中。 我们还解决了尝试登录其他工作程序时出现的序列化问题。

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

翻译自: https://www.javacodegeeks.com/2016/03/log-apache-spark.html

apache spark

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值