koanf

repository·master·Indexed 26 days ago

https://github.com/knadh/koanf

A lightweight, extensible configuration management library for Go. koanf allows developers to read configuration from various sources (including files, environment variables, S3, AWS Parameter Store, and AWS Secrets Manager) in multiple formats (such as JSON, YAML, TOML, and HCL) and merge them into a single unified configuration object. It features a modular system of Providers and Parsers, support for live reloading via Watch(), and the ability to unmarshal configuration into Go structs.

Tokens
17.8K
Snippets
34
Records
160
Agent score
84%

What's inside koanf

  1. Core Concepts of koanf

    master

    Understanding the two primary interfaces:

    • koanf.Provider: A generic interface that provides configuration. It can return raw bytes (which require a parser) or a nested map[string]any (which can be loaded directly).
    • koanf.Parser: A generic interface that takes raw bytes and returns a nested map[string]any (e.g., JSON or YAML parsers).
    • Key Paths: Once loaded, configuration values are accessed using a delimited key path syntax, such as app.server.port. The delimiter is configurable (e.g., ., /).
    • Merging: Multiple sources can be loaded into a single koanf instance. Successive Load() calls merge new configuration into the existing state.
  2. Watch files for changes

    master

    Certain providers (like file, appconfig, vault, and consul) implement a Watch() method. This allows you to trigger a callback when the configuration source changes, enabling live reloads.

    Warning: Watch() is not goroutine safe if concurrent Get() calls are happening on the koanf object during a Load(). Use mutex locking if necessary.

    To stop a watcher, call f.Unwatch().

    // ... imports
    
    f := file.Provider("mock/mock.json")
    if err := k.Load(f, json.Parser()); err != nil {
    	log.Fatalf("error loading config: %v", err)
    }
    
    // Watch the file and get a callback on change.
    f.Watch(func(event any, err error) {
    	if err != nil {
    		log.Printf("watch error: %v", err)
    		return
    	}
    
    	log.Println("config changed. Reloading ...")
    	k = koanf.New(".")
    	k.Load(f, json.Parser())
    	k.Print()
    })
    
    // To stop a file watcher, call:
    // f.Unwatch()
  3. Install koanf v2

    master

    To use koanf, you must install the core library and then separately install the specific Providers and Parsers you need. This keeps dependencies minimal.

    # Install the core.
    go get -u github.com/knadh/koanf/v2
    
    # Install a provider (e.g., file)
    go get -u github.com/knadh/koanf/providers/file
    
    # Install a parser (e.g., toml)
    go get -u github.com/knadh/koanf/parsers/toml
  4. Install Koanf Providers

    master

    Koanf uses a provider-based system to load configuration from various sources. Providers are not included in the core package to keep the footprint small. To use a specific provider, you must install it separately using go get.

    Example for S3: go get -u github.com/knadh/koanf/providers/s3

    Example for Consul v2: go get -u github.com/knadh/koanf/providers/consul/v2

  5. Unmarshal configuration into structs

    master

    You can unmarshal configuration values into Go structs using k.Unmarshal() or k.UnmarshalWithConf().

    • Use the koanf struct tag to map configuration keys to struct fields.
    • FlatPaths: If you need to unmarshal nested configuration keys into a flat struct, set FlatPaths: true in koanf.UnmarshalConf.
    type childStruct struct {
    	Name       string            `koanf:"name"`
    	Type       string            `koanf:"type"`
    	Empty      map[string]string `koanf:"empty"`
    	GrandChild struct {
    		Ids []int `koanf:"ids"`
    		On  bool  `koanf:"on"`
    	} `koanf:"grandchild1"`
    }
    
    var out childStruct
    // Quick unmarshal
    k.Unmarshal("parent1.child1", &out)
    
    // Unmarshal with advanced config (specifying the tag name)
    out = childStruct{}
    k.UnmarshalWithConf("parent1.child1", &out, koanf.UnmarshalConf{Tag: "koanf"})
  6. Install Koanf Parsers

    master

    Parsers are responsible for converting raw bytes from a provider into a nested map. Like providers, parsers must be installed individually.

    To install a parser, use the following command pattern: go get -u github.com/knadh/koanf/parsers/$parser

  7. Use the cliflagv3 provider for urfave/cli/v3 flags

    master
    The cliflagv3 package provides a koanf.Provider implementation that reads command-line parameters from an urfave/cli/v3 command structure. It converts flags into a nested map[string]any using a specified delimiter (e.g., . or _) to define the hierarchy of keys.
  8. Prevent default flags from overriding existing config

    master

    To ensure that command-line default values do not overwrite values already loaded from other providers (like a YAML file), pass your koanf instance to the provider using the Opt struct or the ko variadic argument.

    When an Opt is provided:

    1. The provider tracks which flags were explicitly set by the user via the command line.
    2. If a flag was not explicitly set, the provider checks p.opt.KeyMap.Exists(key).
    3. If the key already exists in koanf, the flag's default value is ignored.
  9. Use the cliflagv2 provider for urfave/cli/v2

    master

    The cliflagv2 provider allows koanf to read command-line parameters defined using the urfave/cli/v2 library. It converts command-line flags into a nested configuration map. The nesting hierarchy is determined by a delimiter (e.g., . or _).

    When using subcommands, the provider builds a path based on the command lineage. For example, if a flag foo is defined under a command bar, and the delimiter is ., the resulting key in koanf will be bar.foo.

  10. Use the posflag provider to read command-line flags

    master

    The posflag package implements a koanf.Provider that reads command-line parameters using spf13/pflag. It converts flags into a nested map based on a provided delimiter (e.g., ".").

    To prevent default flag values from overriding existing configuration (like from a file), you can pass a live koanf.Koanf instance to the provider. If a key already exists in koanf, the provider will only merge values that were explicitly set on the command line.

  11. Use the K8SMount provider for Kubernetes volume mounts

    master

    The k8smount package provides a koanf.Provider designed to load configuration from Kubernetes volume mounts, such as Secrets or ConfigMaps mounted into a Pod.

    This provider is best suited for key-value data. If your mounted files contain structured data like JSON or YAML, it is recommended to use the file.File provider with an appropriate parser instead.

    Key Features

    • Hierarchy Creation: Uses a delimiter to create nested configuration keys based on the file path or filename.
    • Transformation: Supports an optional TransformFunc to modify keys and values (e.g., converting DB_HOST to db.host).
    • Watching: Supports real-time updates via Watch when files in the mount point change.
  12. Read configuration from files

    master

    Use the file.Provider combined with a parser (like json.Parser() or yaml.Parser()) to load configuration from the local filesystem.

    package main
    
    import (
    	"fmt"
    	"log"
    
    	"github.com/knadh/koanf/v2"
    	"github.com/knadh/koanf/parsers/json"
    	"github.com/knadh/koanf/parsers/yaml"
    	"github.com/knadh/koanf/providers/file"
    )
    
    var k = koanf.New(".")
    
    func main() {
    	if err := k.Load(file.Provider("mock/mock.json"), json.Parser()); err != nil {
    		log.Fatalf("error loading config: %v", err)
    	}
    
    	k.Load(file.Provider("mock/mock.yml"), yaml.Parser())
    
    	fmt.Println("parent's name is = ", k.String("parent1.name"))
    	fmt.Println("parent's ID is = ", k.Int("parent1.id"))
    }