gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

README.md (28529B)


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