Heka 使用的是 TOML 格式的配置文件, 有关 golang 加载 TOML 配置文件的技术请参看:  http://www.cnblogs.com/ghj1976/p/4082323.html 

Heka用的 读取 TOML 文件的Go库是: https://github.com/bbangert/toml 虽然跟上面文章的不是一个,但是基本差不多。

 

我们在hekad主进程的配置文件加载的逻辑如下:

  1. 在启动时,先读取hekad部分的配置内容,用于hekad的启动。
  2. 然后再去读其他配置节,把heka的管道启动起来。

github.com\mozilla-services\heka\cmd\hekad\main.go 文件中,我们摘要核心代码如下,就可以看到这个逻辑:

这里删除了一些跟这个逻辑过程无关的代码,方便阅读。

加载 hekad 部分配置

代码实现如下, 注意,这里处理了配置文件内置支持环境变量的功能。

 

对环境变量支持的文档如下:

Using Environment Variables

If you wish to use environmental variables in your config files as a way to configure values, you can simply use %ENV[VARIABLE_NAME] and the text will be replaced with the value of the environmental variable VARIABLE_NAME.

Example:

[AMQPInput]
url = "amqp://%ENV[USER]:%ENV[PASSWORD]@rabbitmq/"
exchange = "testout"
exchangeType = "fanout"

 

加载插件相关的配置逻辑

加载插件配置的逻辑主要是下面代码:

 

每个Heka的TOML配置节,对应的实体类如下:

// The TOML spec for plugin configuration options that will be pulled out by
// Heka itself before the config is passed to the Plugin.Init method. Not all
// options apply to all plugin types.
type PluginGlobals struct {
Typ string `toml:"type"`
Ticker uint `toml:"ticker_interval"`
Matcher string `toml:"message_matcher"` // Filter and Output only.
Signer string `toml:"message_signer"` // Filter and Output only.
Retries RetryOptions
Encoder string // Output only.
UseFraming *bool `toml:"use_framing"` // Output only.
CanExit *bool `toml:"can_exit"`
}

对应的解析时的逻辑如下:

 

func (self *PipelineConfig) loadPluginGlobals(section *ConfigSection) (err error) {

    // Set up default retry policy.

    pGlobals := new(PluginGlobals)

    pGlobals.Retries = RetryOptions{

        MaxDelay:   "30s",

        Delay:      "250ms",

        MaxRetries: -1,

    }

    if err = toml.PrimitiveDecode(section.tomlSection, pGlobals); err != nil {

        err = fmt.Errorf("Unable to decode config for plugin '%s': %s",

            section.name, err)

        return

    }

    if pGlobals.Typ == "" {

        pGlobals.Typ = section.name

    }

    if _, ok := AvailablePlugins[pGlobals.Typ]; !ok {

        err = fmt.Errorf("No registered plugin type: %s", pGlobals.Typ)

    } else {

        section.globals = pGlobals

    }

    return

}

补充说明如下:

 

插件的类型有5种,都是在名字或者type上可以看出来的, 对应的判断类型的代码如下:

var PluginTypeRegex = regexp.MustCompile("(Decoder|Encoder|Filter|Input|Output)$")

func getPluginCategory(pluginType string) string {

    pluginCats := PluginTypeRegex.FindStringSubmatch(pluginType)

    if len(pluginCats) < 2 {

        return ""

    }

    return pluginCats[1]

}

加载配置文件这里,代码在 LoadFromConfigFile 函数, 这里其实就主要做了上面两个事情,外加不同类型插件的特殊处理。

// Loads all plugin configuration from a TOML configuration file. The

// PipelineConfig should be already initialized via the Init function before

// this method is called.

