config
- Simple, full-featured Go application configuration management tool library.
- Support multi format:
JSON
(default),JSON5
,INI
,Properties
,YAML
,TOML
,HCL
,ENV
,Flags
JSON
content support comments. will auto clear comments- 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.key
arr.2
- Support parse ENV name and allow with default value. like
envKey: ${SHELL|/bin/bash}
->envKey: /bin/zsh
- Generic API:
Get
Int
Uint
Int64
Float
String
Bool
Ints
IntMap
Strings
StringMap
... - Complete unit test(code coverage > 95%)
If you just want to use INI for simple config management, recommended use gookit/ini
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
go get github.com/gookit/config/v2
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
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 (json
is 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
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.MapOnExists
likeBindStruct
,but map binding only if key exists
- 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"
Support simple flags parameter parsing, loading
// flags like: --name inhere --env dev --age 99 --debug
// load flag info
keys := []string{"name", "env", "age:int" "debug:bool"}
err := config.LoadFlags(keys)
// read
config.String("name") // "inhere"
config.String("env") // "dev"
config.Int("age") // 99
config.Bool("debug") // true
// os env: APP_NAME=config APP_DEBUG=true
// load ENV info
config.LoadOSEnvs(map[string]string{"APP_NAME": "app_name", "APP_DEBUG": "app_debug"})
// read
config.Bool("app_debug") // true
config.String("app_name") // "config"
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)
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
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.
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 = " "
Dump to YAML file
_, err := config.DumpTo(buf, config.YAML)
ioutil.WriteFile("my-config.yaml", buf.Bytes(), 0755)
// Options config options
type Options struct {
// parse env in string value. like: "${EnvName}" "${EnvName|default}"
ParseEnv bool
// ParseTime parses a duration string to time.Duration
// eg: 10s, 2m
ParseTime bool
// config is readonly. default is False
Readonly bool
// enable config data cache. default is False
EnableCache bool
// parse key, allow find value by key path. default is True eg: 'key.sub' will find `map[key]sub`
ParseKey bool
// the delimiter char for split key path, if `FindByPath=true`. default is '.'
Delimiter byte
// default write format
DumpFormat string
// default input format
ReadFormat string
// DecoderConfig setting for binding data to struct
DecoderConfig *mapstructure.DecoderConfig
// HookFunc on data changed.
HookFunc HookFunc
// ParseDefault tag on binding data to struct. tag: default
ParseDefault bool
}
Examples for set options:
config.WithOptions(config.WithTagName("mytag"))
config.WithOptions(func(opt *Options) {
opt.SetTagNames("config")
})
Support parse default value by struct tag default
// add option: config.ParseDefault
c := config.New("test").WithOptions(config.ParseDefault)
// only set name
c.SetData(map[string]any{
"name": "inhere",
})
// age load from default tag
type User struct {
Age int `default:"30"`
Name string
Tags []int
}
user := &User{}
goutil.MustOk(c.Decode(user))
dump.Println(user)
Output:
&config_test.User {
Age: int(30),
Name: string("inhere"), #len=6
Tags: []int [ #len=0
],
},
LoadOSEnvs(nameToKeyMap map[string]string)
Load data from os ENVLoadData(dataSource ...any) (err error)
Load from struts or mapsLoadFlags(keys []string) (err error)
Load from CLI flagsLoadExists(sourceFiles ...string) (err error)
LoadFiles(sourceFiles ...string) (err error)
LoadFromDir(dirPath, format string) (err error)
Load custom format files from the given directory, the file name will be used as the keyLoadRemote(format, url string) (err error)
LoadSources(format string, src []byte, more ...[]byte) (err error)
LoadStrings(format string, str string, more ...string) (err error)
LoadFilesByFormat(format string, sourceFiles ...string) (err error)
LoadExistsByFormat(format string, sourceFiles ...string) error
Bool(key string, defVal ...bool) bool
Int(key string, defVal ...int) int
Uint(key string, defVal ...uint) uint
Int64(key string, defVal ...int64) int64
Ints(key string) (arr []int)
IntMap(key string) (mp map[string]int)
Float(key string, defVal ...float64) float64
String(key string, defVal ...string) string
Strings(key string) (arr []string)
SubDataMap(key string) maputi.Data
StringMap(key string) (mp map[string]string)
Get(key string, findByPath ...bool) (value any)
Mapping data to struct:
Decode(dst any) error
BindStruct(key string, dst any) error
MapOnExists(key string, dst any) error
Set(key string, val any, setByPath ...bool) (err error)
Getenv(name string, defVal ...string) (val string)
AddDriver(driver Driver)
Data() map[string]any
SetData(data map[string]any)
set data to override the Config.DataExists(key string, findByPath ...bool) bool
DumpTo(out io.Writer, format string) (n int64, err error)
go test -cover
// contains all sub-folder
go test -cover ./...
Check out these projects, which use https://github.com/gookit/config :
- https://github.com/JanDeDobbeleer/oh-my-posh A prompt theme engine for any shell.
- + See More
- gookit/ini Go config management, use INI files
- gookit/rux Simple and fast request router for golang HTTP
- gookit/gcli build CLI application, tool library, running CLI commands
- gookit/event Lightweight event manager and dispatcher implements by Go
- gookit/cache Generic cache use and cache manager for golang. support File, Memory, Redis, Memcached.
- gookit/config Go config management. support JSON, YAML, TOML, INI, HCL, ENV and Flags
- gookit/color A command-line color library with true color support, universal API methods and Windows support
- gookit/filter Provide filtering, sanitizing, and conversion of golang data
- gookit/validate Use for data validation and filtering. support Map, Struct, Form data
- gookit/goutil Some utils for the Go: string, array/slice, map, format, cli, env, filesystem, test and more
- More, please see https://github.com/gookit
- Ini parser gookit/ini/parser
- Properties parser gookit/properties
- Json5 parser
- Json parser
- Yaml parser
- Toml parser go toml
- Data merge mergo
- Map structure mapstructure
MIT