选择的是第一道题
git clone https://github.com/junqianghan/invokeparser.git
提供 make 和 cmake 两种方式,都可完成编译。
g++ : 5.4.0
make
or
mkdir build && cd build
cmake ..
make
题目要求给定一个 corrid 查出这个 id 所对应的调用关系,而日志文件的路径是根据记录时间设置的,如果不知道具体的时间,到所有文件中查找是一个海量的工作,所以,根据题目描述第6条的解释:
- 日志由流式方式进入文件系统存储,如有需要可以在日志流进入文件系统存储时加入需要的代码
在生成corrid的时候,记录下这个corrid对应的时间,这个记录可以记录在一个键值对的数据库当中,给出corrid可以快速查出对应的生成时间。
日志解析的主要流程在 LogParser 类中,有两种构造方法,
- 提供corrid和时间
- 提供corrid和查询corrid生成时间的函数句柄
调用关系最终被解析成一个多叉树, 树的每个结点中存了 application 的名字,及父节点指针,子节点指针. LogParser::parser 负责解析日志返回根节点指针.
日志解析的思路是: 找到时间内的所有日志文件, 一次读取一行, 用C++11的正则表达式做匹配,如果是生成 ri 或者响应请求的日志, 将其中的 application 名字, ri, corrid 提取出来,记录到LogData结构中.
日志中与请求和响应相关的日志条目有三种:
- 生成请求
- 响应请求
- 响应完成(在生成corrid的应用日志中)
其中,1和2可以确定调用关系, 3可以确定调用起点即根节点.
用三种正则表达式分别匹配就可以知道当前日志记录是哪一类,存到 LogData 中.为加快日志分析速度,只读入分析在 corrid 生成后2分钟内的日志.
最开始发起请求的 application 会有一条对应的唯一日志标识, 有这条标识的,就是调用树的根节点.
这样就可以通过一个哈希结构,将生成请求的应用,和响应该应用请求的应用列表对应起来,而后者就是前者的子节点序列. 可以利用这个结构建立调用树.
为了能够用做网络服务,提供了将调用树序列化的接口,序列化为一个字符串.
- file_io.h/cpp : 目录文件操作调用接口
- pattern_parser.h/cpp : 单行日志类型匹配及LogData结构数据提取
- log_parser.h/cpp : 日志解析的主要流程控制
- def.h : LogData 结构定义
- errorid.h : 计算中的异常情况定义
- main.cpp : 测试主函数
- 若不计内存占用,可以将最近生成的 corrid 的调用关系, 定期查询, 缓存在内存中, 当有该 corrid 的查询需求时可直接返回结果.
- 对时间的比较直接用字符串比较的,可以引用 boost 中的 datetime 库精确比较.
- 此工程里只写了日志解析的部分, 可以写成网络服务, 响应连接请求.