func (self *PipelineConfig) LoadFromConfigFile(filename string) (err error) {

    var configFile ConfigFile

    // 更新配置文件中,自定义变量(环境变量)

    contents, err := ReplaceEnvsFile(filename)

    if err != nil {

        return err

    }

    // TOML 解析成 configFile

    if _, err = toml.Decode(contents, &configFile); err != nil {

        return fmt.Errorf("Error decoding config file: %s", err)

    }

    var (

        errcnt              uint

        protobufDRegistered bool

        protobufERegistered bool

    )

    sectionsByCategory := make(map[string][]*ConfigSection)

    // Load all the plugin globals and file them by category.

    for name, conf := range configFile {

        if name == HEKA_DAEMON {

            continue

        }

        log.Printf("Pre-loading: [%s]\n", name)

        section := &ConfigSection{

            name:        name,

            tomlSection: conf,

        }

        // 加载插件配置文件, 这里面做了插件注册的检查

        if err = self.loadPluginGlobals(section); err != nil {

            self.log(err.Error())

            errcnt++

            continue

        }

        // 获取插件的类型

        category := getPluginCategory(section.globals.Typ)

        if category == "" {

            self.log(fmt.Sprintf("Type doesn't contain valid plugin name: %s\n",

                section.globals.Typ))

            errcnt++

            continue

        }

        // 特殊插件类型的处理

        section.category = category

        if section.globals.Typ == "MultiDecoder" {

            // Special case MultiDecoders so we can make sure they get

            // registered *after* all possible subdecoders.

            sectionsByCategory["MultiDecoder"] = append(sectionsByCategory["MultiDecoder"],

                section)

        } else {

            sectionsByCategory[category] = append(sectionsByCategory[category], section)

        }

        if name == "ProtobufDecoder" {

            protobufDRegistered = true

        }

        if name == "ProtobufEncoder" {

            protobufERegistered = true

        }

    }

    // Make sure ProtobufDecoder is registered.

    if !protobufDRegistered {

        var configDefault ConfigFile

        toml.Decode(protobufDecoderToml, &configDefault)

        log.Println("Pre-loading: [ProtobufDecoder]")

        section := &ConfigSection{

            name:        "ProtobufDecoder",

            category:    "Decoder",

            tomlSection: configDefault["ProtobufDecoder"],

        }

        if err = self.loadPluginGlobals(section); err != nil {

            // This really shouldn't happen.

            self.log(err.Error())

            errcnt++

        } else {

            sectionsByCategory["Decoder"] = append(sectionsByCategory["Decoder"],

                section)

        }

    }

    // Make sure ProtobufEncoder is registered.

    if !protobufERegistered {

        var configDefault ConfigFile

        toml.Decode(protobufEncoderToml, &configDefault)

        log.Println("Pre-loading: [ProtobufEncoder]")

        section := &ConfigSection{

            name:        "ProtobufEncoder",

            category:    "Encoder",

            tomlSection: configDefault["ProtobufEncoder"],

        }

        if err = self.loadPluginGlobals(section); err != nil {

            // This really shouldn't happen.

            self.log(err.Error())

            errcnt++

        } else {

            sectionsByCategory["Encoder"] = append(sectionsByCategory["Encoder"],

                section)

        }

    }

    multiDecoders := make([]multiDecoderNode, len(sectionsByCategory["MultiDecoder"]))

    multiConfigs := make(map[string]*ConfigSection)

    for i, section := range sectionsByCategory["MultiDecoder"] {

        multiConfigs[section.name] = section

        multiDecoders[i] = newMultiDecoderNode(section.name, subsFromSection(section.tomlSection))

    }

    multiDecoders, err = orderDependencies(multiDecoders)

    if err != nil {

        return err

    }

    for i, d := range multiDecoders {

        sectionsByCategory["MultiDecoder"][i] = multiConfigs[d.name]

    }

    // Append MultiDecoders to the end of the Decoders list.

    sectionsByCategory["Decoder"] = append(sectionsByCategory["Decoder"],

        sectionsByCategory["MultiDecoder"]...)

    // Force decoders and encoders to be registered before the other plugin

    // types are initialized so we know they'll be there for inputs and

    // outputs to use during initialization.

    order := []string{"Decoder", "Encoder", "Input", "Filter", "Output"}

    for _, category := range order {

        for _, section := range sectionsByCategory[category] {

            log.Printf("Loading: [%s]\n", section.name)

            if err = self.loadSection(section); err != nil {

                self.log(err.Error())

                errcnt++

            }

        }

    }

    if errcnt != 0 {

        return fmt.Errorf("%d errors loading plugins", errcnt)

    }

    return

}

