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