config

package
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 25, 2023 License: ISC Imports: 15 Imported by: 0

README

Go Doc

Config

config is a minimal and unopinionated utility for reading configuration values based on The 12-Factor App.

The idea is that you just define a struct with fields, types, and defaults, then you just use this library to read and populate the values for fields of your struct from either command-line flags, environment variables, or configuration files. It can also watch for new values read from configuration files and notify subscribers.

This library does not use flag package for parsing flags, so you can still parse your flags separately.

Quick Start

You can find examples here.

Example Description asciinema
Basic Using Pick method Watch
Watch Watching for new configurations
Kubernetes Changing the log level without restarting the pods Watch
Telepresence Running an application in a Telepresence session Watch
Supported Types
  • string, *string, []string
  • bool, *bool, []bool
  • float32, float64
  • *float32, *float64
  • []float32, []float64
  • int, int8, int16, int32, int64
  • *int, *int8, *int16, *int32, *int64
  • []int, []int8, []int16, []int32, []int64
  • uint, uint8, uint16, uint32, uint64
  • *uint, *uint8, *uint16, *uint32, *uint64
  • []uint, []uint8, []uint16, []uint32, []uint64
  • url.URL, *url.URL, []url.URL
  • regexp.Regexp, *regexp.Regexp, []regexp.Regexp
  • time.Duration, *time.Duration, []time.Duration
Behaviour

The precedence of sources for reading values is as follows:

  1. command-line flags
  2. environment variables
  3. configuration files
  4. default values (set when creating the instance)

You can pass the configuration values with flags using any of the syntaxes below:

main  -enabled  -log.level info  -timeout 30s  -address http://localhost:8080  -endpoints url1,url2,url3
main  -enabled  -log.level=info  -timeout=30s  -address=http://localhost:8080  -endpoints=url1,url2,url3
main --enabled --log.level info --timeout 30s --address http://localhost:8080 --endpoints url1,url2,url3
main --enabled --log.level=info --timeout=30s --address=http://localhost:8080 --endpoints=url1,url2,url3

You can pass the configuration values using environment variables as follows:

export ENABLED=true
export LOG_LEVEL=info
export TIMEOUT=30s
export ADDRESS=http://localhost:8080
export ENDPOINTS=url1,url2,url3

You can also write the configuration values in files (or mount your configuration values and secrets as files) and pass the paths to the files using environment variables:

export ENABLED_FILE=...
export LOG_LEVEL_FILE=...
export TIMEOUT_FILE=...
export ADDRESS_FILE=...
export ENDPOINTS_FILE=...

The supported syntax for Regexp is POSIX Regular Expressions.

Skipping

If you want to skip a source for reading values, use - as follows:

type Config struct {
  GithubToken string `env:"-" fileenv:"-"`
}

In the example above, GithubToken can only be set using github.token command-line flag.

Customization

You can use Go struct tags to customize the name of expected command-line flags or environment variables.

type Config struct {
  Database string `flag:"config.database" env:"CONFIG_DATABASE" fileenv:"CONFIG_DATABASE_FILE_PATH"`
}

In the example above, Database will be read from either:

  1. The command-line flag config.databas
  2. The environment variable CONFIG_DATABASE
  3. The file specified by environment variable CONFIG_DATABASE_FILE_PATH
  4. The default value set on struct instance
Using flag Package

config plays nice with flag package since it does NOT use flag package for parsing command-line flags. That means you can define, parse, and use your own flags using built-in flag package.

If you use flag package, config will also add the command-line flags it is expecting. Here is an example:

package main

import (
  "flag"
  "time"

  "github.com/gardenbed/basil/config"
)

var config = struct {
  Enabled   bool
  LogLevel  string
} {
  Enabled:  true,   // default
  LogLevel: "info", // default
}

func main() {
  config.Pick(&config)
  flag.Parse()
}

If you run this example with -help or --help flag, you will see -enabled and -log.level flags are also added with descriptions!

Options

Options are helpers for specific situations and setups. You can pass a list of options to Pick and Watch methods. If you want to test or debug something and you don't want to make code changes, you can set options through environment variables as well.

Option Environment Variable Description
config.Debug() CONFIG_DEBUG Printing debugging information.
config.ListSep() CONFIG_LIST_SEP Specifying list separator for all fields with slice type.
config.SkipFlag() CONFIG_SKIP_FLAG Skipping command-line flags as a source for all fields.
config.SkipEnv() CONFIG_SKIP_ENV Skipping environment variables as a source for all fields .
config.SkipFileEnv() CONFIG_SKIP_FILE_ENV Skipping file environment variables (and configuration files) as a source for all fields.
config.PrefixFlag() CONFIG_PREFIX_FLAG Prefixing all flag names with a string.
config.PrefixEnv() CONFIG_PREFIX_ENV Prefixing all environment variable names with a string.
config.PrefixFileEnv() CONFIG_PREFIX_FILE_ENV Prefixing all file environment variable names with a string.
config.Telepresence() CONFIG_TELEPRESENCE Reading configuration files in a Telepresence environment.
Debugging

If for any reason the configuration values are not read as you expected, you can view the debugging logs. You can enable debugging logs either by using Debug option or by setting CONFIG_DEBUG environment variable. In both cases you need to specify a verbosity level for logs.

