hive中打印日志的几种方式实现

简介:

在debug hive的问题时,我们经常需要在源码里面增加必要的日志信息,来跟踪变量的变化或者是方法执行的情况,性能等。。hive里面有下面几个日志的实现方式。

1种是常用的通过

1
org.apache.commons.logging.Log

1
org.apache.commons.logging.LogFactory

类实现的。
比如要打印类的info信息时,只需要下面这样就可以。

1
2
static  final  private  Log LOG = LogFactory.getLog(CLASS_NAME)
LOG.info( "xxxxxx" );

如果要跟踪一个方法的执行时间,只需要在在方法调用前后各加一条日志信息记录当前时间戳,然后取差值即可。

另一种是LogHelper

1
org.apache.hadoop.hive.ql.session.SessionState.LogHelper

LogHelper类是SessionState的内部类

输出日志最终调用的是LOG.xxx和对应日志输出的println方法(比如System.out.println/log4j等)

但是日志只有两个级别,info和error。

以printInfo方法为例,具体实现:

1
2
3
4
5
6
     public  void  printInfo(String info, String detail) {
       if  (!getIsSilent()) {
         getInfoStream().println(info);
       }
       LOG.info(info + StringUtils.defaultString(detail));   //调用LOG.info(即第一种方法)
     }

使用的sample:

1
2
static  final  private  LogHelper console =  new  LogHelper (LOG);
console.printError( "Authorization failed:"  + authExp.getMessage() +  ". Use SHOW GRANT to get more details."  );

还有一种重要的类是PerfLogger类,可以实现记录方法执行时间的信息,在一些情况下可以取代第一种记录性能的方法。

PerfLogger类主要是用在Driver类的compile方法中,用来记录各个step使用的时间。

看下具体实现:

首先声明存储starttime和endtime的map:

1
2
  protected  final  Map<String, Long> startTimes =  new  HashMap<String, Long>();
  protected  final  Map<String, Long> endTimes =  new  HashMap<String, Long>();

主要方法:

wKioL1PyEPKwnF2fAACp11t1K0U988.jpg

1).构造方法可以传入一个boolean参数,控制是否reset(默认是false)

1
2
3
4
5
6
7
8
9
10
11
   protected  static  final  ThreadLocal<PerfLogger> perfLogger =  new  ThreadLocal<PerfLogger>();
   public  static  PerfLogger getPerfLogger( boolean  resetPerfLogger) {
     if  (SessionState.get() ==  null ) {
       if  (perfLogger.get() ==  null  || resetPerfLogger) {
         perfLogger.set( new  PerfLogger());
       }
       return  perfLogger.get();
     else  {
       return  SessionState.get().getPerfLogger(resetPerfLogger);
     }
   }

2).PerfLogBegin 用来记录开始时间,主要是使用了LOG.info(第一种记录日志的方法)

1
2
3
4
5
   public  void  PerfLogBegin(String callerName, String method) {
     long  startTime = System.currentTimeMillis();
     LOG.info(  "<PERFLOG method="  + method +  " from="  + callerName +  ">" ); 
     startTimes.put(method,  new  Long(startTime));   //将方法和对应的startTime放在startTimes的map中
   }

3).相应的PerfLogEnd用来记录结束时间

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
   public  long  PerfLogEnd(String callerName, String method) {
     Long startTime = startTimes.get(method);
     long  endTime = System. currentTimeMillis();
     long  duration = - 1 ;
     endTimes.put(method,  new  Long(endTime));
     StringBuilder sb =  new  StringBuilder( "</PERFLOG method="  ).append(method); 
     if  (startTime !=  null ) {
       sb.append(  " start=" ).append(startTime);
     }
     sb.append( " end=" ).append(endTime);
     if  (startTime !=  null ) {
       duration = endTime - startTime.longValue();
       sb.append(  " duration=" ).append(duration);
     }
     sb.append( " from=" ).append(callerName).append(  ">" );
     LOG.info(sb); 
     return  duration;
   }

getStartTime和getEndTime分别通过对应的map来获取starttime和endtime

