Hive任务日志及日志调试

一、Hive日志介绍

Hive日志记录了程序运行的过程,在Hive中,日志分为两种:

  1. 系统日志。记录了Hive的运行情况,错误状况。
  2. Job日志。记录了Hive中Job的执行过程。

1、系统日志存储在什么地方呢?
在 ${HIVE_HOME}/conf/hive-log4j.properties 文件中记录了Hive日志的存储情况,
默认的存储情况:

hive.root.logger=WARN,DRFA
hive.log.dir=/tmp/${user.name}/ # 默认的存储位置
hive.log.file=hive.log # 默认的文件名

Hive日志默认存储在以下目录中: /tmp/${user.name}/hive.log。当然,也可以设置一个不同的hive日志位置,有两种方式:

(1)Hive启动时指定日志目录。

hive --hiveconf hive.log.dir=/tmp/ --hiveconf hive.log.file=tmp.log

(2)通过在 $HIVE_HOME/conf/hive-log4j.properties文件中设置hive.log.dir参数。

hive.log.dir=/tmp/

2、Job日志又存储在什么地方呢 ?

# 源码加载方式
HIVEHISTORYFILELOC("hive.querylog.location", "/tmp/" + System.getProperty("user.name"))

默认存储在 /tmp/${user.name} 目录下,和系统日志默认存储路径相同。

二、Hive日志调试

Hive默认的日志级别是WARN,不能将DEBUG信息输出,但在进行进行问题定位时,可以修改日志级别,利用调试日志进行错误定位。具体设置方法有两种:

1、启动Hive客户端时添加参数进入DEBUG模式(定位问题的常用方式)

hive --hiveconf hive.root.logger=DEBUG,console

2、在${HIVE_HOME}/conf/hive-log4j.properties文件中找到 hive.root.logger 属性,并将其修改为下面的设置

hive.root.logger=DEBUG,console

方法一的设定只对本次会话有效,下次如果还想继续修改日志输出级别需要重新设定,这种设定适合临时需要查看更多日志的用户。方法二将日志输出级别设定到文件里,这个设定对所有用户都生效,而且每次执行HQL都会输出一大堆日志,这种情况适合那些无时无刻都需要HQL运行日志的用户。

注:针对两个方法的综合,还有一种实现方式,既可以不用每次设定日志级别,也能长期生效,就是设定自己的log4j配置文件,在启动Hive的时候指定自己的配置文件,如下:

hive --hiveconf hive.log4j.file=/home/kwang/hive-log4j.properties

三、如何查看实际环境中Hive的日志级别?

最直接的方式是启动hive cli客户端,可以看到日志文件加载的具体配置文件:

 可以看到,hive cli加载的配置文件是 /opt/cloudera/parcels/CDH-5.14.4-1.cdh5.14.4.p0.3/jars/hive-common-1.1.0-cdh5.14.4.jar!/hive-log4j.properties,日志级别默认是 WARN 级别,这个配置的文件的日志级别可以在 hive-common 源码模块的资源文件 hive-log4j.properties 中看到:

# Define some default values that can be overridden by system properties
hive.log.threshold=ALL
hive.root.logger=WARN,DRFA
hive.log.dir=${java.io.tmpdir}/${user.name}
hive.log.file=hive.log

在这里我们就能看到Hive任务执行时的日志级别。

接下来我们看看Hive是如何加载日志配置文件的。我们知道hive cli启动时主要依赖 hive-common 模块和 hive-exec 模块,在上面介绍的 hive-common 源码模块的资源文件是日志级别是WARN级别的,而在 hive-exec 源码模块的资源文件 hive-exec-log4j.properties 中日志级别是 INFO级别:

hive.log.threshold=ALL
hive.root.logger=INFO,FA
hive.log.dir=${java.io.tmpdir}/${user.name}
hive.query.id=hadoop
hive.log.file=${hive.query.id}.log

这里提到的两个日志文件也就对应前面介绍的系统级别日志与任务级别日志。清楚了这两个日志配置文件,我们再来看看Hive在启动客户端时是如何加载日志的。

首先,Hive客户端启动的入库类是 CliDriver.java,启动时会去加载日志配置。

  public  int run(String[] args) throws Exception {
    OptionsProcessor oproc = new OptionsProcessor();
    if (!oproc.process_stage1(args)) {
      return 1;
   }
    // NOTE: It is critical to do this here so that log4j is reinitialized
    // before any of the other core hive classes are loaded
    boolean logInitFailed = false;
    String logInitDetailMessage;
    try {
      // 加载日志配置
      logInitDetailMessage = LogUtils.initHiveLog4j();
   } catch (LogInitializationException e) {
      logInitFailed = true;
      logInitDetailMessage = e.getMessage();
   }
   ...
}

而真正加载日志的逻辑在 LogUtils.initHiveLog4j( ) 方法里:

/**
  * Initialize log4j.
  *
  * @return an message suitable for display to the user
  * @throws LogInitializationException if log4j fails to initialize correctly
  */
 public static String initHiveLog4j()
   throws LogInitializationException {
   return initHiveLog4jCommon(HiveConf.ConfVars.HIVE_LOG4J_FILE);
}
  
   private static String initHiveLog4jCommon(ConfVars confVarName)
   throws LogInitializationException {
   HiveConf conf = new HiveConf();    // HiveConf初始化时会初始化配置参数(具体加载哪些参数还有待研究)
   if (HiveConf.getVar(conf, confVarName).equals("")) {
     // if log4j configuration file not set, or could not found, use default setting
     return initHiveLog4jDefault(conf, "", confVarName);
  } else { //真正逻辑是进入到这里
     // if log4j configuration file found successfully, use HiveConf property value
     String log4jFileName = HiveConf.getVar(conf, confVarName);
     File log4jConfigFile = new File(log4jFileName);
     boolean fileExists = log4jConfigFile.exists();
     // 判断 /etc/hive/con/ 目录下是否存在 hive-log4j.properties 日志文件(线上环境默认是没有的)
     if (!fileExists) {
       // if property specified file not found in local file system
       // use default setting
       // 线上环境 /etc/hive/conf/ 目录下加载不到文件,此时初始化默认参数,即hive-exec和hive-common模块的日志参数
       return initHiveLog4jDefault(
         conf, "Not able to find conf file: " + log4jConfigFile, confVarName);
    } else {
       // property speficied file found in local file system
       // use the specified file
       // 从指定文件加载,也就是加载jar包对应文件
       // 线上启动Hive加载的日志文件 (Logging initialized using configuration in jar:file:/opt/cloudera/parcels/CDH-5.14.4-1.cdh5.14.4.p0.3/jars/hive-common-1.1.0-cdh5.14.4.jar!/hive-log4j.properties)
       if (confVarName == HiveConf.ConfVars.HIVE_EXEC_LOG4J_FILE) {
         String queryId = HiveConf.getVar(conf, HiveConf.ConfVars.HIVEQUERYID);
         if(queryId == null || (queryId = queryId.trim()).isEmpty()) {
           queryId = "unknown-" + System.currentTimeMillis();
        }
         System.setProperty(HiveConf.ConfVars.HIVEQUERYID.toString(), queryId);
      }
       LogManager.resetConfiguration();
       PropertyConfigurator.configure(log4jFileName);
       logConfigLocation(conf);
       return ("Logging initialized using configuration in " + log4jConfigFile);
    }
  }
}

至此,也就是Hive客户端启动时会去加载 hive-log4j.properties 日志文件,先从 /etc/hive/conf/ 目录中加载,然后再从jar中去加载。

【参考资料】

原文地址:https://www.cnblogs.com/lemonu/p/12368373.html