在hive引擎的产品化过程中,hive执行的日志可视化展示是十分重要的一环。我们在抓取hive引擎的返回日志并导入文件之后发现,存在很多特殊字符。
1 背景
在hive引擎的产品化过程中,hive执行的日志可视化展示是十分重要的一环。我们在抓取hive引擎的返回日志并导入文件之后发现,存在很多特殊字符。
发生这一现象的场景是:当用户执行”beeline -f hql.sql”,且该sql文件较长的时候,返回结果中存在^M。
引发的问题:特殊字符为产品中日志的可视化解析带来了不便。
2 案例
2.1 测试sql
在hql.sql文件中构建测试sql如下:
1 | select * from aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa; |
2.2 测试脚本
编写测试脚本:test.sh,内容如下:
1 | HIVE_HOME/bin/beeline -f hql.sql |
2.3 测试命令
执行并将结果输出到文件
1 | sh test.sh > result 2>&1 |
2.4 结果
1 | Listening for transport dt_socket at address: 8001 |
3 源码剖析
首先通过远程debug调试beeline客户端,跟踪代码.
3.1 beeline客户端开启debug模式
启动beeline客户端时,通过参数 –debug:port=8001 开启debug模式.这里修改上述案例的测试脚本test.sh
1 | HIVE_HOME/bin/beeline --debug:port=8001 -f hql.sql |
3.2 idea开启远程调试监听
参数:
1 | -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8001 |
模块:hive-beeline
3.3 调用栈分析
1 | org.apache.hive.beeline.BeeLine#main |
^M 即 \r(回车符) ,可以看出,在drawBuffer(int)方法中,获取了terminal的宽度,依据该宽度值,对输出进行了分割,13就是\r的ascii编码值。
1 | public static final char RESET_LINE = '\r'; |
3.4 分析及结论
这里是jline源码的实现,目的是为了更友好地将结果显示在terminal界面。
几个求解思路:
- 思路一:
可以看出^M的出现是因为字符串长度超过了terminal的窗口大小(int width = terminal.getWidth();),如果我们可以重置该窗口大小尽可能地大,可以避免切分。
该宽度从哪里来?
首先需要了解stty命令。简单说就是stty命令可以获取终端terminal的相关设置,其中包括窗口大小。这里的实现是执行stty -a,然后通过正则表达式获取到columns(即宽度)。
其中如果获取不到terminal的宽度,采用默认值80。有一个思路就是将该默认值修改为尽可能的大,但不幸的是这里采用了硬编码,我们无法通过修改配置的方式修改默认值。
从这里看出,无法通过修改源码来解这个问题。
- 思路二:
既然切分长度来自于stty,我们是否可以修改terminal的窗口值呢?很不幸,经过调研,没有发现可以修改terminal窗口值的方法。
从上述来看,修改源码无法求解该问题。
退而求其次,建议解决方案:自行替换特殊字符。关于^M特殊字符的替换解决方案网友们有大量的案例。
4 附-相关源码
1 | public static final int DEFAULT_WIDTH = 80; |
本文链接: https://stefanxiepj.github.io/archives/241842c7.html
版权声明: 本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。转载请注明出处!