• Home
  • History
  • Annotate
Name Date Size #Lines LOC

..16-Apr-2020-

remote/H16-Apr-2020-10685

.gitignoreH A D16-Apr-2020266 2419

.travis.ymlH A D16-Apr-2020410 2922

LICENSEH A D16-Apr-20201.1 KiB2117

README.mdH A D16-Apr-202019 KiB644477

flags.goH A D16-Apr-20201.3 KiB5834

flags_test.goH A D16-Apr-20201.3 KiB6649

nohup.outH A D16-Apr-202044 21

overrides_test.goH A D16-Apr-20206.3 KiB174126

util.goH A D16-Apr-20205.2 KiB222161

util_test.goH A D16-Apr-20201.1 KiB5537

viper.goH A D16-Apr-202049.8 KiB1,7761,235

viper_test.goH A D16-Apr-202030.1 KiB1,4071,146

README.md

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