Library for easy configuration of a golang service

go-conf - Configuration with less code

Mentioned in Awesome Go Go Reference build Go Report Card Quality Gate Status Coverage Code Smells Security Rating Maintainability Rating Reliability Rating Vulnerabilities CodeQL

Installation

go get github.com/ThomasObenaus/go-conf

What is go-conf?

go-conf is a solution for handling configurations in golang applications.

go-conf supports reading configuration parameters from multiple sources. The order they are applied is:

  1. Default values are overwritten by
  2. Parameters defined in the config-file, which are overwritten by
  3. Environment variables, which are overwritten by
  4. Command-Line parameters

The aim is to write as less code as possible:

  • No need to write code to integrate multiple libraries that support reading a configuration from file/ commandline or the environment.
  • No need to code to take the values from that library to fill it into the config struct you want to use in your app anyway.

Instead one just has to define the config structure and annotates it with struct tags.

default value will be used "--color=#ff00ff", "--name=Arial", "-s=12", // use -s (short hand version) instead of --size } // 1. Create an instance of the config struct that should be filled cfg := MyFontConfig{} // 2. Create an instance of the config provider provider, err := config.NewConfigProvider(&cfg, "MY_APP", "MY_APP") if err != nil { panic(err) } // 3. Read the config and populate the struct if err := provider.ReadConfig(args); err != nil { panic(err) } // 4. Thats it! Now the config can be used. fmt.Printf("FontConfig: color=%s, name=%s, size=%d\n", cfg.Color, cfg.Name, cfg.Size) } ">
package main

import (
    "fmt"

    config "github.com/ThomasObenaus/go-conf"
)

// Define the config struct and annotate it with the cfg tag.
type MyFontConfig struct {
    Color string `cfg:"{'name':'color','desc':'The value of the color as hexadecimal RGB string.','default':'#FFFFFF'}"`
    Name  string `cfg:"{'name':'name','desc':'Name of the font to be used.'}"`
    Size  int    `cfg:"{'name':'size','desc':'Size of the font.','short':'s'}"`
}

func main() {

    // Some command line arguments
    args := []string{
        // color not set  --> default value will be used "--color=#ff00ff",
        "--name=Arial",
        "-s=12", // use -s (short hand version) instead of --size
    }

    // 1. Create an instance of the config struct that should be filled
    cfg := MyFontConfig{}

    // 2. Create an instance of the config provider
    provider, err := config.NewConfigProvider(&cfg, "MY_APP", "MY_APP")
    if err != nil {
        panic(err)
    }

    // 3. Read the config and populate the struct
    if err := provider.ReadConfig(args); err != nil {
        panic(err)
    }

    // 4. Thats it! Now the config can be used.
    fmt.Printf("FontConfig: color=%s, name=%s, size=%d\n", cfg.Color, cfg.Name, cfg.Size)
}

Features

  • Automatically populates a struct using values given via command line
  • Read config parameters from multiple sources like command line, environment variables and config files (yaml)
  • Support of default values
  • Short hand parameters for command line flags
  • Print usage on command line
  • Custom mapping functions to support parsing of config parameters into complex structures and type conversion
  • Support of config parameter lists
  • Support of complex structs with multiple levels

License

FOSSA Status

