golang零配置多源优先级管理插件库zerocfg的使用

Golang零配置多源优先级管理插件库zerocfg的使用

zerocfg是一个受Go flag包启发的零配置管理库,支持多配置源和优先级管理。它提供了简单灵活的API,支持YAML配置,并且禁止样板代码。

特性

  • 🛠️ 受flag包启发的简单灵活API
  • 🍳 设计上禁止样板代码
  • 🚦 早期检测错误配置键
  • ✨ 支持多配置源和基于优先级的值解析
  • 🕵️‍♂️ 支持隐藏敏感配置
  • 🧩 支持自定义选项类型和提供者

安装

go get -u github.com/chaindead/zerocfg

快速开始

package main

import (
    "fmt"

    zfg "github.com/chaindead/zerocfg"
    "github.com/chaindead/zerocfg/env"
    "github.com/chaindead/zerocfg/yaml"
)

var (
    // 配置变量
    path     = zfg.Str("config.path", "", "path to yaml conf file", zfg.Alias("c"))
    ip       = zfg.IP("db.ip", "127.0.0.1", "database location")
    port     = zfg.Uint("db.port", 5678, "database port")
    username = zfg.Str("db.user", "guest", "user of database")
    password = zfg.Str("db.password", "qwerty", "password for user", zfg.Secret())
)

func main() {
    // 使用多源初始化配置
    err := zfg.Parse(
        env.New(),
        yaml.New(path),
    )
    if err != nil {
        panic(err)
    }

    fmt.Printf("Connect to %s:%d creds=%s:%s\n", *ip, *port, *username, *password)
    // 输出: Connect to 127.0.0.1:5678 creds=guest:qwerty

    fmt.Println(zfg.Show())
    // 命令: go run ./... -c test.yaml
    // 输出:
    //  config.path = test.yaml      (path to yaml conf file)
    //  db.ip       = 127.0.0.1      (database location)
    //  db.password = <secret>       (password for user)
    //  db.port     = 5678           (database port)
    //  db.user     = guest          (user of database)
}

使用说明

选项命名

  • 使用点(.)作为分层选项的分隔符
  • 选项子名称推荐使用camelCase、下划线(_)和短横线(-)风格
zfg.Str("groupOptions.thisOption", "", "camelCase usage")
zfg.Str("group_options.this_option", "", "underscore usage")
zfg.Str("group-options.this-option", "", "dash usage")

限制

  1. 选项在导入时注册,不支持运行时动态注册
  2. 不允许键重复
  3. 不允许同时使用键和子键(如mapmap.value)

未知值处理

如果zfg.Parse遇到未知值(未注册为选项的变量),它会返回错误。但可以选择忽略未知值:

err := zfg.Parse(
    env.New(),
    yaml.New(path),
)
if u, ok := zfg.IsUnknown(err); !ok {
    panic(err)
} else {
    // u是<source_name>到未知键切片的映射
    fmt.Println(u)
}

env源不会触发未知选项以避免误报

复杂类型作为字符串

  • 基本值通过fmt.Sprint("%v")转换
  • 如果类型有String()方法,则使用它(如time.Duration)
  • 否则使用JSON表示复杂类型(如切片、映射)
var (
    _ = zfg.Dur("timeout", 5*time.Second, "duration via fmt.Stringer interface")
    _ = zfg.Floats64("floats", nil, "list via json")
)

func main() {
    _ = zfg.Parse()

    fmt.Printf(zfg.Show())
    // 命令: go run ./... --timeout 10s --floats '[1.1, 2.2, 3.3]'
    // 输出:
    //   floats  = [1.1,2.2,3.3] (list via json)
    //   timeout = 10s           (duration via fmt.Stringer interface)
}

配置源

配置系统遵循严格的优先级层次结构:

  1. 命令行参数(始终最高优先级,默认启用)
  2. 按添加顺序的可选提供者(先添加=更高优先级)
  3. 默认值(最低优先级)

命令行参数

  • 默认启用,始终具有最高优先级
  • 可以为选项定义别名方便CLI使用
  • 值作为空格分隔的参数传递(不允许使用=)
  • 支持单横线(-)和双横线(–)前缀
path := zfg.Str("config.path", "", "path to yaml conf file", zfg.Alias("c"))

运行方式:

go run ./... -c test.yaml
# 或
go run ./... --config.path test.yaml

环境变量

环境变量会自动从配置键格式转换:

配置键 环境变量 说明
db.user DB_USER 基本转换
app.api.key APP_API_KEY 多级路径
camelCase.value CAMELCASE_VALUE 驼峰式处理
api-key.secret APIKEY_SECRET 移除短横线
under_score.value UNDERSCORE_VALUE 移除下划线

转换规则:

  1. 移除特殊字符(保留字母、数字和点)
  2. 将点替换为下划线
  3. 转换为大写

示例:

import (
    "fmt"
    zfg "github.com/chaindead/zerocfg"
    "github.com/chaindead/zerocfg/env"
)
var dbUser = zfg.Str("db.user", "", "database's username")

func main() {
    _ = zfg.Parse(
        env.New(),
    )
    fmt.Printf("DB user: %s", *dbUser)
}

运行方式:

DB_USER=admin go run main.go
# 输出: DB user: admin

YAML源

  • 选项使用点路径映射到YAML键,支持分层配置
  • 支持所有命名风格并按原样映射到YAML键

示例YAML文件:

group:
  option: "foo"

numbers:
  - 1
  - 2
  - 3

limits:
  max: 10
  min: 1

示例Go配置:

