github.com/tickoalcantara12/micro/v3@v3.0.0-20221007104245-9d75b9bcbab9/docs/v2/library/go-config.md (about) 1 --- 2 title: Go Config 3 keywords: config 4 tags: [config] 5 sidebar: home_sidebar 6 permalink: /go-config 7 summary: Go Config is a pluggable dynamic config library 8 --- 9 10 # Overview 11 12 Most config in applications are statically configured or include complex logic to load from multiple sources. 13 Go-config makes this easy, pluggable and mergeable. You'll never have to deal with config in the same way again. 14 15 ## Features 16 17 - **Dynamic Loading** - Load configuration from multiple source as and when needed. Go Config manages watching config sources 18 in the background and automatically merges and updates an in memory view. 19 20 - **Pluggable Sources** - Choose from any number of sources to load and merge config. The backend source is abstracted away into 21 a standard format consumed internally and decoded via encoders. Sources can be env vars, flags, file, etcd, k8s configmap, etc. 22 23 - **Mergeable Config** - If you specify multiple sources of config, regardless of format, they will be merged and presented in 24 a single view. This massively simplifies priority order loading and changes based on environment. 25 26 - **Observe Changes** - Optionally watch the config for changes to specific values. Hot reload your app using Go Config's watcher. 27 You don't have to handle ad-hoc hup reloading or whatever else, just keep reading the config and watch for changes if you need 28 to be notified. 29 30 - **Safe Recovery** - In case config loads badly or is completely wiped away for some unknown reason, you can specify fallback 31 values when accessing any config values directly. This ensures you'll always be reading some sane default in the event of a problem. 32 33 ## Getting Started 34 35 - [Source](#source) - A backend from which config is loaded 36 - [Encoder](#encoder) - Handles encoding/decoding source config 37 - [Reader](#reader) - Merges multiple encoded sources as a single format 38 - [Config](#config) - Config manager which manages multiple sources 39 - [Usage](#usage) - Example usage of go-config 40 - [FAQ](#faq) - General questions and answers 41 - [TODO](#todo) - TODO tasks/features 42 43 ## Sources 44 45 A `Source` is a backend from which config is loaded. Multiple sources can be used at the same time. 46 47 The following sources are supported: 48 49 - [cli](https://github.com/micro/go-micro/tree/master/config/source/cli) - read from parsed CLI flags 50 - [consul](https://github.com/micro/go-micro/tree/master/config/source/consul) - read from consul 51 - [env](https://github.com/micro/go-micro/tree/master/config/source/env) - read from environment variables 52 - [etcd](https://github.com/micro/go-micro/tree/master/config/source/etcd) - read from etcd v3 53 - [file](https://github.com/micro/go-micro/tree/master/config/source/file) - read from file 54 - [flag](https://github.com/micro/go-micro/tree/master/config/source/flag) - read from flags 55 - [memory](https://github.com/micro/go-micro/tree/master/config/source/memory) - read from memory 56 57 There are also community-supported plugins, which support the following sources: 58 59 - [configmap](https://github.com/micro/go-plugins/tree/master/config/source/configmap) - read from k8s configmap 60 - [grpc](https://github.com/micro/go-plugins/tree/master/config/source/grpc) - read from grpc server 61 - [runtimevar](https://github.com/micro/go-plugins/tree/master/config/source/runtimevar) - read from Go Cloud Development Kit runtime variable 62 - [url](https://github.com/micro/go-plugins/tree/master/config/source/url) - read from URL 63 - [vault](https://github.com/micro/go-plugins/tree/master/config/source/vault) - read from Vault server 64 65 TODO: 66 67 - git url 68 69 ### ChangeSet 70 71 Sources return config as a ChangeSet. This is a single internal abstraction for multiple backends. 72 73 ```go 74 type ChangeSet struct { 75 // Raw encoded config data 76 Data []byte 77 // MD5 checksum of the data 78 Checksum string 79 // Encoding format e.g json, yaml, toml, xml 80 Format string 81 // Source of the config e.g file, consul, etcd 82 Source string 83 // Time of loading or update 84 Timestamp time.Time 85 } 86 ``` 87 88 ## Encoder 89 90 An `Encoder` handles source config encoding/decoding. Backend sources may store config in many different 91 formats. Encoders give us the ability to handle any format. If an Encoder is not specified it defaults to json. 92 93 The following encoding formats are supported: 94 95 - json 96 - yaml 97 - toml 98 - xml 99 - hcl 100 101 ## Reader 102 103 A `Reader` represents multiple changesets as a single merged and queryable set of values. 104 105 ```go 106 type Reader interface { 107 // Merge multiple changeset into a single format 108 Merge(...*source.ChangeSet) (*source.ChangeSet, error) 109 // Return return Go assertable values 110 Values(*source.ChangeSet) (Values, error) 111 // Name of the reader e.g a json reader 112 String() string 113 } 114 ``` 115 116 The reader makes use of Encoders to decode changesets into `map[string]interface{}` then merge them into 117 a single changeset. It looks at the Format field to determine the Encoder. The changeset is then represented 118 as a set of `Values` with the ability to retrive Go types and fallback where values cannot be loaded. 119 120 ```go 121 122 // Values is returned by the reader 123 type Values interface { 124 // Return raw data 125 Bytes() []byte 126 // Retrieve a value 127 Get(path ...string) Value 128 // Return values as a map 129 Map() map[string]interface{} 130 // Scan config into a Go type 131 Scan(v interface{}) error 132 } 133 ``` 134 135 The `Value` interface allows casting/type asserting to go types with fallback defaults. 136 137 ```go 138 type Value interface { 139 Bool(def bool) bool 140 Int(def int) int 141 String(def string) string 142 Float64(def float64) float64 143 Duration(def time.Duration) time.Duration 144 StringSlice(def []string) []string 145 StringMap(def map[string]string) map[string]string 146 Scan(val interface{}) error 147 Bytes() []byte 148 } 149 ``` 150 151 ## Config 152 153 `Config` manages all config, abstracting away sources, encoders and the reader. 154 155 It manages reading, syncing, watching from multiple backend sources and represents them as a single merged and queryable source. 156 157 ```go 158 159 // Config is an interface abstraction for dynamic configuration 160 type Config interface { 161 // provide the reader.Values interface 162 reader.Values 163 // Stop the config loader/watcher 164 Close() error 165 // Load config sources 166 Load(source ...source.Source) error 167 // Force a source changeset sync 168 Sync() error 169 // Watch a value for changes 170 Watch(path ...string) (Watcher, error) 171 } 172 ``` 173 174 ## Usage 175 176 - [Sample Config](#sample-config) 177 - [New Config](#new-config) 178 - [Load File](#load-file) 179 - [Read Config](#read-config) 180 - [Read Values](#read-values) 181 - [Watch Path](#watch-path) 182 - [Multiple Sources](#merge-sources) 183 - [Set Source Encoder](#set-source-encoder) 184 - [Add Reader Encoder](#add-reader-encoder) 185 186 187 188 ### Sample Config 189 190 A config file can be of any format as long as we have an Encoder to support it. 191 192 Example json config: 193 194 ```json 195 { 196 "hosts": { 197 "database": { 198 "address": "10.0.0.1", 199 "port": 3306 200 }, 201 "cache": { 202 "address": "10.0.0.2", 203 "port": 6379 204 } 205 } 206 } 207 ``` 208 209 ### New Config 210 211 Create a new config (or just make use of the default instance) 212 213 ```go 214 import "github.com/micro/go-micro/v2/config" 215 216 conf := config.NewConfig() 217 ``` 218 219 ### Load File 220 221 Load config from a file source. It uses the file extension to determine config format. 222 223 ```go 224 import ( 225 "github.com/micro/go-micro/v2/config" 226 ) 227 228 // Load json config file 229 config.LoadFile("/tmp/config.json") 230 ``` 231 232 Load a yaml, toml or xml file by specifying a file with the appropriate file extension 233 234 ```go 235 // Load yaml config file 236 config.LoadFile("/tmp/config.yaml") 237 ``` 238 239 If an extension does not exist, specify the encoder 240 241 ```go 242 import ( 243 "github.com/micro/go-micro/v2/config" 244 "github.com/micro/go-micro/v2/config/source/file" 245 ) 246 247 enc := toml.NewEncoder() 248 249 // Load toml file with encoder 250 config.Load(file.NewSource( 251 file.WithPath("/tmp/config"), 252 source.WithEncoder(enc), 253 )) 254 ``` 255 256 ### Read Config 257 258 Read the entire config as a map 259 260 ```go 261 // retrieve map[string]interface{} 262 conf := config.Map() 263 264 // map[cache:map[address:10.0.0.2 port:6379] database:map[address:10.0.0.1 port:3306]] 265 fmt.Println(conf["hosts"]) 266 ``` 267 268 Scan the config into a struct 269 270 ```go 271 type Host struct { 272 Address string `json:"address"` 273 Port int `json:"port"` 274 } 275 276 type Config struct{ 277 Hosts map[string]Host `json:"hosts"` 278 } 279 280 var conf Config 281 282 config.Scan(&conf) 283 284 // 10.0.0.1 3306 285 fmt.Println(conf.Hosts["database"].Address, conf.Hosts["database"].Port) 286 ``` 287 288 ### Read Values 289 290 Scan a value from the config into a struct 291 292 ```go 293 type Host struct { 294 Address string `json:"address"` 295 Port int `json:"port"` 296 } 297 298 var host Host 299 300 config.Get("hosts", "database").Scan(&host) 301 302 // 10.0.0.1 3306 303 fmt.Println(host.Address, host.Port) 304 ``` 305 306 Read individual values as Go types 307 308 ```go 309 // Get address. Set default to localhost as fallback 310 address := config.Get("hosts", "database", "address").String("localhost") 311 312 // Get port. Set default to 3000 as fallback 313 port := config.Get("hosts", "database", "port").Int(3000) 314 ``` 315 316 ### Watch Path 317 318 Watch a path for changes. When the file changes the new value will be made available. 319 320 ```go 321 w, err := config.Watch("hosts", "database") 322 if err != nil { 323 // do something 324 } 325 326 // wait for next value 327 v, err := w.Next() 328 if err != nil { 329 // do something 330 } 331 332 var host Host 333 334 v.Scan(&host) 335 ``` 336 337 ### Multiple Sources 338 339 Multiple sources can be loaded and merged. Merging priority is in reverse order. 340 341 ```go 342 config.Load( 343 // base config from env 344 env.NewSource(), 345 // override env with flags 346 flag.NewSource(), 347 // override flags with file 348 file.NewSource( 349 file.WithPath("/tmp/config.json"), 350 ), 351 ) 352 ``` 353 354 ### Set Source Encoder 355 356 A source requires an encoder to encode/decode data and specify the changeset format. 357 358 The default encoder is json. To change the encoder to yaml, xml, toml specify as an option. 359 360 ```go 361 e := yaml.NewEncoder() 362 363 s := consul.NewSource( 364 source.WithEncoder(e), 365 ) 366 ``` 367 368 ### Add Reader Encoder 369 370 The reader uses encoders to decode data from sources with different formats. 371 372 The default reader supports json, yaml, xml, toml and hcl. It represents the merged config as json. 373 374 Add a new encoder by specifying it as an option. 375 376 ```go 377 e := yaml.NewEncoder() 378 379 r := json.NewReader( 380 reader.WithEncoder(e), 381 ) 382 ``` 383 384 ## FAQ 385 386 ### How is this different from Viper? 387 388 [Viper](https://github.com/spf13/viper) and go-config are solving the same problem. Go-config provides a different interface 389 and is part of the larger micro ecosystem of tooling. 390 391 ### What's the difference between Encoder and Reader? 392 393 The encoder is used by a backend source to encode/decode it's data. The reader uses encoders to decode data from multiple 394 sources with different formats, it then merges them into a single encoding format. 395 396 In the case of a file source , we use the file extension to determine the config format so the encoder is not used. 397 398 In the case of consul, etcd or similar key-value source we may load from a prefix containing multiple keys which means 399 the source needs to understand the encoding so it can return a single changeset. 400 401 In the case of environment variables and flags we also need a way to encode the values as bytes and specify the format so 402 it can later be merged by the reader. 403 404 ### Why is changeset data not represented as map[string]interface{}? 405 406 In some cases source data may not actually be key-value so it's easier to represent it as bytes and defer decoding to 407 the reader. 408