github.com/jyny/viper@v1.4.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 ## Install 19 ```console 20 go get -u 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, HCL, envfile 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, HCL, envfile 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, HCL, envfile 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 You can handle the specific case where no config file is found like this: 111 112 ```go 113 if err := viper.ReadInConfig(); err != nil { 114 if _, ok := err.(viper.ConfigFileNotFoundError); ok { 115 // Config file not found; ignore error if desired 116 } else { 117 // Config file was found but another error was produced 118 } 119 } 120 121 // Config file found and successfully parsed 122 ``` 123 124 ### Writing Config Files 125 126 Reading from config files is useful, but at times you want to store all modifications made at run time. 127 For that, a bunch of commands are available, each with its own purpose: 128 129 * 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. 130 * 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. 131 * WriteConfigAs - writes the current viper configuration to the given filepath. Will overwrite the given file, if it exists. 132 * SafeWriteConfigAs - writes the current viper configuration to the given filepath. Will not overwrite the given file, if it exists. 133 134 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. 135 136 A small examples section: 137 138 ```go 139 viper.WriteConfig() // writes current config to predefined path set by 'viper.AddConfigPath()' and 'viper.SetConfigName' 140 viper.SafeWriteConfig() 141 viper.WriteConfigAs("/path/to/my/.config") 142 viper.SafeWriteConfigAs("/path/to/my/.config") // will error since it has already been written 143 viper.SafeWriteConfigAs("/path/to/my/.other_config") 144 ``` 145 146 ### Watching and re-reading config files 147 148 Viper supports the ability to have your application live read a config file while running. 149 150 Gone are the days of needing to restart a server to have a config take effect, 151 viper powered applications can read an update to a config file while running and 152 not miss a beat. 153 154 Simply tell the viper instance to watchConfig. 155 Optionally you can provide a function for Viper to run each time a change occurs. 156 157 **Make sure you add all of the configPaths prior to calling `WatchConfig()`** 158 159 ```go 160 viper.WatchConfig() 161 viper.OnConfigChange(func(e fsnotify.Event) { 162 fmt.Println("Config file changed:", e.Name) 163 }) 164 ``` 165 166 ### Reading Config from io.Reader 167 168 Viper predefines many configuration sources such as files, environment 169 variables, flags, and remote K/V store, but you are not bound to them. You can 170 also implement your own required configuration source and feed it to viper. 171 172 ```go 173 viper.SetConfigType("yaml") // or viper.SetConfigType("YAML") 174 175 // any approach to require this configuration into your program. 176 var yamlExample = []byte(` 177 Hacker: true 178 name: steve 179 hobbies: 180 - skateboarding 181 - snowboarding 182 - go 183 clothing: 184 jacket: leather 185 trousers: denim 186 age: 35 187 eyes : brown 188 beard: true 189 `) 190 191 viper.ReadConfig(bytes.NewBuffer(yamlExample)) 192 193 viper.Get("name") // this would be "steve" 194 ``` 195 196 ### Setting Overrides 197 198 These could be from a command line flag, or from your own application logic. 199 200 ```go 201 viper.Set("Verbose", true) 202 viper.Set("LogFile", LogFile) 203 ``` 204 205 ### Registering and Using Aliases 206 207 Aliases permit a single value to be referenced by multiple keys 208 209 ```go 210 viper.RegisterAlias("loud", "Verbose") 211 212 viper.Set("verbose", true) // same result as next line 213 viper.Set("loud", true) // same result as prior line 214 215 viper.GetBool("loud") // true 216 viper.GetBool("verbose") // true 217 ``` 218 219 ### Working with Environment Variables 220 221 Viper has full support for environment variables. This enables 12 factor 222 applications out of the box. There are five methods that exist to aid working 223 with ENV: 224 225 * `AutomaticEnv()` 226 * `BindEnv(string...) : error` 227 * `SetEnvPrefix(string)` 228 * `SetEnvKeyReplacer(string...) *strings.Replacer` 229 * `AllowEmptyEnv(bool)` 230 231 _When working with ENV variables, it’s important to recognize that Viper 232 treats ENV variables as case sensitive._ 233 234 Viper provides a mechanism to try to ensure that ENV variables are unique. By 235 using `SetEnvPrefix`, you can tell Viper to use a prefix while reading from 236 the environment variables. Both `BindEnv` and `AutomaticEnv` will use this 237 prefix. 238 239 `BindEnv` takes one or two parameters. The first parameter is the key name, the 240 second is the name of the environment variable. The name of the environment 241 variable is case sensitive. If the ENV variable name is not provided, then 242 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), 243 it **does not** automatically add the prefix. For example if the second parameter is "id", 244 Viper will look for the ENV variable "ID". 245 246 One important thing to recognize when working with ENV variables is that the 247 value will be read each time it is accessed. Viper does not fix the value when 248 the `BindEnv` is called. 249 250 `AutomaticEnv` is a powerful helper especially when combined with 251 `SetEnvPrefix`. When called, Viper will check for an environment variable any 252 time a `viper.Get` request is made. It will apply the following rules. It will 253 check for a environment variable with a name matching the key uppercased and 254 prefixed with the `EnvPrefix` if set. 255 256 `SetEnvKeyReplacer` allows you to use a `strings.Replacer` object to rewrite Env 257 keys to an extent. This is useful if you want to use `-` or something in your 258 `Get()` calls, but want your environmental variables to use `_` delimiters. An 259 example of using it can be found in `viper_test.go`. 260 261 By default empty environment variables are considered unset and will fall back to 262 the next configuration source. To treat empty environment variables as set, use 263 the `AllowEmptyEnv` method. 264 265 #### Env example 266 267 ```go 268 SetEnvPrefix("spf") // will be uppercased automatically 269 BindEnv("id") 270 271 os.Setenv("SPF_ID", "13") // typically done outside of the app 272 273 id := Get("id") // 13 274 ``` 275 276 ### Working with Flags 277 278 Viper has the ability to bind to flags. Specifically, Viper supports `Pflags` 279 as used in the [Cobra](https://github.com/spf13/cobra) library. 280 281 Like `BindEnv`, the value is not set when the binding method is called, but when 282 it is accessed. This means you can bind as early as you want, even in an 283 `init()` function. 284 285 For individual flags, the `BindPFlag()` method provides this functionality. 286 287 Example: 288 289 ```go 290 serverCmd.Flags().Int("port", 1138, "Port to run Application server on") 291 viper.BindPFlag("port", serverCmd.Flags().Lookup("port")) 292 ``` 293 294 You can also bind an existing set of pflags (pflag.FlagSet): 295 296 Example: 297 298 ```go 299 pflag.Int("flagname", 1234, "help message for flagname") 300 301 pflag.Parse() 302 viper.BindPFlags(pflag.CommandLine) 303 304 i := viper.GetInt("flagname") // retrieve values from viper instead of pflag 305 ``` 306 307 The use of [pflag](https://github.com/spf13/pflag/) in Viper does not preclude 308 the use of other packages that use the [flag](https://golang.org/pkg/flag/) 309 package from the standard library. The pflag package can handle the flags 310 defined for the flag package by importing these flags. This is accomplished 311 by a calling a convenience function provided by the pflag package called 312 AddGoFlagSet(). 313 314 Example: 315 316 ```go 317 package main 318 319 import ( 320 "flag" 321 "github.com/spf13/pflag" 322 ) 323 324 func main() { 325 326 // using standard library "flag" package 327 flag.Int("flagname", 1234, "help message for flagname") 328 329 pflag.CommandLine.AddGoFlagSet(flag.CommandLine) 330 pflag.Parse() 331 viper.BindPFlags(pflag.CommandLine) 332 333 i := viper.GetInt("flagname") // retrieve value from viper 334 335 ... 336 } 337 ``` 338 339 #### Flag interfaces 340 341 Viper provides two Go interfaces to bind other flag systems if you don’t use `Pflags`. 342 343 `FlagValue` represents a single flag. This is a very simple example on how to implement this interface: 344 345 ```go 346 type myFlag struct {} 347 func (f myFlag) HasChanged() bool { return false } 348 func (f myFlag) Name() string { return "my-flag-name" } 349 func (f myFlag) ValueString() string { return "my-flag-value" } 350 func (f myFlag) ValueType() string { return "string" } 351 ``` 352 353 Once your flag implements this interface, you can simply tell Viper to bind it: 354 355 ```go 356 viper.BindFlagValue("my-flag-name", myFlag{}) 357 ``` 358 359 `FlagValueSet` represents a group of flags. This is a very simple example on how to implement this interface: 360 361 ```go 362 type myFlagSet struct { 363 flags []myFlag 364 } 365 366 func (f myFlagSet) VisitAll(fn func(FlagValue)) { 367 for _, flag := range flags { 368 fn(flag) 369 } 370 } 371 ``` 372 373 Once your flag set implements this interface, you can simply tell Viper to bind it: 374 375 ```go 376 fSet := myFlagSet{ 377 flags: []myFlag{myFlag{}, myFlag{}}, 378 } 379 viper.BindFlagValues("my-flags", fSet) 380 ``` 381 382 ### Remote Key/Value Store Support 383 384 To enable remote support in Viper, do a blank import of the `viper/remote` 385 package: 386 387 `import _ "github.com/spf13/viper/remote"` 388 389 Viper will read a config string (as JSON, TOML, YAML, HCL or envfile) retrieved from a path 390 in a Key/Value store such as etcd or Consul. These values take precedence over 391 default values, but are overridden by configuration values retrieved from disk, 392 flags, or environment variables. 393 394 Viper uses [crypt](https://github.com/xordataexchange/crypt) to retrieve 395 configuration from the K/V store, which means that you can store your 396 configuration values encrypted and have them automatically decrypted if you have 397 the correct gpg keyring. Encryption is optional. 398 399 You can use remote configuration in conjunction with local configuration, or 400 independently of it. 401 402 `crypt` has a command-line helper that you can use to put configurations in your 403 K/V store. `crypt` defaults to etcd on http://127.0.0.1:4001. 404 405 ```bash 406 $ go get github.com/xordataexchange/crypt/bin/crypt 407 $ crypt set -plaintext /config/hugo.json /Users/hugo/settings/config.json 408 ``` 409 410 Confirm that your value was set: 411 412 ```bash 413 $ crypt get -plaintext /config/hugo.json 414 ``` 415 416 See the `crypt` documentation for examples of how to set encrypted values, or 417 how to use Consul. 418 419 ### Remote Key/Value Store Example - Unencrypted 420 421 #### etcd 422 ```go 423 viper.AddRemoteProvider("etcd", "http://127.0.0.1:4001","/config/hugo.json") 424 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" 425 err := viper.ReadRemoteConfig() 426 ``` 427 428 #### Consul 429 You need to set a key to Consul key/value storage with JSON value containing your desired config. 430 For example, create a Consul key/value store key `MY_CONSUL_KEY` with value: 431 432 ```json 433 { 434 "port": 8080, 435 "hostname": "myhostname.com" 436 } 437 ``` 438 439 ```go 440 viper.AddRemoteProvider("consul", "localhost:8500", "MY_CONSUL_KEY") 441 viper.SetConfigType("json") // Need to explicitly set this to json 442 err := viper.ReadRemoteConfig() 443 444 fmt.Println(viper.Get("port")) // 8080 445 fmt.Println(viper.Get("hostname")) // myhostname.com 446 ``` 447 448 ### Remote Key/Value Store Example - Encrypted 449 450 ```go 451 viper.AddSecureRemoteProvider("etcd","http://127.0.0.1:4001","/config/hugo.json","/etc/secrets/mykeyring.gpg") 452 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" 453 err := viper.ReadRemoteConfig() 454 ``` 455 456 ### Watching Changes in etcd - Unencrypted 457 458 ```go 459 // alternatively, you can create a new viper instance. 460 var runtime_viper = viper.New() 461 462 runtime_viper.AddRemoteProvider("etcd", "http://127.0.0.1:4001", "/config/hugo.yml") 463 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" 464 465 // read from remote config the first time. 466 err := runtime_viper.ReadRemoteConfig() 467 468 // unmarshal config 469 runtime_viper.Unmarshal(&runtime_conf) 470 471 // open a goroutine to watch remote changes forever 472 go func(){ 473 for { 474 time.Sleep(time.Second * 5) // delay after each request 475 476 // currently, only tested with etcd support 477 err := runtime_viper.WatchRemoteConfig() 478 if err != nil { 479 log.Errorf("unable to read remote config: %v", err) 480 continue 481 } 482 483 // unmarshal new config into our runtime config struct. you can also use channel 484 // to implement a signal to notify the system of the changes 485 runtime_viper.Unmarshal(&runtime_conf) 486 } 487 }() 488 ``` 489 490 ## Getting Values From Viper 491 492 In Viper, there are a few ways to get a value depending on the value’s type. 493 The following functions and methods exist: 494 495 * `Get(key string) : interface{}` 496 * `GetBool(key string) : bool` 497 * `GetFloat64(key string) : float64` 498 * `GetInt(key string) : int` 499 * `GetIntSlice(key string) : []int` 500 * `GetString(key string) : string` 501 * `GetStringMap(key string) : map[string]interface{}` 502 * `GetStringMapString(key string) : map[string]string` 503 * `GetStringSlice(key string) : []string` 504 * `GetTime(key string) : time.Time` 505 * `GetDuration(key string) : time.Duration` 506 * `IsSet(key string) : bool` 507 * `AllSettings() : map[string]interface{}` 508 509 One important thing to recognize is that each Get function will return a zero 510 value if it’s not found. To check if a given key exists, the `IsSet()` method 511 has been provided. 512 513 Example: 514 ```go 515 viper.GetString("logfile") // case-insensitive Setting & Getting 516 if viper.GetBool("verbose") { 517 fmt.Println("verbose enabled") 518 } 519 ``` 520 ### Accessing nested keys 521 522 The accessor methods also accept formatted paths to deeply nested keys. For 523 example, if the following JSON file is loaded: 524 525 ```json 526 { 527 "host": { 528 "address": "localhost", 529 "port": 5799 530 }, 531 "datastore": { 532 "metric": { 533 "host": "127.0.0.1", 534 "port": 3099 535 }, 536 "warehouse": { 537 "host": "198.0.0.1", 538 "port": 2112 539 } 540 } 541 } 542 543 ``` 544 545 Viper can access a nested field by passing a `.` delimited path of keys: 546 547 ```go 548 GetString("datastore.metric.host") // (returns "127.0.0.1") 549 ``` 550 551 This obeys the precedence rules established above; the search for the path 552 will cascade through the remaining configuration registries until found. 553 554 For example, given this configuration file, both `datastore.metric.host` and 555 `datastore.metric.port` are already defined (and may be overridden). If in addition 556 `datastore.metric.protocol` was defined in the defaults, Viper would also find it. 557 558 However, if `datastore.metric` was overridden (by a flag, an environment variable, 559 the `Set()` method, …) with an immediate value, then all sub-keys of 560 `datastore.metric` become undefined, they are “shadowed” by the higher-priority 561 configuration level. 562 563 Lastly, if there exists a key that matches the delimited key path, its value 564 will be returned instead. E.g. 565 566 ```json 567 { 568 "datastore.metric.host": "0.0.0.0", 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 GetString("datastore.metric.host") // returns "0.0.0.0" 586 ``` 587 588 ### Extract sub-tree 589 590 Extract sub-tree from Viper. 591 592 For example, `viper` represents: 593 594 ```json 595 app: 596 cache1: 597 max-items: 100 598 item-size: 64 599 cache2: 600 max-items: 200 601 item-size: 80 602 ``` 603 604 After executing: 605 606 ```go 607 subv := viper.Sub("app.cache1") 608 ``` 609 610 `subv` represents: 611 612 ```json 613 max-items: 100 614 item-size: 64 615 ``` 616 617 Suppose we have: 618 619 ```go 620 func NewCache(cfg *Viper) *Cache {...} 621 ``` 622 623 which creates a cache based on config information formatted as `subv`. 624 Now it’s easy to create these 2 caches separately as: 625 626 ```go 627 cfg1 := viper.Sub("app.cache1") 628 cache1 := NewCache(cfg1) 629 630 cfg2 := viper.Sub("app.cache2") 631 cache2 := NewCache(cfg2) 632 ``` 633 634 ### Unmarshaling 635 636 You also have the option of Unmarshaling all or a specific value to a struct, map, 637 etc. 638 639 There are two methods to do this: 640 641 * `Unmarshal(rawVal interface{}) : error` 642 * `UnmarshalKey(key string, rawVal interface{}) : error` 643 644 Example: 645 646 ```go 647 type config struct { 648 Port int 649 Name string 650 PathMap string `mapstructure:"path_map"` 651 } 652 653 var C config 654 655 err := viper.Unmarshal(&C) 656 if err != nil { 657 t.Fatalf("unable to decode into struct, %v", err) 658 } 659 ``` 660 661 Viper uses [github.com/mitchellh/mapstructure](https://github.com/mitchellh/mapstructure) under the hood for unmarshaling values which uses `mapstructure` tags by default. 662 663 ### Marshalling to string 664 665 You may need to marshal all the settings held in viper into a string rather than write them to a file. 666 You can use your favorite format's marshaller with the config returned by `AllSettings()`. 667 668 ```go 669 import ( 670 yaml "gopkg.in/yaml.v2" 671 // ... 672 ) 673 674 func yamlStringSettings() string { 675 c := viper.AllSettings() 676 bs, err := yaml.Marshal(c) 677 if err != nil { 678 log.Fatalf("unable to marshal config to YAML: %v", err) 679 } 680 return string(bs) 681 } 682 ``` 683 684 ## Viper or Vipers? 685 686 Viper comes ready to use out of the box. There is no configuration or 687 initialization needed to begin using Viper. Since most applications will want 688 to use a single central repository for their configuration, the viper package 689 provides this. It is similar to a singleton. 690 691 In all of the examples above, they demonstrate using viper in its singleton 692 style approach. 693 694 ### Working with multiple vipers 695 696 You can also create many different vipers for use in your application. Each will 697 have its own unique set of configurations and values. Each can read from a 698 different config file, key value store, etc. All of the functions that viper 699 package supports are mirrored as methods on a viper. 700 701 Example: 702 703 ```go 704 x := viper.New() 705 y := viper.New() 706 707 x.SetDefault("ContentDir", "content") 708 y.SetDefault("ContentDir", "foobar") 709 710 //... 711 ``` 712 713 When working with multiple vipers, it is up to the user to keep track of the 714 different vipers. 715 716 ## Q & A 717 718 Q: Why not INI files? 719 720 A: Ini files are pretty awful. There’s no standard format, and they are hard to 721 validate. Viper is designed to work with JSON, TOML or YAML files. If someone 722 really wants to add this feature, I’d be happy to merge it. It’s easy to specify 723 which formats your application will permit. 724 725 Q: Why is it called “Viper”? 726 727 A: Viper is designed to be a [companion](http://en.wikipedia.org/wiki/Viper_(G.I._Joe)) 728 to [Cobra](https://github.com/spf13/cobra). While both can operate completely 729 independently, together they make a powerful pair to handle much of your 730 application foundation needs. 731 732 Q: Why is it called “Cobra”? 733 734 A: Is there a better name for a [commander](http://en.wikipedia.org/wiki/Cobra_Commander)?