venom

package module
v0.5.0 Latest Latest
Warning

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

Go to latest
Published: Nov 25, 2020 License: MIT Imports: 14 Imported by: 2

README

venom

A pluggable hierarchical configuration management library with zero dependencies, for golang.

Build Status Go Report Card GoDoc

Install

With dep:

dep ensure -add github.com/moogar0880/venom

Or with go get:

go get github.com/moogar0880/venom

Why Venom?

This library aims to provide the basic building blocks of a configuration management library. It exposes as many aspects as the standard lib will reasonably support, such as:

  1. Explicitly set defaults or overrides.
  2. Find and load JSON config files.
  3. Load configuration files from a directory, with the option to recursively load configs from sub-directories.
  4. Load configs from environment variables.
  5. Load command line arguments using the flags library.

These mechanisms are exposed in a completely extendible way which will allow you to easily perform the following actions:

  1. Specify your own config level precedence (eg, environment variables can be made to override command line arguments).
  2. Default behavior can be replaced with custom behavior by writing a custom Resolver.
  3. Custom config levels can be easily implemented by writing a custom Resolver.

Loading Configs

Setting Defaults

You can easily set default values for configuration options that are not required to be specified by config levels with a higher precedence.

// simple values can easily be set as defaults
venom.SetDefault("verbose", false)
venom.SetDefault("hostname", "localhost")

// more complex objects can also be set
venom.SetDefault("log", map[string]interface{
    "level": "INFO",
    "fields": map[string]interface{
        "origin": "my_awesome_app", 
        "category": "categories",
    },
})
Loading Configs From Files

Venom allows you to specify custom file loaders for specific file types. By default the only implementation is the JSONLoader which loads any file with an extension of .json using json.Unmarshal.

If you wish to implement your own type of config file reader you need only to implement the IOFileLoader interface:

type IOFileLoader func(io.Reader) (map[string]interface{}, error)

Once you have any custom IOFileLoaders registered via RegisterExtension, you can easily load a single file or all files in a directory.

// load a single file
venom.LoadFile("config.json")

// load all files within a directory
venom.LoadDirectory("/etc/conf.d", false)

// recursively load all files within a directory or it's sub-directories
venom.LoadDirectory("/etc/conf.d", true)
Setting Overrides

You can easily set values which overrides all other values for a single configuration.

venom.SetOverride("verbose", true)
Environment Variables

Configuration values may be loaded from any set environment variables, which is enabled by default in the global venom instance and when creating a custom venom instance via venom.Default().

Note: Environment variables are case sensitive and should be set as uppercase strings with words that are separated by an underscore ("_") character.

package main

import (
    "fmt"
    "os"

    "github.com/moogar0880/venom"
)

func main() {
    os.Setenv("LOG_LEVEL", "INFO")

    fmt.Println(venom.Get("log.level"))  // Output: "INFO"
}

To specify a custom environment variable prefix, you can simply create and register a new EnvironmentVariableResolver.

package main

import (
    "fmt"
    "os"

    "github.com/moogar0880/venom"
)

func main() {
    envVarResolver := &venom.EnvironmentVariableResolver{
        Prefix: "MYSERVICE",
    }

    venom.RegisterResolver(venom.EnvironmentLevel, envVarResolver)

    os.Setenv("LOG_LEVEL", "IGNORED")
    os.Setenv("MYSERVICE_LOG_LEVEL", "INFO")

    fmt.Println(venom.Get("log.level"))  // Output: "INFO"
}

To perform specific character mapping translations for environment variables you can provide a custom KeyTranslator to an EnvironmentVariableResolver.

package main

import (
    "fmt"
    "os"
    "unicode"

    "github.com/moogar0880/venom"
)

func main() {
    envVarResolver := &venom.EnvironmentVariableResolver{
        // Provide a custom KeyTranslator to an EnvironmentVariableResolver
        Translator: func(b byte) byte {
            switch b {
            case '-':
                // Convert all hypens to underscores.
                return '_'
            default:
                // And otherwise translate all other characters to their
                // uppercase equivalents.
                return byte(unicode.ToUpper(rune(b)))
            }
        },
    }

    venom.RegisterResolver(venom.EnvironmentLevel, envVarResolver)

    os.Setenv("LOG_LEVEL", "IGNORED")
    os.Setenv("MYSERVICE_LOG_LEVEL", "INFO")

    fmt.Println(venom.Get("log.level"))  // Output: "INFO"
}
Flags

By default commandline flags can be parsed using the standard lib flag library. There are two different ways that you can approach loading command line configs, and they both involve creating and registering a new FlagsetResolver instance with Venom.

Note: Venom will parse flags if they have not already been parsed, but Venom will not attempt to re-parse an already parsed FlagSet.

Straight From os.Args

If you configure your commandline options to be loaded from the global flags FlagSet, you can pass a zero-value FlagsetResolver when registering the resolver with Venom.

fs.String("log-level", "WARNING", "set log level")

flagResolver := &venom.FlagsetResolver{}

venom.RegisterResolver(venom.FlagLevel, flagResolver)
Default and Custom Logging

You can initialize Venom to log to stdout (default) on reads and writes or provide a logging interface of your choice.

venDef := venom.NewLoggable()
venDef.SetDefault("baz", "bee")
venDef.Get("baz")
// 2019-04-21T10:01:39.529Z[venom]: writing level=0 key=baz val=bee
// 2019-04-21T10:01:39.529Z[venom]: reading key=baz val=bee exist=true

