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