github.com/Billyyoyo/xviper@v1.15.1/README.md (about)

     1  ### 改写了Viper增加了一点小功能
     2  1. 支持多配置中心文件加载
     3  2. 支持配置中心文件动态修改配置对象
     4  3. 支持配置文件中使用占位符,仅支持值来自系统环境变量
     5  
     6  ---
     7  
     8  > ## Viper v2 feedback
     9  > Viper is heading towards v2 and we would love to hear what _**you**_ would like to see in it. Share your thoughts here: https://forms.gle/R6faU74qPRPAzchZ9
    10  >
    11  > **Thank you!**
    12  
    13  ![Viper](.github/logo.png?raw=true)
    14  
    15  [![Mentioned in Awesome Go](https://awesome.re/mentioned-badge-flat.svg)](https://github.com/avelino/awesome-go#configuration)
    16  [![run on repl.it](https://repl.it/badge/github/sagikazarmark/Viper-example)](https://repl.it/@sagikazarmark/Viper-example#main.go)
    17  
    18  [![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/spf13/viper/ci.yaml?branch=master&style=flat-square)](https://github.com/spf13/viper/actions?query=workflow%3ACI)
    19  [![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)
    20  [![Go Report Card](https://goreportcard.com/badge/github.com/spf13/viper?style=flat-square)](https://goreportcard.com/report/github.com/spf13/viper)
    21  ![Go Version](https://img.shields.io/badge/go%20version-%3E=1.16-61CFDD.svg?style=flat-square)
    22  [![PkgGoDev](https://pkg.go.dev/badge/mod/github.com/spf13/viper)](https://pkg.go.dev/mod/github.com/spf13/viper)
    23  
    24  **Go configuration with fangs!**
    25  
    26  Many Go projects are built using Viper including:
    27  
    28  * [Hugo](http://gohugo.io)
    29  * [EMC RexRay](http://rexray.readthedocs.org/en/stable/)
    30  * [Imgur’s Incus](https://github.com/Imgur/incus)
    31  * [Nanobox](https://github.com/nanobox-io/nanobox)/[Nanopack](https://github.com/nanopack)
    32  * [Docker Notary](https://github.com/docker/Notary)
    33  * [BloomApi](https://www.bloomapi.com/)
    34  * [doctl](https://github.com/digitalocean/doctl)
    35  * [Clairctl](https://github.com/jgsqware/clairctl)
    36  * [Mercure](https://mercure.rocks)
    37  
    38  
    39  ## Install
    40  
    41  ```shell
    42  go get github.com/spf13/viper
    43  ```
    44  
    45  **Note:** Viper uses [Go Modules](https://github.com/golang/go/wiki/Modules) to manage dependencies.
    46  
    47  
    48  ## What is Viper?
    49  
    50  Viper is a complete configuration solution for Go applications including [12-Factor apps](https://12factor.net/#the_twelve_factors).
    51  It is designed to work within an application, and can handle all types of configuration needs
    52  and formats. It supports:
    53  
    54  * setting defaults
    55  * reading from JSON, TOML, YAML, HCL, envfile and Java properties config files
    56  * live watching and re-reading of config files (optional)
    57  * reading from environment variables
    58  * reading from remote config systems (etcd or Consul), and watching changes
    59  * reading from command line flags
    60  * reading from buffer
    61  * setting explicit values
    62  
    63  Viper can be thought of as a registry for all of your applications configuration needs.
    64  
    65  
    66  ## Why Viper?
    67  
    68  When building a modern application, you don’t want to worry about
    69  configuration file formats; you want to focus on building awesome software.
    70  Viper is here to help with that.
    71  
    72  Viper does the following for you:
    73  
    74  1. Find, load, and unmarshal a configuration file in JSON, TOML, YAML, HCL, INI, envfile or Java properties formats.
    75  2. Provide a mechanism to set default values for your different configuration options.
    76  3. Provide a mechanism to set override values for options specified through command line flags.
    77  4. Provide an alias system to easily rename parameters without breaking existing code.
    78  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.
    79  
    80  Viper uses the following precedence order. Each item takes precedence over the item below it:
    81  
    82   * explicit call to `Set`
    83   * flag
    84   * env
    85   * config
    86   * key/value store
    87   * default
    88  
    89  **Important:** Viper configuration keys are case insensitive.
    90  There are ongoing discussions about making that optional.
    91  
    92  
    93  ## Putting Values into Viper
    94  
    95  ### Establishing Defaults
    96  
    97  A good configuration system will support default values. A default value is not
    98  required for a key, but it’s useful in the event that a key hasn't been set via
    99  config file, environment variable, remote configuration or flag.
   100  
   101  Examples:
   102  
   103  ```go
   104  viper.SetDefault("ContentDir", "content")
   105  viper.SetDefault("LayoutDir", "layouts")
   106  viper.SetDefault("Taxonomies", map[string]string{"tag": "tags", "category": "categories"})
   107  ```
   108  
   109  ### Reading Config Files
   110  
   111  Viper requires minimal configuration so it knows where to look for config files.
   112  Viper supports JSON, TOML, YAML, HCL, INI, envfile and Java Properties files. Viper can search multiple paths, but
   113  currently a single Viper instance only supports a single configuration file.
   114  Viper does not default to any configuration search paths leaving defaults decision
   115  to an application.
   116  
   117  Here is an example of how to use Viper to search for and read a configuration file.
   118  None of the specific paths are required, but at least one path should be provided
   119  where a configuration file is expected.
   120  
   121  ```go
   122  viper.SetConfigName("config") // name of config file (without extension)
   123  viper.SetConfigType("yaml") // REQUIRED if the config file does not have the extension in the name
   124  viper.AddConfigPath("/etc/appname/")   // path to look for the config file in
   125  viper.AddConfigPath("$HOME/.appname")  // call multiple times to add many search paths
   126  viper.AddConfigPath(".")               // optionally look for config in the working directory
   127  err := viper.ReadInConfig() // Find and read the config file
   128  if err != nil { // Handle errors reading the config file
   129  	panic(fmt.Errorf("fatal error config file: %w", err))
   130  }
   131  ```
   132  
   133  You can handle the specific case where no config file is found like this:
   134  
   135  ```go
   136  if err := viper.ReadInConfig(); err != nil {
   137  	if _, ok := err.(viper.ConfigFileNotFoundError); ok {
   138  		// Config file not found; ignore error if desired
   139  	} else {
   140  		// Config file was found but another error was produced
   141  	}
   142  }
   143  
   144  // Config file found and successfully parsed
   145  ```
   146  
   147  *NOTE [since 1.6]:* You can also have a file without an extension and specify the format programmaticaly. For those configuration files that lie in the home of the user without any extension like `.bashrc`
   148  
   149  ### Writing Config Files
   150  
   151  Reading from config files is useful, but at times you want to store all modifications made at run time.
   152  For that, a bunch of commands are available, each with its own purpose:
   153  
   154  * WriteConfig - writes the current viper configuration to the predefined path, if exists. Errors if no predefined path. Will overwrite the current config file, if it exists.
   155  * SafeWriteConfig - writes the current viper configuration to the predefined path. Errors if no predefined path. Will not overwrite the current config file, if it exists.
   156  * WriteConfigAs - writes the current viper configuration to the given filepath. Will overwrite the given file, if it exists.
   157  * SafeWriteConfigAs - writes the current viper configuration to the given filepath. Will not overwrite the given file, if it exists.
   158  
   159  As a rule of the thumb, everything marked with safe won't overwrite any file, but just create if not existent, whilst the default behavior is to create or truncate.
   160  
   161  A small examples section:
   162  
   163  ```go
   164  viper.WriteConfig() // writes current config to predefined path set by 'viper.AddConfigPath()' and 'viper.SetConfigName'
   165  viper.SafeWriteConfig()
   166  viper.WriteConfigAs("/path/to/my/.config")
   167  viper.SafeWriteConfigAs("/path/to/my/.config") // will error since it has already been written
   168  viper.SafeWriteConfigAs("/path/to/my/.other_config")
   169  ```
   170  
   171  ### Watching and re-reading config files
   172  
   173  Viper supports the ability to have your application live read a config file while running.
   174  
   175  Gone are the days of needing to restart a server to have a config take effect,
   176  viper powered applications can read an update to a config file while running and
   177  not miss a beat.
   178  
   179  Simply tell the viper instance to watchConfig.
   180  Optionally you can provide a function for Viper to run each time a change occurs.
   181  
   182  **Make sure you add all of the configPaths prior to calling `WatchConfig()`**
   183  
   184  ```go
   185  viper.OnConfigChange(func(e fsnotify.Event) {
   186  	fmt.Println("Config file changed:", e.Name)
   187  })
   188  viper.WatchConfig()
   189  ```
   190  
   191  ### Reading Config from io.Reader
   192  
   193  Viper predefines many configuration sources such as files, environment
   194  variables, flags, and remote K/V store, but you are not bound to them. You can
   195  also implement your own required configuration source and feed it to viper.
   196  
   197  ```go
   198  viper.SetConfigType("yaml") // or viper.SetConfigType("YAML")
   199  
   200  // any approach to require this configuration into your program.
   201  var yamlExample = []byte(`
   202  Hacker: true
   203  name: steve
   204  hobbies:
   205  - skateboarding
   206  - snowboarding
   207  - go
   208  clothing:
   209    jacket: leather
   210    trousers: denim
   211  age: 35
   212  eyes : brown
   213  beard: true
   214  `)
   215  
   216  viper.ReadConfig(bytes.NewBuffer(yamlExample))
   217  
   218  viper.Get("name") // this would be "steve"
   219  ```
   220  
   221  ### Setting Overrides
   222  
   223  These could be from a command line flag, or from your own application logic.
   224  
   225  ```go
   226  viper.Set("Verbose", true)
   227  viper.Set("LogFile", LogFile)
   228  ```
   229  
   230  ### Registering and Using Aliases
   231  
   232  Aliases permit a single value to be referenced by multiple keys
   233  
   234  ```go
   235  viper.RegisterAlias("loud", "Verbose")
   236  
   237  viper.Set("verbose", true) // same result as next line
   238  viper.Set("loud", true)   // same result as prior line
   239  
   240  viper.GetBool("loud") // true
   241  viper.GetBool("verbose") // true
   242  ```
   243  
   244  ### Working with Environment Variables
   245  
   246  Viper has full support for environment variables. This enables 12 factor
   247  applications out of the box. There are five methods that exist to aid working
   248  with ENV:
   249  
   250   * `AutomaticEnv()`
   251   * `BindEnv(string...) : error`
   252   * `SetEnvPrefix(string)`
   253   * `SetEnvKeyReplacer(string...) *strings.Replacer`
   254   * `AllowEmptyEnv(bool)`
   255  
   256  _When working with ENV variables, it’s important to recognize that Viper
   257  treats ENV variables as case sensitive._
   258  
   259  Viper provides a mechanism to try to ensure that ENV variables are unique. By
   260  using `SetEnvPrefix`, you can tell Viper to use a prefix while reading from
   261  the environment variables. Both `BindEnv` and `AutomaticEnv` will use this
   262  prefix.
   263  
   264  `BindEnv` takes one or more parameters. The first parameter is the key name, the
   265  rest are the name of the environment variables to bind to this key. If more than
   266  one are provided, they will take precedence in the specified order. The name of
   267  the environment variable is case sensitive. If the ENV variable name is not provided, then
   268  Viper will automatically assume that the ENV variable matches the following format: prefix + "_" + the key name in ALL CAPS. When you explicitly provide the ENV variable name (the second parameter),
   269  it **does not** automatically add the prefix. For example if the second parameter is "id",
   270  Viper will look for the ENV variable "ID".
   271  
   272  One important thing to recognize when working with ENV variables is that the
   273  value will be read each time it is accessed. Viper does not fix the value when
   274  the `BindEnv` is called.
   275  
   276  `AutomaticEnv` is a powerful helper especially when combined with
   277  `SetEnvPrefix`. When called, Viper will check for an environment variable any
   278  time a `viper.Get` request is made. It will apply the following rules. It will
   279  check for an environment variable with a name matching the key uppercased and
   280  prefixed with the `EnvPrefix` if set.
   281  
   282  `SetEnvKeyReplacer` allows you to use a `strings.Replacer` object to rewrite Env
   283  keys to an extent. This is useful if you want to use `-` or something in your
   284  `Get()` calls, but want your environmental variables to use `_` delimiters. An
   285  example of using it can be found in `viper_test.go`.
   286  
   287  Alternatively, you can use `EnvKeyReplacer` with `NewWithOptions` factory function.
   288  Unlike `SetEnvKeyReplacer`, it accepts a `StringReplacer` interface allowing you to write custom string replacing logic.
   289  
   290  By default empty environment variables are considered unset and will fall back to
   291  the next configuration source. To treat empty environment variables as set, use
   292  the `AllowEmptyEnv` method.
   293  
   294  #### Env example
   295  
   296  ```go
   297  SetEnvPrefix("spf") // will be uppercased automatically
   298  BindEnv("id")
   299  
   300  os.Setenv("SPF_ID", "13") // typically done outside of the app
   301  
   302  id := Get("id") // 13
   303  ```
   304  
   305  ### Working with Flags
   306  
   307  Viper has the ability to bind to flags. Specifically, Viper supports `Pflags`
   308  as used in the [Cobra](https://github.com/spf13/cobra) library.
   309  
   310  Like `BindEnv`, the value is not set when the binding method is called, but when
   311  it is accessed. This means you can bind as early as you want, even in an
   312  `init()` function.
   313  
   314  For individual flags, the `BindPFlag()` method provides this functionality.
   315  
   316  Example:
   317  
   318  ```go
   319  serverCmd.Flags().Int("port", 1138, "Port to run Application server on")
   320  viper.BindPFlag("port", serverCmd.Flags().Lookup("port"))
   321  ```
   322  
   323  You can also bind an existing set of pflags (pflag.FlagSet):
   324  
   325  Example:
   326  
   327  ```go
   328  pflag.Int("flagname", 1234, "help message for flagname")
   329  
   330  pflag.Parse()
   331  viper.BindPFlags(pflag.CommandLine)
   332  
   333  i := viper.GetInt("flagname") // retrieve values from viper instead of pflag
   334  ```
   335  
   336  The use of [pflag](https://github.com/spf13/pflag/) in Viper does not preclude
   337  the use of other packages that use the [flag](https://golang.org/pkg/flag/)
   338  package from the standard library. The pflag package can handle the flags
   339  defined for the flag package by importing these flags. This is accomplished
   340  by a calling a convenience function provided by the pflag package called
   341  AddGoFlagSet().
   342  
   343  Example:
   344  
   345  ```go
   346  package main
   347  
   348  import (
   349  	"flag"
   350  	"github.com/spf13/pflag"
   351  )
   352  
   353  func main() {
   354  
   355  	// using standard library "flag" package
   356  	flag.Int("flagname", 1234, "help message for flagname")
   357  
   358  	pflag.CommandLine.AddGoFlagSet(flag.CommandLine)
   359  	pflag.Parse()
   360  	viper.BindPFlags(pflag.CommandLine)
   361  
   362  	i := viper.GetInt("flagname") // retrieve value from viper
   363  
   364  	// ...
   365  }
   366  ```
   367  
   368  #### Flag interfaces
   369  
   370  Viper provides two Go interfaces to bind other flag systems if you don’t use `Pflags`.
   371  
   372  `FlagValue` represents a single flag. This is a very simple example on how to implement this interface:
   373  
   374  ```go
   375  type myFlag struct {}
   376  func (f myFlag) HasChanged() bool { return false }
   377  func (f myFlag) Name() string { return "my-flag-name" }
   378  func (f myFlag) ValueString() string { return "my-flag-value" }
   379  func (f myFlag) ValueType() string { return "string" }
   380  ```
   381  
   382  Once your flag implements this interface, you can simply tell Viper to bind it:
   383  
   384  ```go
   385  viper.BindFlagValue("my-flag-name", myFlag{})
   386  ```
   387  
   388  `FlagValueSet` represents a group of flags. This is a very simple example on how to implement this interface:
   389  
   390  ```go
   391  type myFlagSet struct {
   392  	flags []myFlag
   393  }
   394  
   395  func (f myFlagSet) VisitAll(fn func(FlagValue)) {
   396  	for _, flag := range flags {
   397  		fn(flag)
   398  	}
   399  }
   400  ```
   401  
   402  Once your flag set implements this interface, you can simply tell Viper to bind it:
   403  
   404  ```go
   405  fSet := myFlagSet{
   406  	flags: []myFlag{myFlag{}, myFlag{}},
   407  }
   408  viper.BindFlagValues("my-flags", fSet)
   409  ```
   410  
   411  ### Remote Key/Value Store Support
   412  
   413  To enable remote support in Viper, do a blank import of the `viper/remote`
   414  package:
   415  
   416  `import _ "github.com/spf13/viper/remote"`
   417  
   418  Viper will read a config string (as JSON, TOML, YAML, HCL or envfile) retrieved from a path
   419  in a Key/Value store such as etcd or Consul.  These values take precedence over
   420  default values, but are overridden by configuration values retrieved from disk,
   421  flags, or environment variables.
   422  
   423  Viper uses [crypt](https://github.com/bketelsen/crypt) to retrieve
   424  configuration from the K/V store, which means that you can store your
   425  configuration values encrypted and have them automatically decrypted if you have
   426  the correct gpg keyring.  Encryption is optional.
   427  
   428  You can use remote configuration in conjunction with local configuration, or
   429  independently of it.
   430  
   431  `crypt` has a command-line helper that you can use to put configurations in your
   432  K/V store. `crypt` defaults to etcd on http://127.0.0.1:4001.
   433  
   434  ```bash
   435  $ go get github.com/bketelsen/crypt/bin/crypt
   436  $ crypt set -plaintext /config/hugo.json /Users/hugo/settings/config.json
   437  ```
   438  
   439  Confirm that your value was set:
   440  
   441  ```bash
   442  $ crypt get -plaintext /config/hugo.json
   443  ```
   444  
   445  See the `crypt` documentation for examples of how to set encrypted values, or
   446  how to use Consul.
   447  
   448  ### Remote Key/Value Store Example - Unencrypted
   449  
   450  #### etcd
   451  ```go
   452  viper.AddRemoteProvider("etcd", "http://127.0.0.1:4001","/config/hugo.json")
   453  viper.SetConfigType("json") // because there is no file extension in a stream of bytes, supported extensions are "json", "toml", "yaml", "yml", "properties", "props", "prop", "env", "dotenv"
   454  err := viper.ReadRemoteConfig()
   455  ```
   456  
   457  #### etcd3
   458  ```go
   459  viper.AddRemoteProvider("etcd3", "http://127.0.0.1:4001","/config/hugo.json")
   460  viper.SetConfigType("json") // because there is no file extension in a stream of bytes, supported extensions are "json", "toml", "yaml", "yml", "properties", "props", "prop", "env", "dotenv"
   461  err := viper.ReadRemoteConfig()
   462  ```
   463  
   464  #### Consul
   465  You need to set a key to Consul key/value storage with JSON value containing your desired config.
   466  For example, create a Consul key/value store key `MY_CONSUL_KEY` with value:
   467  
   468  ```json
   469  {
   470      "port": 8080,
   471      "hostname": "myhostname.com"
   472  }
   473  ```
   474  
   475  ```go
   476  viper.AddRemoteProvider("consul", "localhost:8500", "MY_CONSUL_KEY")
   477  viper.SetConfigType("json") // Need to explicitly set this to json
   478  err := viper.ReadRemoteConfig()
   479  
   480  fmt.Println(viper.Get("port")) // 8080
   481  fmt.Println(viper.Get("hostname")) // myhostname.com
   482  ```
   483  
   484  #### Firestore
   485  
   486  ```go
   487  viper.AddRemoteProvider("firestore", "google-cloud-project-id", "collection/document")
   488  viper.SetConfigType("json") // Config's format: "json", "toml", "yaml", "yml"
   489  err := viper.ReadRemoteConfig()
   490  ```
   491  
   492  Of course, you're allowed to use `SecureRemoteProvider` also
   493  
   494  ### Remote Key/Value Store Example - Encrypted
   495  
   496  ```go
   497  viper.AddSecureRemoteProvider("etcd","http://127.0.0.1:4001","/config/hugo.json","/etc/secrets/mykeyring.gpg")
   498  viper.SetConfigType("json") // because there is no file extension in a stream of bytes,  supported extensions are "json", "toml", "yaml", "yml", "properties", "props", "prop", "env", "dotenv"
   499  err := viper.ReadRemoteConfig()
   500  ```
   501  
   502  ### Watching Changes in etcd - Unencrypted
   503  
   504  ```go
   505  // alternatively, you can create a new viper instance.
   506  var runtime_viper = viper.New()
   507  
   508  runtime_viper.AddRemoteProvider("etcd", "http://127.0.0.1:4001", "/config/hugo.yml")
   509  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", "env", "dotenv"
   510  
   511  // read from remote config the first time.
   512  err := runtime_viper.ReadRemoteConfig()
   513  
   514  // unmarshal config
   515  runtime_viper.Unmarshal(&runtime_conf)
   516  
   517  // open a goroutine to watch remote changes forever
   518  go func(){
   519  	for {
   520  		time.Sleep(time.Second * 5) // delay after each request
   521  
   522  		// currently, only tested with etcd support
   523  		err := runtime_viper.WatchRemoteConfig()
   524  		if err != nil {
   525  			log.Errorf("unable to read remote config: %v", err)
   526  			continue
   527  		}
   528  
   529  		// unmarshal new config into our runtime config struct. you can also use channel
   530  		// to implement a signal to notify the system of the changes
   531  		runtime_viper.Unmarshal(&runtime_conf)
   532  	}
   533  }()
   534  ```
   535  
   536  ## Getting Values From Viper
   537  
   538  In Viper, there are a few ways to get a value depending on the value’s type.
   539  The following functions and methods exist:
   540  
   541   * `Get(key string) : interface{}`
   542   * `GetBool(key string) : bool`
   543   * `GetFloat64(key string) : float64`
   544   * `GetInt(key string) : int`
   545   * `GetIntSlice(key string) : []int`
   546   * `GetString(key string) : string`
   547   * `GetStringMap(key string) : map[string]interface{}`
   548   * `GetStringMapString(key string) : map[string]string`
   549   * `GetStringSlice(key string) : []string`
   550   * `GetTime(key string) : time.Time`
   551   * `GetDuration(key string) : time.Duration`
   552   * `IsSet(key string) : bool`
   553   * `AllSettings() : map[string]interface{}`
   554  
   555  One important thing to recognize is that each Get function will return a zero
   556  value if it’s not found. To check if a given key exists, the `IsSet()` method
   557  has been provided.
   558  
   559  Example:
   560  ```go
   561  viper.GetString("logfile") // case-insensitive Setting & Getting
   562  if viper.GetBool("verbose") {
   563  	fmt.Println("verbose enabled")
   564  }
   565  ```
   566  ### Accessing nested keys
   567  
   568  The accessor methods also accept formatted paths to deeply nested keys. For
   569  example, if the following JSON file is loaded:
   570  
   571  ```json
   572  {
   573      "host": {
   574          "address": "localhost",
   575          "port": 5799
   576      },
   577      "datastore": {
   578          "metric": {
   579              "host": "127.0.0.1",
   580              "port": 3099
   581          },
   582          "warehouse": {
   583              "host": "198.0.0.1",
   584              "port": 2112
   585          }
   586      }
   587  }
   588  
   589  ```
   590  
   591  Viper can access a nested field by passing a `.` delimited path of keys:
   592  
   593  ```go
   594  GetString("datastore.metric.host") // (returns "127.0.0.1")
   595  ```
   596  
   597  This obeys the precedence rules established above; the search for the path
   598  will cascade through the remaining configuration registries until found.
   599  
   600  For example, given this configuration file, both `datastore.metric.host` and
   601  `datastore.metric.port` are already defined (and may be overridden). If in addition
   602  `datastore.metric.protocol` was defined in the defaults, Viper would also find it.
   603  
   604  However, if `datastore.metric` was overridden (by a flag, an environment variable,
   605  the `Set()` method, …) with an immediate value, then all sub-keys of
   606  `datastore.metric` become undefined, they are “shadowed” by the higher-priority
   607  configuration level.
   608  
   609  Viper can access array indices by using numbers in the path. For example:
   610  
   611  ```jsonc
   612  {
   613      "host": {
   614          "address": "localhost",
   615          "ports": [
   616              5799,
   617              6029
   618          ]
   619      },
   620      "datastore": {
   621          "metric": {
   622              "host": "127.0.0.1",
   623              "port": 3099
   624          },
   625          "warehouse": {
   626              "host": "198.0.0.1",
   627              "port": 2112
   628          }
   629      }
   630  }
   631  
   632  GetInt("host.ports.1") // returns 6029
   633  
   634  ```
   635  
   636  Lastly, if there exists a key that matches the delimited key path, its value
   637  will be returned instead. E.g.
   638  
   639  ```jsonc
   640  {
   641      "datastore.metric.host": "0.0.0.0",
   642      "host": {
   643          "address": "localhost",
   644          "port": 5799
   645      },
   646      "datastore": {
   647          "metric": {
   648              "host": "127.0.0.1",
   649              "port": 3099
   650          },
   651          "warehouse": {
   652              "host": "198.0.0.1",
   653              "port": 2112
   654          }
   655      }
   656  }
   657  
   658  GetString("datastore.metric.host") // returns "0.0.0.0"
   659  ```
   660  
   661  ### Extracting a sub-tree
   662  
   663  When developing reusable modules, it's often useful to extract a subset of the configuration
   664  and pass it to a module. This way the module can be instantiated more than once, with different configurations.
   665  
   666  For example, an application might use multiple different cache stores for different purposes:
   667  
   668  ```yaml
   669  cache:
   670    cache1:
   671      max-items: 100
   672      item-size: 64
   673    cache2:
   674      max-items: 200
   675      item-size: 80
   676  ```
   677  
   678  We could pass the cache name to a module (eg. `NewCache("cache1")`),
   679  but it would require weird concatenation for accessing config keys and would be less separated from the global config.
   680  
   681  So instead of doing that let's pass a Viper instance to the constructor that represents a subset of the configuration:
   682  
   683  ```go
   684  cache1Config := viper.Sub("cache.cache1")
   685  if cache1Config == nil { // Sub returns nil if the key cannot be found
   686  	panic("cache configuration not found")
   687  }
   688  
   689  cache1 := NewCache(cache1Config)
   690  ```
   691  
   692  **Note:** Always check the return value of `Sub`. It returns `nil` if a key cannot be found.
   693  
   694  Internally, the `NewCache` function can address `max-items` and `item-size` keys directly:
   695  
   696  ```go
   697  func NewCache(v *Viper) *Cache {
   698  	return &Cache{
   699  		MaxItems: v.GetInt("max-items"),
   700  		ItemSize: v.GetInt("item-size"),
   701  	}
   702  }
   703  ```
   704  
   705  The resulting code is easy to test, since it's decoupled from the main config structure,
   706  and easier to reuse (for the same reason).
   707  
   708  
   709  ### Unmarshaling
   710  
   711  You also have the option of Unmarshaling all or a specific value to a struct, map,
   712  etc.
   713  
   714  There are two methods to do this:
   715  
   716   * `Unmarshal(rawVal interface{}) : error`
   717   * `UnmarshalKey(key string, rawVal interface{}) : error`
   718  
   719  Example:
   720  
   721  ```go
   722  type config struct {
   723  	Port int
   724  	Name string
   725  	PathMap string `mapstructure:"path_map"`
   726  }
   727  
   728  var C config
   729  
   730  err := viper.Unmarshal(&C)
   731  if err != nil {
   732  	t.Fatalf("unable to decode into struct, %v", err)
   733  }
   734  ```
   735  
   736  If you want to unmarshal configuration where the keys themselves contain dot (the default key delimiter),
   737  you have to change the delimiter:
   738  
   739  ```go
   740  v := viper.NewWithOptions(viper.KeyDelimiter("::"))
   741  
   742  v.SetDefault("chart::values", map[string]interface{}{
   743  	"ingress": map[string]interface{}{
   744  		"annotations": map[string]interface{}{
   745  			"traefik.frontend.rule.type":                 "PathPrefix",
   746  			"traefik.ingress.kubernetes.io/ssl-redirect": "true",
   747  		},
   748  	},
   749  })
   750  
   751  type config struct {
   752  	Chart struct{
   753  		Values map[string]interface{}
   754  	}
   755  }
   756  
   757  var C config
   758  
   759  v.Unmarshal(&C)
   760  ```
   761  
   762  Viper also supports unmarshaling into embedded structs:
   763  
   764  ```go
   765  /*
   766  Example config:
   767  
   768  module:
   769      enabled: true
   770      token: 89h3f98hbwf987h3f98wenf89ehf
   771  */
   772  type config struct {
   773  	Module struct {
   774  		Enabled bool
   775  
   776  		moduleConfig `mapstructure:",squash"`
   777  	}
   778  }
   779  
   780  // moduleConfig could be in a module specific package
   781  type moduleConfig struct {
   782  	Token string
   783  }
   784  
   785  var C config
   786  
   787  err := viper.Unmarshal(&C)
   788  if err != nil {
   789  	t.Fatalf("unable to decode into struct, %v", err)
   790  }
   791  ```
   792  
   793  Viper uses [github.com/mitchellh/mapstructure](https://github.com/mitchellh/mapstructure) under the hood for unmarshaling values which uses `mapstructure` tags by default.
   794  
   795  ### Decoding custom formats
   796  
   797  A frequently requested feature for Viper is adding more value formats and decoders.
   798  For example, parsing character (dot, comma, semicolon, etc) separated strings into slices.
   799  
   800  This is already available in Viper using mapstructure decode hooks.
   801  
   802  Read more about the details in [this blog post](https://sagikazarmark.hu/blog/decoding-custom-formats-with-viper/).
   803  
   804  ### Marshalling to string
   805  
   806  You may need to marshal all the settings held in viper into a string rather than write them to a file.
   807  You can use your favorite format's marshaller with the config returned by `AllSettings()`.
   808  
   809  ```go
   810  import (
   811  	yaml "gopkg.in/yaml.v2"
   812  	// ...
   813  )
   814  
   815  func yamlStringSettings() string {
   816  	c := viper.AllSettings()
   817  	bs, err := yaml.Marshal(c)
   818  	if err != nil {
   819  		log.Fatalf("unable to marshal config to YAML: %v", err)
   820  	}
   821  	return string(bs)
   822  }
   823  ```
   824  
   825  ## Viper or Vipers?
   826  
   827  Viper comes ready to use out of the box. There is no configuration or
   828  initialization needed to begin using Viper. Since most applications will want
   829  to use a single central repository for their configuration, the viper package
   830  provides this. It is similar to a singleton.
   831  
   832  In all of the examples above, they demonstrate using viper in its singleton
   833  style approach.
   834  
   835  ### Working with multiple vipers
   836  
   837  You can also create many different vipers for use in your application. Each will
   838  have its own unique set of configurations and values. Each can read from a
   839  different config file, key value store, etc. All of the functions that viper
   840  package supports are mirrored as methods on a viper.
   841  
   842  Example:
   843  
   844  ```go
   845  x := viper.New()
   846  y := viper.New()
   847  
   848  x.SetDefault("ContentDir", "content")
   849  y.SetDefault("ContentDir", "foobar")
   850  
   851  //...
   852  ```
   853  
   854  When working with multiple vipers, it is up to the user to keep track of the
   855  different vipers.
   856  
   857  
   858  ## Q & A
   859  
   860  ### Why is it called “Viper”?
   861  
   862  A: Viper is designed to be a [companion](http://en.wikipedia.org/wiki/Viper_(G.I._Joe))
   863  to [Cobra](https://github.com/spf13/cobra). While both can operate completely
   864  independently, together they make a powerful pair to handle much of your
   865  application foundation needs.
   866  
   867  ### Why is it called “Cobra”?
   868  
   869  Is there a better name for a [commander](http://en.wikipedia.org/wiki/Cobra_Commander)?
   870  
   871  ### Does Viper support case sensitive keys?
   872  
   873  **tl;dr:** No.
   874  
   875  Viper merges configuration from various sources, many of which are either case insensitive or uses different casing than the rest of the sources (eg. env vars).
   876  In order to provide the best experience when using multiple sources, the decision has been made to make all keys case insensitive.
   877  
   878  There has been several attempts to implement case sensitivity, but unfortunately it's not that trivial. We might take a stab at implementing it in [Viper v2](https://github.com/spf13/viper/issues/772), but despite the initial noise, it does not seem to be requested that much.
   879  
   880  You can vote for case sensitivity by filling out this feedback form: https://forms.gle/R6faU74qPRPAzchZ9
   881  
   882  ### Is it safe to concurrently read and write to a viper?
   883  
   884  No, you will need to synchronize access to the viper yourself (for example by using the `sync` package). Concurrent reads and writes can cause a panic.
   885  
   886  ## Troubleshooting
   887  
   888  See [TROUBLESHOOTING.md](TROUBLESHOOTING.md).