前言

在YARN术语中,执行者和应用程序masters在“容器”内部运行。在应用程序完成后,YARN有两种处理容器日志的模式。

如果打开日志聚合(使用 yarn.log-aggregation-enable配置),容器日志将复制到HDFS中,而本地计算机上的日志将被删除。查看日志可以通过 yarn logs 命令从群集中的任何位置查看。

yarn logs -applicationId <app ID>

该命令会将指定的应用程序日志从所有的容器中打印所有的日志内容。您也可以使用HDFS shell 或API直接在HDFS中查看容器日志文件。

他们所在的目录参考YARN配置(yarn.nodemanager.remote-app-log-dir和 yarn.nodemanager.remote-app-log-dir-suffix)。

日志也可以通过Spark Web UI中的Executors 标签页查看。你需要运行spark 历史服务器和MapReduce历史服务器,并在yarn-site.xml正确配置yarn.log.server.url

Spark历史记录服务器UI上的日志URL会将您重定向到MapReduce历史记录服务器以显示聚合日志。

如果日志聚合未打开时,日志将保存在每台计算机上的本地 YARN_APP_LOGS_DIR,通常配置为 /tmp/logs 或 $HADOOP_HOME/logs/userlogs,取决于Hadoop版本和安装配置。

查看容器的日志需要转到包含它们的主机并查看此目录。子目录按应用程序ID和容器ID组织日志文件。日志也可以在执行程序选项卡下的Spark Web UI上使用,并且不需要运行MapReduce历史记录服务器。

要查看每个容器的启动环境,请增加 yarn.nodemanager.delete.debug-delay-sec 一个较大的值(例如36000),然后通过 yarn.nodemanager.local-dirs

该目录包含启动脚本,JAR以及用于启动每个容器的所有环境变量。这个过程特别适用于调试类路径问题。

(请注意,启用此功能需要具有群集设置的管理权限并重新启动所有节点管理器。因此,这不适用于托管群集)。

 

日志参数

yarn-site.xml中有几个配置项与日志的保存与删除,本地job执行文件的保留与删除有关。若不做配置,日志和job.jar会在application执行结束后被直接删除掉。

yarn.log-aggregation-enable      true                  执行结束后收集(聚合)各个container本地的日志
yarn.nodemanager.remote-app-log-dir  /app-logs          聚合日志后在hdfs的存放地址
yarn.nodemanager.remote-app-log-dir-suffix  logs         聚合日志存放的后缀,存放地址由 ${remote-app-log-dir}/${user}/{thisParam}构成
yarn.log-aggregation.retain-seconds 2592000            聚合日志在hdfs上的保留时间,以秒为单位,到时后被删除,保留30天后删除 
yarn.log.server.url http://hostname:19888/jobhistory/logs   log server的地址  
yarn.nodemanager.local-dirs /hadoop/yarn/local          存放 application 运行的本地文件(计算过程中的中间数据存储)的根目录,执行完毕后删除,按用户名存储 
yarn.nodemanager.log-dirs /hadoop/yarn/log             存放 container 运行的本地日志的根目录,执行完毕后删除,按用户名存储 
yarn.nodemanager.log.retain-seconds 604800             本地日志的保留时间,只有aggregation没有enable时才生效 
yarn.nodemanager.delete.debug-delay-sec 600            yarn 的 DeletionService 在任务结束多长时间后,删除本地化的日志(yarn.nodemanager.local-dirs)
                                      和container的运行日志(yarn.nodemanager.log-dirs)。 这个时间最好设置的大一点。

 

日志聚合

其中executor日志分为运行时日志以及结束日志,两种日志分别存放于不同的位置,运行时候的日志文件存放于yarn.nodemanager.log−dirs/{ApplicationID}。

1、比如配置如下:

<property>
    <!--开启日志聚合-->
    <name>yarn.log-aggregation-enable</name>
    <value>true</value>