Comments
  • Add license scan report and status

    Add license scan report and status

    Your FOSSA integration was successful! Attached in this PR is a badge and license report to track scan status in your README.

    Below are docs for integrating FOSSA license checks into your CI:

  • Conf returns no value for complex types read form yaml

    Conf returns no value for complex types read form yaml

    To reproduce

    this test can be used

    func Test_Things(t *testing.T) {
    	// GIVEN
    	entry := NewEntry("things", "A list of things [{'user':'user1','age':25},{'user':'user2','age':55}]. The user has to be unique.", Default(""))
    	type myCfg struct {
    	}
    
    	cfg := myCfg{}
    	provider, err := NewConfigProvider(&cfg, "MyConfig", "MY_APP", CustomConfigEntries([]Entry{entry}))
    	require.NoError(t, err)
    
    	args := []string{
    		"--config-file=test/data/things.yaml",
    	}
    
    	// WHEN
    	err = provider.ReadConfig(args)
    	require.NoError(t, err)
    
    	// THEN
    	things := provider.Get("things")
    	assert.NotEmpty(t, things)
    	assert.Equal(t, []interface{}{
    		map[interface{}]interface{}{"age": 25, "user": "user1"},
    		map[interface{}]interface{}{"age": 55, "user": "user2"},
    	}, things)
    }
    
  • Nil ptr when having non annotated non primitive types as part of the config struct

    Nil ptr when having non annotated non primitive types as part of the config struct

    When running this test

    func Test_extractConfigTagsOfStruct_NonPrimitiveWithoutAnnotation(t *testing.T) {
    	// GIVEN
    	type nested struct {
    		FieldA string
    	}
    
    	type my struct {
    		Field1 string `cfg:"{'name':'field-1','desc':'a string field','default':'field-1 default'}"`
    		Field3 nested
    	}
    	strct := my{}
    
    	// WHEN
    	cfgTags, errNoPointer := extractConfigTagsOfStruct(&strct, interfaces.NoLogging, "", configTag{})
    
    	// THEN
    	require.NoError(t, errNoPointer)
    	require.Len(t, cfgTags, 5)
    }
    

    a nilptr access is happening

    panic: runtime error: invalid memory address or nil pointer dereference [recovered]
    	panic: runtime error: invalid memory address or nil pointer dereference
    [signal SIGSEGV: segmentation violation code=0x1 addr=0x60 pc=0x67bc97]
    
    goroutine 6 [running]:
    testing.tRunner.func1.2(0x6d2520, 0x8fa2d0)
    	/usr/local/go/src/testing/testing.go:1143 +0x332
    testing.tRunner.func1(0xc000001b00)
    	/usr/local/go/src/testing/testing.go:1146 +0x4b6
    panic(0x6d2520, 0x8fa2d0)
    	/usr/local/go/src/runtime/panic.go:965 +0x1b9
    github.com/ThomasObenaus/go-conf.processAllConfigTagsOfStruct(0x6b5100, 0xc00007c640, 0x7393f8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
    	/home/winnietom/work/code/go-conf/extract.go:241 +0x8f7
    github.com/ThomasObenaus/go-conf.extractConfigTagsOfStruct(0x6b5100, 0xc00007c640, 0x7393f8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
    	/home/winnietom/work/code/go-conf/extract.go:168 +0x2e8
    github.com/ThomasObenaus/go-conf.Test_extractConfigTagsOfStruct_NonPrimitiveWithoutAnnotation(0xc000001b00)
    	/home/winnietom/work/code/go-conf/extract_test.go:418 +0x98
    testing.tRunner(0xc000001b00, 0x739330)
    	/usr/local/go/src/testing/testing.go:1193 +0xef
    created by testing.(*T).Run
    	/usr/local/go/src/testing/testing.go:1238 +0x2b3
    
  • Error messages for structs are misleading

    Error messages for structs are misleading

    Code

    package main
    
    import (
    	"fmt"
    	"os"
    	"time"
    
    	config "github.com/ThomasObenaus/go-conf"
    	"github.com/ThomasObenaus/go-conf/interfaces"
    	"github.com/davecgh/go-spew/spew"
    )
    
    type PrimitiveTypes struct {
    	Field6 time.Time `cfg:"{'name':'aa'}"`
    }
    
    func main() {
    
    	args := []string{
    		"--aa=dd", //2021-02-22 12:34:00 +0000 UTC",
    	}
    
    	// 1. Create an instance of the config struct that should be filled
    	cfg := PrimitiveTypes{}
    
    	// 2. Create an instance of the config provider which is responsible to read the config
    	// from defaults, environment variables, config file or command line
    	prefixForEnvironmentVariables := "MY_APP"
    	nameOfTheConfig := "MY_APP"
    	provider, err := config.NewConfigProvider(
    		&cfg,
    		nameOfTheConfig,
    		prefixForEnvironmentVariables,
    		config.Logger(interfaces.DebugLogger),
    	)
    	if err != nil {
    		panic(err)
    	}
    
    	// 3. Start reading and fill the config parameters
    	err = provider.ReadConfig(args)
    	if err != nil {
    		fmt.Println("##### Failed reading the config")
    		fmt.Printf("Error: %s\n", err.Error())
    		fmt.Println("Usage:")
    		fmt.Print(provider.Usage())
    		os.Exit(1)
    	}
    
    	fmt.Println("##### Successfully read the config")
    	fmt.Println()
    	spew.Dump(cfg)
    }
    

    Returns

    Debug] [Extract-()] structure-type=*main.PrimitiveTypes definition=name:"",desc:"",default:<nil> (<nil>),required=true
    [Debug] [Process-(Field6)] field-type=time.Time
    [Debug] [Process-(Field6)] parsed config entry=name:"aa",desc:"",default:<nil> (<nil>),required=true. Is primitive=false.
    [Debug] [Extract-(Field6)] structure-type=*time.Time definition=name:"aa",desc:"",default:<nil> (<nil>),required=true
    [Debug] [Process-(Field6.wall)] field-type=uint64
    [Info] [Process-(Field6.wall)] no tag found entry will be skipped.
    [Debug] [Process-(Field6.ext)] field-type=int64
    [Info] [Process-(Field6.ext)] no tag found entry will be skipped.
    [Debug] [Process-(Field6.loc)] field-type=*time.Location
    [Info] [Process-(Field6.loc)] no tag found entry will be skipped.
    [Debug] [Extract-(Field6)] added 0 configTags.
    ##### Failed reading the config
    Error: unknown flag: --aa
    

    Actual Result

    Error: unknown flag: --aa

    Expected Result

    Error: No annotations given for fields of struct on field ('Field6'). Please annotate the relevant fields or provide a mapping function.

  • Required parameters can be emtpy

    Required parameters can be emtpy

    package main
    
    import (
    	"fmt"
    	"os"
    
    	config "github.com/ThomasObenaus/go-conf"
    	"github.com/davecgh/go-spew/spew"
    )
    
    // Just a struct with the desired config parameters has to be defined.
    // Each field has to be annotated with the cfg struct tag
    //	`cfg:{'name':'<name of the parameter>','desc':'<description>'}`
    // The tag has to be specified as json structure using single quotes.
    // Mandatory fields are 'name' and 'desc'.
    type MyFontConfig struct {
    	Color string `cfg:"{'name':'color','desc':'The value of the color as hexadecimal RGB string.'}"`
    	Name  string `cfg:"{'name':'name','desc':'Name of the font to be used.'}"`
    	Size  int    `cfg:"{'name':'size','desc':'Size of the font.'}"`
    }
    
    func main() {
    
    	args := []string{}
    
    	// 1. Create an instance of the config struct that should be filled
    	cfg := MyFontConfig{}
    
    	// 2. Create an instance of the config provider which is responsible to read the config
    	// from defaults, environment variables, config file or command line
    	prefixForEnvironmentVariables := "MY_APP"
    	nameOfTheConfig := "MY_APP"
    	provider, err := config.NewConfigProvider(
    		&cfg,
    		nameOfTheConfig,
    		prefixForEnvironmentVariables,
    	)
    	if err != nil {
    		panic(err)
    	}
    
    	// 3. Start reading and fill the config parameters
    	err = provider.ReadConfig(args)
    	if err != nil {
    		fmt.Println("##### Failed reading the config")
    		fmt.Printf("Error: %s\n", err.Error())
    		fmt.Println("Usage:")
    		fmt.Print(provider.Usage())
    		os.Exit(1)
    	}
    
    	fmt.Println("##### Successfully read the config")
    	fmt.Println()
    	spew.Dump(cfg)
    }
    
Golang library for managing configuration data from environment variables

envconfig import "github.com/kelseyhightower/envconfig" Documentation See godoc Usage Set some environment variables: export MYAPP_DEBUG=false export

Dec 26, 2022
Cfginterpolator is an interpolate library in golang allowing to include data from external sources in your configuration

cfginterpolator cfginterpolator is an interpolate library in golang allowing to include data from external sources in your configuration cfginterpolat

Dec 14, 2021
Golang library for reading properties from configuration files in JSON and YAML format or from environment variables.

go-config Golang library for reading properties from configuration files in JSON and YAML format or from environment variables. Usage Create config in

Aug 22, 2022
Small library to read your configuration from environment variables

envconfig envconfig is a library which allows you to parse your configuration from environment variables and fill an arbitrary struct. See the example

Nov 3, 2022
A minimalist Go configuration library
A minimalist Go configuration library

fig fig is a tiny library for loading an application's config file and its environment into a Go struct. Individual fields can have default values def

Dec 23, 2022
go-up! A simple configuration library with recursive placeholders resolution and no magic.

go-up! A simple configuration library with placeholders resolution and no magic. go-up provides a simple way to configure an application from multiple

Nov 23, 2022
go implementation of lightbend's HOCON configuration library https://github.com/lightbend/config

HOCON (Human-Optimized Config Object Notation) Configuration library for working with the Lightbend's HOCON format. HOCON is a human-friendly JSON sup

Dec 3, 2022
πŸ›  A configuration library for Go that parses environment variables, JSON files, and reloads automatically on SIGHUP
πŸ›  A configuration library for Go that parses environment variables, JSON files, and reloads automatically on SIGHUP

config A small configuration library for Go that parses environment variables, JSON files, and reloads automatically on SIGHUP. Example func main() {

Dec 11, 2022
Light weight, extensible configuration management library for Go. Built in support for JSON, TOML, YAML, env, command line, file, S3 etc. Alternative to viper.
Light weight, extensible configuration management library for Go. Built in support for JSON, TOML, YAML, env, command line, file, S3 etc. Alternative to viper.

koanf (pronounced conf; a play on the Japanese Koan) is a library for reading configuration from different sources in different formats in Go applicat

Jan 8, 2023
A flexible and composable configuration library for Go that doesn't suck

croconf A flexible and composable configuration library for Go that doesn't suck Ned's spec for Go configuration which doesn't suck: Fully testable: t

Nov 17, 2022
A flexible and composable configuration library for Go that doesn't suck

croconf A flexible and composable configuration library for Go Why? We know that there are plenty of other Go configuration and CLI libraries out ther

Nov 17, 2022
Tinyini - Bare-bones Go library for reading INI-like configuration files

tinyini tinyini is a minimalistic library for parsing INI-like configuration files. example configuration file globalkey = globalvalue [section] key

Jan 10, 2022
Genv is a library for Go (golang) that makes it easy to read and use environment variables in your projects. It also allows environment variables to be loaded from the .env file.

genv Genv is a library for Go (golang) that makes it easy to read and use environment variables in your projects. It also allows environment variables

Dec 21, 2022
✨Clean and minimalistic environment configuration reader for Golang

Clean Env Minimalistic configuration reader Overview This is a simple configuration reading tool. It just does the following: reads and parses configu

Jan 8, 2023
A golang package for parsing ini-style configuration files

Mini Mini is a simple ini configuration file parser. The ini syntax supported includes: The standard name=value Comments on new lines starting with #

Jan 7, 2023
Golang Configuration tool that support YAML, JSON, TOML, Shell Environment

Configor Golang Configuration tool that support YAML, JSON, TOML, Shell Environment (Supports Go 1.10+) Usage package main import ( "fmt" "github.c

Dec 29, 2022
πŸ”₯πŸ”₯ 🌈 Golang configuration,use to Viper reading from remote Nacos config systems. Viper remote for Naocs.

Viper remote for Nacos Golang configuration,use to Viper reading from remote Nacos config systems. Viper remote for Naocs. runtime_viper := viper.New(

Dec 6, 2022
Nginx Configuration Golang Parser

Nginx Configuration Golang Parser

Oct 21, 2022
DanaConfig is a static configuration extractor implemented in Golang for the main component of DanaBot
DanaConfig is a static configuration extractor implemented in Golang for the main component of DanaBot

DanaConfig is a static configuration extractor implemented in Golang for the main component of DanaBot (targeting Microsoft Windows). By de

Mar 7, 2022