4.是不是所有的method都可以用这种方法获取执行的性能?答案是no,在PerfLogger类中定义了部分属性,对应于method

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
   public  static  final  String ACQUIRE_READ_WRITE_LOCKS =  "acquireReadWriteLocks" ;
   public  static  final  String COMPILE =  "compile" ;
   public  static  final  String PARSE =  "parse" ;
   public  static  final  String ANALYZE =  "semanticAnalyze" ;
   public  static  final  String DO_AUTHORIZATION =  "doAuthorization" ;
   public  static  final  String DRIVER_EXECUTE =  "Driver.execute" ;
   public  static  final  String INPUT_SUMMARY =  "getInputSummary" ;
   public  static  final  String GET_SPLITS =  "getSplits" ;
   public  static  final  String RUN_TASKS =  "runTasks" ;
   public  static  final  String SERIALIZE_PLAN =  "serializePlan" ;
   public  static  final  String DESERIALIZE_PLAN =  "deserializePlan" ;
   public  static  final  String CLONE_PLAN =  "clonePlan" ;
   public  static  final  String TASK =  "task." ;
   public  static  final  String RELEASE_LOCKS =  "releaseLocks" ;
   public  static  final  String PRUNE_LISTING =  "prune-listing" ;
   public  static  final  String PARTITION_RETRIEVING =  "partition-retrieving" ;
   public  static  final  String PRE_HOOK =  "PreHook." ;
   public  static  final  String POST_HOOK =  "PostHook." ;
   public  static  final  String FAILURE_HOOK =  "FailureHook." ;
   public  static  final  String DRIVER_RUN =  "Driver.run" ;
   public  static  final  String TIME_TO_SUBMIT =  "TimeToSubmit" ;
   public  static  final  String TEZ_SUBMIT_TO_RUNNING =  "TezSubmitToRunningDag" ;
   public  static  final  String TEZ_BUILD_DAG =  "TezBuildDag" ;
   public  static  final  String TEZ_SUBMIT_DAG =  "TezSubmitDag" ;
   public  static  final  String TEZ_RUN_DAG =  "TezRunDag" ;
   public  static  final  String TEZ_CREATE_VERTEX =  "TezCreateVertex." ;
   public  static  final  String TEZ_RUN_VERTEX =  "TezRunVertex." ;
   public  static  final  String TEZ_INITIALIZE_PROCESSOR =  "TezInitializeProcessor" ;
   public  static  final  String TEZ_RUN_PROCESSOR =  "TezRunProcessor" ;
   public  static  final  String TEZ_INIT_OPERATORS =  "TezInitializeOperators" ;
   public  static  final  String LOAD_HASHTABLE =  "LoadHashtable" ;
   public  static  final  String ORC_GET_SPLITS =  "OrcGetSplits" ;


再来看一下其调用方式:

1
2
3
4
5
6
7
8
9
10
比如org.apache.hadoop.hive.ql.Driver类中的compile方法:
static  final  private  String CLASS_NAME = Driver.  class .getName();
   public  int  compile(String command,  boolean  resetTaskIds) {
     PerfLogger perfLogger = PerfLogger.getPerfLogger();  //实例化一个PerfLogger的对象
.......
       perfLogger.PerfLogBegin( CLASS_NAME, PerfLogger.PARSE);   //记录开始时间,传入本类的类名记录的方法(方法对应了PerfLogger类中对应的属性)
       ParseDriver pd =  new  ParseDriver();
       ASTNode tree = pd.parse(command, ctx);
       tree = ParseUtils.findRootNonNullToken(tree);
       perfLogger.PerfLogEnd( CLASS_NAME, PerfLogger.PARSE);

记录parse消耗时间的对应日志:

1
2
3
14 / 07 / 31  14 : 33 : 21  INFO log.PerfLogger: <PERFLOG method=parse from=org.apache.hadoop.hive.ql.Driver>
.....
14 / 07 / 31  14 : 33 : 21  INFO log.PerfLogger: </PERFLOG method=parse start= 1406788401914  end= 1406788401916  duration= 2  from=org.apache.hadoop.hive.ql.Driver>

3种方法可以根据需要选择使用。



本文转自菜菜光 51CTO博客,原文链接:http://blog.51cto.com/caiguangguang/1541771,如需转载请自行联系原作者

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
8天前
|
SQL 存储 算法
【Hive】Hive 小文件过多怎么解决?
【4月更文挑战第16天】【Hive】Hive 小文件过多怎么解决?
|
7天前
|
SQL 存储 关系型数据库
【Hive】Hive有哪些方式保存元数据,各有哪些特点?
【4月更文挑战第17天】【Hive】Hive有哪些方式保存元数据,各有哪些特点?
|
10天前
|
SQL HIVE
Hive【基础知识 04】【Hive 属性配置的三种方式及配置的优先级说明】
【4月更文挑战第7天】Hive【基础知识 04】【Hive 属性配置的三种方式及配置的优先级说明】
13 0
|
2月前
|
SQL 消息中间件 Apache
Flink报错问题之使用hive udf函数报错如何解决
Apache Flink是由Apache软件基金会开发的开源流处理框架,其核心是用Java和Scala编写的分布式流数据流引擎。本合集提供有关Apache Flink相关技术、使用技巧和最佳实践的资源。
|
2月前
|
SQL 消息中间件 Java
Flink报错问题之写入Hive报错如何解决
Apache Flink是由Apache软件基金会开发的开源流处理框架,其核心是用Java和Scala编写的分布式流数据流引擎。本合集提供有关Apache Flink相关技术、使用技巧和最佳实践的资源。
|
6月前
|
SQL 分布式计算 Java
如何在 hive udf 中访问配置数据-踩坑记录,方案汇总与对比-udf中可以写sql吗?
如何在 hive udf 中访问配置数据-踩坑记录,方案汇总与对比-udf中可以写sql吗?
|
SQL 存储 分布式计算
Hive 2.1.1 MetaException(在metastore中找不到消息:版本信息)
Hive 2.1.1 MetaException(在metastore中找不到消息:版本信息)
217 0
|
SQL 分布式计算 编译器
【Hive】(十六)Hive 执行过程实例分析
【Hive】(十六)Hive 执行过程实例分析
128 0
【Hive】(十六)Hive 执行过程实例分析
|
SQL 分布式计算 Hadoop
|
SQL 移动开发 Java
HIVE自动刷表导数据
代码实例 package mysql.to.hdfs.hive; import java.sql.Connection; import java.
969 0