There is a tiny bit of overhead to use a custom logger but is straight forward to do. For example, using sirupsen/logrus:

// create a wrapping struct to hold the logging mechanism
type LogrusLogger struct {
    log *logrus.Entry
}

// create read and write methods which have these signatures
// and configure the log line as you choose
func (l *LogrusLogger) LogWrite(level venom.ConfigLevel, key string, val interface{}) {
    l.log.WithFields(logrus.Fields{"level": level,"key": key,"val": val}).Info("writing config value")
}

func (l *LogrusLogger) LogRead(key string, val interface{}, bl bool) {
    l.log.WithFields(logrus.Fields{"key": key,"val": val,"exist": bl}).Info("read config value")
}

lgr := logrus.New()
l := logrus.NewEntry(lgr)
ven := venom.NewLoggableWith(&LogrusLogger{log: l})

ven.SetDefault("foo", "bar")
ven.Get("foo")
// INFO[0000] writing config value               fields.level=0 key=foo val=bar
// INFO[0000] read config value                  exist=true key=foo val=bar
Provide a Custom flag.FlagSet

You also have the option to provide a custom flag.FlagSet instance via a FlagsetResolver.

Note: When providing a FlagSet, you may also provide the arguments to be parsed if the FlagSet has not already been parsed. The arguments will default to os.Args[1:] if none are specified.

fs := flag.NewFlagSet("example", flag.ContinueOnError)
fs.String("log-level", "WARNING", "set log level")

flagResolver := &venom.FlagsetResolver{
    Flags: fs,
}
venom.RegisterResolver(venom.FlagLevel, flagResolver)
Custom ConfigLevels

Consuming applications are able to define their own ConfigLevels in order to define configuration values with higher or lower precedence. For example, to set configs at levels above Override (not recommended), you could do something similar to the following:

const MySuperImportantLevel venom.ConfigLevel = venom.OverrideLevel + 1

venom.SetLevel(MySuperImportantLevel, "verbose", true)

Reading Config Values

There are several ways to access config values from Venom:

  • Get(key string) interface{}
  • Find(key string) (interface{}, bool)

If you're unsure whether or not a config value has been set, Find will return an optional boolean value indicating whether or not the value has been specified. Otherwise, Get will return nil in the event that a config has not been specified.

Key Management

Venom automatically nests config values that are specified as separated by the value of Delim, which defaults to ".". This means that you can express more complex config structures when setting and reading variables.

venom.SetDefault("log.level", "INFO")
fmt.Printf("%v", venom.Get("log"))  // Output: map[string]interface{"level": "INFO"}
fmt.Printf("%v", venom.Get("log.level"))  // Output: "INFO"

Aliasing Keys

Venom exposes the ability to alias one key to another. This allows applications to more easily modify their configuration without breaking backwards compatibility when doing so.

venom.SetDefault("log.enabled", true)
venom.Alias("verbose", "log.enabled")
fmt.Println(venom.Get("verbose"))  // Output: true

Unmarshal Configs

Venom supports the ability to unmarshal configuration data into struct values and also introduces the new venom struct field tag, which allows callers to specify different configuration fields to set to fields. Nested structs

Note: that errors are returned if the stored type and the type of the struct field do not match.

Note: Nested structs are supported and will carry the context of the name of the parent config. See the following example for more on this

type LoggingConfig struct {
    // this field will be loaded from log.level if Unmarshalled via the 
    // following Config struct
    Level string `venom:"level"`
}

type Config struct {
    Log LoggingConfig `venom:"log"` 
}

var c Config
err := venom.Unmarshal(nil, &c)

Safety

As of 0.2.0, venom now exposes optional functions for defining Venom instances that are safe for concurrent goroutine access.

Two functions are exposed to provide new goroutine safe Venom instances, the behavior of which mimics the functions unsafe counterparts:

// generate a new, empty, venom instance that is safe for concurrent access 
ven := venom.NewSafe()

// or generate a new venom instance with some default levels applied to it
ven = venom.DefaultSafe()

Custom Venom Behavior

The above examples show how to use the global venom instance for the sake of brevity, but you can create your own venom instances to use directly.

ven := venom.New()

ven.SetDefault("verbose", false)

Additionally, as of 0.2.0, you can define your own ConfigStore to control how venom manages it's underlying configuration storage. This can be achieved by creating a new Venom instance with a predefined ConfigStore via the NewWithStore function.

ven := venom.NewWithStore(venom.NewSafeConfigStore())

ven.SetDefault("verbose", false)

Benchmarks

goos: darwin
goarch: amd64
pkg: github.com/moogar0880/venom
BenchmarkVenomGet/single_ConfigLevel_with_one_key/value_pair-8         	20000000	        84.6 ns/op	      16 B/op	       1 allocs/op
BenchmarkVenomGet/many_key/value_pairs_in_a_single_ConfigLevel-8       	20000000	       102 ns/op	      16 B/op	       1 allocs/op
BenchmarkVenomGet/many_key/value_pairs_spread_across_multiple_ConfigLevels-8         	20000000	        99.2 ns/op	      16 B/op	       1 allocs/op
BenchmarkVenomWrite/single_key/value_pair_in_one_ConfigLevel-8                       	20000000	        89.0 ns/op	      16 B/op	       1 allocs/op
BenchmarkVenomWrite/many_key/value_pairs_in_one_ConfigLevel-8                        	 2000000	       648 ns/op	     121 B/op	       3 allocs/op
BenchmarkVenomWrite/many_nested_key/value_pairs_in_one_ConfigLevel-8                 	 1000000	      2055 ns/op	     922 B/op	       7 allocs/op
BenchmarkVenomWrite/many_key/value_pairs_in_many_ConfigLevels-8                      	 2000000	       589 ns/op	     121 B/op	       3 allocs/op
BenchmarkVenomWrite/many_nested_key/value_pairs_in_many_ConfigLevels-8               	 1000000	      1679 ns/op	     922 B/op	       7 allocs/op

