github.com/Be-MobileNV/viper@v1.0.2-0.20190415120027-e0a6cbb1bd49/README.md (about)

     1  ![viper logo](https://cloud.githubusercontent.com/assets/173412/10886745/998df88a-8151-11e5-9448-4736db51020d.png)
     2  
     3  Go configuration with fangs!
     4  
     5  Many Go projects are built using Viper including:
     6  
     7  * [Hugo](http://gohugo.io)
     8  * [EMC RexRay](http://rexray.readthedocs.org/en/stable/)
     9  * [Imgur’s Incus](https://github.com/Imgur/incus)
    10  * [Nanobox](https://github.com/nanobox-io/nanobox)/[Nanopack](https://github.com/nanopack)
    11  * [Docker Notary](https://github.com/docker/Notary)
    12  * [BloomApi](https://www.bloomapi.com/)
    13  * [doctl](https://github.com/digitalocean/doctl)
    14  * [Clairctl](https://github.com/jgsqware/clairctl)
    15  
    16  [![Build Status](https://travis-ci.org/spf13/viper.svg)](https://travis-ci.org/spf13/viper) [![Join the chat at https://gitter.im/spf13/viper](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/spf13/viper?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![GoDoc](https://godoc.org/github.com/spf13/viper?status.svg)](https://godoc.org/github.com/spf13/viper)
    17  
    18  
    19  ## Adjustments Be-Mobile
    20  
    21  What did we adjust?
    22  
    23  * added a username/password field on the defaultRemoteProvider, also the interface reflects this
    24  * adjusted Viper's AddRemoteProvider function, accepting username password
    25  
    26  TBH: we should refactor this code so providers can be added to Viper in a transparent way:
    27  
    28  ```
    29  type RemoteProvider interface {
    30  	Provider() string
    31  	Endpoint() string
    32  	Path() string
    33  }
    34  ```
    35  
    36  ETCD, CONSUL or others just need to make structs that adhere this interface. In the constructor of these structs, you can pass keyring, username/password. The interface doesn't need to know about the authentication! 
    37  
    38  ## What is Viper?
    39  
    40  Viper is a complete configuration solution for Go applications including 12-Factor apps. It is designed
    41  to work within an application, and can handle all types of configuration needs
    42  and formats. It supports:
    43  
    44  * setting defaults
    45  * reading from JSON, TOML, YAML, HCL, and Java properties config files
    46  * live watching and re-reading of config files (optional)
    47  * reading from environment variables
    48  * reading from remote config systems (etcd or Consul), and watching changes
    49  * reading from command line flags
    50  * reading from buffer
    51  * setting explicit values
    52  
    53  Viper can be thought of as a registry for all of your applications
    54  configuration needs.
    55  
    56  ## Why Viper?
    57  
    58  When building a modern application, you don’t want to worry about
    59  configuration file formats; you want to focus on building awesome software.
    60  Viper is here to help with that.
    61  
    62  Viper does the following for you:
    63  
    64  1. Find, load, and unmarshal a configuration file in JSON, TOML, YAML, HCL, or Java properties formats.
    65  2. Provide a mechanism to set default values for your different
    66     configuration options.
    67  3. Provide a mechanism to set override values for options specified through
    68     command line flags.
    69  4. Provide an alias system to easily rename parameters without breaking existing
    70     code.
    71  5. Make it easy to tell the difference between when a user has provided a
    72     command line or config file which is the same as the default.
    73  
    74  Viper uses the following precedence order. Each item takes precedence over the
    75  item below it:
    76  
    77   * explicit call to Set
    78   * flag
    79   * env
    80   * config
    81   * key/value store
    82   * default
    83  
    84  Viper configuration keys are case insensitive.
    85  
    86  ## Putting Values into Viper
    87  
    88  ### Establishing Defaults
    89  
    90  A good configuration system will support default values. A default value is not
    91  required for a key, but it’s useful in the event that a key hasn’t been set via
    92  config file, environment variable, remote configuration or flag.
    93  
    94  Examples:
    95  
    96  ```go
    97  viper.SetDefault("ContentDir", "content")
    98  viper.SetDefault("LayoutDir", "layouts")
    99  viper.SetDefault("Taxonomies", map[string]string{"tag": "tags", "category": "categories"})
   100  ```
   101  
   102  ### Reading Config Files
   103  
   104  Viper requires minimal configuration so it knows where to look for config files.
   105  Viper supports JSON, TOML, YAML, HCL, and Java Properties files. Viper can search multiple paths, but
   106  currently a single Viper instance only supports a single configuration file.
   107  Viper does not default to any configuration search paths leaving defaults decision
   108  to an application.
   109  
   110  Here is an example of how to use Viper to search for and read a configuration file.
   111  None of the specific paths are required, but at least one path should be provided
   112  where a configuration file is expected.
   113  
   114  ```go
   115  viper.SetConfigName("config") // name of config file (without extension)
   116  viper.AddConfigPath("/etc/appname/")   // path to look for the config file in
   117  viper.AddConfigPath("$HOME/.appname")  // call multiple times to add many search paths
   118  viper.AddConfigPath(".")               // optionally look for config in the working directory
   119  err := viper.ReadInConfig() // Find and read the config file
   120  if err != nil { // Handle errors reading the config file
   121  	panic(fmt.Errorf("Fatal error config file: %s \n", err))
   122  }
   123  ```
   124  
   125  ### Watching and re-reading config files
   126  
   127  Viper supports the ability to have your application live read a config file while running.
   128  
   129  Gone are the days of needing to restart a server to have a config take effect,
   130  viper powered applications can read an update to a config file while running and
   131  not miss a beat.
   132  
   133  Simply tell the viper instance to watchConfig.
   134  Optionally you can provide a function for Viper to run each time a change occurs.
   135  
   136  **Make sure you add all of the configPaths prior to calling `WatchConfig()`**
   137  
   138  ```go
   139  viper.WatchConfig()
   140  viper.OnConfigChange(func(e fsnotify.Event) {
   141  	fmt.Println("Config file changed:", e.Name)
   142  })
   143  ```
   144  
   145  ### Reading Config from io.Reader
   146  
   147  Viper predefines many configuration sources such as files, environment
   148  variables, flags, and remote K/V store, but you are not bound to them. You can
   149  also implement your own required configuration source and feed it to viper.
   150  
   151  ```go
   152  viper.SetConfigType("yaml") // or viper.SetConfigType("YAML")
   153  
   154  // any approach to require this configuration into your program.
   155  var yamlExample = []byte(`
   156  Hacker: true
   157  name: steve
   158  hobbies:
   159  - skateboarding
   160  - snowboarding
   161  - go
   162  clothing:
   163    jacket: leather
   164    trousers: denim
   165  age: 35
   166  eyes : brown
   167  beard: true
   168  `)
   169  
   170  viper.ReadConfig(bytes.NewBuffer(yamlExample))
   171  
   172  viper.Get("name") // this would be "steve"
   173  ```
   174  
   175  ### Setting Overrides
   176  
   177  These could be from a command line flag, or from your own application logic.
   178  
   179  ```go
   180  viper.Set("Verbose", true)
   181  viper.Set("LogFile", LogFile)
   182  ```
   183  
   184  ### Registering and Using Aliases
   185  
   186  Aliases permit a single value to be referenced by multiple keys
   187  
   188  ```go
   189  viper.RegisterAlias("loud", "Verbose")
   190  
   191  viper.Set("verbose", true) // same result as next line
   192  viper.Set("loud", true)   // same result as prior line
   193  
   194  viper.GetBool("loud") // true
   195  viper.GetBool("verbose") // true
   196  ```
   197  
   198  ### Working with Environment Variables
   199  
   200  Viper has full support for environment variables. This enables 12 factor
   201  applications out of the box. There are four methods that exist to aid working
   202  with ENV:
   203  
   204   * `AutomaticEnv()`
   205   * `BindEnv(string...) : error`
   206   * `SetEnvPrefix(string)`
   207   * `SetEnvKeyReplacer(string...) *strings.Replacer`
   208  
   209  _When working with ENV variables, it’s important to recognize that Viper
   210  treats ENV variables as case sensitive._
   211  
   212  Viper provides a mechanism to try to ensure that ENV variables are unique. By
   213  using `SetEnvPrefix`, you can tell Viper to use add a prefix while reading from
   214  the environment variables. Both `BindEnv` and `AutomaticEnv` will use this
   215  prefix.
   216  
   217  `BindEnv` takes one or two parameters. The first parameter is the key name, the
   218  second is the name of the environment variable. The name of the environment
   219  variable is case sensitive. If the ENV variable name is not provided, then
   220  Viper will automatically assume that the key name matches the ENV variable name,
   221  but the ENV variable is IN ALL CAPS. When you explicitly provide the ENV
   222  variable name, it **does not** automatically add the prefix.
   223  
   224  One important thing to recognize when working with ENV variables is that the
   225  value will be read each time it is accessed. Viper does not fix the value when
   226  the `BindEnv` is called.
   227  
   228  `AutomaticEnv` is a powerful helper especially when combined with
   229  `SetEnvPrefix`. When called, Viper will check for an environment variable any
   230  time a `viper.Get` request is made. It will apply the following rules. It will
   231  check for a environment variable with a name matching the key uppercased and
   232  prefixed with the `EnvPrefix` if set.
   233  
   234  `SetEnvKeyReplacer` allows you to use a `strings.Replacer` object to rewrite Env
   235  keys to an extent. This is useful if you want to use `-` or something in your
   236  `Get()` calls, but want your environmental variables to use `_` delimiters. An
   237  example of using it can be found in `viper_test.go`.
   238  
   239  #### Env example
   240  
   241  ```go
   242  SetEnvPrefix("spf") // will be uppercased automatically
   243  BindEnv("id")
   244  
   245  os.Setenv("SPF_ID", "13") // typically done outside of the app
   246  
   247  id := Get("id") // 13
   248  ```
   249  
   250  ### Working with Flags
   251  
   252  Viper has the ability to bind to flags. Specifically, Viper supports `Pflags`
   253  as used in the [Cobra](https://github.com/spf13/cobra) library.
   254  
   255  Like `BindEnv`, the value is not set when the binding method is called, but when
   256  it is accessed. This means you can bind as early as you want, even in an
   257  `init()` function.
   258  
   259  For individual flags, the `BindPFlag()` method provides this functionality.
   260  
   261  Example:
   262  
   263  ```go
   264  serverCmd.Flags().Int("port", 1138, "Port to run Application server on")
   265  viper.BindPFlag("port", serverCmd.Flags().Lookup("port"))
   266  ```
   267  
   268  You can also bind an existing set of pflags (pflag.FlagSet):
   269  
   270  Example:
   271  
   272  ```go
   273  pflag.Int("flagname", 1234, "help message for flagname")
   274  
   275  pflag.Parse()
   276  viper.BindPFlags(pflag.CommandLine)
   277  
   278  i := viper.GetInt("flagname") // retrieve values from viper instead of pflag
   279  ```
   280  
   281  The use of [pflag](https://github.com/spf13/pflag/) in Viper does not preclude
   282  the use of other packages that use the [flag](https://golang.org/pkg/flag/)
   283  package from the standard library. The pflag package can handle the flags
   284  defined for the flag package by importing these flags. This is accomplished
   285  by a calling a convenience function provided by the pflag package called
   286  AddGoFlagSet().
   287  
   288  Example:
   289  
   290  ```go
   291  package main
   292  
   293  import (
   294  	"flag"
   295  	"github.com/spf13/pflag"
   296  )
   297  
   298  func main() {
   299  
   300  	// using standard library "flag" package
   301  	flag.Int("flagname", 1234, "help message for flagname")
   302  
   303  	pflag.CommandLine.AddGoFlagSet(flag.CommandLine)
   304  	pflag.Parse()
   305  	viper.BindPFlags(pflag.CommandLine)
   306  
   307  	i := viper.GetInt("flagname") // retrieve value from viper
   308  
   309  	...
   310  }
   311  ```
   312  
   313  #### Flag interfaces
   314  
   315  Viper provides two Go interfaces to bind other flag systems if you don’t use `Pflags`.
   316  
   317  `FlagValue` represents a single flag. This is a very simple example on how to implement this interface:
   318  
   319  ```go
   320  type myFlag struct {}
   321  func (f myFlag) HasChanged() bool { return false }
   322  func (f myFlag) Name() string { return "my-flag-name" }
   323  func (f myFlag) ValueString() string { return "my-flag-value" }
   324  func (f myFlag) ValueType() string { return "string" }
   325  ```
   326  
   327  Once your flag implements this interface, you can simply tell Viper to bind it:
   328  
   329  ```go
   330  viper.BindFlagValue("my-flag-name", myFlag{})
   331  ```
   332  
   333  `FlagValueSet` represents a group of flags. This is a very simple example on how to implement this interface:
   334  
   335  ```go
   336  type myFlagSet struct {
   337  	flags []myFlag
   338  }
   339  
   340  func (f myFlagSet) VisitAll(fn func(FlagValue)) {
   341  	for _, flag := range flags {
   342  		fn(flag)
   343  	}
   344  }
   345  ```
   346  
   347  Once your flag set implements this interface, you can simply tell Viper to bind it:
   348  
   349  ```go
   350  fSet := myFlagSet{
   351  	flags: []myFlag{myFlag{}, myFlag{}},
   352  }
   353  viper.BindFlagValues("my-flags", fSet)
   354  ```
   355  
   356  ### Remote Key/Value Store Support
   357  
   358  To enable remote support in Viper, do a blank import of the `viper/remote`
   359  package:
   360  
   361  `import _ "github.com/spf13/viper/remote"`
   362  
   363  Viper will read a config string (as JSON, TOML, YAML or HCL) retrieved from a path
   364  in a Key/Value store such as etcd or Consul.  These values take precedence over
   365  default values, but are overridden by configuration values retrieved from disk,
   366  flags, or environment variables.
   367  
   368  Viper uses [crypt](https://github.com/xordataexchange/crypt) to retrieve
   369  configuration from the K/V store, which means that you can store your
   370  configuration values encrypted and have them automatically decrypted if you have
   371  the correct gpg keyring.  Encryption is optional.
   372  
   373  You can use remote configuration in conjunction with local configuration, or
   374  independently of it.
   375  
   376  `crypt` has a command-line helper that you can use to put configurations in your
   377  K/V store. `crypt` defaults to etcd on http://127.0.0.1:4001.
   378  
   379  ```bash
   380  $ go get github.com/xordataexchange/crypt/bin/crypt
   381  $ crypt set -plaintext /config/hugo.json /Users/hugo/settings/config.json
   382  ```
   383  
   384  Confirm that your value was set:
   385  
   386  ```bash
   387  $ crypt get -plaintext /config/hugo.json
   388  ```
   389  
   390  See the `crypt` documentation for examples of how to set encrypted values, or
   391  how to use Consul.
   392  
   393  ### Remote Key/Value Store Example - Unencrypted
   394  
   395  ```go
   396  viper.AddRemoteProvider("etcd", "http://127.0.0.1:4001","/config/hugo.json")
   397  viper.SetConfigType("json") // because there is no file extension in a stream of bytes, supported extensions are "json", "toml", "yaml", "yml", "properties", "props", "prop"
   398  err := viper.ReadRemoteConfig()
   399  ```
   400  
   401  ### Remote Key/Value Store Example - Encrypted
   402  
   403  ```go
   404  viper.AddSecureRemoteProvider("etcd","http://127.0.0.1:4001","/config/hugo.json","/etc/secrets/mykeyring.gpg")
   405  viper.SetConfigType("json") // because there is no file extension in a stream of bytes,  supported extensions are "json", "toml", "yaml", "yml", "properties", "props", "prop"
   406  err := viper.ReadRemoteConfig()
   407  ```
   408  
   409  ### Watching Changes in etcd - Unencrypted
   410  
   411  ```go
   412  // alternatively, you can create a new viper instance.
   413  var runtime_viper = viper.New()
   414  
   415  runtime_viper.AddRemoteProvider("etcd", "http://127.0.0.1:4001", "/config/hugo.yml")
   416  runtime_viper.SetConfigType("yaml") // because there is no file extension in a stream of bytes, supported extensions are "json", "toml", "yaml", "yml", "properties", "props", "prop"
   417  
   418  // read from remote config the first time.
   419  err := runtime_viper.ReadRemoteConfig()
   420  
   421  // unmarshal config
   422  runtime_viper.Unmarshal(&runtime_conf)
   423  
   424  // open a goroutine to watch remote changes forever
   425  go func(){
   426  	for {
   427  	    time.Sleep(time.Second * 5) // delay after each request
   428  
   429  	    // currently, only tested with etcd support
   430  	    err := runtime_viper.WatchRemoteConfig()
   431  	    if err != nil {
   432  	        log.Errorf("unable to read remote config: %v", err)
   433  	        continue
   434  	    }
   435  
   436  	    // unmarshal new config into our runtime config struct. you can also use channel
   437  	    // to implement a signal to notify the system of the changes
   438  	    runtime_viper.Unmarshal(&runtime_conf)
   439  	}
   440  }()
   441  ```
   442  
   443  ## Getting Values From Viper
   444  
   445  In Viper, there are a few ways to get a value depending on the value’s type.
   446  The following functions and methods exist:
   447  
   448   * `Get(key string) : interface{}`
   449   * `GetBool(key string) : bool`
   450   * `GetFloat64(key string) : float64`
   451   * `GetInt(key string) : int`
   452   * `GetString(key string) : string`
   453   * `GetStringMap(key string) : map[string]interface{}`
   454   * `GetStringMapString(key string) : map[string]string`
   455   * `GetStringSlice(key string) : []string`
   456   * `GetTime(key string) : time.Time`
   457   * `GetDuration(key string) : time.Duration`
   458   * `IsSet(key string) : bool`
   459  
   460  One important thing to recognize is that each Get function will return a zero
   461  value if it’s not found. To check if a given key exists, the `IsSet()` method
   462  has been provided.
   463  
   464  Example:
   465  ```go
   466  viper.GetString("logfile") // case-insensitive Setting & Getting
   467  if viper.GetBool("verbose") {
   468      fmt.Println("verbose enabled")
   469  }
   470  ```
   471  ### Accessing nested keys
   472  
   473  The accessor methods also accept formatted paths to deeply nested keys. For
   474  example, if the following JSON file is loaded:
   475  
   476  ```json
   477  {
   478      "host": {
   479          "address": "localhost",
   480          "port": 5799
   481      },
   482      "datastore": {
   483          "metric": {
   484              "host": "127.0.0.1",
   485              "port": 3099
   486          },
   487          "warehouse": {
   488              "host": "198.0.0.1",
   489              "port": 2112
   490          }
   491      }
   492  }
   493  
   494  ```
   495  
   496  Viper can access a nested field by passing a `.` delimited path of keys:
   497  
   498  ```go
   499  GetString("datastore.metric.host") // (returns "127.0.0.1")
   500  ```
   501  
   502  This obeys the precedence rules established above; the search for the path
   503  will cascade through the remaining configuration registries until found.
   504  
   505  For example, given this configuration file, both `datastore.metric.host` and
   506  `datastore.metric.port` are already defined (and may be overridden). If in addition
   507  `datastore.metric.protocol` was defined in the defaults, Viper would also find it.
   508  
   509  However, if `datastore.metric` was overridden (by a flag, an environment variable,
   510  the `Set()` method, …) with an immediate value, then all sub-keys of
   511  `datastore.metric` become undefined, they are “shadowed” by the higher-priority
   512  configuration level.
   513  
   514  Lastly, if there exists a key that matches the delimited key path, its value
   515  will be returned instead. E.g.
   516  
   517  ```json
   518  {
   519      "datastore.metric.host": "0.0.0.0",
   520      "host": {
   521          "address": "localhost",
   522          "port": 5799
   523      },
   524      "datastore": {
   525          "metric": {
   526              "host": "127.0.0.1",
   527              "port": 3099
   528          },
   529          "warehouse": {
   530              "host": "198.0.0.1",
   531              "port": 2112
   532          }
   533      }
   534  }
   535  
   536  GetString("datastore.metric.host") // returns "0.0.0.0"
   537  ```
   538  
   539  ### Extract sub-tree
   540  
   541  Extract sub-tree from Viper.
   542  
   543  For example, `viper` represents:
   544  
   545  ```json
   546  app:
   547    cache1:
   548      max-items: 100
   549      item-size: 64
   550    cache2:
   551      max-items: 200
   552      item-size: 80
   553  ```
   554  
   555  After executing:
   556  
   557  ```go
   558  subv := viper.Sub("app.cache1")
   559  ```
   560  
   561  `subv` represents:
   562  
   563  ```json
   564  max-items: 100
   565  item-size: 64
   566  ```
   567  
   568  Suppose we have:
   569  
   570  ```go
   571  func NewCache(cfg *Viper) *Cache {...}
   572  ```
   573  
   574  which creates a cache based on config information formatted as `subv`.
   575  Now it’s easy to create these 2 caches separately as:
   576  
   577  ```go
   578  cfg1 := viper.Sub("app.cache1")
   579  cache1 := NewCache(cfg1)
   580  
   581  cfg2 := viper.Sub("app.cache2")
   582  cache2 := NewCache(cfg2)
   583  ```
   584  
   585  ### Unmarshaling
   586  
   587  You also have the option of Unmarshaling all or a specific value to a struct, map,
   588  etc.
   589  
   590  There are two methods to do this:
   591  
   592   * `Unmarshal(rawVal interface{}) : error`
   593   * `UnmarshalKey(key string, rawVal interface{}) : error`
   594  
   595  Example:
   596  
   597  ```go
   598  type config struct {
   599  	Port int
   600  	Name string
   601  	PathMap string `mapstructure:"path_map"`
   602  }
   603  
   604  var C config
   605  
   606  err := Unmarshal(&C)
   607  if err != nil {
   608  	t.Fatalf("unable to decode into struct, %v", err)
   609  }
   610  ```
   611  
   612  ## Viper or Vipers?
   613  
   614  Viper comes ready to use out of the box. There is no configuration or
   615  initialization needed to begin using Viper. Since most applications will want
   616  to use a single central repository for their configuration, the viper package
   617  provides this. It is similar to a singleton.
   618  
   619  In all of the examples above, they demonstrate using viper in its singleton
   620  style approach.
   621  
   622  ### Working with multiple vipers
   623  
   624  You can also create many different vipers for use in your application. Each will
   625  have its own unique set of configurations and values. Each can read from a
   626  different config file, key value store, etc. All of the functions that viper
   627  package supports are mirrored as methods on a viper.
   628  
   629  Example:
   630  
   631  ```go
   632  x := viper.New()
   633  y := viper.New()
   634  
   635  x.SetDefault("ContentDir", "content")
   636  y.SetDefault("ContentDir", "foobar")
   637  
   638  //...
   639  ```
   640  
   641  When working with multiple vipers, it is up to the user to keep track of the
   642  different vipers.
   643  
   644  ## Q & A
   645  
   646  Q: Why not INI files?
   647  
   648  A: Ini files are pretty awful. There’s no standard format, and they are hard to
   649  validate. Viper is designed to work with JSON, TOML or YAML files. If someone
   650  really wants to add this feature, I’d be happy to merge it. It’s easy to specify
   651  which formats your application will permit.
   652  
   653  Q: Why is it called “Viper”?
   654  
   655  A: Viper is designed to be a [companion](http://en.wikipedia.org/wiki/Viper_(G.I._Joe))
   656  to [Cobra](https://github.com/spf13/cobra). While both can operate completely
   657  independently, together they make a powerful pair to handle much of your
   658  application foundation needs.
   659  
   660  Q: Why is it called “Cobra”?
   661  
   662  A: Is there a better name for a [commander](http://en.wikipedia.org/wiki/Cobra_Commander)?