</property>
<property>
    <!--日志聚合hdfs存储路径-->
    <name>yarn.nodemanager.remote-app-log-dir</name>
    <value>/tmp/logs</value>
</property>
<property>
    <!--hdfs上的日志保留时间-->
    <name>yarn.log-aggregation.retain-seconds</name>
    <value>604800</value>
</property>

<property>
    <!--应用执行时存储路径-->
    <name>yarn.nodemanager.log-dirs</name>
    <value>file:/mnt/ddb/2/hadoop/nm</value>
</property>

<property>
    <!--应用执行完日志保留的时间,默认0,即执行完立刻删除-->
    <name>yarn.nodemanager.delete.debug-delay-sec</name>
    <value>0</value>
</property>

2、运行时候的executor日志存放于:

root@xxx:/mnt/ddb/2/hadoop/nm/application_1471515078641_0007# ls
container_1471515078641_0007_01_000001  container_1471515078641_0007_01_000002  container_1471515078641_0007_01_000003

注:其中container_1471515078641_0007_01_000001为RM为application_1471515078641_0007分配的第一个container,即AM所在的container,

第一个container都是运来启动AM的,containerID形式为,container_APPID_01_000001,你在RM日志文件里面根据container_APPID搜索即可看到为该APPID分配的container的分布情况及生命周期。

3、运行结束以后日志会聚合到HDFS上面去,运行结束的日志文件存入于/tmp/logs/${user}/logs。

drwxrwx---   - root supergroup          0 2016-08-18 18:29 /tmp/logs/root/logs/application_1471515078641_0002
drwxrwx---   - root supergroup          0 2016-08-18 19:10 /tmp/logs/root/logs/application_1471515078641_0003
drwxrwx---   - root supergroup          0 2016-08-18 19:17 /tmp/logs/root/logs/application_1471515078641_0004

4、运行结束后,可以通过以下命令查看日志: 

yarn logs --applicationId <id>

 

统一配置log4j

spark中提供了log4j的方式记录日志。可以在$SPARK_HOME/conf/下,将 log4j.properties.template 文件copy为 log4j.properties 来启用log4j配置。但这个配置为全局配置,不能单独配置某个job的运行日志。

在Spark的conf目录下,把log4j.properties.template修改为log4j.properties,原来的内容如下:

# Set everything to be logged to the console
log4j.rootCategory=INFO, 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=INFO, console,改为log4j.rootCategory=WARN, console,即可抑制Spark把INFO级别的日志打到控制台上。如果要显示全面的信息,则把INFO改为DEBUG。

 

独立配置log4j

如果想要使用自定义的log4j日志配置,需要下面几个步骤:

 1、使用spark-submit的--files参数,上传自定义 log4j-driver.properties和log4j-executor.properties;

 2、使用 --conf参数,增加 -Dlog4j.configuration配置:

  • 用于驱动程序:spark.driver.extraJavaOptions = -Dlog4j.configuration = <配置文件的位置>
  • 用于执行者:spark.executor.extraJavaOptions= -Dlog4j.configuration = <配置文件的位置>

方案一:使用  spark-submit的 --files 参数将自定义的配置文件上传到应用程序的文件列表中。

spark-submit 
--class com.hm.spark.Application 
--master yarn --deploy-mode cluster 
--driver-cores 1 --driver-memory 1G 
--num-executors 2 --executor-cores 1 --executor-memory 1G 
--driver-java-options "-Dlog4j.configuration=log4j-driver.properties" 
--conf spark.executor.extraJavaOptions="-Dlog4j.configuration=log4j-executor.properties" 
--files /home/hadoop/spark-workspace/log4j-driver.properties,/home/hadoop/spark-workspace/log4j-executor.properties 
/home/hadoop/spark-workspace/my-spark-etl-assembly-1.0-SNAPSHOT.jar

注:这里没有使用spark.driver.extraJavaOptions参数去配置,而是使用spark-submit的--driver-java-options参数进行设置的。

方案二:不使用  spark-submit的 --files 参数上传文件,直接使用文件。

