golang基于结构体标签的配置管理插件GoCfg的使用
Golang基于结构体标签的配置管理插件GoCfg的使用
GoCfg简介
GoCfg是一个基于结构体标签的配置管理插件,支持从环境变量、.env文件等多种来源解析配置到结构体。
主要特性
- 支持从环境变量、.env文件等来源解析配置到结构体
- 可以通过标签设置字段的默认值
- 支持自定义解析器
- 支持自定义值提供器
- 自动生成文档
快速开始
安装包
go get -u github.com/Jagerente/gocfg
基本用法
package main
import (
"github.com/Jagerente/gocfg"
"github.com/Jagerente/gocfg/pkg/parsers"
"github.com/Jagerente/gocfg/pkg/values"
"time"
)
type LoggerConfig struct {
LogLevel string `env:"LOG_LEVEL" default:"debug"`
}
type RedisConfig struct {
RedisHost string `env:"REDIS_HOST" default:"localhost"`
RedisPort uint16 `env:"REDIS_PORT" default:"6379"`
RedisUser string `env:"REDIS_USER,omitempty"`
RedisPassword string `env:"REDIS_PASS"`
RedisDatabase string `env:"REDIS_DATABASE"`
}
type AppConfig struct {
// 支持的标签:
// - env: 指定环境变量名
// - default: 指定字段的默认值
// - example: 为文档生成指定示例值
// - omitempty: 允许空字段
// 如果解析值和默认值都为空,
// 该字段将被设置为Go类型的零值
// - description: 为文档生成描述字段
// - title: 为嵌套结构体文档指定标题
LogLevel LoggerConfig
RedisConfig RedisConfig
BoolField bool `env:"BOOL_FIELD"`
StringField string `env:"STRING_FIELD"`
IntField int `env:"INT_FIELD"`
Int8Field int8 `env:"INT8_FIELD"`
Int16Field int16 `env:"INT16_FIELD"`
Int32Field int32 `env:"INT32_FIELD"`
Int64Field int64 `env:"INT64_FIELD"`
UintField uint `env:"UINT_FIELD"`
Uint8Field uint8 `env:"UINT8_FIELD"`
Uint16Field uint16 `env:"UINT16_FIELD"`
Uint32Field uint32 `env:"UINT32_FIELD"`
Uint64Field uint64 `env:"UINT64_FIELD"`
Float32Field float32 `env:"FLOAT32_FIELD"`
Float64Field float64 `env:"FLOAT64_FIELD"`
TimeDurationField time.Duration `env:"TIME_DURATION_FIELD"`
ByteSliceField []byte `env:"BYTE_SLICE_FIELD"`
StringSliceField []string `env:"STRING_SLICE_FIELD" default:"string1,string2,string3"`
IntSliceField []int `env:"INT_SLICE_FIELD" default:"3,2,1,0,-1,-2,-3"`
EmptyField string `env:"EMPTY_FIELD,omitempty"`
WithDefaultField string `env:"WITH_DEFAULT_FIELD" default:"ave"`
}
func main() {
cfg := gocfg.NewDefault()
// 等同于
cfg = gocfg.NewEmpty().
UseDefaults().
AddParserProviders(parsers.NewDefaultParserProvider()).
AddValueProviders(values.NewEnvProvider())
appConfig := new(AppConfig)
if err := cfg.Unmarshal(appConfig); err != nil {
panic(err)
}
}
默认类型解析器
默认支持以下类型解析:
- time.Duration
- bool
- string
- int, int8, int16, int32, int64
- uint, uint8, uint16, uint32, uint64
- float32, float64
- 切片: bytes, strings, ints
.env文件支持
package main
import (
"github.com/Jagerente/gocfg"
"github.com/Jagerente/gocfg/pkg/parsers"
"github.com/Jagerente/gocfg/pkg/values"
)
type AppConfig struct {
BoolField bool `env:"BOOL_FIELD"`
StringField string `env:"STRING_FIELD"`
IntField int `env:"INT_FIELD"`
}
func main() {
// 使用默认的'.env'文件
dotEnvProvider, _ := values.NewDotEnvProvider()
// 使用自定义env文件路径
dotEnvProvider, _ = values.NewDotEnvProvider("local.env")
// 使用多个env文件
dotEnvProvider, _ = values.NewDotEnvProvider("local.env", "dev.env")
cfg := gocfg.NewDefault().
AddValueProviders(dotEnvProvider)
// 等同于
cfg = gocfg.NewEmpty().
UseDefaults().
AddParserProviders(parsers.NewDefaultParserProvider()).
AddValueProviders(
values.NewEnvProvider(),
dotEnvProvider,
)
appConfig := new(AppConfig)
if err := cfg.Unmarshal(appConfig); err != nil {
panic(err)
}
}
自定义键标签
package main
import (
"github.com/Jagerente/gocfg"
)
type AppConfig struct {
BoolField bool `mapstructure:"BOOL_FIELD"`
StringField string `mapstructure:"STRING_FIELD"`
IntField int `mapstructure:"INT_FIELD"`
}
func main() {
cfg := gocfg.NewDefault().
UseCustomKeyTag("mapstructure")
appConfig := new(AppConfig)
if err := cfg.Unmarshal(appConfig); err != nil {
panic(err)
}
}
自定义解析器提供器
package main
import (
"github.com/Jagerente/gocfg"
"reflect"
"time"
)
type CustomParserProvider struct {
}
func NewCustomParserProvider() *CustomParserProvider {
return &CustomParserProvider{}
}
func (p *CustomParserProvider) Get(field reflect.Value) (func(v string) (any, error), bool) {
switch field.Type() {
case reflect.TypeOf(time.Duration(83)):
return func(v string) (any, error) {
return time.ParseDuration(v)
}, true
default:
return nil, false
}
}
type AppConfig struct {
BoolField bool `env:"BOOL_FIELD"`
StringField string `env:"STRING_FIELD"`
IntField int `env:"INT_FIELD"`
}
func main() {
customParserProvider := NewCustomParserProvider()
cfg := gocfg.NewDefault().
AddParserProviders(customParserProvider)
appConfig := new(AppConfig)
if err := cfg.Unmarshal(appConfig); err != nil {
panic(err)
}
}
自定义值提供器
package main
import (
"github.com/Jagerente/gocfg"
"os"
)
type CustomValueProvider struct {
}
func NewCustomValueProvider() *CustomValueProvider {
return &CustomValueProvider{}
}
func (p *CustomValueProvider) Get(key string) string {
return os.Getenv("CUSTOM_" + key)
}
type AppConfig struct {
BoolField bool `env:"BOOL_FIELD"`
StringField string `env:"STRING_FIELD"`
IntField int `env:"INT_FIELD"`
}
func main() {
customValueProvider := NewCustomValueProvider()
cfg := gocfg.NewDefault().
AddValueProviders(customValueProvider)
appConfig := new(AppConfig)
if err := cfg.Unmarshal(appConfig); err != nil {
panic(err)
}
}
文档生成
- 首先创建一个配置文件
/internal/config/config.go
:
package config
import (
"github.com/Jagerente/gocfg"
"github.com/Jagerente/gocfg/pkg/values"
"time"
cache_factory "your_cool_app/internal/router/cache"
)
type LoggerConfig struct {
LogLevel int `env:"LOG_LEVEL" default:"6" example:"4" description:"https://pkg.go.dev/github.com/sirupsen/logrus@v1.9.3#Level"`
ReportCaller bool `env:"REPORT_CALLER" default:"true" example:"false"`
LogFormatter int `env:"LOG_FORMATTER" default:"0" example:"1"`
}
type CassandraConfig struct {
CassandraHosts string `env:"CASSANDRA_HOSTS" default:"127.0.0.1" example:"cassandra.example.com"`
CassandraKeyspace string `env:"CASSANDRA_KEYSPACE" default:"user_data_service" example:"production_keyspace"`
}
type RouterConfig struct {
ServerPort uint16 `env:"SERVER_PORT" default:"8080" example:"3000"`
Debug bool `env:"ROUTER_DEBUG" default:"true" example:"false"`
CacheAdapter string `env:"CACHE_ADAPTER,omitempty" example:"redis" description:"Leave blank to not use.\nPossible values:\n- redis\n- memcache"`
CacheAdapterTTL time.Duration `env:"CACHE_ADAPTER_TTL,omitempty" default:"1m" example:"5m"`
CacheAdapterNoCacheParam string `env:"CACHE_ADAPTER_NOCACHE_PARAM,omitempty" default:"no-cache" example:"skip-cache"`
}
type RedisCacheAdapterConfig struct {
RedisAddr string `env:"CACHE_ADAPTER_REDIS_ADDR,omitempty" default:":6379"`
RedisDB int `env:"CACHE_ADAPTER_REDIS_DB,omitempty" default:"0"`
RedisUsername string `env:"CACHE_ADAPTER_REDIS_USERNAME,omitempty"`
RedisPassword string `env:"CACHE_ADAPTER_REDIS_PASSWORD,omitempty"`
}
type MemcacheCacheAdapterConfig struct {
Capacity int `env:"CACHE_ADAPTER_MEMCACHE_CAPACITY,omitempty" default:"10000000"`
CachingAlgorithm cache_factory.Algorithm `env:"CACHE_ADAPTER_MEMCACHE_CACHING_ALGORITHM,omitempty" default:"LRU"`
}
type Config struct {
LoggerConfig `title:"Logger configuration"`
RouterConfig `title:"Router configuration"`
RedisCacheAdapterConfig `title:"Redis Cache Adapter configuration"`
MemcacheCacheAdapterConfig `title:"Memcache Cache Adapter configuration"`
CassandraConfig `title:"Cassandra configuration"`
}
func New() (*Config, error) {
var cfg = new(Config)
cfgManager := gocfg.NewDefault()
if dotEnvProvider, err := values.NewDotEnvProvider(); err == nil {
cfgManager = cfgManager.AddValueProviders(dotEnvProvider)
}
if err := cfgManager.Unmarshal(cfg); err != nil {
return nil, err
}
return cfg, nil
}
- 创建一个文档生成应用
/cmd/docs/main.go
:
package main
import (
"fmt"
"github.com/Jagerente/gocfg"
"github.com/Jagerente/gocfg/pkg/docgens"
"os"
"your_cool_app/internal/config"
)
const outputFile = ".env.dist.generated"
func main() {
cfg := new(config.Config)
file, err := os.Create(outputFile)
if err != nil {
panic(fmt.Errorf("error creating %s file: %v", outputFile, err))
}
cfgManager := gocfg.NewDefault()
if err := cfgManager.GenerateDocumentation(cfg, docgens.NewEnvDocGenerator(file)); err != nil {
panic(err)
}
}
- 运行
go run cmd/docs/main.go
会生成.env.dist.generated
文件:
# Auto-generated config
#############################
# Logger configuration
#############################
# Description:
# https://pkg.go.dev/github.com/sirupsen/logrus@v1.9.3#Level
#
# Default: `6`
LOG_LEVEL=4
# Default: `true`
REPORT_CALLER=false
# Default: `0`
LOG_FORMATTER=1
#############################
# Router configuration
#############################
# Default: `8080`
SERVER_PORT=3000
# Default: `true`
ROUTER_DEBUG=false
# Allowed to be empty
# Description:
# Leave blank to not use.
# Possible values:
# - redis
# - memcache
CACHE_ADAPTER=redis
# Allowed to be empty
# Default: `1m`
CACHE_ADAPTER_TTL=5m
# Allowed to be empty
# Default: `no-cache`
CACHE_ADAPTER_NOCACHE_PARAM=skip-cache
#############################
# Redis Cache Adapter configuration
#############################
# Allowed to be empty
CACHE_ADAPTER_REDIS_ADDR=:6379
# Allowed to be empty
CACHE_ADAPTER_REDIS_DB=0
# Allowed to be empty
CACHE_ADAPTER_REDIS_USERNAME=
# Allowed to be empty
CACHE_ADAPTER_REDIS_PASSWORD=
#############################
# Memcache Cache Adapter configuration
#############################
# Allowed to be empty
CACHE_ADAPTER_MEMCACHE_CAPACITY=10000000
# Allowed to be empty
CACHE_ADAPTER_MEMCACHE_CACHING_ALGORITHM=LRU
#############################
# Cassandra configuration
#############################
# Default: `127.0.0.1`
CASSANDRA_HOSTS=cassandra.example.com
# Default: `user_data_service`
CASSANDRA_KEYSPACE=production_keyspace
更多关于golang基于结构体标签的配置管理插件GoCfg的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
1 回复
更多关于golang基于结构体标签的配置管理插件GoCfg的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
GoCfg: 基于结构体标签的Go配置管理插件
GoCfg 是一个基于结构体标签的轻量级配置管理工具,它可以帮助开发者轻松地将各种配置源(如JSON、YAML、环境变量等)映射到Go结构体中。
基本特性
- 支持多种配置格式:JSON、YAML、TOML等
- 支持环境变量自动映射
- 支持默认值设置
- 支持配置校验
- 支持热加载
安装
go get github.com/gookit/gocfg
基本使用示例
1. 定义配置结构体
type ServerConfig struct {
Host string `cfg:"host" default:"localhost"`
Port int `cfg:"port" default:"8080"`
Debug bool `cfg:"debug" default:"false"`
LogLevel string `cfg:"log_level" default:"info" validate:"oneof=debug info warn error"`
}
2. 从JSON文件加载配置
package main
import (
"fmt"
"github.com/gookit/gocfg"
)
func main() {
cfg := &ServerConfig{}
// 从JSON文件加载配置
err := gocfg.Load(cfg, gocfg.WithFile("config.json"))
if err != nil {
panic(err)
}
fmt.Printf("Server running on %s:%d\n", cfg.Host, cfg.Port)
}
3. 从环境变量加载配置
// 假设有以下环境变量:
// APP_HOST=0.0.0.0
// APP_PORT=9090
// APP_DEBUG=true
type AppConfig struct {
Host string `cfg:"host" env:"APP_HOST" default:"localhost"`
Port int `cfg:"port" env:"APP_PORT" default:"8080"`
Debug bool `cfg:"debug" env:"APP_DEBUG" default:"false"`
}
func main() {
cfg := &AppConfig{}
err := gocfg.Load(cfg, gocfg.WithEnv())
if err != nil {
panic(err)
}
fmt.Printf("App running on %s:%d, debug: %v\n", cfg.Host, cfg.Port, cfg.Debug)
}
高级用法
嵌套结构体配置
type DatabaseConfig struct {
Host string `cfg:"host" default:"localhost"`
Port int `cfg:"port" default:"5432"`
Username string `cfg:"username" required:"true"`
Password string `cfg:"password" required:"true"`
}
type AppConfig struct {
Server ServerConfig `cfg:"server"`
Database DatabaseConfig `cfg:"database"`
}
func main() {
cfg := &AppConfig{}
err := gocfg.Load(cfg,
gocfg.WithFile("config.yaml"),
gocfg.WithEnv(),
)
if err != nil {
panic(err)
}
// 使用配置...
}
配置热加载
func main() {
cfg := &ServerConfig{}
// 启用热加载,每30秒检查一次配置变更
err := gocfg.Load(cfg,
gocfg.WithFile("config.json"),
gocfg.WithReload(30*time.Second),
)
if err != nil {
panic(err)
}
// 主程序循环
for {
fmt.Printf("Current config: %+v\n", cfg)
time.Sleep(10 * time.Second)
}
}
自定义配置源
type CustomSource struct {
data map[string]interface{}
}
func (c *CustomSource) Load() (map[string]interface{}, error) {
return c.data, nil
}
func main() {
cfg := &ServerConfig{}
customSource := &CustomSource{
data: map[string]interface{}{
"host": "custom-host",
"port": 9999,
},
}
err := gocfg.Load(cfg, gocfg.WithSource(customSource))
if err != nil {
panic(err)
}
fmt.Printf("Loaded from custom source: %+v\n", cfg)
}
标签说明
GoCfg 支持以下结构体标签:
cfg
- 指定配置字段的名称default
- 设置默认值env
- 指定环境变量名称required
- 设为"true"表示该字段必须提供validate
- 设置验证规则
最佳实践
- 为所有配置字段提供合理的默认值
- 对关键配置使用
required:"true"
确保配置完整性 - 使用
validate
标签添加简单的验证规则 - 生产环境推荐使用环境变量注入敏感配置
- 开发环境可以使用配置文件方便管理
GoCfg 通过简洁的API和强大的标签系统,为Go应用程序提供了灵活的配置管理方案,既适合小型项目也适用于大型分布式系统。