Documentation

Overview

Code generated by "go run generate_coercers.go"; DO NOT EDIT.

Package venom aims to provide the basic building blocks of a configuration management library.

It exposes as many aspects as the standard lib will reasonably support.

Code generated by "go run generate_getters.go"; DO NOT EDIT.

Index

Examples

Constants

View Source
const (
	TIME_FORMAT = "2006-01-02T15:04:05.999Z"
	LOG_NAME    = "[venom]"
)

Variables

View Source
var Delim = defaultDelim

Delim is the delimiter used for separating nested key spaces. The default is to separate on "." characters.

View Source
var EnvSeparator = "_"

EnvSeparator is used as the delimiter for separating keys prior to looking them up in the current environment.

ie, an EnvSeparator of "_" will result in a lookup for "log.level" searching for an environment variable named "LOG_LEVEL".

View Source
var FlagSeparator = "-"

FlagSeparator is used as the delimiter for separating keys prior to looking up their value from a FlagSet.

ie, a FlagSeparator of "-" will result in a lookup for "log.level" searching for a flag named "log-level".

Functions

func Alias

func Alias(from, to string)

Alias registers an alias for a given key in the global venom instance

Example
package main

import (
	"fmt"

	"github.com/moogar0880/venom"
)

func main() {
	venom.SetDefault("log.enabled", true)
	venom.Alias("verbose", "log.enabled")
	fmt.Println(venom.Get("verbose"))
}
Output:

true

func Clear

func Clear()

Clear removes all data from the ConfigMap and resets the heap of config levels

func Debug

func Debug() string

Debug returns the current venom ConfigMap as a pretty-printed JSON string

func DefaultEnvironmentVariableKeyTranslator added in v0.5.0

func DefaultEnvironmentVariableKeyTranslator(b byte) byte

The DefaultEnvironmentVariableKeyTranslator is the default KeyTranslator used by the EnvironmentVariableResolver.

It is responsible for mapping arbitrary input keys to an environment variable to lookup. This is done by converting all characters to upper case.

func Find

func Find(key string) (interface{}, bool)

Find searches for the given key, returning the discovered value and a boolean indicating whether or not the key was found

Example
package main

import (
	"fmt"

	"github.com/moogar0880/venom"
)

func main() {
	key := "some.config"
	venom.SetDefault(key, 12)

	if val, ok := venom.Find(key); !ok {
		fmt.Printf("unable to find value for key %s", key)
	} else {
		fmt.Println(val)
	}
}
Output:

12

func Get

func Get(key string) interface{}

Get retrieves the requested key from the global venom instance

Example
package main

import (
	"fmt"

	"github.com/moogar0880/venom"
)

