Heka源码解析
Heka是目前我需要在工作中使用的唯一Go语言项目,出于对Golang的好感,我觉得仔细学习以下Heka的源码。如果力所能及的话,也可以为代码做出一些贡献。
先看最外层的文件目录结构(0.11.0dev):
1 | $ tree -L 1 -av --dirsfirst |
这是一个比较大的项目,从这里可以学到一些大型工程的基础知识,这是我所欠缺的。
.gitattributes
里面是控制git对换行符的处理的;.gitmodules
比较有意思,是用来在项目中引用其他git项目的。仔细查找了一些资料,得出的结论是:submodule用起来并不友好,尽量小心使用。
.travis.yml
是Travis Ci的配置文件,这个东西是用来做持续集成的。可以看到很多github repo的ReadMe中有一个图标表示build|passing
之类的信息,一般就是来自于Travis Ci的反馈信息。
项目使用cmake构建,所以根目录有一个CMakeLists.txt
文件。
Dockerfile用来搭建一个纯净的docker环境,方便各种构建。使用sudo docker build .
来根据该文件创造docker镜像。
入口
从examples/host_filter.go
中可以看出,插件的入口在init
函数中的pipeline.RegisterPlugin
中。那么就从这里开始看起。
这个函数位于pipeline/config.go
中,它的作用仅仅是把注册的组件放入一个pipeline
包的全局变量中。
通过搜索这个变量,可以看到在plugin_maker.go
的NewPluginMaker
中被使用,而这个函数是用来通过toml
产生新插件的。继续反向搜索使用这个函数的文件,迭代此过程,可以找到整个程序的入口文件heka/cmd/hekad/main.go
文件。
自上而下
从main函数开始读代码,逻辑是很清晰的。首先是命令行解析,使用了标准库中的flag
库。 Heka的命令行参数很少,除了打印版本号以外,只剩下加载配置文件一个功能。
加载配置文件后,首先进行全局配置,然后如果pid文件存在,就检测进程是否仍然存活。 (这里defer的顺序值得学习, os.Exit
会忽略所有的defer,所以必须放在最前面,最后执行)。
然后是各种profile的记录,最后来到了pipeline. 通过全局配置生成一个PipelineConfig
,然后再遍历配置文件。
PreloadFromConfigFile
从TOML配置文件里面生成PluginMaker
,并存放起来(category->maker的映射)。这个过程中就调用了注册插件的构造函数。
LoadConfig
集中处理MultiDecoder
的情况,然后将plugin分类到几个不同的字段(runner)中。
最后,调用Run
方法,开始运行。
运行过程
定位到pipeline/pipeline_runner文件中的Run函数,该函数驱动整个工作流的进行。
首先启动的是Output插件,随之是Filter,最后是input相关插件。各个插件运行在不同的goroutine里。最后注册外界信号处理函数。
最后是注册各种清理函数,当程序收到信号退出时执行。
各类Runner要实现pipeline/pipeline_runners.go中的接口才能正常运行。
Runner
PluginRunner
是各类Runner的接口(抽象基类),不过这里还有一个更基础的flag_interfaces.go
,里面定义了一些接口。