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