Level Descriptions
0 No logging (default).
1 Logging all errors.
2 Logging initialization information.
3 Logging information related to new values read from files.
4 Logging information related to notifying subscribers.
5 Logging information related to setting values of fields.
6 Logging miscellaneous information.
Watching

config allows you to watch configuration files and dynamically update your configurations as your application is running.

When using Watch() method, your struct should have a sync.Mutex field on it for synchronization and preventing data races. You can find an example of using Watch() method here.

Here you will find a real-world example of using config.Watch() for dynamic configuration management and secret injection for Go applications running in Kubernetes.

Documentation

Overview

package config is a minimal and unopinionated library for reading configuration values in Go applications based on The 12-Factor App (https://12factor.net/config).

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Pick

func Pick(config interface{}, opts ...Option) error

Pick reads values for exported fields of a struct from either command-line flags, environment variables, or configuration files. Default values can also be specified. You should pass the pointer to a struct for config; otherwise you will get an error.

Example
package main

import (
	"fmt"
	"net/url"
	"time"

	"github.com/gardenbed/basil/config"
)

func main() {
	// First, you need to define a struct.
	// Each field of the struct represents a configuration value.
	// Create an object from the struct with default values for its fields.
	var params = struct {
		LogLevel    string
		Environment string
		Region      string
		Timeout     time.Duration
		Replicas    []url.URL
	}{
		LogLevel:    "info",           // default
		Environment: "dev",            // default
		Region:      "local",          // default
		Timeout:     10 * time.Second, // default
	}

	// Second, pass the pointer to the struct object to the Pick method.
	// For each field, a value will be read either from flags, environment variables, or files.
	_ = config.Pick(&params)

	// Now, you can access the configuration values on the struct object.
	fmt.Printf("%+v\n", params)
}
Output:

func Watch

func Watch(config sync.Locker, subscribers []chan Update, opts ...Option) (func(), error)

Watch first reads values for exported fields of a struct from either command-line flags, environment variables, or configuration files. It then watches any change to those fields that their values are read from configuration files and notifies subscribers on a channel.

Example
package main

import (
	"fmt"
	"sync"

	"github.com/gardenbed/basil/config"
)

func main() {
	// When using the Watch method, your struct needs to implement the sync.Locker interface.
	// You can simply achieve that by embedding the sync.Mutex type in your struct.
	var params = struct {
		sync.Mutex
		LogLevel string
	}{
		LogLevel: "info", // default
	}

	// For using the Watch method, you need to define a channel for receiving updates.
	// If a configuration value gets a new value (through files), you will get notified on this channel.
	ch := make(chan config.Update, 1)

	// In a separate goroutine, you can receive the new configuration values and re-configure your application accordingly.
	go func() {
		for update := range ch {
			if update.Name == "LogLevel" {
				params.Lock()
				fmt.Printf("Log level is updated to %s", params.LogLevel)
				params.Unlock()
			}
		}
	}()

	// You can now watch for configuration values.
	close, _ := config.Watch(&params, []chan config.Update{ch})
	defer close()
}
Output:

Types

type Option

type Option func(*reader)

Option sets optional parameters for reader.

func Debug

func Debug(verbosity uint) Option

Debug is the option for enabling logs for debugging purposes. verbosity is the verbosity level of logs. You can also enable this option by setting CONFIG_DEBUG environment variable to a verbosity level. You should not use this option in production.

func ListSep

func ListSep(sep string) Option

ListSep is the option for specifying list separator for all fields with slice type. You can specify a list separator for each field using `sep` struct tag. Using `tag` struct tag for a field will override this option for that field.

func PrefixEnv

func PrefixEnv(prefix string) Option

PrefixEnv is the option for prefixing all environment variable names with a given string. You can specify a custom name for environment variable for each field using `env` struct tag. Using `env` struct tag for a field will override this option for that field.

func PrefixFileEnv

func PrefixFileEnv(prefix string) Option

PrefixFileEnv is the option for prefixing all file environment variable names with a given string. You can specify a custom name for file environment variable for each field using `fileenv` struct tag. Using `fileenv` struct tag for a field will override this option for that field.

func PrefixFlag

func PrefixFlag(prefix string) Option

PrefixFlag is the option for prefixing all flag names with a given string. You can specify a custom name for command-line flag for each field using `flag` struct tag. Using `flag` struct tag for a field will override this option for that field.

func SkipEnv

func SkipEnv() Option

SkipEnv is the option for skipping environment variables as a source for all fields. You can skip environment variables as a source for each field by setting `env` struct tag to `-`.

func SkipFileEnv

func SkipFileEnv() Option

SkipFileEnv is the option for skipping file environment variables as a source for all fields. You can skip file environment variable as a source for each field by setting `fileenv` struct tag to `-`.

func SkipFlag

func SkipFlag() Option

SkipFlag is the option for skipping command-line flags as a source for all fields. You can skip command-line flag as a source for each field by setting `flag` struct tag to `-`.

func Telepresence

func Telepresence() Option

Telepresence is the option for reading files when running in a Telepresence shell. If the TELEPRESENCE_ROOT environment variable exist, files will be read from mounted volume. See https://telepresence.io/howto/volumes.html for details.

type Update

type Update struct {
	Name  string
	Value interface{}
}

Update represents a configuration field that received a new value.

Directories

Path Synopsis
example

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL