Spark Application日志输出的问题

在本机开发的Spark Application,如果用到了log4j作为日志记录组件,本机调试时,日志输出都是正常的,如果部署到Spark集群上,你会发现日志不输出了,即便是应用log4j.properties文件。

原因是Spark本身就是用的log4j来记录日志的,他的配置位于{SPARK_HOME}/conf/log4j.properties下,默认的配置如下:

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

# Settings to quiet third party logs that are too verbose
log4j.logger.org.eclipse.jetty=WARN  
log4j.logger.org.apache.spark.repl.SparkIMain$exprTyper=INFO  
log4j.logger.org.apache.spark.repl.SparkILoop$SparkILoopInterpreter=INFO  

使用spark-submit提交应用时,spark使用的就是此配置,可以看到只有WARN以上级别的日志才会输出。

所以如果你的应用中记录的是INFO日志,是看不到任何输出的。

使用自己的log4j配置并隔离Spark日志

一个系统如果没有日志记录,是不完整的。

我们开发的Spark Application依赖spark-core,日志记录方面,需要跟spark的隔离开,又不能影响spark默认记录的日志的行为。

为了达到以上目的,可以单独创建一个log4j的配置文件,假设为log4j.properties,添加以下配置内容:

# Set everything to be logged to the console
log4j.rootCategory=WARN,console  
log4j.logger.stan=INFO,file,console,e

# don't log to rootCategory
log4j.additivity.stan=false

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=%p %d{yy/MM/dd HH:mm:ss} %c{1}: %m%n

# info log file
log4j.appender.file=org.apache.log4j.DailyRollingFileAppender  
log4j.appender.file.Encoding=UTF8  
log4j.appender.file.Threshold=INFO  
log4j.appender.file.File=logs/stan.log  
log4j.appender.file.DatePattern='_'yyyyMMdd'.log'  
log4j.appender.file.layout=org.apache.log4j.PatternLayout  
log4j.appender.file.layout.ConversionPattern=[%p] [%d{yy/MM/dd HH:mm:ss}] [%c{1}]: %m%n

# error log file
log4j.appender.e=org.apache.log4j.DailyRollingFileAppender  
log4j.appender.e.Encoding=UTF8  
log4j.appender.e.Threshold=ERROR  
log4j.appender.e.File=logs/stan_error.log  
log4j.appender.e.DatePattern='_'yyyyMMdd'.log'  
log4j.appender.e.layout=org.apache.log4j.PatternLayout  
log4j.appender.e.layout.ConversionPattern=[%p] [%d{yy/MM/dd HH:mm:ss}] [%c{1}]: %m%n

# Settings to quiet third party logs that are too verbose
log4j.logger.org.eclipse.jetty=WARN  
log4j.logger.org.apache.spark.repl.SparkIMain$exprTyper=INFO  
log4j.logger.org.apache.spark.repl.SparkILoop$SparkILoopInterpreter=INFO  

假设stan是我们专用的日志记录器,通过log4j.logger.stan=INFO,file,console,e指定专用的appender,使用过程中还会发现,记录到console中的日志会出现两次,原因是rootCategory也是会输出console日志的。

可以通过log4j.additivity.stan=false,设定stan的日志不会输出到rootCategory中。

为了使用我们自定义的篇日志,需要在应用入口添加以下代码:

PropertyConfigurator.configure("log4j.properties")  

通过以下代码构建日志记录器:

// Scala代码
val logger: Logger =  
    LoggerFactory.getLogger("stan")

这样我们的日志系统就算完备了,记录关键日志到我们指定的文件中,同时还能隔离Spark的日志,互不影响。

参考:

http://lvqionghua.blog.163.com/blog/static/1852774201193161946939/