Config
📝 Go configuration manage(load,get,set,export). support JSON, YAML, TOML, Properties, INI, HCL, ENV and Flags. Multi file load, data override merge, parse ENV var. Go应用配置加载管理,支持多种格式,多文件加载,远程文件加载,支持数据合并,解析环境变量名
Install / Use
/learn @gookit/ConfigREADME
Config
config - Simple, full-featured Go application configuration management tool library.
Features
- Support multi format:
JSON(default),JSON5,INI,Properties,YAML,TOML,ENV,FlagsJSONcontent support comments. will auto clear commentsHCLneed to importgithub.com/hashicorp/hclfor custom driver- Other drivers are used on demand, not used will not be loaded into the application.
- Possibility to add custom driver for your specific format
- Support multi-file and multi-data loading
- Support for loading configuration from system ENV
- Support for loading configuration data from remote URLs
- Support for setting configuration data from command line(
flags) - Support listen and fire events on config data changed.
- allow events:
set.value,set.data,load.data,clean.data,reload.data
- allow events:
- Support data overlay and merge, automatically load by key when loading multiple copies of data
- Support for binding all or part of the configuration data to the structure
- Support init default value by struct tag
default:"def_value" - Support init default value from ENV
default:"${APP_ENV | dev}"
- Support init default value by struct tag
- Support get sub value by key-path, like
map.keyarr.2 - Support parse ENV name and allow with default value. like
envKey: ${SHELL|/bin/bash}->envKey: /bin/zsh - Generic API:
GetIntUintInt64FloatStringBoolIntsIntMapStringsStringMap... - Complete unit test(code coverage > 95%)
Only use INI
If you just want to use INI for simple config management, recommended use gookit/ini
Load dotenv file
On gookit/ini: Provide a sub-package dotenv that supports importing data from files (eg .env) to ENV
go get github.com/gookit/ini/v2/dotenv
GoDoc
Install
go get github.com/gookit/config/v2
Usage
Here using the yaml format as an example(testdata/yml_other.yml):
name: app2
debug: false
baseKey: value2
shell: ${SHELL}
envKey1: ${NotExist|defValue}
map1:
key: val2
key2: val20
arr1:
- val1
- val21
Load data
examples code please see _examples/yaml.go:
package main
import (
"github.com/gookit/config/v2"
"github.com/gookit/config/v2/yaml"
)
// go run ./examples/yaml.go
func main() {
// config.ParseEnv: will parse env var in string value. eg: shell: ${SHELL}
config.WithOptions(config.ParseEnv)
// add driver for support yaml content
config.AddDriver(yaml.Driver)
err := config.LoadFiles("testdata/yml_base.yml")
if err != nil {
panic(err)
}
// load more files
err = config.LoadFiles("testdata/yml_other.yml")
// can also load multi at once
// err := config.LoadFiles("testdata/yml_base.yml", "testdata/yml_other.yml")
if err != nil {
panic(err)
}
// fmt.Printf("config data: \n %#v\n", config.Data())
}
Usage tips:
- More extra options can be added using
WithOptions(). For example:ParseEnv,ParseDefault - You can use
AddDriver()to add the required format driver (jsonis loaded by default, no need to add) - The configuration data can then be loaded using
LoadFiles()LoadStrings()etc.- You can pass in multiple files or call multiple times
- Data loaded multiple times will be automatically merged by key
Bind Structure
Note: The default binding mapping tag of a structure is
mapstructure, which can be changed by setting the decoder's optionoptions.DecoderConfig.TagName
type User struct {
Age int `mapstructure:"age"`
Key string `mapstructure:"key"`
UserName string `mapstructure:"user_name"`
Tags []int `mapstructure:"tags"`
}
user := User{}
err = config.BindStruct("user", &user)
fmt.Println(user.UserName) // inhere
Change struct tag name
config.WithOptions(func(opt *Options) {
options.DecoderConfig.TagName = "config"
})
// use custom tag name.
type User struct {
Age int `config:"age"`
Key string `config:"key"`
UserName string `config:"user_name"`
Tags []int `config:"tags"`
}
user := User{}
err = config.Decode(&user)
Can bind all config data to a struct:
config.Decode(&myConf)
// can also
config.BindStruct("", &myConf)
config.MapOnExistslikeBindStruct,but map binding only if key exists
Direct read data
- Get integer
age := config.Int("age")
fmt.Print(age) // 100
- Get bool
val := config.Bool("debug")
fmt.Print(val) // true
- Get string
name := config.String("name")
fmt.Print(name) // inhere
- Get strings(slice)
arr1 := config.Strings("arr1")
fmt.Printf("%#v", arr1) // []string{"val1", "val21"}
- Get string map
val := config.StringMap("map1")
fmt.Printf("%#v",val) // map[string]string{"key":"val2", "key2":"val20"}
- Value contains ENV var
value := config.String("shell")
fmt.Print(value) // "/bin/zsh"
- Get value by key path
// from array
value := config.String("arr1.0")
fmt.Print(value) // "val1"
// from map
value := config.String("map1.key")
fmt.Print(value) // "val2"
- Setting new value
// set value
config.Set("name", "new name")
name = config.String("name")
fmt.Print(name) // "new name"
Load from ENV
Support load ENV vars to config data.
- Support set value to sub key in map.
- eg:
{"DB_USERNAME": "db.username"}value will set tousernameindb
- eg:
// os env: APP_NAME=config APP_DEBUG=true DB_USERNAME=someone
// load ENV info
config.LoadOSEnvs(map[string]string{"APP_NAME": "app_name", "APP_DEBUG": "app_debug", "DB_USERNAME": "db.username"})
// read
config.Bool("app_debug") // true
config.String("app_name") // "config"
Load from flags
Support simple CLI flags parameter parsing, load to config data.
- define format:
name:type:descORname:typeORname:desc(type, desc is optional)typecan setflagtype. allow:bool,int,string(default)desccan setflagdescription
namecan be in key path format.- eg:
db.username, input:--db.username=someonevalues will be mapped tousernameof thedbconfiguration
- eg:
// 'debug' flag is bool type
config.LoadFlags([]string{"env", "debug:bool"})
// can with flag desc message
config.LoadFlags([]string{"env:set the run env"})
config.LoadFlags([]string{"debug:bool:set debug mode"})
// can set value to map key. eg: myapp --map1.sub-key=val
config.LoadFlags([]string{"map1.sub-key"})
Examples:
// flags like: --name inhere --env dev --age 99 --debug --map1.sub-key=val
// load flag info
keys := []string{
"name",
"env:set the run env",
"age:int",
"debug:bool:set debug mode",
"map1.sub-key",
}
err := config.LoadFlags(keys)
// read
config.String("name") // "inhere"
config.String("env") // "dev"
config.Int("age") // 99
config.Bool("debug") // true
config.Get("map1") // map[string]any{"sub-key":"val"}
New config instance
You can create custom config instance
// create new instance, will auto register JSON driver
myConf := config.New("my-conf")
// create empty instance
myConf := config.NewEmpty("my-conf")
// create and with some options
myConf := config.NewWithOptions("my-conf", config.ParseEnv, config.ReadOnly)
Listen config change
Now, you can add a hook func for listen config data change. then, you can do something like: write data to file
Add hook func on create config:
hookFn := func(event string, c *Config) {
fmt.Println("fire the:", event)
}
c := NewWithOptions("test", config.WithHookFunc(hookFn))
// for global config
config.WithOptions(config.WithHookFunc(hookFn))
After that, when calling LoadXXX, Set, SetData, ClearData methods, it will output:
fire the: load.data
fire the: set.value
fire the: set.data
fire the: clean.data
Watch loaded config files
To listen for changes to loaded config files, and reload the config when it changes, you need to use the https://github.com/fsnotify/fsnotify library. For usage, please refer to the example ./_example/watch_file.go
Also, you need to listen to the reload.data event:
config.WithOptions(config.WithHookFunc(func(event string, c *config.Config) {
if event == config.OnReloadData {
fmt.Println("config reloaded, you can do something ....")
}
}))
When the configuration changes, you can do related things, for example: rebind the configuration to your struct.
Dump config data
Can use
config.DumpTo()export the configuration data to the specifiedwriter, such as: buffer,file
Dump to JSON file
buf := new(bytes.Buffer)
_, err := config.DumpTo(buf, config.JSON)
ioutil.WriteFile("my-config.json", buf.Bytes(), 0755)
Dump pretty JSON
You can set the default var JSONMarshalIndent or custom a new JSON driver.
config.JSONMarshalIndent = " "