spark-submit 
--class com.hm.spark.Application 
--master yarn --deploy-mode cluster 
--driver-cores 1 --driver-memory 1G 
--num-executors 2 --executor-cores 1 --executor-memory 1G 
--driver-java-options "-Dlog4j.configuration=file:/home/hadoop/spark-workspace/log4j-driver.properties " 
--conf spark.executor.extraJavaOptions="-Dlog4j.configuration=file:/home/hadoop/spark-workspace/log4j-executor.properties" 
/home/hadoop/spark-workspace/my-spark-etl-assembly-1.0-SNAPSHOT.jar

 注:如果使用文件,file: 则应明确提供配置文件的,并且文件需要在所有节点上本地存在。

 

Log4j配置示例

  • driver日志配置

控制台不打印日志,采用Rolling模式按天切割日志和滚动删除,保留最新7天日志数据,输出到指定文件(spark-driver.log),

日志存放目录和yarn日志一样,以便YARN可以正确显示并聚合它们(在开始日志聚合的前提下).

# Set everything to be logged to the console
log4j.rootCategory=INFO, rolling
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.target=System.out
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

# rolling
log4j.appender.rolling=org.apache.log4j.DailyRollingFileAppender
log4j.appender.rolling.file=${spark.yarn.app.container.log.dir}/spark-driver.log
log4j.appender.rolling.DatePattern='.'yyyy-MM-dd
log4j.appender.rolling.layout=org.apache.log4j.PatternLayout
log4j.appender.rolling.layout.ConversionPattern=%d{ISO8601} [%20.20t] [%-5p] [%50.50l] %-40m %n
log4j.appender.rolling.Append=true
log4j.appender.rolling.Encoding=UTF-8
log4j.appender.rolling.MaxBackupIndex=7

log4j.logger.org.apache.spark=INFO
log4j.logger.org.eclipse.jetty=WARN

如果希望一方面打印到控制台,另一方面又保留spark本身输出的日志到日志文件中,配置内容如下:

log4j.rootCategory=INFO, console, rolling
............
  • executor日志配置

控制台不打印日志,采用Rolling模式按天切割日志和滚动删除,保留最新7天日志数据,输出到指定文件(spark-executor.log),

日志存放目录和yarn日志一样,以便YARN可以正确显示并聚合它们(在开始日志聚合的前提下).

# Set everything to be logged to the console
log4j.rootCategory=INFO, rolling
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.target=System.out
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

# rolling
log4j.appender.rolling=org.apache.log4j.DailyRollingFileAppender
log4j.appender.rolling.file=${spark.yarn.app.container.log.dir}/spark-executor.log
log4j.appender.rolling.DatePattern='.'yyyy-MM-dd
log4j.appender.rolling.layout=org.apache.log4j.PatternLayout
log4j.appender.rolling.layout.ConversionPattern=%d{ISO8601} [%20.20t] [%-5p] [%50.50l] %-40m %n
log4j.appender.rolling.Append=true
log4j.appender.rolling.Encoding=UTF-8
log4j.appender.rolling.MaxBackupIndex=7

log4j.logger.org.apache.spark=INFO
log4j.logger.org.eclipse.jetty=WARN

如果希望输出的日志文件跟默认的(stdout)一样,配置内容如下:

.....................
# rolling
log4j.appender.rolling=org.apache.log4j.DailyRollingFileAppender
log4j.appender.rolling.file=${spark.yarn.app.container.log.dir}/stdout.log
log4j.appender.rolling.DatePattern='.'yyyy-MM-dd
log4j.appender.rolling.layout=org.apache.log4j.PatternLayout
log4j.appender.rolling.layout.ConversionPattern=%d{ISO8601} [%20.20t] [%-5p] [%50.50l] %-40m %n
log4j.appender.rolling.Append=true
log4j.appender.rolling.Encoding=UTF-8
log4j.appender.rolling.MaxBackupIndex=7
......................

 

 

引用: