2024-10-19 23:05:20 +07:00
# Config
**config** is a simple golang library and designed to read configurations from JSON, Yaml files, environment variables and command line. **config** depends on [go-yaml ](https://github.com/go-yaml/yaml ) to analyze Yaml file and uses built-in golang library to handle JSON file.
2017-12-12 21:51:25 +07:00
## Installation
2024-10-19 23:05:20 +07:00
2017-12-12 21:51:25 +07:00
1. Install [Yaml ](https://github.com/go-yaml/yaml ) library first:
2024-10-19 23:05:20 +07:00
```sh
2024-10-19 22:48:50 +07:00
go get gopkg.in/yaml.v3
2017-12-12 21:51:25 +07:00
```
2024-10-19 23:05:20 +07:00
1. Install **config** library:
```sh
2024-11-03 11:11:32 +07:00
git@git.mousesoft.ru:ms/config.git
2017-12-12 21:51:25 +07:00
```
## Usage
2024-10-19 23:05:20 +07:00
2017-12-13 08:33:21 +07:00
### I. Define configuration name in structure tags
2024-10-19 23:05:20 +07:00
2017-12-13 08:33:21 +07:00
Like JSON, Yaml, **config** uses tags to define configurations:
2024-10-19 22:48:50 +07:00
| Tag | Example | Function |
| --------- | --------------------------------------- | --------------------------------------------------------------- |
| json | Host string `json:"host"` | Maps `Host` to a JSON field: **host** |
| yaml | Host string `yaml:"host"` | Maps `Host` to a Yaml field: **host** |
| env | Host string `env:"HOST"` | Maps `Host` to a Environment variable: **HOST** |
| cli | Host string `cli:"host database host"` | Maps `Host` to a command line argument: ** -host** or ** --host** |
| default | Port int `default:"8080"` | Defines the port with default value: **8080** |
| separator | Path string `json:"path" separator:";"` | Separator is used to split string to a slice |
2024-10-21 00:15:51 +07:00
| usage | Usage string `usage:"host address"` | Usage description |
2017-12-13 08:33:21 +07:00
#### 1. Data types
2024-10-19 23:05:20 +07:00
2017-12-13 08:33:21 +07:00
**config** supports the following golang data types:
2024-10-19 23:05:20 +07:00
* bool
* string
* int8, int16, int, int32, int64
* uint8, uint16, uint, uint32, uint64
* float32, float64
2024-11-03 11:11:32 +07:00
* time.Duration
2024-10-19 23:05:20 +07:00
* slice type. e.g: []string, []int ...
2017-12-12 23:27:48 +07:00
2017-12-13 08:33:21 +07:00
#### 2. Defines **default** values
2024-10-19 23:05:20 +07:00
2017-12-13 08:52:27 +07:00
Using **default** keyword in structure tags to define default value:
2024-10-19 23:05:20 +07:00
2017-12-12 22:33:47 +07:00
```golang
2024-10-19 23:05:20 +07:00
type Log struct {
2017-12-12 22:33:47 +07:00
Path string `default:"/var/logs"`
Level string `default:"debug"`
2024-10-19 23:05:20 +07:00
}
2017-12-12 22:33:47 +07:00
```
2024-10-19 23:05:20 +07:00
#### 3. Defines configuration name for JSON
2017-12-13 08:52:27 +07:00
Like parsing JSON object, using **json** keyword to define configuration name:
2024-10-19 23:05:20 +07:00
2017-12-12 22:18:55 +07:00
```golang
type Database struct {
2017-12-15 23:10:09 +07:00
Host string `json:"host"`
Port int `json:"port"`
2024-10-21 18:55:14 +07:00
Username string `default:"admin" json:"username"`
Password string `default:"admin" json:"password"`
2017-12-15 23:10:09 +07:00
Log Log `json:"log"`
2017-12-12 22:18:55 +07:00
}
```
2017-12-13 08:52:27 +07:00
Corresponding JSON file:
2024-10-19 23:05:20 +07:00
2017-12-13 08:52:27 +07:00
```json
{
2017-12-13 09:19:42 +07:00
"host": "test.db.hostname",
"port": 8080,
2024-10-19 23:05:20 +07:00
"username": "admin",
2017-12-13 10:01:34 +07:00
"password": "admin",
2017-12-13 08:52:27 +07:00
"log": {
2017-12-13 09:19:42 +07:00
"path": "/var/logs/db",
2017-12-13 08:52:27 +07:00
"level": "debug"
}
}
```
2017-12-13 08:33:21 +07:00
#### 4. Defines configuration name for Yaml
2024-10-19 23:05:20 +07:00
2017-12-13 08:33:21 +07:00
Like parsing Yaml object, using **yaml** keyword to define configuration name
2024-10-19 23:05:20 +07:00
2017-12-13 08:33:21 +07:00
```golang
type Database struct {
2017-12-15 23:10:09 +07:00
Host string `yaml:"host"`
Port int `yaml:"port"`
2024-10-21 18:55:14 +07:00
Username string `default:"admin" yaml:"username"`
Password string `default:"admin" yaml:"password"`
2017-12-15 23:10:09 +07:00
Log Log `yaml:"log"`
2017-12-13 08:33:21 +07:00
}
```
2024-10-19 23:05:20 +07:00
2017-12-13 08:52:27 +07:00
Corresponding Yaml file:
2024-10-19 23:05:20 +07:00
2017-12-13 08:52:27 +07:00
```yaml
2024-10-19 23:05:20 +07:00
host: test.db.hostname
port: 8080
username: admin
password: admin
log:
path: /var/logs/db
level: debug
2017-12-13 08:52:27 +07:00
```
2024-10-19 23:05:20 +07:00
2017-12-13 08:33:21 +07:00
#### 5. Defines configuration name for Environment variable
2024-10-19 23:05:20 +07:00
2017-12-13 08:33:21 +07:00
Using **env** keyword to define configuration name
2024-10-19 23:05:20 +07:00
2017-12-13 08:33:21 +07:00
```golang
type Database struct {
2017-12-15 23:10:09 +07:00
Host string `env:"DB_HOST"`
Port int `env:"DB_PORT"`
2024-10-21 18:55:14 +07:00
Username string `default:"admin" env:"DB_USER"`
Password string `default:"admin" env:"DB_PASSWORD"`
2017-12-15 23:10:09 +07:00
Log Log `env:"DB_LOG_"`
2017-12-13 08:33:21 +07:00
}
```
2017-12-13 08:52:27 +07:00
Corresponding Environment variables:
2024-10-19 23:05:20 +07:00
2017-12-13 08:52:27 +07:00
```shell
export DB_HOST=test.db.hostname
export DB_PORT=8080
export DB_USER=admin
export DB_PASSWORD=admin
export DB_LOG_PATH=/var/logs/db
export DB_LOG_LEVEL=debug
```
2024-10-19 23:05:20 +07:00
Since the `Log` is a structure and nested in `Database` structure, the tag of `Log`
and tags of its structure members will be combined to be an unique environment variable,
for example: `Path` will be mapped to environment var: `DB_LOG_PATH` .
But if the `Log` has no tag definition, only tags of its structure members will
be used, that means the `Path` will be mapped to `PATH` .
2017-12-13 08:52:27 +07:00
2017-12-13 08:33:21 +07:00
#### 6. Defines configuration name for Command line
2024-10-19 23:05:20 +07:00
2024-10-21 18:55:14 +07:00
Using **cli** keyword to define configuration name:
2024-10-19 23:05:20 +07:00
2017-12-13 08:33:21 +07:00
```golang
type Database struct {
2024-10-21 00:15:51 +07:00
Host string `cli:"host" usage:"database host name"`
Port int `cli:"port" usage:"database port"`
Username string `cli:"username" default:"admin" usage:"database username"`
Password string `cli:"password" default:"admin" usage:"database password"`
Log Log `cli:"log" usage:"database log configurations"`
2017-12-13 08:33:21 +07:00
}
```
2024-10-19 23:05:20 +07:00
2024-10-21 18:55:14 +07:00
For **cli** definition, the string is command line argument, and the **usage**
tag are the command line usage and will be outputted when printing usage.
2017-12-13 08:33:21 +07:00
2017-12-13 09:19:42 +07:00
Corresponding command line:
2024-10-19 23:05:20 +07:00
2017-12-13 09:19:42 +07:00
```shell
2024-10-21 18:55:14 +07:00
./main --host test.db.hostname --port 8080 --username admin --password admin --log-path /var/logs/db --log-level debug
2017-12-13 09:19:42 +07:00
```
2024-10-19 23:05:20 +07:00
2017-12-13 09:19:42 +07:00
or
2024-10-19 23:05:20 +07:00
2017-12-13 09:19:42 +07:00
```shell
2024-10-21 18:55:14 +07:00
./main --host=test.db.hostname --port=8080 --username=admin --password=admin --log-path=/var/logs/db --log-level=debug
2017-12-13 09:19:42 +07:00
```
2017-12-13 08:33:21 +07:00
2017-12-13 09:19:42 +07:00
#### 7. Defines configuration name as a slice type
2024-10-19 23:05:20 +07:00
2017-12-13 09:19:42 +07:00
Using **separator** to split string as a slice:
2024-10-19 23:05:20 +07:00
2017-12-12 23:27:48 +07:00
```golang
2017-12-13 09:19:42 +07:00
type Log struct {
2024-10-21 18:55:14 +07:00
Levels []string `env:"LEVELS" cli:"levels" separator:";" usage:"log levels"`
2017-12-12 23:27:48 +07:00
}
```
2024-10-19 23:05:20 +07:00
If the separator is not given, its default is ** :**, The separator only works on
2024-10-21 18:55:14 +07:00
**env** and **cli** tags.
2024-10-19 23:05:20 +07:00
2017-12-13 09:19:42 +07:00
```golang
logConfig := Log{}
// export LEVELS=debug;error;info
config.ParseEnv(& logConfig)
// logConfig[0] == debug
// logConfig[1] == error
// logConfig[2] == info
```
### II. Parses configurations
2024-10-19 23:05:20 +07:00
2017-12-13 09:19:42 +07:00
#### 1. Parses default values
2024-10-19 23:05:20 +07:00
When default values are defined in tags, calls `config.ParseDefault(interface{})`
to assign them to given structure instance **BEFORE** parsing any other configuration
types:
2017-12-13 09:19:42 +07:00
```golang
logConfig := Log{}
config.ParseDefault(& logConfig)
```
2024-10-19 23:05:20 +07:00
>Note: Other parsing functions don't set structure instance with default values
whatever if the configuration value is provided or not
2017-12-13 09:19:42 +07:00
2017-12-13 09:39:18 +07:00
#### 2. Parses from Environment variables
2024-10-19 23:05:20 +07:00
2017-12-13 09:39:18 +07:00
```golang
dbConfig := Database{}
config.ParseEnv(& dbConfig)
```
2017-12-13 09:19:42 +07:00
2017-12-13 09:39:18 +07:00
#### 3. Parses from Command line
2024-10-19 23:05:20 +07:00
2017-12-13 09:39:18 +07:00
```golang
dbConfig := Database{}
config.ParseCli(& dbConfig)
```
#### 4. Parses from default configuration files
2024-10-19 23:05:20 +07:00
2017-12-13 09:39:18 +07:00
Calls **ParseConfigFile(interface{}, string)** to parse given configuration file:
2024-10-19 23:05:20 +07:00
2017-12-12 22:18:55 +07:00
```golang
dbConfig := Database{}
2017-12-12 22:33:47 +07:00
config.ParseConfigFile(& dbConfig, "config.json")
2017-12-12 22:18:55 +07:00
```
2017-12-13 09:39:18 +07:00
2024-10-19 23:05:20 +07:00
If the configuration file is not given, the default configuration files:
**config.json** and **config.yaml** will be located under the same folder with
fixed searching order.
The **config.json** will always be located first, if it doesn't exist, then checks\
**config.yaml**. If all of them are not found, parsing will fail.
2017-12-13 09:39:18 +07:00
```golang
dbConfig := Database{}
config.ParseConfigFile(& dbConfig, "")
```
#### 4. Parses from configuration file specified by command line
2024-10-19 23:05:20 +07:00
Calls **ParseConfig(interface{}, string)** to parse the configuration file given
by command line. The second parameter is a command line argument which is used
to specify config file:
2017-12-13 09:39:18 +07:00
```golang
dbConfig := Database{}
config.ParseConfig(& dbConfig, "c")
```
2024-10-19 23:05:20 +07:00
2017-12-13 09:39:18 +07:00
Run application like:
2024-10-19 23:05:20 +07:00
2017-12-13 09:39:18 +07:00
```shell
./main -c config.json
```
2024-10-19 23:05:20 +07:00
**ParseConfig()** will analyze command line arguments and get configure file:
**config.json** from argument ** -c**
### III. Multi-Configurations
You can define all supported configuration tags in a structure and call corresponding
functions in your desired order to parse.
2017-12-13 09:39:18 +07:00
2017-12-13 10:01:34 +07:00
Examples:
2024-10-19 23:05:20 +07:00
2017-12-13 10:01:34 +07:00
```golang
type Log struct {
2024-10-21 18:55:14 +07:00
Path string `cli:"path" default:"/var/logs" env:"PATH" json:"path" usage:"log path" yaml:"path"`
Levels string `cli:"levels" default:"debug;error" env:"LEVELS" json:"levels" usage:"log levels" yaml:"levels"`
2017-12-13 10:01:34 +07:00
}
type Database struct {
2024-10-21 18:55:14 +07:00
Host string `cli:"host" env:"DB_HOST" json:"host" usage:"database host name" yaml:"host"`
Port int `cli:"port" env:"DB_PORT" json:"port" usage:"database port" yaml:"port"`
Username string `cli:"username" default:"admin" env:"DB_USER" json:"user" usage:"database username" yaml" user"`
Password string `cli:"password" default:"admin" env:"DB_PASSWD" json:"passwd" usage:"database password" yaml:"passwd"`
Log Log `cli:"log" env:"DB_LOG_" json:"log" usage:"database log configurations" yaml:"log"`
2017-12-13 10:01:34 +07:00
}
```
2024-10-19 23:05:20 +07:00
2017-12-13 10:09:01 +07:00
Then, you can parse as below:
2024-10-19 23:05:20 +07:00
2017-12-13 10:01:34 +07:00
```golang
2024-11-03 11:11:32 +07:00
dbConfig := Database{}
2017-12-13 10:01:34 +07:00
2024-11-03 11:11:32 +07:00
// parse default values
if err := config.ParseDefault(&dbConfig); err != nil {
// error handling
}
cmd := config.NewCLI("")
if err := cmd.Init(&dbConfig); err != nil {
// error handling
}
// capture cli flags
args := cmd.Capture(os.Args)
// parse cli flags of application, urfave for example
flagSet.Parse(args)
// parse captured cli flags of config
if err := cmd.Parse(cmd.Args); err != nil {
// error handling
}
2017-12-13 10:01:34 +07:00
2024-11-03 11:11:32 +07:00
// parse configuration file from command line
err := config.ParseConfig(& dbConfig, "c")
2017-12-13 10:01:34 +07:00
2024-11-03 11:11:32 +07:00
// parse default configurations
if err != nil {
err = config.ParseConfigFile(& dbConfig), "")
}
2017-12-13 10:01:34 +07:00
2024-11-03 11:11:32 +07:00
// parse environment variables
if err != nil {
err = config.ParseEnv(& dbConfig)
}
2017-12-13 10:01:34 +07:00
2024-11-03 11:11:32 +07:00
// parse command line
if err != nil {
err = config.ParseCli(& dbConfig)
}
2017-12-13 10:12:11 +07:00
2024-11-03 11:11:32 +07:00
// check if all required configurations are set
...
2017-12-13 10:01:34 +07:00
```
2017-12-30 14:54:00 +07:00
You don't need to call all of them. Just invokes parsing function that your need.
2017-12-13 09:39:18 +07:00
2017-12-13 10:09:01 +07:00
## License
2024-10-19 23:05:20 +07:00
This project is licensed under the Apache License Version 2.0.