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