func main() {
	venom.SetDefault("log.level", "INFO")
	fmt.Printf("%v\n", venom.Get("log"))
	fmt.Printf("%v\n", venom.Get("log.level")) 
Output:

map[level:INFO]
INFO

func GetBool

func GetBool(key string) bool

GetBool attempts to cast the returned config value from the global Venom instance

func GetFloat32

func GetFloat32(key string) float32

GetFloat32 attempts to cast the returned config value from the global Venom instance

func GetFloat64

func GetFloat64(key string) float64

GetFloat64 attempts to cast the returned config value from the global Venom instance

func GetInt

func GetInt(key string) int

GetInt attempts to cast the returned config value from the global Venom instance

func GetInt16

func GetInt16(key string) int16

GetInt16 attempts to cast the returned config value from the global Venom instance

func GetInt32

func GetInt32(key string) int32

GetInt32 attempts to cast the returned config value from the global Venom instance

func GetInt64

func GetInt64(key string) int64

GetInt64 attempts to cast the returned config value from the global Venom instance

func GetInt8

func GetInt8(key string) int8

GetInt8 attempts to cast the returned config value from the global Venom instance

func GetString

func GetString(key string) string

GetString attempts to cast the returned config value from the global Venom instance

func GetUint

func GetUint(key string) uint

GetUint attempts to cast the returned config value from the global Venom instance

func GetUint16

func GetUint16(key string) uint16

GetUint16 attempts to cast the returned config value from the global Venom instance

func GetUint32

func GetUint32(key string) uint32

GetUint32 attempts to cast the returned config value from the global Venom instance

func GetUint64

func GetUint64(key string) uint64

GetUint64 attempts to cast the returned config value from the global Venom instance

func GetUint8

func GetUint8(key string) uint8

GetUint8 attempts to cast the returned config value from the global Venom instance

func JSONLoader

func JSONLoader(r io.Reader) (map[string]interface{}, error)

JSONLoader is an IOFileLoader which loads JSON config data

func LoadDirectory

func LoadDirectory(dir string, recurse bool) error

LoadDirectory loads any config files found in the provided directory, optionally recursing into any sub-directories

func LoadFile

func LoadFile(name string) error

LoadFile loads the file from the provided path into Venoms configs. If the file can't be opened, if no loader for the files extension exists, or if loading the file fails, an error is returned

func NoOpKeyTranslator added in v0.5.0

func NoOpKeyTranslator(b byte) byte

The NoOpKeyTranslator is a KeyTranslator which returns all input bytes unmodified.

func RegisterExtension

func RegisterExtension(ext string, loader IOFileLoader)

RegisterExtension registers an IOFileLoader for the provided file extension

func RegisterResolver

func RegisterResolver(level ConfigLevel, r Resolver)

RegisterResolver registers a custom config resolver into the global venom instance

func SetDefault

func SetDefault(key string, value interface{})

SetDefault sets the provided key and value into the global venom instance at the default level

Example
package main

import (
	"fmt"

	"github.com/moogar0880/venom"
)

func main() {
	venom.SetDefault("verbose", true)
	fmt.Println(venom.Get("verbose"))
}
Output:

true

func SetLevel

func SetLevel(level ConfigLevel, key string, value interface{})

SetLevel is a generic key/value setter method. It sets the provided k/v at the specified level inside the global venom instance.

Example
package main

import (
	"fmt"

	"github.com/moogar0880/venom"
)

func main() {
	var MySuperImportantLevel = venom.OverrideLevel + 1
	venom.SetLevel(MySuperImportantLevel, "verbose", true)
	venom.SetOverride("verbose", false)
	fmt.Println(venom.Get("verbose"))
}
Output:

true

func SetOverride

func SetOverride(key string, value interface{})

SetOverride sets the provided key and value into the global venom instance at the override level

Example
package main

import (
	"fmt"

	"github.com/moogar0880/venom"
)

func main() {
	venom.SetDefault("verbose", true)
	venom.SetOverride("verbose", false)
	fmt.Println(venom.Get("verbose"))
}
Output:

false

func Unmarshal

func Unmarshal(data *Venom, dst interface{}) error

Unmarshal unmarshals the provided Venom config into the provided interface

Types

type CoerceErr

type CoerceErr struct {
	From interface{}
	To   string
	Err  error
}

A CoerceErr is returned when incompatible types are attempted to be coerced

func (*CoerceErr) Error

func (e *CoerceErr) Error() string

type ConfigLevel

type ConfigLevel int

ConfigLevel is a type alias used to identify various configuration levels

const (
	DefaultLevel ConfigLevel = iota
	FileLevel
	EnvironmentLevel
	FlagLevel
	OverrideLevel ConfigLevel = 99
)

Default the default set of available config levels

type ConfigLevelHeap

type ConfigLevelHeap []ConfigLevel

An ConfigLevelHeap is a max-heap of ConfigLevels

func NewConfigLevelHeap

func NewConfigLevelHeap() *ConfigLevelHeap

NewConfigLevelHeap creates a pre-initialized ConfigLevelHeap instance

func (ConfigLevelHeap) Len

func (h ConfigLevelHeap) Len() int

func (ConfigLevelHeap) Less

func (h ConfigLevelHeap) Less(i, j int) bool

func (*ConfigLevelHeap) Pop

func (h *ConfigLevelHeap) Pop() interface{}

Pop removes the right-most (lowest) value from the heap

func (*ConfigLevelHeap) Push

func (h *ConfigLevelHeap) Push(x interface{})

Push pushes a new value onto the heap, inserting in sort order

func (ConfigLevelHeap) Swap

func (h ConfigLevelHeap) Swap(i, j int)

type ConfigLevelMap

type ConfigLevelMap map[ConfigLevel]ConfigMap

ConfigLevelMap is a mapping of config levels to the maps which contain various configuration values at those levels

type ConfigMap

type ConfigMap map[string]interface{}

ConfigMap defines the inner map type which holds actual config data. These are nested under a ConfigLevel which determines their priority

type ConfigStore

type ConfigStore interface {
	RegisterResolver(level ConfigLevel, r Resolver)
	SetLevel(level ConfigLevel, key string, value interface{})
	Merge(l ConfigLevel, data ConfigMap)
	Alias(from, to string)
	Find(key string) (interface{}, bool)
	Clear()
	Debug() string
	Size() int
}

The ConfigStore interface defines a type capable of performing basic operations required for configuration management within a venom instance.

func NewLoggableConfigStore

func NewLoggableConfigStore() ConfigStore

NewLoggableConfigStore returns a ConfigStore with a default logging mechanism set to write to os.Stdout.

func NewLoggableConfigStoreWith

func NewLoggableConfigStoreWith(l Logger) ConfigStore

NewLoggableConfigStore takes a Logger and returns a new ConfigStore with said interface as the logging mechanism used for read and writes.

func NewSafeConfigStore

func NewSafeConfigStore() ConfigStore

NewSafeConfigStore returns a new SafeConfigStore.

type DefaultConfigStore

type DefaultConfigStore struct {
	// contains filtered or unexported fields
}

DefaultConfigStore is the minimum implementation of a ConfigStore. It is capable of storing and managing arbitrary configuration keys and values.

func NewDefaultConfigStore

func NewDefaultConfigStore() *DefaultConfigStore

NewDefaultConfigStore returns a newly allocated DefaultConfigStore.

func (*DefaultConfigStore) Alias

func (s *DefaultConfigStore) Alias(from, to string)

Alias registers an alias for a given key. This allows consumers to access the same config via a different key, increasing the backwards compatibility of an application.

func (*DefaultConfigStore) Clear

func (s *DefaultConfigStore) Clear()

Clear removes all data from the ConfigLevelMap and resets the heap of config levels.

func (*DefaultConfigStore) Debug

func (s *DefaultConfigStore) Debug() string

Debug returns the current venom ConfigLevelMap as a pretty-printed JSON string.

func (*DefaultConfigStore) Find

func (s *DefaultConfigStore) Find(key string) (interface{}, bool)

Find searches for the given key, returning the discovered value and a boolean indicating whether or not the key was found

func (*DefaultConfigStore) Merge

func (s *DefaultConfigStore) Merge(l ConfigLevel, data ConfigMap)

Merge merges the provided config map into the ConfigLevel l, allocating space for ConfigLevel l if the level hasn't already been allocated.

func (*DefaultConfigStore) RegisterResolver

func (s *DefaultConfigStore) RegisterResolver(level ConfigLevel, r Resolver)

RegisterResolver registers a custom config resolver for the specified ConfigLevel.

Additionally, if the provided level is not already in the current collection of active config levels, it will be added automatically

func (*DefaultConfigStore) SetLevel

func (s *DefaultConfigStore) SetLevel(level ConfigLevel, key string, value interface{})

SetLevel is a generic key/value setter method. It sets the provided k/v at the specified level inside the map, conditionally creating a new ConfigMap if one didn't previously exist.

func (*DefaultConfigStore) Size

func (s *DefaultConfigStore) Size() int

Size returns the number of config levels stored in this ConfigStore.

type DefaultResolver

type DefaultResolver struct{}

DefaultResolver is the default resolver function used to resolve configuration values for a level which does not specify a custom resolver.

func (*DefaultResolver) Resolve

func (r *DefaultResolver) Resolve(keys []string, config ConfigMap) (val interface{}, ok bool)

Resolve will attempt to resolve the specified key using the configuration data stored in the provided ConfigMap

type EnvironmentVariableResolver

type EnvironmentVariableResolver struct {
	Prefix     string
	Translator KeyTranslator
}

An EnvironmentVariableResolver is a resolver specifically capable of adding additional context in the form of a prefix to any loaded environment variables

func (*EnvironmentVariableResolver) Resolve

func (r *EnvironmentVariableResolver) Resolve(keys []string, _ ConfigMap) (val interface{}, ok bool)

Resolve is a Resolver implementation which attempts to load the requested configuration from an environment variable

Example
package main

import (
	"fmt"
	"os"

	"github.com/moogar0880/venom"
)

func main() {
	os.Setenv("LOG_LEVEL", "INFO")
	fmt.Println(venom.Get("log.level"))
}
Output:

INFO

type ErrNoFileLoader

type ErrNoFileLoader struct {
	// contains filtered or unexported fields
}

ErrNoFileLoader is the error returned when a file is attempted to be loaded without a matching extension IOFileLoader

func (ErrNoFileLoader) Error

func (e ErrNoFileLoader) Error() string

Error implements the error interface and returns a custom error message for the current ErrNoFileLoader instance

type Event

type Event struct {
	Key   string
	Value interface{}
}

An Event represents an update published to a ConfigStore. The Key represents the config value that was updated. The Value contains the value that the key was updated to.

type FlagsetResolver

type FlagsetResolver struct {
	Flags     *flag.FlagSet
	Arguments []string
	// contains filtered or unexported fields
}

The FlagsetResolver is used to resolve configuration from a FlagSet using the standard flag library.

If no FlagSet is provided, then flag.Parse and flag.Lookup are used to pull values directly from os.Args. If a FlagSet is provided, then any arguments required when Parsing the FlagSet may also be specified, otherwise the arguments default to os.Args[1:].

func (*FlagsetResolver) Resolve

func (r *FlagsetResolver) Resolve(keys []string, _ ConfigMap) (val interface{}, ok bool)

Resolve is a Resolver function and will lookup the requested config value from a FlagSet

Example
package main

import (
	"flag"
	"fmt"

	"github.com/moogar0880/venom"
)

func main() {
	fs := flag.NewFlagSet("example", flag.ContinueOnError)
	fs.String("log-level", "WARNING", "set log level")

	flagResolver := &venom.FlagsetResolver{
		Flags:     fs,
		Arguments: []string{"-log-level=INFO"},
	}
	venom.RegisterResolver(venom.FlagLevel, flagResolver)
	fmt.Println(venom.Get("log.level"))
}
Output:

INFO

type IOFileLoader

type IOFileLoader func(io.Reader) (map[string]interface{}, error)

IOFileLoader is the function signature for a function which can load an io.Reader into a map[string]interface{}

type InvalidUnmarshalError

type InvalidUnmarshalError struct {
	Type reflect.Type
}

InvalidUnmarshalError is an error returned when an an invalid destination value is provided to Unmarshal. (The argument to Unmarshal must be a non-nil pointer.)

func (InvalidUnmarshalError) Error

func (e InvalidUnmarshalError) Error() string

type KeyTranslator added in v0.5.0

type KeyTranslator func(b byte) byte

A KeyTranslator is used for translating portions of config keys in a level-agnostic manner.

Functions like these may be useful for performing operations such as normalizing hyphens ('-') to underscores ('_') when performing environment variable lookups, or perhaps the inverse when performing command line flag lookups.

type LoggableConfigStore

type LoggableConfigStore struct {
	// contains filtered or unexported fields
}

LoggableConfigStore implements the ConfigStore interface and provides a log field for reference to a Logger which will log on reads and writes.

func (*LoggableConfigStore) Alias

func (l *LoggableConfigStore) Alias(from, to string)

Alias registers an alias for a given key. This allows consumers to access the same config via a different key, increasing the backwards compatibility of an application.

func (*LoggableConfigStore) Clear

func (l *LoggableConfigStore) Clear()

Clear removes all data from the ConfigLevelMap and resets the heap of config levels.

func (*LoggableConfigStore) Debug

func (l *LoggableConfigStore) Debug() string

Debug returns the current venom ConfigLevelMap as a pretty-printed JSON string.

func (*LoggableConfigStore) Find

func (l *LoggableConfigStore) Find(key string) (interface{}, bool)

Find searches for the given key, returning the discovered value and a boolean indicating whether or not the key was found

func (*LoggableConfigStore) Merge

func (l *LoggableConfigStore) Merge(cl ConfigLevel, data ConfigMap)

Merge merges the provided config map into the ConfigLevel l, allocating space for ConfigLevel l if the level hasn't already been allocated.

func (*LoggableConfigStore) RegisterResolver

func (l *LoggableConfigStore) RegisterResolver(level ConfigLevel, r Resolver)

RegisterResolver registers a custom config resolver for the specified ConfigLevel.

Additionally, if the provided level is not already in the current collection of active config levels, it will be added automatically

func (*LoggableConfigStore) SetLevel

func (l *LoggableConfigStore) SetLevel(level ConfigLevel, key string, value interface{})

SetLevel is a generic key/value setter method. It sets the provided k/v at the specified level inside the map, conditionally creating a new ConfigMap if one didn't previously exist.

func (*LoggableConfigStore) Size

func (l *LoggableConfigStore) Size() int

Size returns the number of config levels stored in this ConfigStore.

type Logger

type Logger interface {
	LogWrite(level ConfigLevel, key string, val interface{})
	LogRead(key string, val interface{}, bl bool)
}

Logger is the interface a user must implement in order to be used by the LogableConfigStore.

func NewStoreLogger

func NewStoreLogger(l *log.Logger) Logger

NewStoreLogger returns a Logger suitable for default use case.

type Resolver

type Resolver interface {
	Resolve([]string, ConfigMap) (val interface{}, ok bool)
}

A Resolver is responsible for performing a lookup of a config returning the value stored for that config or an error.

type SafeConfigStore

type SafeConfigStore struct {
	// contains filtered or unexported fields
}

SafeConfigStore implements the ConfigStore interface and provides a store that is safe to read and write from multiple go routines.

func (*SafeConfigStore) Alias

func (s *SafeConfigStore) Alias(from, to string)

Alias registers an alias for a given key. This allows consumers to access the same config via a different key, increasing the backwards compatibility of an application.

func (*SafeConfigStore) Clear

func (s *SafeConfigStore) Clear()

Clear removes all data from the ConfigLevelMap and resets the heap of config levels.

func (*SafeConfigStore) Debug

func (s *SafeConfigStore) Debug() string

Debug returns the current venom ConfigLevelMap as a pretty-printed JSON string.

func (*SafeConfigStore) Find

func (s *SafeConfigStore) Find(key string) (interface{}, bool)

Find searches for the given key, returning the discovered value and a boolean indicating whether or not the key was found

func (*SafeConfigStore) Merge

func (s *SafeConfigStore) Merge(l ConfigLevel, data ConfigMap)

Merge merges the provided config map into the ConfigLevel l, allocating space for ConfigLevel l if the level hasn't already been allocated.

func (*SafeConfigStore) RegisterResolver

func (s *SafeConfigStore) RegisterResolver(level ConfigLevel, r Resolver)

RegisterResolver registers a custom config resolver for the specified ConfigLevel.

Additionally, if the provided level is not already in the current collection of active config levels, it will be added automatically

func (*SafeConfigStore) SetLevel

func (s *SafeConfigStore) SetLevel(level ConfigLevel, key string, value interface{})

SetLevel is a generic key/value setter method. It sets the provided k/v at the specified level inside the map, conditionally creating a new ConfigMap if one didn't previously exist.

func (*SafeConfigStore) Size

func (s *SafeConfigStore) Size() int

Size returns the number of config levels stored in this ConfigStore.

type StoreLogger

type StoreLogger struct {
	Log *log.Logger
}

StoreLogger is Venom's default Logger.

func (*StoreLogger) LogRead

func (sl *StoreLogger) LogRead(key string, val interface{}, bl bool)

LogWrite is the default logging behavior of a LoggableConfigStore on an action to read a value in the ConfigStore.

func (*StoreLogger) LogWrite

func (sl *StoreLogger) LogWrite(level ConfigLevel, key string, val interface{})

LogWrite is the default logging behavior of a LoggableConfigStore on an action to set a value in the ConfigStore.

type SubscriptionStore

type SubscriptionStore struct {
	// contains filtered or unexported fields
}

A SubscriptionStore allows callers to subscribe to specific key namespaces, allowing them to be notified when a config under that space is modified.

Key-spaces can be subscribed to via the Subscribe method, which return a channel over which events for that key-space are emitted. This means that an update to the config `db.host` would trigger an event to be emitted if a subscription existed on either `db` or `db.host`.

func NewSubscriptionStore

func NewSubscriptionStore(s ConfigStore) (*SubscriptionStore, func())

NewSubscriptionStore returns a newly allocated SubscriptionStore which wraps the specified ConfigStore. The channels created by this method will be un-buffered by default. To customize the buffer size of these channels, see NewSubscriptionStoreWithSize.

func NewSubscriptionStoreWithSize

func NewSubscriptionStoreWithSize(s ConfigStore, size int) (*SubscriptionStore, func())

NewSubscriptionStoreWithSize returns a newly allocated SubscriptionStore which wraps the provided ConfigStore as well as a closure which, when called, will close all channels managed by this SubscriptionStore. The size parameter of this function allows for the caller to toggle the buffer size of the channels created by this ConfigStore.

func (*SubscriptionStore) Alias

func (s *SubscriptionStore) Alias(from, to string)

Alias registers an alias for a given key. This allows consumers to access the same config via a different key, increasing the backwards compatibility of an application.

func (*SubscriptionStore) Clear

func (s *SubscriptionStore) Clear()

Clear removes all data from the ConfigLevelMap and resets the heap of config levels.

func (*SubscriptionStore) Close

func (s *SubscriptionStore) Close()

Close iterates over all allocated channels, closes them, and removes the subscriptions from the map of event subscriptions.

func (*SubscriptionStore) Debug

func (s *SubscriptionStore) Debug() string

Debug returns the current venom ConfigLevelMap as a pretty-printed JSON string.

func (*SubscriptionStore) Find

func (s *SubscriptionStore) Find(key string) (interface{}, bool)

Find searches for the given key, returning the discovered value and a boolean indicating whether or not the key was found.

func (*SubscriptionStore) Merge

func (s *SubscriptionStore) Merge(l ConfigLevel, data ConfigMap)

Merge merges the provided config map into the ConfigLevel l, allocating space for ConfigLevel l if the level hasn't already been allocated.

func (*SubscriptionStore) RegisterResolver

func (s *SubscriptionStore) RegisterResolver(level ConfigLevel, r Resolver)

RegisterResolver registers a custom config resolver for the specified ConfigLevel.

Additionally, if the provided level is not already in the current collection of active config levels, it will be added automatically

func (*SubscriptionStore) SetLevel

func (s *SubscriptionStore) SetLevel(level ConfigLevel, key string, value interface{})

SetLevel is a generic key/value setter method. It sets the provided k/v at the specified level inside the map, conditionally creating a new ConfigMap if one didn't previously exist.

Once written, a new event will be emitted by this Subscription store, if any matching key-spaces have subscription channels.

func (*SubscriptionStore) Size

func (s *SubscriptionStore) Size() int

Size returns the number of config levels stored in this ConfigStore.

func (*SubscriptionStore) Subscribe

func (s *SubscriptionStore) Subscribe(key string) <-chan Event

Subscribe returns a channel over which updates to any value located at, or under, the specified key will be emitted.

Note that if no buffer size was specified when the SubscriptionStore was created, the channels will default to being un-buffered.

Also note that multiple subscriptions to the same key will result in the same channel being returned. To clear an existing subscription and to close it's corresponding channel, use the Unsubscribe method.

Subscriptions to the root space (empty string) will result in events being emitted for any and all config updates.

func (*SubscriptionStore) Unsubscribe

func (s *SubscriptionStore) Unsubscribe(key string) error

Unsubscribe removes an existing subscription. The removal of this subscription results in the subscription channel being closed, and the subscription being completely removed from this Store.

To remove all existing subscriptions, use Close.

type Venom

type Venom struct {
	Store ConfigStore
}

Venom is the configuration registry responsible for storing and managing arbitrary configuration keys and values.

func Default

func Default() *Venom

Default returns a new venom instance with some default resolver configuration applied to it.

func DefaultSafe

func DefaultSafe() *Venom

Default returns a new goroutine-safe venom instance with some default resolver configuration applied to it.

func New

func New() *Venom

New returns a newly initialized Venom instance.

The internal config map is created empty, only allocating space for a given config level once a value is set to that level.

func NewLoggable

func NewLoggable() *Venom

NewLoggable returns a Venom instance with a default log set to standard out.

func NewLoggableWith

func NewLoggableWith(l Logger) *Venom

NewLoggable takes a Logger and returns a newly initialized Venom instance that will log to a Logger interface upon reads and writes.

func NewSafe

func NewSafe() *Venom

NewSafe returns a newly initialized Venom instance that is safe to read and write from multiple goroutines.

The internal config map is created empty, only allocating space for a given config level once a value is set to that level.

func NewWithStore

func NewWithStore(s ConfigStore) *Venom

NewWithStore returns a newly initialized Venom instance that wraps the provided ConfigStore.

func (*Venom) Alias

func (v *Venom) Alias(from, to string)

Alias registers an alias for a given key. This allows consumers to access the same config via a different key, increasing the backwards compatibility of an application.

func (*Venom) Clear

func (v *Venom) Clear()

Clear removes all data from the ConfigLevelMap and resets the heap of config levels

func (*Venom) Debug

func (v *Venom) Debug() string

Debug returns the current venom ConfigLevelMap as a pretty-printed JSON string.

func (*Venom) Find

func (v *Venom) Find(key string) (interface{}, bool)

Find searches for the given key, returning the discovered value and a boolean indicating whether or not the key was found

func (*Venom) Get

func (v *Venom) Get(key string) interface{}

Get performs a fetch on a given key from the inner config collection.

func (*Venom) GetBool

func (v *Venom) GetBool(key string) bool

GetBool attempts to cast the returned config value from the current Venom instance.

If the key does not exist, or if the type contained in Venom can not be cast to the requested type, then the zero value of false will be returned.

func (*Venom) GetFloat32

func (v *Venom) GetFloat32(key string) float32

GetFloat32 attempts to cast the returned config value from the current Venom instance.

If the key does not exist, or if the type contained in Venom can not be cast to the requested type, then the zero value of 0 will be returned.

func (*Venom) GetFloat64

func (v *Venom) GetFloat64(key string) float64

GetFloat64 attempts to cast the returned config value from the current Venom instance.

If the key does not exist, or if the type contained in Venom can not be cast to the requested type, then the zero value of 0 will be returned.

func (*Venom) GetInt

func (v *Venom) GetInt(key string) int

GetInt attempts to cast the returned config value from the current Venom instance.

If the key does not exist, or if the type contained in Venom can not be cast to the requested type, then the zero value of 0 will be returned.

func (*Venom) GetInt16

func (v *Venom) GetInt16(key string) int16

GetInt16 attempts to cast the returned config value from the current Venom instance.

If the key does not exist, or if the type contained in Venom can not be cast to the requested type, then the zero value of 0 will be returned.

func (*Venom) GetInt32

func (v *Venom) GetInt32(key string) int32

GetInt32 attempts to cast the returned config value from the current Venom instance.

If the key does not exist, or if the type contained in Venom can not be cast to the requested type, then the zero value of 0 will be returned.

func (*Venom) GetInt64

func (v *Venom) GetInt64(key string) int64

GetInt64 attempts to cast the returned config value from the current Venom instance.

If the key does not exist, or if the type contained in Venom can not be cast to the requested type, then the zero value of 0 will be returned.

func (*Venom) GetInt8

func (v *Venom) GetInt8(key string) int8

GetInt8 attempts to cast the returned config value from the current Venom instance.

If the key does not exist, or if the type contained in Venom can not be cast to the requested type, then the zero value of 0 will be returned.

func (*Venom) GetString

func (v *Venom) GetString(key string) string

GetString attempts to cast the returned config value from the current Venom instance.

If the key does not exist, or if the type contained in Venom can not be cast to the requested type, then the zero value of "" will be returned.

func (*Venom) GetUint

func (v *Venom) GetUint(key string) uint

GetUint attempts to cast the returned config value from the current Venom instance.

If the key does not exist, or if the type contained in Venom can not be cast to the requested type, then the zero value of 0 will be returned.

func (*Venom) GetUint16

func (v *Venom) GetUint16(key string) uint16

GetUint16 attempts to cast the returned config value from the current Venom instance.

If the key does not exist, or if the type contained in Venom can not be cast to the requested type, then the zero value of 0 will be returned.

func (*Venom) GetUint32

func (v *Venom) GetUint32(key string) uint32

GetUint32 attempts to cast the returned config value from the current Venom instance.

If the key does not exist, or if the type contained in Venom can not be cast to the requested type, then the zero value of 0 will be returned.

func (*Venom) GetUint64

func (v *Venom) GetUint64(key string) uint64

GetUint64 attempts to cast the returned config value from the current Venom instance.

If the key does not exist, or if the type contained in Venom can not be cast to the requested type, then the zero value of 0 will be returned.

func (*Venom) GetUint8

func (v *Venom) GetUint8(key string) uint8

GetUint8 attempts to cast the returned config value from the current Venom instance.

If the key does not exist, or if the type contained in Venom can not be cast to the requested type, then the zero value of 0 will be returned.

func (*Venom) LoadDirectory

func (v *Venom) LoadDirectory(dir string, recurse bool) error

LoadDirectory loads any config files found in the provided directory, optionally recursing into any sub-directories

func (*Venom) LoadFile

func (v *Venom) LoadFile(name string) error

LoadFile loads the file from the provided path into Venoms configs. If the file can't be opened, if no loader for the files extension exists, or if loading the file fails, an error is returned

func (*Venom) Merge

func (v *Venom) Merge(l ConfigLevel, data ConfigMap)

Merge merges the provided config map into the ConfigLevel l, allocating space for ConfigLevel l if the level hasn't already been allocated.

func (*Venom) RegisterResolver

func (v *Venom) RegisterResolver(level ConfigLevel, r Resolver)

RegisterResolver registers a custom config resolver for the specified ConfigLevel.

Additionally, if the provided level is not already in the current collection of active config levels, it will be added automatically

func (*Venom) SetDefault

func (v *Venom) SetDefault(key string, value interface{})

SetDefault sets the provided key and value into the DefaultLevel of the config collection.

func (*Venom) SetLevel

func (v *Venom) SetLevel(level ConfigLevel, key string, value interface{})

SetLevel is a generic key/value setter method. It sets the provided k/v at the specified level inside the map, conditionally creating a new ConfigMap if one didn't previously exist.

func (*Venom) SetOverride

func (v *Venom) SetOverride(key string, value interface{})

SetOverride sets the provided key and value into the OverrideLevel of the config collection.

func (*Venom) Size

func (v *Venom) Size() int

Size returns the number of config levels stored in the underlying ConfigStore.

Jump to

Keyboard shortcuts

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