zfg.Str("group.option", "", "hierarchical usage")
zfg.Ints("numbers", nil, "slice of server configs")
zfg.Map("limits", nil, "map of limits")

高级用法

自定义选项

可以通过实现Value接口并通过Any函数注册来定义自己的选项类型。SetString方法应该兼容。

// 自定义类型
type MyType struct{ V string }

func newValue(val MyType, p *MyType) zfg.Value {
    *p = val
    return p
}

func (m *MyType) Set(s string) error { m.V = s; return nil }
func (m *MyType) Type() string       { return "custom" }
func (m *MyType) String() string { return m.V }

func Custom(name string, defVal MyType, desc string, opts ...zfg.OptNode) *MyType {
     return zfg.Any(name, defVal, desc, newValue, opts...)
}

// 注册自定义选项
var myOpt = Custom("custom.opt", MyType{"default"}, "custom option")

自定义提供者

可以通过实现Provider接口添加自己的配置源。

type MyProvider struct{}

func (p *MyProvider) Type() string { return "my" }
func (p *MyProvider) Provide(awaited map[string]bool, conv func(any) string) (map[string]string, map[string]string, error) {
    found := map[string]string{}
    unknown := map[string]string{}
    // ... 根据awaited填充found/unknown ...
    return found, unknown, nil
}

// 使用
zfg.Parse(&MyProvider{})

更多关于golang零配置多源优先级管理插件库zerocfg的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang零配置多源优先级管理插件库zerocfg的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


zerocfg - Golang零配置多源优先级管理插件库

zerocfg 是一个轻量级的 Golang 配置管理库,支持多配置源自动合并与优先级管理,无需繁琐的初始化配置即可使用。

核心特性

  1. 零配置开箱即用
  2. 多配置源自动合并(支持文件、环境变量、命令行参数等)
  3. 智能优先级管理
  4. 类型安全的值获取
  5. 支持动态监听配置变化

安装

go get github.com/zerocfg/zerocfg

基础用法

package main

import (
	"fmt"
	"github.com/zerocfg/zerocfg"
)

func main() {
	// 零配置初始化
	cfg := zerocfg.New()
	
	// 获取配置值(自动从环境变量、命令行参数等来源获取)
	port := cfg.GetInt("server.port", 8080) // 默认值8080
	fmt.Printf("Server will run on port: %d\n", port)
	
	// 获取字符串配置
	env := cfg.GetString("app.env", "development")
	fmt.Printf("Current environment: %s\n", env)
}

多源优先级示例

zerocfg 按照以下优先级顺序加载配置(从高到低):

  1. 命令行参数
  2. 环境变量
  3. 配置文件(如 config.yaml)
  4. 默认值
package main

import (
	"fmt"
	"github.com/zerocfg/zerocfg"
)

func main() {
	cfg := zerocfg.New()
	
	// 假设有以下配置来源:
	// 1. 命令行: --db.host=127.0.0.1
	// 2. 环境变量: DB_HOST=localhost
	// 3. config.yaml: db.host: db.example.com
	
	host := cfg.GetString("db.host", "default.host")
	// 由于命令行优先级最高,将返回 "127.0.0.1"
	fmt.Println("Database host:", host)
}

高级用法

添加自定义配置源

package main

import (
	"fmt"
	"github.com/zerocfg/zerocfg"
	"github.com/zerocfg/source/memory"
)

func main() {
	cfg := zerocfg.New()
	
	// 添加内存配置源
	memSource := memory.NewSource(map[string]interface{}{
		"app.name":    "MyApp",
		"app.version": "1.0.0",
	})
	cfg.AddSource(memSource)
	
	fmt.Println("App name:", cfg.GetString("app.name", ""))
	fmt.Println("App version:", cfg.GetString("app.version", ""))
}

监听配置变化

package main

import (
	"fmt"
	"github.com/zerocfg/zerocfg"
	"time"
)

func main() {
	cfg := zerocfg.New()
	
	// 监听配置变化
	cfg.Watch("server.port", func(key string, value interface{}) {
		fmt.Printf("Config changed: %s = %v\n", key, value)
	})
	
	// 模拟配置变化(实际中可能是文件修改或远程配置更新)
	go func() {
		time.Sleep(2 * time.Second)
		cfg.Set("server.port", 9090)
	}()
	
	// 保持程序运行
	select {}
}

使用结构体绑定

package main

import (
	"fmt"
	"github.com/zerocfg/zerocfg"
)

type ServerConfig struct {
	Port int    `cfg:"server.port"`
	Host string `cfg:"server.host"`
}

func main() {
	cfg := zerocfg.New()
	
	var serverCfg ServerConfig
	err := cfg.Unmarshal(&serverCfg)
	if err != nil {
		panic(err)
	}
	
	fmt.Printf("Server config: %+v\n", serverCfg)
}

最佳实践

  1. 为关键配置设置合理的默认值
  2. 使用命名空间(如 server.port)避免键冲突
  3. 生产环境优先使用环境变量或配置文件
  4. 开发环境可以使用命令行参数快速覆盖

性能考虑

zerocfg 在首次访问配置时会进行初始化加载,后续访问直接从缓存读取,性能开销极小。对于高频访问的配置项,建议在程序启动时获取并保存到局部变量中。

总结

zerocfg 提供了简单而强大的配置管理能力,特别适合需要灵活配置来源的微服务应用。其零配置设计让开发者可以快速集成,而多源优先级管理则确保了配置的灵活性和一致性。

更多高级用法和插件支持,请参考官方文档:https://github.com/zerocfg/zerocfg

回到顶部