2014-11-13 20:38:47 +00:00
|
|
|
|
viper [![Build Status](https://travis-ci.org/spf13/viper.svg)](https://travis-ci.org/spf13/viper)
|
2014-04-02 14:33:33 +00:00
|
|
|
|
=====
|
|
|
|
|
|
|
|
|
|
Go configuration with fangs
|
2014-04-05 19:44:26 +00:00
|
|
|
|
|
|
|
|
|
## What is Viper?
|
|
|
|
|
|
2014-12-07 01:03:49 +00:00
|
|
|
|
Viper is a complete configuration solution for go applications. It has
|
|
|
|
|
been designed to work within an application to handle all types of
|
2015-03-06 19:21:50 +00:00
|
|
|
|
configuration. It supports
|
2014-12-07 01:03:49 +00:00
|
|
|
|
|
|
|
|
|
* setting defaults
|
2015-03-07 10:52:13 +00:00
|
|
|
|
* reading from json, toml and yaml config files
|
2014-12-07 01:03:49 +00:00
|
|
|
|
* reading from environment variables
|
|
|
|
|
* reading from remote config systems (Etcd or Consul)
|
|
|
|
|
* reading from command line flags
|
|
|
|
|
* setting explicit values
|
|
|
|
|
|
|
|
|
|
It can be thought of as a registry for all of your applications
|
|
|
|
|
configuration needs.
|
2014-04-05 19:44:26 +00:00
|
|
|
|
|
|
|
|
|
## Why Viper?
|
|
|
|
|
|
2015-03-07 10:52:13 +00:00
|
|
|
|
When building a modern application, you don’t want to have to worry about
|
|
|
|
|
configuration file formats; you want to focus on building awesome software.
|
2014-04-05 19:44:26 +00:00
|
|
|
|
Viper is here to help with that.
|
|
|
|
|
|
|
|
|
|
Viper does the following for you:
|
|
|
|
|
|
2015-03-07 10:52:13 +00:00
|
|
|
|
1. Find, load and marshal a configuration file in JSON, TOML or YAML.
|
2014-12-07 01:03:49 +00:00
|
|
|
|
2. Provide a mechanism to set default values for your different
|
2015-03-07 10:52:13 +00:00
|
|
|
|
configuration options.
|
2014-12-07 01:03:49 +00:00
|
|
|
|
3. Provide a mechanism to set override values for options specified
|
|
|
|
|
through command line flags.
|
|
|
|
|
4. Provide an alias system to easily rename parameters without breaking
|
|
|
|
|
existing code.
|
|
|
|
|
5. Make it easy to tell the difference between when a user has provided
|
|
|
|
|
a command line or config file which is the same as the default.
|
|
|
|
|
|
|
|
|
|
Viper uses the following precedence order. Each item takes precedence
|
|
|
|
|
over the item below it:
|
|
|
|
|
|
|
|
|
|
* explicit call to Set
|
|
|
|
|
* flag
|
|
|
|
|
* env
|
|
|
|
|
* config
|
|
|
|
|
* key/value store
|
|
|
|
|
* default
|
2014-04-05 19:44:26 +00:00
|
|
|
|
|
|
|
|
|
Viper configuration keys are case insensitive.
|
|
|
|
|
|
2014-12-23 02:45:56 +00:00
|
|
|
|
## Putting Values into Viper
|
2014-04-05 19:44:26 +00:00
|
|
|
|
|
2014-12-07 01:03:49 +00:00
|
|
|
|
### Establishing Defaults
|
2014-04-05 19:44:26 +00:00
|
|
|
|
|
2014-12-07 01:03:49 +00:00
|
|
|
|
A good configuration system will support default values. A default value
|
|
|
|
|
is not required for a key, but can establish a default to be used in the
|
|
|
|
|
event that the key hasn’t be set via config file, environment variable,
|
|
|
|
|
remote configuration or flag.
|
2014-04-05 19:44:26 +00:00
|
|
|
|
|
2014-12-07 01:03:49 +00:00
|
|
|
|
Examples:
|
2014-04-05 19:44:26 +00:00
|
|
|
|
|
|
|
|
|
viper.SetDefault("ContentDir", "content")
|
|
|
|
|
viper.SetDefault("LayoutDir", "layouts")
|
2015-03-07 10:52:13 +00:00
|
|
|
|
viper.SetDefault("Taxonomies", map[string]string{"tag": "tags", "category": "categories"})
|
2014-04-05 19:44:26 +00:00
|
|
|
|
|
2014-12-07 01:03:49 +00:00
|
|
|
|
### Reading Config Files
|
|
|
|
|
|
|
|
|
|
If you want to support a config file, Viper requires a minimal
|
|
|
|
|
configuration so it knows where to look for the config file. Viper
|
2015-03-07 10:52:13 +00:00
|
|
|
|
supports json, toml and yaml files. Viper can search multiple paths, but
|
2014-12-07 01:03:49 +00:00
|
|
|
|
currently a single viper only supports a single config file.
|
|
|
|
|
|
|
|
|
|
viper.SetConfigName("config") // name of config file (without extension)
|
|
|
|
|
viper.AddConfigPath("/etc/appname/") // path to look for the config file in
|
|
|
|
|
viper.AddConfigPath("$HOME/.appname") // call multiple times to add many search paths
|
|
|
|
|
viper.ReadInConfig() // Find and read the config file
|
|
|
|
|
|
2014-04-05 19:44:26 +00:00
|
|
|
|
### Setting Overrides
|
|
|
|
|
|
2014-12-07 01:03:49 +00:00
|
|
|
|
These could be from a command line flag, or from your own application logic.
|
|
|
|
|
|
2014-04-05 19:44:26 +00:00
|
|
|
|
viper.Set("Verbose", true)
|
|
|
|
|
viper.Set("LogFile", LogFile)
|
|
|
|
|
|
|
|
|
|
### Registering and Using Aliases
|
|
|
|
|
|
2014-12-07 01:03:49 +00:00
|
|
|
|
Aliases permit a single value to be referenced by multiple keys
|
|
|
|
|
|
2014-04-05 19:44:26 +00:00
|
|
|
|
viper.RegisterAlias("loud", "Verbose")
|
|
|
|
|
|
|
|
|
|
viper.Set("verbose", true) // same result as next line
|
|
|
|
|
viper.Set("loud", true) // same result as prior line
|
|
|
|
|
|
|
|
|
|
viper.GetBool("loud") // true
|
|
|
|
|
viper.GetBool("verbose") // true
|
|
|
|
|
|
2014-12-07 01:03:49 +00:00
|
|
|
|
### Working with Environment Variables
|
|
|
|
|
|
|
|
|
|
Viper has full support for environment variables. This enables 12 factor
|
2015-03-06 19:21:17 +00:00
|
|
|
|
applications out of the box. There are four methods that exist to aid
|
2014-12-07 01:03:49 +00:00
|
|
|
|
with working with ENV:
|
|
|
|
|
|
|
|
|
|
* AutomaticEnv()
|
2014-12-23 02:45:56 +00:00
|
|
|
|
* BindEnv(string...) : error
|
|
|
|
|
* SetEnvPrefix(string)
|
2015-03-06 19:21:17 +00:00
|
|
|
|
* SetEnvReplacer(string...) *strings.Replacer
|
2014-12-23 02:45:56 +00:00
|
|
|
|
|
2015-03-07 10:52:13 +00:00
|
|
|
|
_When working with ENV variables, it’s important to recognize that Viper
|
2014-12-23 02:45:56 +00:00
|
|
|
|
treats ENV variables as case sensitive._
|
2014-12-07 01:03:49 +00:00
|
|
|
|
|
2014-12-23 02:45:56 +00:00
|
|
|
|
Viper provides a mechanism to try to ensure that ENV variables are
|
2015-03-07 10:52:13 +00:00
|
|
|
|
unique. By using SetEnvPrefix, you can tell Viper to use add a prefix
|
2014-12-23 02:45:56 +00:00
|
|
|
|
while reading from the environment variables. Both BindEnv and
|
|
|
|
|
AutomaticEnv will use this prefix.
|
2014-12-07 01:03:49 +00:00
|
|
|
|
|
|
|
|
|
BindEnv takes one or two parameters. The first parameter is the key
|
|
|
|
|
name, the second is the name of the environment variable. The name of
|
2014-12-23 02:45:56 +00:00
|
|
|
|
the environment variable is case sensitive. If the ENV variable name is
|
2015-03-07 10:52:13 +00:00
|
|
|
|
not provided, then Viper will automatically assume that the key name
|
2014-12-23 02:45:56 +00:00
|
|
|
|
matches the ENV variable name but the ENV variable is IN ALL CAPS. When
|
2015-03-07 10:52:13 +00:00
|
|
|
|
you explicitly provide the ENV variable name, it **does not**
|
2014-12-23 02:45:56 +00:00
|
|
|
|
automatically add the prefix.
|
2014-12-07 01:03:49 +00:00
|
|
|
|
|
|
|
|
|
One important thing to recognize when working with ENV variables is that
|
|
|
|
|
the value will be read each time it is accessed. It does not fix the
|
|
|
|
|
value when the BindEnv is called.
|
|
|
|
|
|
2014-12-23 03:47:25 +00:00
|
|
|
|
AutomaticEnv is a powerful helper especially when combined with
|
|
|
|
|
SetEnvPrefix. When called, Viper will check for an environment variable
|
|
|
|
|
any time a viper.Get request is made. It will apply the following rules.
|
|
|
|
|
It will check for a environment variable with a name matching the key
|
|
|
|
|
uppercased and prefixed with the EnvPrefix if set.
|
2014-12-07 01:03:49 +00:00
|
|
|
|
|
2015-03-06 19:21:17 +00:00
|
|
|
|
SetEnvReplacer allows you to use a `strings.Replacer` object to rewrite Env keys
|
|
|
|
|
to an extent. This is useful if you want to use `-` or something in your Get()
|
|
|
|
|
calls, but want your environmental variables to use `_` delimiters. An example
|
2015-03-07 10:52:13 +00:00
|
|
|
|
of using it can be found in `viper_test.go`.
|
2015-03-06 19:21:17 +00:00
|
|
|
|
|
2014-12-23 02:45:56 +00:00
|
|
|
|
#### Env example
|
|
|
|
|
|
|
|
|
|
SetEnvPrefix("spf") // will be uppercased automatically
|
|
|
|
|
BindEnv("id")
|
|
|
|
|
|
|
|
|
|
os.Setenv("SPF_ID", "13") // typically done outside of the app
|
|
|
|
|
|
2015-03-26 13:24:28 +00:00
|
|
|
|
id := Get("id") // 13
|
2014-12-23 02:45:56 +00:00
|
|
|
|
|
|
|
|
|
|
2014-12-07 01:03:49 +00:00
|
|
|
|
### Working with Flags
|
|
|
|
|
|
2015-03-07 10:52:13 +00:00
|
|
|
|
Viper has the ability to bind to flags. Specifically, Viper supports
|
|
|
|
|
Pflags as used in the [Cobra](https://github.com/spf13/cobra) library.
|
2014-12-07 01:03:49 +00:00
|
|
|
|
|
2015-03-07 10:52:13 +00:00
|
|
|
|
Like BindEnv, the value is not set when the binding method is called, but
|
2014-12-07 01:03:49 +00:00
|
|
|
|
when it is accessed. This means you can bind as early as you want, even
|
|
|
|
|
in an init() function.
|
|
|
|
|
|
|
|
|
|
The BindPFlag() method provides this functionality.
|
|
|
|
|
|
|
|
|
|
Example:
|
|
|
|
|
|
2015-03-07 10:52:13 +00:00
|
|
|
|
serverCmd.Flags().Int("port", 1138, "Port to run Application server on")
|
|
|
|
|
viper.BindPFlag("port", serverCmd.Flags().Lookup("port"))
|
2014-12-07 01:03:49 +00:00
|
|
|
|
|
|
|
|
|
|
2014-10-27 19:32:46 +00:00
|
|
|
|
### Remote Key/Value Store Support
|
|
|
|
|
Viper will read a config string (as JSON, TOML, or YAML) retrieved from a
|
|
|
|
|
path in a Key/Value store such as Etcd or Consul. These values take precedence
|
2015-03-06 19:21:50 +00:00
|
|
|
|
over default values, but are overriden by configuration values retrieved from disk,
|
2014-10-27 19:32:46 +00:00
|
|
|
|
flags, or environment variables.
|
|
|
|
|
|
|
|
|
|
Viper uses [crypt](https://github.com/xordataexchange/crypt) to retrieve configuration
|
2015-03-07 10:52:13 +00:00
|
|
|
|
from the K/V store, which means that you can store your configuration values
|
2014-10-27 19:32:46 +00:00
|
|
|
|
encrypted and have them automatically decrypted if you have the correct
|
|
|
|
|
gpg keyring. Encryption is optional.
|
|
|
|
|
|
|
|
|
|
You can use remote configuration in conjunction with local configuration, or
|
2015-03-06 19:21:50 +00:00
|
|
|
|
independently of it.
|
2014-10-27 19:32:46 +00:00
|
|
|
|
|
|
|
|
|
`crypt` has a command-line helper that you can use to put configurations
|
2015-03-07 10:52:13 +00:00
|
|
|
|
in your K/V store. `crypt` defaults to etcd on http://127.0.0.1:4001.
|
2014-10-27 19:32:46 +00:00
|
|
|
|
|
|
|
|
|
go get github.com/xordataexchange/crypt/bin/crypt
|
|
|
|
|
crypt set -plaintext /config/hugo.json /Users/hugo/settings/config.json
|
|
|
|
|
|
|
|
|
|
Confirm that your value was set:
|
|
|
|
|
|
|
|
|
|
crypt get -plaintext /config/hugo.json
|
|
|
|
|
|
|
|
|
|
See the `crypt` documentation for examples of how to set encrypted values, or how
|
|
|
|
|
to use Consul.
|
|
|
|
|
|
|
|
|
|
### Remote Key/Value Store Example - Unencrypted
|
|
|
|
|
|
|
|
|
|
viper.AddRemoteProvider("etcd", "http://127.0.0.1:4001","/config/hugo.json")
|
2014-10-28 01:53:22 +00:00
|
|
|
|
viper.SetConfigType("json") // because there is no file extension in a stream of bytes
|
2014-10-27 19:32:46 +00:00
|
|
|
|
err := viper.ReadRemoteConfig()
|
|
|
|
|
|
|
|
|
|
### Remote Key/Value Store Example - Encrypted
|
|
|
|
|
|
2014-10-29 06:43:14 +00:00
|
|
|
|
viper.AddSecureRemoteProvider("etcd","http://127.0.0.1:4001","/config/hugo.json","/etc/secrets/mykeyring.gpg")
|
2014-10-28 01:53:22 +00:00
|
|
|
|
viper.SetConfigType("json") // because there is no file extension in a stream of bytes
|
2014-10-27 19:32:46 +00:00
|
|
|
|
err := viper.ReadRemoteConfig()
|
|
|
|
|
|
|
|
|
|
|
2014-12-23 02:45:56 +00:00
|
|
|
|
## Getting Values From Viper
|
|
|
|
|
|
2015-03-07 10:52:13 +00:00
|
|
|
|
In Viper, there are a few ways to get a value depending on what type of value you want to retrieved.
|
2015-03-06 19:21:50 +00:00
|
|
|
|
The following functions and methods exist:
|
2014-12-23 02:45:56 +00:00
|
|
|
|
|
|
|
|
|
* Get(key string) : interface{}
|
|
|
|
|
* GetBool(key string) : bool
|
|
|
|
|
* GetFloat64(key string) : float64
|
|
|
|
|
* GetInt(key string) : int
|
|
|
|
|
* GetString(key string) : string
|
|
|
|
|
* GetStringMap(key string) : map[string]interface{}
|
|
|
|
|
* GetStringMapString(key string) : map[string]string
|
|
|
|
|
* GetStringSlice(key string) : []string
|
|
|
|
|
* GetTime(key string) : time.Time
|
2015-02-19 03:03:20 +00:00
|
|
|
|
* GetDuration(key string) : time.Duration
|
2014-12-23 02:45:56 +00:00
|
|
|
|
* IsSet(key string) : bool
|
|
|
|
|
|
|
|
|
|
One important thing to recognize is that each Get function will return
|
2015-03-07 10:52:13 +00:00
|
|
|
|
its zero value if it’s not found. To check if a given key exists, the IsSet()
|
2014-12-23 02:45:56 +00:00
|
|
|
|
method has been provided.
|
|
|
|
|
|
|
|
|
|
Example:
|
|
|
|
|
|
2015-03-07 10:52:13 +00:00
|
|
|
|
viper.GetString("logfile") // case-insensitive Setting & Getting
|
|
|
|
|
if viper.GetBool("verbose") {
|
2014-12-23 02:45:56 +00:00
|
|
|
|
fmt.Println("verbose enabled")
|
2015-03-07 10:52:13 +00:00
|
|
|
|
}
|
2014-12-23 02:45:56 +00:00
|
|
|
|
|
|
|
|
|
### Marshaling
|
|
|
|
|
|
|
|
|
|
You also have the option of Marshaling all or a specific value to a struct, map, etc.
|
|
|
|
|
|
|
|
|
|
There are two methods to do this:
|
|
|
|
|
|
|
|
|
|
* Marshal(rawVal interface{}) : error
|
|
|
|
|
* MarshalKey(key string, rawVal interface{}) : error
|
|
|
|
|
|
|
|
|
|
Example:
|
|
|
|
|
|
|
|
|
|
type config struct {
|
|
|
|
|
Port int
|
|
|
|
|
Name string
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var C config
|
|
|
|
|
|
|
|
|
|
err := Marshal(&C)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("unable to decode into struct, %v", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## Viper or Vipers?
|
2014-12-07 01:03:49 +00:00
|
|
|
|
|
|
|
|
|
Viper comes ready to use out of the box. There is no configuration or
|
|
|
|
|
initialization needed to begin using Viper. Since most applications will
|
2015-03-07 10:52:13 +00:00
|
|
|
|
want to use a single central repository for their configuration, the
|
2014-12-07 01:03:49 +00:00
|
|
|
|
viper package provides this. It is similar to a singleton.
|
|
|
|
|
|
2015-03-07 10:52:13 +00:00
|
|
|
|
In all of the examples above, they demonstrate using viper in its
|
2014-12-07 01:03:49 +00:00
|
|
|
|
singleton style approach.
|
|
|
|
|
|
|
|
|
|
### Working with multiple vipers
|
|
|
|
|
|
|
|
|
|
You can also create many different vipers for use in your application.
|
|
|
|
|
Each will have it’s own unique set of configurations and values. Each
|
|
|
|
|
can read from a different config file, key value store, etc. All of the
|
|
|
|
|
functions that viper package supports are mirrored as methods on a viper.
|
|
|
|
|
|
|
|
|
|
Example:
|
|
|
|
|
|
2015-03-07 10:52:13 +00:00
|
|
|
|
x := viper.New()
|
|
|
|
|
y := viper.New()
|
2014-12-07 01:03:49 +00:00
|
|
|
|
|
|
|
|
|
x.SetDefault("ContentDir", "content")
|
|
|
|
|
y.SetDefault("ContentDir", "foobar")
|
|
|
|
|
|
|
|
|
|
...
|
|
|
|
|
|
2015-03-07 10:52:13 +00:00
|
|
|
|
When working with multiple vipers, it is up to the user to keep track of
|
2014-12-07 01:03:49 +00:00
|
|
|
|
the different vipers.
|
2014-04-05 19:44:26 +00:00
|
|
|
|
|
|
|
|
|
## Q & A
|
|
|
|
|
|
|
|
|
|
Q: Why not INI files?
|
|
|
|
|
|
2015-03-07 10:52:13 +00:00
|
|
|
|
A: Ini files are pretty awful. There’s no standard format, and they are hard to
|
|
|
|
|
validate. Viper is designed to work with JSON, TOML or YAML files. If someone
|
2014-04-05 19:44:26 +00:00
|
|
|
|
really wants to add this feature, I’d be happy to merge it. It’s easy to
|
|
|
|
|
specify which formats your application will permit.
|
|
|
|
|
|
2015-03-07 10:52:13 +00:00
|
|
|
|
Q: Why is it called “Viper”?
|
2014-04-05 19:44:26 +00:00
|
|
|
|
|
2015-03-07 10:52:13 +00:00
|
|
|
|
A: Viper is designed to be a [companion](http://en.wikipedia.org/wiki/Viper_(G.I._Joe)) to
|
|
|
|
|
[Cobra](https://github.com/spf13/cobra). While both can operate completely
|
2014-04-05 19:44:26 +00:00
|
|
|
|
independently, together they make a powerful pair to handle much of your
|
|
|
|
|
application foundation needs.
|
|
|
|
|
|
2015-03-07 10:52:13 +00:00
|
|
|
|
Q: Why is it called “Cobra”?
|
2014-04-05 19:44:26 +00:00
|
|
|
|
|
2015-03-07 10:52:13 +00:00
|
|
|
|
A: Is there a better name for a [commander](http://en.wikipedia.org/wiki/Cobra_Commander)?
|