Documentation ¶
Overview ¶
Package xconf provides a configuration registry for an application. Configurations can be extracted from a file / env / flag set / remote system. Supported formats are json, yaml, ini, (java) properties, toml, plain.
Index ¶
- Constants
- Variables
- func DeepCopyConfigMap(src map[string]any) map[string]any
- func FilterEmptyValue(_ string, value any) bool
- func FilterExactKeys(keys ...string) func(key string, _ any) bool
- func FilterKeyWithPrefix(prefix string) func(key string, _ any) bool
- func FilterKeyWithSuffix(suffix string) func(key string, _ any) bool
- func LogErrorHandler(loggerGetter func() xlog.Logger) func(error)
- func LogLevelProvider(config Config, lvlKey string, defaultLvl string, ...) xlog.LevelProvider
- type AlterValueFunc
- type Config
- type ConfigObserver
- type ConsulLoader
- type ConsulLoaderOption
- func ConsulLoaderWithCache() ConsulLoaderOption
- func ConsulLoaderWithContext(ctx context.Context) ConsulLoaderOption
- func ConsulLoaderWithHTTPClient(client *http.Client) ConsulLoaderOption
- func ConsulLoaderWithHost(host string) ConsulLoaderOption
- func ConsulLoaderWithPrefix() ConsulLoaderOption
- func ConsulLoaderWithQueryDataCenter(dc string) ConsulLoaderOption
- func ConsulLoaderWithQueryNamespace(ns string) ConsulLoaderOption
- func ConsulLoaderWithRequestHeader(hName, hValue string) ConsulLoaderOption
- func ConsulLoaderWithValueFormat(valueFormat string) ConsulLoaderOption
- type DefaultConfig
- type DefaultConfigOption
- type EtcdLoader
- type EtcdLoaderOption
- func EtcdLoaderWithAuth(username, pwd string) EtcdLoaderOption
- func EtcdLoaderWithContext(ctx context.Context) EtcdLoaderOption
- func EtcdLoaderWithEndpoints(endpoints []string) EtcdLoaderOption
- func EtcdLoaderWithPrefix() EtcdLoaderOption
- func EtcdLoaderWithTLS(tlsCfg *tls.Config) EtcdLoaderOption
- func EtcdLoaderWithValueFormat(valueFormat string) EtcdLoaderOption
- func EtcdLoaderWithWatcher() EtcdLoaderOption
- type FileCacheLoader
- type FilterKV
- type FilterKVBlacklistFunc
- type FilterKVWhitelistFunc
- type FilterType
- type FlattenLoader
- type FlattenLoaderOption
- type IniFileLoader
- type IniFileLoaderOption
- type KeyConflictError
- type Loader
- func AliasLoader(loader Loader, aliasKeyKey ...string) Loader
- func AlterValueLoader(loader Loader, transformation AlterValueFunc, keys ...string) Loader
- func DotEnvFileLoader(filePath string) Loader
- func DotEnvReaderLoader(reader io.Reader) Loader
- func EnvLoader() Loader
- func FileLoader(filePath string) Loader
- func FilterKVLoader(loader Loader, filters ...FilterKV) Loader
- func FlagSetLoader(flgSet *flag.FlagSet, visitAll ...bool) Loader
- func IgnoreErrorLoader(loader Loader, errs ...error) Loader
- func JSONFileLoader(filePath string) Loader
- func JSONReaderLoader(reader io.Reader) Loader
- func PlainLoader(configMap map[string]any) Loader
- func PropertiesBytesLoader(propertiesContent []byte) Loader
- func PropertiesFileLoader(filePath string) Loader
- func TOMLFileLoader(filePath string) Loader
- func TOMLReaderLoader(reader io.Reader) Loader
- func YAMLFileLoader(filePath string) Loader
- func YAMLReaderLoader(reader io.Reader) Loader
- type LoaderFunc
- type MockConfig
- type MultiLoader
- type NopConfig
Examples ¶
- AliasLoader
- AlterValueLoader
- ConsulLoader
- DefaultConfig
- DotEnvFileLoader
- EnvLoader
- EtcdLoader
- FileCacheLoader
- FileLoader
- FilterEmptyValue
- FilterExactKeys
- FilterKVLoader
- FilterKeyWithPrefix
- FilterKeyWithSuffix
- FlagSetLoader
- FlattenLoader
- IgnoreErrorLoader
- IniFileLoader
- JSONFileLoader
- LogErrorHandler
- LogLevelProvider
- MultiLoader
- PropertiesFileLoader
- TOMLFileLoader
- YAMLFileLoader
Constants ¶
const ( // RemoteValueJSON indicates that content under a key is in JSON format. RemoteValueJSON = "json" // RemoteValueYAML indicates that content under a key is in YAML format. RemoteValueYAML = "yaml" // RemoteValuePlain indicates that content under a key is plain text. RemoteValuePlain = "plain" )
const ( // ConsulHeaderAuthToken is the header name for setting a token. // See also [Consul API Ref]. // // [Consul API Ref]: https://www.consul.io/api-docs#authentication ConsulHeaderAuthToken = "X-Consul-Token" )
Variables ¶
var ErrAliasPairBroken = errors.New("alias - missing key")
ErrAliasPairBroken is an error returned by AliasLoader when the variadic list of aliases and their keys consists of odd no. of elements.
var ErrConsulKeyNotFound = errors.New("404 - Consul Key Not Found")
ErrConsulKeyNotFound is thrown when a Consul read key request responds with 404.
var ErrUnknownConfigFileExt = errors.New("unknown configuration file extension")
ErrUnknownConfigFileExt is an error returned by FileLoader if file extension does not match any supported format.
Functions ¶
func DeepCopyConfigMap ¶
DeepCopyConfigMap is a utility function to make a deep "copy"/clone of a config map.
func FilterEmptyValue ¶
FilterEmptyValue returns true if a value is nil or "". It can be used as a FilterKV like:
xconf.FilterKVBlacklistFunc(xconf.FilterEmptyValue)
Example ¶
package main import ( "fmt" "github.com/actforgood/xconf" ) func main() { origLoader := xconf.PlainLoader(map[string]any{ "redis_dial_timeout": "5s", "redis_dsn": "", }) loader := xconf.FilterKVLoader( origLoader, xconf.FilterKVBlacklistFunc(xconf.FilterEmptyValue), ) configMap, _ := loader.Load() fmt.Println(configMap) }
Output: map[redis_dial_timeout:5s]
func FilterExactKeys ¶
FilterExactKeys returns true if a key is present in the provided list. It can be used as a FilterKV like:
xconf.FilterKVWhitelistFunc(xconf.FilterExactKeys(key1, key2)) xconf.FilterKVBlacklistFunc(xconf.FilterExactKeys(key1, key2))
Example ¶
package main import ( "fmt" "github.com/actforgood/xconf" ) func main() { origLoader := xconf.PlainLoader(map[string]any{ "FOO": "foo value", "BAR": "bar value", "BAZ": "baz value", }) loader := xconf.FilterKVLoader( origLoader, xconf.FilterKVWhitelistFunc(xconf.FilterExactKeys("FOO", "BAR")), ) configMap, _ := loader.Load() for key, value := range configMap { fmt.Println(key+":", value) } }
Output: FOO: foo value BAR: bar value
func FilterKeyWithPrefix ¶
FilterKeyWithPrefix returns true if a key has given prefix. It can be used as a FilterKV like:
xconf.FilterKVWhitelistFunc(xconf.FilterKeyWithPrefix(prefix)) xconf.FilterKVBlacklistFunc(xconf.FilterKeyWithPrefix(prefix))
Example ¶
package main import ( "fmt" "github.com/actforgood/xconf" ) func main() { origLoader := xconf.PlainLoader(map[string]any{ "APP_FOO_1": "bar 1", "APP_FOO_2": "bar 2", "OS": "Windows", }) loader := xconf.FilterKVLoader( origLoader, xconf.FilterKVWhitelistFunc(xconf.FilterKeyWithPrefix("APP_")), ) configMap, _ := loader.Load() for key, value := range configMap { fmt.Println(key+":", value) } }
Output: APP_FOO_1: bar 1 APP_FOO_2: bar 2
func FilterKeyWithSuffix ¶
FilterKeyWithSuffix returns true if a key has given suffix. It can be used as a FilterKV like:
xconf.FilterKVWhitelistFunc(xconf.FilterKeyWithSuffix(suffix)) xconf.FilterKVBlacklistFunc(xconf.FilterKeyWithSuffix(suffix))
Example ¶
package main import ( "fmt" "github.com/actforgood/xconf" ) func main() { origLoader := xconf.PlainLoader(map[string]any{ "REDIS_SERVICE_HOST": "10.0.0.11", "REDIS_SERVICE_PORT": "6379", "OS": "Windows", }) loader := xconf.FilterKVLoader( origLoader, // K8s style accessible Services xconf.FilterKVWhitelistFunc(xconf.FilterKeyWithSuffix("_SERVICE_HOST")), xconf.FilterKVWhitelistFunc(xconf.FilterKeyWithSuffix("_SERVICE_PORT")), ) configMap, _ := loader.Load() for key, value := range configMap { fmt.Println(key+":", value) } }
Output: REDIS_SERVICE_HOST: 10.0.0.11 REDIS_SERVICE_PORT: 6379
func LogErrorHandler ¶
LogErrorHandler is a handler which can be used in a xconf.DefaultConfig object as a reload error handler. It logs the error with a xlog.Logger. Passed parameter is a function that returns the logger (Logger and Config depend one of each other, this way we can instantiate them separately...)
Example ¶
package main import ( "fmt" "os" "time" "github.com/actforgood/xconf" "github.com/actforgood/xlog" ) func main() { // initialize the logger. logger := xlog.NewSyncLogger(os.Stdout) defer logger.Close() // initialize Config object, // loader can be any other Loader, used this for the sake of simplicity and readability. loader := xconf.PlainLoader(map[string]any{ "foo": "bar", }) loggerGetter := func() xlog.Logger { return logger } config, _ := xconf.NewDefaultConfig( // treat the error on live code! loader, xconf.DefaultConfigWithReloadInterval(time.Second), xconf.DefaultConfigWithReloadErrorHandler(xconf.LogErrorHandler(loggerGetter)), ) defer config.Close() foo := config.Get("foo", "default foo").(string) fmt.Println(foo) }
Output: bar
func LogLevelProvider ¶
func LogLevelProvider( config Config, lvlKey string, defaultLvl string, levelLabels map[xlog.Level]string, ) xlog.LevelProvider
LogLevelProvider provides a level read from a Config object. It can be used to configure log level for a xlog.Logger. If the level configuration key is not found, the default provided level is returned. If the reload option is present on the config object, you may change during application run the underlying key without restarting the app, and new configured value will be used in place, if suitable.
Example ¶
package main import ( "os" "time" "github.com/actforgood/xconf" "github.com/actforgood/xlog" ) func main() { const logLevelKey = "APP_LOG_LEVEL" const defaultLogLevel = "WARN" // initialize Config object, // loader can be any other Loader, used this for the sake of simplicity and readability. loader := xconf.PlainLoader(map[string]any{ logLevelKey: "INFO", }) config, _ := xconf.NewDefaultConfig( // treat the error on live code! loader, xconf.DefaultConfigWithReloadInterval(time.Second), ) defer config.Close() // initialize the logger with min level taken from Config. opts := xlog.NewCommonOpts() opts.MinLevel = xconf.LogLevelProvider(config, logLevelKey, defaultLogLevel, opts.LevelLabels) opts.Time = func() any { // mock time for output check return "2022-06-21T17:17:20Z" } opts.Source = xlog.SourceProvider(4, 1) // keep only filename for output check logger := xlog.NewSyncLogger( os.Stdout, xlog.SyncLoggerWithOptions(opts), ) defer logger.Close() logger.Info(xlog.MessageKey, "log level is taken from xconf.Config") logger.Debug(xlog.MessageKey, "this message should not end up being logged as min level is INFO") }
Output: {"date":"2022-06-21T17:17:20Z","lvl":"INFO","msg":"log level is taken from xconf.Config","src":"/xlog_adapter_test.go:49"}
Types ¶
type AlterValueFunc ¶
AlterValueFunc is a function that manipulates a config's value.
func ToIntList ¶
func ToIntList(sep string) AlterValueFunc
ToIntList makes a slice of integers from a string value, who's items are separated by given separator parameter.
If the original value is not a string, the value remains unaltered.
Example: "10,100,1000" => [10, 100, 1000].
func ToStringList ¶
func ToStringList(sep string) AlterValueFunc
ToStringList makes a slice of strings from a string value, who's items are separated by given separator parameter.
If the original value is not a string, the value remains unaltered.
Example: "bread,eggs,milk" => ["bread", "eggs", "milk"].
type Config ¶
type Config interface { // Get returns a configuration value for a given key. // The first parameter is the key to return the value for. // The second parameter is optional, and represents a default // value in case key is not found. It also has a role in inferring // the type of key's value (if it exists) and thus key's value // will be casted to default's value type. Get(key string, def ...any) any }
Config provides prototype for returning configurations.
type ConfigObserver ¶
ConfigObserver gets called to notify about changed keys on Config reload.
type ConsulLoader ¶
type ConsulLoader struct {
// contains filtered or unexported fields
}
ConsulLoader loads configuration from Consul Key-Value Store.
Example ¶
package main import ( "fmt" "github.com/actforgood/xconf" ) func main() { // load all keys starting with "APP_" host := "http://127.0.0.1:8500" loader := xconf.NewConsulLoader( "APP_", xconf.ConsulLoaderWithHost(host), xconf.ConsulLoaderWithPrefix(), ) configMap, err := loader.Load() if err != nil { panic(err) } for key, value := range configMap { fmt.Println(key+":", value) } }
Output:
func NewConsulLoader ¶
func NewConsulLoader(key string, opts ...ConsulLoaderOption) ConsulLoader
NewConsulLoader instantiates a new ConsulLoader object that loads configuration from Consul.
type ConsulLoaderOption ¶
type ConsulLoaderOption func(*ConsulLoader)
ConsulLoaderOption defines optional function for configuring a Consul Loader.
func ConsulLoaderWithCache ¶
func ConsulLoaderWithCache() ConsulLoaderOption
ConsulLoaderWithCache enables cache.
func ConsulLoaderWithContext ¶
func ConsulLoaderWithContext(ctx context.Context) ConsulLoaderOption
ConsulLoaderWithContext sets request 's context. By default, a context.Background() is used.
func ConsulLoaderWithHTTPClient ¶
func ConsulLoaderWithHTTPClient(client *http.Client) ConsulLoaderOption
ConsulLoaderWithHTTPClient sets the http client used for calls. A default one is provided if you don't use this option.
func ConsulLoaderWithHost ¶
func ConsulLoaderWithHost(host string) ConsulLoaderOption
ConsulLoaderWithHost sets Consul's base url. By default, is set to "http://127.0.0.1:8500". Consul host can also be set through CONSUL_HTTP_ADDR and CONSUL_HTTP_SSL ENV as in official hashicorp's client.
Example:
xconf.ConsulLoaderWithHost("http://consul.example.com:8500")
func ConsulLoaderWithPrefix ¶
func ConsulLoaderWithPrefix() ConsulLoaderOption
ConsulLoaderWithPrefix specifies if the lookup should be recursive and the "key" treated as a prefix instead of a literal match.
func ConsulLoaderWithQueryDataCenter ¶
func ConsulLoaderWithQueryDataCenter(dc string) ConsulLoaderOption
ConsulLoaderWithQueryDataCenter specifies the datacenter to query. This will default to the datacenter of the agent being queried. See also official doc. Example:
xconf.ConsulLoaderWithQueryDataCenter("my-dc")
func ConsulLoaderWithQueryNamespace ¶
func ConsulLoaderWithQueryNamespace(ns string) ConsulLoaderOption
ConsulLoaderWithQueryNamespace specifies the namespace to query (enterprise). If not provided, the namespace will be inferred from the request's ACL token, or will default to the default namespace. For recursive lookups, the namespace may be specified as '*' and then results will be returned for all namespaces. Added in Consul 1.7.0. See also official doc.
Example:
xconf.ConsulLoaderWithQueryNamespace("my-ns")
func ConsulLoaderWithRequestHeader ¶
func ConsulLoaderWithRequestHeader(hName, hValue string) ConsulLoaderOption
ConsulLoaderWithRequestHeader adds a request header. You can set the auth token for example:
xconf.ConsulLoaderWithRequestHeader(xconf.ConsulHeaderAuthToken, "someSecretToken")
or some basic auth header:
xconf.ConsulLoaderWithRequestHeader( "Authorization", "Basic " + base64.StdEncoding.EncodeToString([]byte(usr + ":" + pwd)), )
func ConsulLoaderWithValueFormat ¶
func ConsulLoaderWithValueFormat(valueFormat string) ConsulLoaderOption
ConsulLoaderWithValueFormat sets the value format for a key.
If is set to RemoteValueJSON, the key's value will be treated as JSON and configuration will be loaded from it.
If is set to RemoteValueYAML, the key's value will be treated as YAML and configuration will be loaded from it.
If is set to RemoteValuePlain, the key's value will be treated as plain content and configuration will contain the key and its plain value.
By default, is set to RemoteValuePlain.
type DefaultConfig ¶
type DefaultConfig struct {
// contains filtered or unexported fields
}
DefaultConfig is the default implementation for the Config contract. It is based on a Loader to retrieve configuration from. Is implements io.Closer and thus Close should be called at your application shutdown in order to avoid memory leaks.
Example ¶
package main import ( "fmt" "time" "github.com/actforgood/xconf" ) func main() { loader := xconf.NewMultiLoader( true, xconf.EnvLoader(), xconf.JSONFileLoader("testdata/config.json"), ) cfg, err := xconf.NewDefaultConfig( loader, xconf.DefaultConfigWithIgnoreCaseSensitivity(), xconf.DefaultConfigWithReloadInterval(time.Minute), ) if err != nil { panic(err) } defer cfg.Close() fmt.Println(cfg.Get("json_foo", "baz")) }
Output: bar
func NewDefaultConfig ¶
func NewDefaultConfig(loader Loader, opts ...DefaultConfigOption) (*DefaultConfig, error)
NewDefaultConfig instantiates a new default config object. The first parameter is the loader used as a source of getting the key-value configuration map. The second parameter represents a list of optional functions to configure the object.
func (*DefaultConfig) Close ¶
func (cfg *DefaultConfig) Close() error
Close stops the underlying ticker used to reload config, avoiding memory leaks. It should be called at your application shutdown. It implements io.Closer and the returned error can be disregarded (is nil all the time).
func (DefaultConfig) Get ¶
Get returns a configuration value for a given key. The first parameter is the key to return the value for. The second parameter is optional, and represents a default value in case key is not found. It so has a role in inferring the type of key's value (if it exists) and thus key's value will be casted to default's value type. Only basic types (string, bool, int, uint, float, and their flavours), time.Duration, time.Time, []int, []string are covered. If a cast error occurs, the defaultValue is returned.
func (DefaultConfig) RegisterObserver ¶
func (cfg DefaultConfig) RegisterObserver(observer ConfigObserver)
RegisterObserver adds a new observer that will get notified of keys changes.
type DefaultConfigOption ¶
type DefaultConfigOption func(*DefaultConfig)
DefaultConfigOption defines optional function for configuring a DefaultConfig object.
func DefaultConfigWithIgnoreCaseSensitivity ¶
func DefaultConfigWithIgnoreCaseSensitivity() DefaultConfigOption
DefaultConfigWithIgnoreCaseSensitivity disables case sensitivity for keys.
For example, if the configuration map contains a key "Foo", calling Get() with "foo" / "FOO" / etc. will return Foo's value.
Usage example:
cfg, err := xconf.NewDefaultConfig(loader, xconf.DefaultConfigWithIgnoreCaseSensitivity()) if err != nil { panic(err) } value1 := cfg.Get("foo") value2 := cfg.Get("FOO") value3 := cfg.Get("foO") // all values are equal
func DefaultConfigWithReloadErrorHandler ¶
func DefaultConfigWithReloadErrorHandler(errHandler func(error)) DefaultConfigOption
DefaultConfigWithReloadErrorHandler sets the handler for errors that may occur during reloading configuration, if DefaultConfigWithReloadInterval was applied. If reload fails, "old"/previous configuration is active.
You can choose to log the error, for example.
By default, error is simply ignored.
func DefaultConfigWithReloadInterval ¶
func DefaultConfigWithReloadInterval(reloadInterval time.Duration) DefaultConfigOption
DefaultConfigWithReloadInterval sets interval to reload configuration. Passing a value <= 0 disables the config reload.
By default, configuration reload is disabled.
Usage example:
// enable config reload at an interval of 5 minutes: cfg, err := xconf.NewDefaultConfig(loader, xconf.DefaultConfigWithReloadInterval(5 * time.Minute))
type EtcdLoader ¶
type EtcdLoader struct {
// contains filtered or unexported fields
}
EtcdLoader loads configuration from etcd. Close it if watcher option is enabled, in order to properly release resources.
Example ¶
package main import ( "fmt" "github.com/actforgood/xconf" ) func main() { // load all keys starting with "APP_" hosts := []string{"127.0.0.1:2379"} loader := xconf.NewEtcdLoader( "APP_", xconf.EtcdLoaderWithEndpoints(hosts), xconf.EtcdLoaderWithPrefix(), ) configMap, err := loader.Load() if err != nil { panic(err) } for key, value := range configMap { fmt.Println(key+":", value) } }
Output:
func NewEtcdLoader ¶
func NewEtcdLoader(key string, opts ...EtcdLoaderOption) EtcdLoader
NewEtcdLoader instantiates a new EtcdLoader object that loads configuration from etcd.
func (EtcdLoader) Close ¶
func (loader EtcdLoader) Close() error
Close needs to be called in case watch key changes were enabled. It releases associated resources.
type EtcdLoaderOption ¶
type EtcdLoaderOption func(*EtcdLoader)
EtcdLoaderOption defines optional function for configuring an Etcd Loader.
func EtcdLoaderWithAuth ¶
func EtcdLoaderWithAuth(username, pwd string) EtcdLoaderOption
EtcdLoaderWithAuth sets the authentication username and password.
func EtcdLoaderWithContext ¶
func EtcdLoaderWithContext(ctx context.Context) EtcdLoaderOption
EtcdLoaderWithContext sets request's context. By default, a context.Background() is used.
func EtcdLoaderWithEndpoints ¶
func EtcdLoaderWithEndpoints(endpoints []string) EtcdLoaderOption
EtcdLoaderWithEndpoints sets the etcd host(s) for the client. By default, is set to "127.0.0.1:2379". Etcd hosts can also be set through ETCD_ENDPOINTS ENV (comma separated, if there is more than 1 ep).
func EtcdLoaderWithPrefix ¶
func EtcdLoaderWithPrefix() EtcdLoaderOption
EtcdLoaderWithPrefix sets the WithPrefix() option on etcd client. The loaded key will be treated as a prefix, and thus all the keys having that prefix will be returned.
func EtcdLoaderWithTLS ¶ added in v1.5.0
func EtcdLoaderWithTLS(tlsCfg *tls.Config) EtcdLoaderOption
EtcdLoaderWithTLS sets the TLS configuration for secure communication between client and server.
func EtcdLoaderWithValueFormat ¶
func EtcdLoaderWithValueFormat(valueFormat string) EtcdLoaderOption
EtcdLoaderWithValueFormat sets the value format for a key.
If is set to RemoteValueJSON, the key's value will be treated as JSON and configuration will be loaded from it.
If is set to RemoteValueYAML, the key's value will be treated as YAML and configuration will be loaded from it.
If is set to RemoteValuePlain, the key's value will be treated as plain content and configuration will contain the key and its plain value.
By default, is set to RemoteValuePlain.
func EtcdLoaderWithWatcher ¶
func EtcdLoaderWithWatcher() EtcdLoaderOption
EtcdLoaderWithWatcher enables watch for keys changes. Use this if you intend to load configuration intensively, multiple times. If you plan to load configuration only once, or rarely, don't use this feature. If you use this feature, call Close() method on the loader to gracefully release resources (at your application shutdown).
type FileCacheLoader ¶
type FileCacheLoader struct {
// contains filtered or unexported fields
}
FileCacheLoader decorates another "file" loader to load configuration only if the file was modified. If the file was not modified since the previous load, the file won't be read and parsed again. You can improve performance this way, if you plan to load configuration multiple times (like using it in DefaultConfig with reload enabled).
Example ¶
package main import ( "fmt" "github.com/actforgood/xconf" ) func main() { var ( filePath = "testdata/config.json" loader = xconf.NewFileCacheLoader( xconf.JSONFileLoader(filePath), filePath, ) configMap map[string]any err error ) for i := 0; i < 3; i++ { // 1st time original loader will be called, // 2nd and 3rd time, config will be retrieved from cache. configMap, err = loader.Load() if err != nil { panic(err) } } for key, value := range configMap { fmt.Println(key+":", value) } }
Output: json_foo: bar json_year: 2022 json_temperature: 37.5 json_shopping_list: [bread milk eggs]
func NewFileCacheLoader ¶
func NewFileCacheLoader(loader Loader, filePath string) FileCacheLoader
NewFileCacheLoader instantiates a new FileCacheLoader object that loads and caches the configuration from the original "file" loader. The second parameter should be the same file as the original loader's one.
func (FileCacheLoader) Load ¶
func (decorator FileCacheLoader) Load() (map[string]any, error)
Load returns decorated loader's key-value configuration map. If the file was modified since last load, that file will be read and parsed again, if not, the previous, already processed, configuration map will be returned.
type FilterKV ¶
type FilterKV interface { // IsAllowed returns true if a key-value is eligible to be returned // in the configuration map. IsAllowed(key string, value any) bool // Type returns filter's type (FilterTypeWhitelist / FilterTypeBlacklist). Type() FilterType }
FilterKV is the contract for a key-value filter.
type FilterKVBlacklistFunc ¶
The FilterKVBlacklistFunc type is an adapter to allow the use of ordinary functions as FilterKV of "blacklist" type. If fn is a function with the appropriate signature, FilterKVBlacklistFunc(fn) is a FilterKV that calls fn and has type FilterTypeBlacklist. fn should return true if the KV is blacklisted.
Example:
xconf.FilterKVBlacklistFunc(func(key string, _ any) bool { return key == "DENY_ME_1" || key == "DENY_ME_2" })
func (FilterKVBlacklistFunc) IsAllowed ¶
func (filter FilterKVBlacklistFunc) IsAllowed(key string, value any) bool
IsAllowed returns false if a key-value is blacklisted.
func (FilterKVBlacklistFunc) Type ¶
func (filter FilterKVBlacklistFunc) Type() FilterType
Type returns filter's type (FilterTypeBlacklist).
type FilterKVWhitelistFunc ¶
The FilterKVWhitelistFunc type is an adapter to allow the use of ordinary functions as FilterKV of "whitelist" type. If fn is a function with the appropriate signature, FilterKVWhitelistFunc(fn) is a FilterKV that calls fn of type FilterTypeWhitelist. fn should return true if the KV is whitelisted.
Example:
xconf.FilterKVWhitelistFunc(func(key string, _ any) bool { return key == "KEEP_ME_1" || key == "KEEP_ME_2" })
func (FilterKVWhitelistFunc) IsAllowed ¶
func (filter FilterKVWhitelistFunc) IsAllowed(key string, value any) bool
IsAllowed returns true if a key-value is whitelisted.
func (FilterKVWhitelistFunc) Type ¶
func (filter FilterKVWhitelistFunc) Type() FilterType
Type returns filter's type (FilterTypeWhitelist).
type FilterType ¶
type FilterType byte
FilterType is just an alias for byte.
const ( // FilterTypeWhitelist represents a whitelist filter. FilterTypeWhitelist FilterType = 1 // FilterTypeBlacklist represents a blacklist filter. FilterTypeBlacklist FilterType = 2 )
type FlattenLoader ¶
type FlattenLoader struct {
// contains filtered or unexported fields
}
FlattenLoader decorates another loader to add shortcuts to leaves' information in a nested configuration key.
Example, given the configuration:
{ "mysql": { "host": "127.0.0.1", "port": 3306 } }
2 additional flat keys will be added to above standard configuration: "mysql.host", "mysql.port" for easy access of leaf-keys. Note: original nested configuration is still kept by default, if you want to remove it, apply FlattenLoaderWithFlatKeysOnly option.
Example ¶
package main import ( "bytes" "fmt" "github.com/actforgood/xconf" ) func main() { jsonConfig := []byte(`{ "db": { "mysql": { "host": "192.168.10.10", "port": 3306 }, "adapter": "mysql" }, "foo": "bar" }`) origLoader := xconf.JSONReaderLoader(bytes.NewReader(jsonConfig)) loader := xconf.NewFlattenLoader(origLoader) configMap, err := loader.Load() if err != nil { panic(err) } fmt.Println(configMap["foo"]) fmt.Println(configMap["db"].(map[string]any)["mysql"].(map[string]any)["host"]) fmt.Println(configMap["db.mysql.host"]) // much easier way to access information compared to previous statement. }
Output: bar 192.168.10.10 192.168.10.10
func NewFlattenLoader ¶
func NewFlattenLoader(loader Loader, opts ...FlattenLoaderOption) FlattenLoader
NewFlattenLoader instantiates a new FlattenLoader object that adds flat version for nested keys for easily access.
type FlattenLoaderOption ¶
type FlattenLoaderOption func(*FlattenLoader)
FlattenLoaderOption defines optional function for configuring a Flatten Loader.
func FlattenLoaderWithFlatKeysOnly ¶
func FlattenLoaderWithFlatKeysOnly() FlattenLoaderOption
FlattenLoaderWithFlatKeysOnly triggers nested keys to be removed, and only their flat version to be kept.
func FlattenLoaderWithSeparator ¶
func FlattenLoaderWithSeparator(keySeparator string) FlattenLoaderOption
FlattenLoaderWithSeparator sets the separator for the new, flat keys. By default, is set to "."(dot).
type IniFileLoader ¶
type IniFileLoader struct {
// contains filtered or unexported fields
}
IniFileLoader is a loader that returns configuration from an INI content based file.
Example ¶
package main import ( "fmt" "github.com/actforgood/xconf" ) func main() { loader := xconf.NewIniFileLoader("testdata/config.ini") configMap, err := loader.Load() if err != nil { panic(err) } fmt.Println(configMap["ini_foo"]) fmt.Println(configMap["temperature"].(map[string]any)["ini_celsius"]) fmt.Println(configMap["temperature"].(map[string]any)["ini_fahrenheit"]) }
Output: bar 37.5 99.5
func NewIniFileLoader ¶
func NewIniFileLoader(filePath string, opts ...IniFileLoaderOption) IniFileLoader
NewIniFileLoader instantiates a new IniFileLoader object that loads INI configuration from a file. The location of INI content based file is given as parameter.
type IniFileLoaderOption ¶
type IniFileLoaderOption func(*IniFileLoader)
IniFileLoaderOption defines optional function for configuring an INI File Loader.
func IniFileLoaderWithLoadOptions ¶
func IniFileLoaderWithLoadOptions(iniLoadOpts ini.LoadOptions) IniFileLoaderOption
IniFileLoaderWithLoadOptions sets given ini load options on the loader. By default, an empty object is used.
type KeyConflictError ¶
type KeyConflictError struct {
// contains filtered or unexported fields
}
KeyConflictError is an error returned by MultiLoader in case of a duplicate key. If key overwrite is allowed, this error will not be returned.
func NewKeyConflictError ¶
func NewKeyConflictError(key string) KeyConflictError
NewKeyConflictError instantiates a new KeyConflictError. The duplicate key must be provided.
func (KeyConflictError) Error ¶
func (e KeyConflictError) Error() string
Error returns string representation of the KeyConflictError. It implements standard go error interface.
type Loader ¶
type Loader interface { // Load returns a configuration key value map or an error. // // It's Loader's responsibility to return a map that is safe for // an eventual later mutation (decorator pattern can be used to // modify a loader's returned configuration key value map and // that's why this must/should be accomplished safely; safely // from concurrency point of view / data integrity point of view; // in other words, Loader should return a disposable config map - // see also DeepCopyConfigMap utility and current usages as example). Load() (map[string]any, error) }
Loader is responsible for loading a configuration key value map.
func AliasLoader ¶
AliasLoader decorates another loader to set aliases for keys. The aliases will be added to decorated loader's configuration map. The second parameter represents a list of alias and keys they're for under the form "aliasForKey1, key1, aliasForKey2, key2".
Example ¶
package main import ( "fmt" "github.com/actforgood/xconf" ) func main() { origLoader := xconf.PlainLoader(map[string]any{ "foo": "foo val", "bar": "bar val", "baz": "baz val", }) loader := xconf.AliasLoader( origLoader, "NEW_FOO", "foo", "NEW_BAZ", "baz", ) configMap, err := loader.Load() if err != nil { panic(err) } for key, value := range configMap { fmt.Println(key+":", value) } }
Output: foo: foo val bar: bar val baz: baz val NEW_FOO: foo val NEW_BAZ: baz val
func AlterValueLoader ¶
func AlterValueLoader(loader Loader, transformation AlterValueFunc, keys ...string) Loader
AlterValueLoader decorates another loader to manipulate a config's value. The transformation function is applied to all passed keys.
Example ¶
package main import ( "fmt" "github.com/actforgood/xconf" ) func main() { origLoader := xconf.PlainLoader(map[string]any{ "foo": "foo val", "bar": 100, "shopping_list": "bread,eggs,milk", "weekend_days": "friday,saturday,sunday", }) loader := xconf.AlterValueLoader( origLoader, xconf.ToStringList(","), "shopping_list", "weekend_days", ) configMap, err := loader.Load() if err != nil { panic(err) } for key, value := range configMap { fmt.Println(key+":", value) } }
Output: foo: foo val bar: 100 shopping_list: [bread eggs milk] weekend_days: [friday saturday sunday]
func DotEnvFileLoader ¶
DotEnvFileLoader loads .env configuration from a file. The location of .env content based file is given as parameter.
Example ¶
package main import ( "fmt" "github.com/actforgood/xconf" ) func main() { loader := xconf.DotEnvFileLoader("testdata/.env") configMap, err := loader.Load() if err != nil { panic(err) } for key, value := range configMap { fmt.Println(key+":", value) } }
Output: DOTENV_FOO: bar DOTENV_YEAR: 2022 DOTENV_TEMPERATURE: 37.5 DOTENV_SHOPPING_LIST: bread,milk,eggs
func DotEnvReaderLoader ¶
DotEnvReaderLoader loads .env configuration from an io.Reader.
func EnvLoader ¶
func EnvLoader() Loader
EnvLoader loads configuration from OS's ENV.
Example ¶
package main import ( "crypto/rand" "fmt" "math/big" "os" "strconv" "github.com/actforgood/xconf" ) // setUpEnv sets OS env with provided value. // Returns the previous value, if env name already exists. func setUpEnv(envName, value string) string { prevValue := os.Getenv(envName) _ = os.Setenv(envName, value) return prevValue } // tearDownEnv unsets the OS env provided or restores previous value. func tearDownEnv(envName, prevValue string) { if prevValue != "" { _ = os.Setenv(envName, prevValue) } else { _ = os.Unsetenv(envName) } } // getRandomEnvName returns a "XCONF_TEST_ENV_LOADER_FOO_<randomInt>" env name. func getRandomEnvName() string { nBig, err := rand.Int(rand.Reader, big.NewInt(9999999)) if err != nil { return "" } randInt := nBig.Int64() return "XCONF_TEST_ENV_LOADER_FOO_" + strconv.FormatInt(randInt, 10) } func main() { // setup an env envName := getRandomEnvName() prevValue := setUpEnv(envName, "bar") defer tearDownEnv(envName, prevValue) loader := xconf.EnvLoader() configMap, err := loader.Load() if err != nil { panic(err) } fmt.Println(configMap[envName]) }
Output: bar
func FileLoader ¶ added in v1.3.0
FileLoader is a factory for appropriate XFileLoader based on file's extension. This is useful when you don't want to tie an application to a certain config format. Supported extensions are: .json, .yml, .yaml, .ini, .properties, .env, .toml.
Example ¶
package main import ( "fmt" "github.com/actforgood/xconf" ) func main() { exampleFiles := []string{ "testdata/config.json", "testdata/config.yaml", "testdata/config.yml", "testdata/.env", "testdata/config.ini", "testdata/config.properties", "testdata/config.toml", } for _, filePath := range exampleFiles { loader := xconf.FileLoader(filePath) configMap, err := loader.Load() if err != nil { panic(err) } fmt.Println(len(configMap)) } }
Output: 4 4 4 4 3 4 7
func FilterKVLoader ¶
FilterKVLoader decorates another loader to whitelist/blacklist key-values.
A blacklist filter has more weight than a whitelist filter, as if a blacklist denies a KV and a whitelist allows it, that KV will not be returned in the configuration map.
If there are only whitelist filters, a KV will be returned into the configuration map if at least one filter allows it.
If there are only blacklist filters, a KV will be returned into the configuration map if no filter denies it.
Example ¶
package main import ( "fmt" "github.com/actforgood/xconf" ) func main() { // in this example we assume our application's configs are // prefixed with APP_ and we want to allow them, // we also want to allow K8s services, // we also want to get rid of empty value configs. origLoader := xconf.PlainLoader(map[string]any{ "APP_FOO_1": "bar 1", // whitelisted "APP_FOO_2": "bar 2", // whitelisted "APP_FOO_3": "", // blacklisted "REDIS_SERVICE_HOST": "10.0.0.11", // whitelisted "REDIS_SERVICE_PORT": "6379", // whitelisted "MYSQL_SERVICE_HOST": "10.0.0.12", // whitelisted "MYSQL_SERVICE_PORT": "3306", // whitelisted "OS": "darwin", "HOME": "/Users/JohnDoe", "USER": "JohnDoe", }) loader := xconf.FilterKVLoader( origLoader, xconf.FilterKVWhitelistFunc(xconf.FilterKeyWithPrefix("APP_")), xconf.FilterKVWhitelistFunc(xconf.FilterKeyWithSuffix("_SERVICE_HOST")), xconf.FilterKVWhitelistFunc(xconf.FilterKeyWithSuffix("_SERVICE_PORT")), xconf.FilterKVBlacklistFunc(xconf.FilterEmptyValue), ) configMap, _ := loader.Load() for key, value := range configMap { fmt.Println(key+":", value) } }
Output: APP_FOO_1: bar 1 APP_FOO_2: bar 2 REDIS_SERVICE_HOST: 10.0.0.11 REDIS_SERVICE_PORT: 6379 MYSQL_SERVICE_HOST: 10.0.0.12 MYSQL_SERVICE_PORT: 3306
func FlagSetLoader ¶ added in v1.5.0
FlagSetLoader reduces flags to a configuration map. The first parameter is the flag.FlagSet holding flags. The second, optional, parameter indicates if all flags (even those not explicitly set) should be taken into consideration; by default, is true.
Example ¶
package main import ( "flag" "fmt" "github.com/actforgood/xconf" ) func main() { // setup a test flag set flgSet := flag.NewFlagSet("example-flag-set", flag.ContinueOnError) _ = flgSet.String("flag_foo", "baz", "foo description") _ = flgSet.Int("flag_year", 2022, "year description") _ = flgSet.Float64("flag_temperature", 37.5, "temperature description") _ = flgSet.String("flag_shopping_list", "bread,milk,eggs", "shopping list description") args := []string{"-flag_foo=bar", "-flag_temperature=37.5"} // you will usually pass os.Args[1:] here if err := flgSet.Parse(args); err != nil { panic(err) } loader := xconf.FlagSetLoader(flgSet) configMap, err := loader.Load() if err != nil { panic(err) } for key, value := range configMap { fmt.Println(key+":", value) } }
Output: flag_foo: bar flag_year: 2022 flag_temperature: 37.5 flag_shopping_list: bread,milk,eggs
func IgnoreErrorLoader ¶
IgnoreErrorLoader decorates another loader to ignore the error returned by it, if error is present in the list of errors passed as second parameter. You can ignore, for example, os.ErrNotExist for a file based Loader if that file is not mandatory to exist, or Consul's ErrConsulKeyNotFound, etc.
Example ¶
package main import ( "fmt" "os" "github.com/actforgood/xconf" ) func main() { // in this example we assume we want to load configs from // a main source (OS Env for example - here we provide a PlainLoader) // and eventually from a JSON configuration file. loader := xconf.NewMultiLoader( true, // allow keys overwrite xconf.PlainLoader(map[string]any{ "APP_FOO_1": "bar 1", "APP_FOO_2": "bar 2", }), xconf.IgnoreErrorLoader( xconf.JSONFileLoader("/this/path/might/not/exist/config.json"), os.ErrNotExist, ), ) configMap, _ := loader.Load() for key, value := range configMap { fmt.Println(key+":", value) } }
Output: APP_FOO_1: bar 1 APP_FOO_2: bar 2
func JSONFileLoader ¶
JSONFileLoader loads JSON configuration from a file. The location of JSON content based file is given as parameter.
Example ¶
package main import ( "fmt" "github.com/actforgood/xconf" ) func main() { loader := xconf.JSONFileLoader("testdata/config.json") configMap, err := loader.Load() if err != nil { panic(err) } for key, value := range configMap { fmt.Println(key+":", value) } }
Output: json_foo: bar json_year: 2022 json_temperature: 37.5 json_shopping_list: [bread milk eggs]
func JSONReaderLoader ¶
JSONReaderLoader loads JSON configuration from an io.Reader.
func PlainLoader ¶
PlainLoader is an explicit go configuration map retriever. It simply returns a copy of the given config map parameter.
It can be used for example:
- in a MultiLoader (with allowing keys overwrite) as the first loader in order to specify default configurations.
- to provide any application hardcoded configs.
func PropertiesBytesLoader ¶
PropertiesBytesLoader loads Properties configuration from bytes.
func PropertiesFileLoader ¶
PropertiesFileLoader loads Java Properties configuration from a file. The location of properties content based file is given as parameter.
Example ¶
package main import ( "fmt" "github.com/actforgood/xconf" ) func main() { loader := xconf.PropertiesFileLoader("testdata/config.properties") configMap, err := loader.Load() if err != nil { panic(err) } for key, value := range configMap { fmt.Println(key+":", value) } }
Output: properties_foo: bar properties_baz: bar properties_year: 2022 properties_temperature: 37.5
func TOMLFileLoader ¶ added in v1.4.0
TOMLFileLoader loads TOML configuration from a file. The location of TOML content based file is given as parameter.
Example ¶
package main import ( "fmt" "github.com/actforgood/xconf" ) func main() { loader := xconf.TOMLFileLoader("testdata/config.toml") configMap, err := loader.Load() if err != nil { panic(err) } fmt.Println("toml_foo:", configMap["toml_foo"]) fmt.Println("toml_year:", configMap["toml_year"]) fmt.Println("toml_temperature:", configMap["toml_temperature"]) fmt.Println("toml_shopping_list:", configMap["toml_shopping_list"]) }
Output: toml_foo: bar toml_year: 2022 toml_temperature: 37.5 toml_shopping_list: [bread milk eggs]
func TOMLReaderLoader ¶ added in v1.4.0
TOMLReaderLoader loads TOML configuration from an io.Reader.
func YAMLFileLoader ¶
YAMLFileLoader loads YAML configuration from a file. The location of YAML content based file is given as parameter.
Example ¶
package main import ( "fmt" "github.com/actforgood/xconf" ) func main() { loader := xconf.YAMLFileLoader("testdata/config.yaml") configMap, err := loader.Load() if err != nil { panic(err) } for key, value := range configMap { fmt.Println(key+":", value) } }
Output: yaml_foo: bar yaml_year: 2022 yaml_temperature: 37.5 yaml_shopping_list: [bread milk eggs]
type LoaderFunc ¶
The LoaderFunc type is an adapter to allow the use of ordinary functions as Loaders. If fn is a function with the appropriate signature, LoaderFunc(fn) is a Loader that calls fn.
type MockConfig ¶
type MockConfig struct {
// contains filtered or unexported fields
}
MockConfig is a mock for xconf.Config contract, to be used in UT.
func NewMockConfig ¶
func NewMockConfig(kv ...any) *MockConfig
NewMockConfig instantiates new mocked Config with given key-values configuration. Make sure you pass an even number of elements and that the keys are strings.
Usage example:
mock := xconf.NewMockConfig( "foo", "bar", "year", 2022, )
func (*MockConfig) GetCallsCount ¶
func (mock *MockConfig) GetCallsCount() int
GetCallsCount returns the no. of times Get() method was called.
func (*MockConfig) SetGetCallback ¶
func (mock *MockConfig) SetGetCallback(callback func(key string, def ...any))
SetGetCallback sets the given callback to be executed inside Get() method. You can inject yourself to make assertions upon passed parameter(s) this way.
Usage example:
mock.SetGetCallback(func(key string, def ...any) { switch mock.GetCallsCount() { case 1: if key != "expectedKeyAtCall1" { t.Error("...") } case 2: if key != "expectedKeyAtCall2" { t.Error("...") } } })
func (*MockConfig) SetKeyValues ¶
func (mock *MockConfig) SetKeyValues(kv ...any)
SetKeyValues sets/resets given key-values. Make sure you pass an even number of elements and that the keys are strings.
type MultiLoader ¶
type MultiLoader struct {
// contains filtered or unexported fields
}
MultiLoader is a composite loader that returns configurations from multiple loaders.
Example ¶
package main import ( "fmt" "github.com/actforgood/xconf" ) func main() { loader := xconf.NewMultiLoader( true, // allow key overwrite xconf.PlainLoader(map[string]any{ "json_foo": "bar from plain, will get overwritten", "yaml_foo": "bar from plain, will get overwritten", "plain_key": "plain value", }), xconf.JSONFileLoader("testdata/config.json"), xconf.YAMLFileLoader("testdata/config.yaml"), ) configMap, err := loader.Load() if err != nil { panic(err) } for key, value := range configMap { fmt.Println(key+":", value) } }
Output: json_foo: bar json_year: 2022 json_temperature: 37.5 json_shopping_list: [bread milk eggs] yaml_foo: bar yaml_year: 2022 yaml_temperature: 37.5 yaml_shopping_list: [bread milk eggs] plain_key: plain value
func NewMultiLoader ¶
func NewMultiLoader(allowKeyOverwrite bool, loaders ...Loader) MultiLoader
NewMultiLoader instantiates a new MultiLoader object that loads and merges configuration from multiple loaders. The first parameter is a flag indicating whether a key is allowed to be overwritten, if found more than once. If not, a KeyConflictError will be returned. If yes, the order of loaders matters, meaning a later provided loader, will overwrite a previous provided loader's same found key. The rest of the parameters consist of the list of loaders configuration should be retrieved from.
Source Files ¶
- config.go
- config_mock.go
- config_nop.go
- deepcopy.go
- doc.go
- loader.go
- loader_consul.go
- loader_decorator_alias.go
- loader_decorator_alter_value.go
- loader_decorator_filecache_loader.go
- loader_decorator_filter_kv.go
- loader_decorator_flatten.go
- loader_decorator_ignore_error.go
- loader_dotenv.go
- loader_env.go
- loader_etcd.go
- loader_file.go
- loader_flagset.go
- loader_ini.go
- loader_json.go
- loader_multi.go
- loader_plain.go
- loader_properties.go
- loader_toml.go
- loader_yaml.go
- remote.go
- xlog_adapter.go