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