Heka 的配置文件加载逻辑的更多相关文章

  1. Spring Boot 2.4.0正式发布,全新的配置文件加载机制(不向下兼容)

    千里之行,始于足下.关注公众号[BAT的乌托邦],有Spring技术栈.MyBatis.JVM.中间件等小而美的原创专栏供以免费学习.分享.成长,拒绝浅尝辄止.本文已被 https://www.you ...

  2. Spring Boot源码分析-配置文件加载原理

    在Spring Boot源码分析-启动过程中我们进行了启动源码的分析,大致了解了整个Spring Boot的启动过程,具体细节这里不再赘述,感兴趣的同学可以自行阅读.今天让我们继续阅读源码,了解配置文 ...

  3. Spring使用环境变量控制配置文件加载

    项目中需要用到很多配置文件,不同环境的配置文件是不一样的,因此如果只用一个配置文件,势必会造成配置文件混乱,这里提供一种利用环境变量控制配置文件加载的方法,如下: 一.配置环境变量 如果是window ...

  4. struts几个配置文件加载顺序_2015.01.04

    struts几个配置文件加载顺序: 01:struts-default.xml 02:struts-plugin.xml 03:struts.xml 04:struts.properties 05:w ...

  5. asp.netcore 深入了解配置文件加载过程

    前言     配置文件中程序运行中,担当着不可或缺的角色:通常情况下,使用 visual studio 进行创建项目过程中,项目配置文件会自动生成在项目根目录下,如 appsettings.json, ...

  6. bash 的配置文件加载顺序

    bash配置文件的加载顺序和登陆方式有关,下面先介绍下登陆方式. 1 登陆方式有2种 登陆式SHELL: su - oracle    su -l oracle 正常从终端登陆 非登录式SHELL: ...

  7. 解决eclipse部署maven时,src/main/resources里面配置文件加载不到webapp下classes路径下的问题

    解决eclipse部署maven时,src/main/resources里面配置文件加载不到webapp下classes路径下的问题. 有时候是src/main/resources下面的,有时候是sr ...

  8. node 加载逻辑

    [node 加载逻辑] require(X) from module at path Y . If X is a core module, a. return the core module b. S ...

  9. springboot的yaml基础语法与取值,配置类,配置文件加载优先级

    1.基本语法k:(空格)v:表示一对键值对(一个空格必须有):以空格的缩进来控制层级关系:只要是左对齐的一列数据,都是同一个层级的属性和值也是大小写敏感: server: port: 8081 pat ...

随机推荐

  1. PHP内核研究 静态变量

    静态变量 它可以是 静态全局变量,如果不调用unset,那么这个静态变量会一直存在,直到程序退出时才由Zend内存管理来释放 它可以是 静态局部变量:在函数里定义,函数执行完后,该静态变量不会消失 它 ...

  2. NVIDIA | 一种重建照片的 AI 图像技术

    简评:或许可以称之为「擦擦乐」~ 建议大家看看视频示例 ~ 前几天,NVIDIA 的研究人员介绍了一种新的 深度学习 方法,使用该方法可以重建缺失像素的图像内容. 这种方法被称为「image inpa ...

  3. 51nod2004 终结之时 (支配树+树剖+树链的并)

    link 我永远喜欢洛天依 给定一张图世末积雨云,你需要维护其支配树: 单点修改,子树修改,树链修改 子树求和,树链求和,多条树链的并集求和 撤销之前的操作 可以先用 Lengauer-Tarjan ...

  4. CRC32算法笔记

    这几天在研究CRC32的计算过程,看了CRC算法的原理,也看了不少通过移位法实现的代码,但是算出的结果跟校验工具算的不一致. 折腾了好长时间,终于找到一个手工计算CRC32的文章,再对照IEEE 80 ...

  5. MySQL压缩版Windows环境进行安装配置

    MySQL下载地址:https://dev.mysql.com/downloads/mysql/ 选择对应的系统和相应的版本后点击Download进入下载页面,不需要登录,点击下面的“No thank ...

  6. #PHP 数组添加元素、统计数组相同元素个数、改变数组key值~_~

    一.数组添加元素 1.定义和用法: array_push() 函数向第一个参数的数组尾部添加一个或多个元素(入栈),然后返回新数组的长度. 2.语法: array_push(array,value1, ...

  7. 2019年华南理工大学程序设计竞赛(春季赛) B 修仙时在做什么?有没有空?可以来炼丹吗?(思维建图搜索)

    https://ac.nowcoder.com/acm/contest/625/B 分析: 全部的状态只有1<<18 个 , 所以我们可以预处理 f[u][j] , 然后建立出全部的u可以 ...

  8. DP 免费馅饼 HDU1176

    DP 免费馅饼 HDU1176 vjudge题面 一道基本的DP题,状态转移很好想,每一个状态的位置\(pos\)都只能由上一秒的\(pos-1, pos, pos+1\)三个位置转移而来(当然要判断 ...

  9. Rx

    more detailed in WIKI's document SDP :session description protocal book AAA AA-Answer 鉴权授权应答AAR AA-R ...

  10. TP5.1 查看具体版本

    https://blog.csdn.net/haibo0668/article/details/80865785 echo \think\facade\App::version(); composer ...