How to handle configuration in Go

GoConfiguration Files

Go Problem Overview


I'm new at Go programming, and I'm wondering: what is the preferred way to handle configuration parameters for a Go program (the kind of stuff one might use properties files or ini files for, in other contexts)?

Go Solutions


Solution 1 - Go

The JSON format worked for me quite well. The standard library offers methods to write the data structure indented, so it is quite readable.

See also this golang-nuts thread.

The benefits of JSON are that it is fairly simple to parse and human readable/editable while offering semantics for lists and mappings (which can become quite handy), which is not the case with many ini-type config parsers.

Example usage:

conf.json:

{
    "Users": ["UserA","UserB"],
    "Groups": ["GroupA"]
}

Program to read the configuration

import (
    "encoding/json"
    "os"
    "fmt"
)

type Configuration struct {
    Users    []string
    Groups   []string
}

file, _ := os.Open("conf.json")
defer file.Close()
decoder := json.NewDecoder(file)
configuration := Configuration{}
err := decoder.Decode(&configuration)
if err != nil {
  fmt.Println("error:", err)
}
fmt.Println(configuration.Users) // output: [UserA, UserB]

Solution 2 - Go

Another option is to use [TOML][1], which is an INI-like format created by Tom Preston-Werner. I [built a Go parser for it][2] that is [extensively tested][3]. You can use it like other options proposed here. For example, if you have this TOML data in something.toml

Age = 198
Cats = [ "Cauchy", "Plato" ]
Pi = 3.14
Perfection = [ 6, 28, 496, 8128 ]
DOB = 1987-07-05T05:45:00Z

Then you can load it into your Go program with something like

type Config struct {
    Age int
    Cats []string
    Pi float64
    Perfection []int
    DOB time.Time
}

var conf Config
if _, err := toml.DecodeFile("something.toml", &conf); err != nil {
    // handle error
}

[1]: https://github.com/mojombo/toml "TOML" [2]: https://github.com/BurntSushi/toml [3]: https://github.com/BurntSushi/toml-test

Solution 3 - Go

Viper is a golang configuration management system that works with JSON, YAML, and TOML. It looks pretty interesting.

Solution 4 - Go

I usually use JSON for more complicated data structures. The downside is that you easily end up with a bunch of code to tell the user where the error was, various edge cases and what not.

For base configuration (api keys, port numbers, ...) I've had very good luck with the gcfg package. It is based on the git config format.

From the documentation:

Sample config:

; Comment line
[section]
name = value # Another comment
flag # implicit value for bool is true

Go struct:

type Config struct {
    Section struct {
            Name string
            Flag bool
    }
}

And the code needed to read it:

var cfg Config
err := gcfg.ReadFileInto(&cfg, "myconfig.gcfg")

It also supports slice values, so you can allow specifying a key multiple times and other nice features like that.

Solution 5 - Go

Just use standard go flags with iniflags.

go flags > go > import "flag" > var nFlag = flag.Int("n", 1234, "help message for flag n") >

iniflags >go >package main > >import ( > "flag" > ... > "github.com/vharitonsky/iniflags" > ... >) > >var ( > flag1 = flag.String("flag1", "default1", "Description1") > ... > flagN = flag.Int("flagN", 123, "DescriptionN") >) > >func main() { > iniflags.Parse() // use instead of flag.Parse() >} >

Standard go flags have the following benefits:

  • Idiomatic.
  • Easy to use. Flags can be easily added and scattered across arbitrary packages your project uses.
  • Flags have out-of-the-box support for default values and description.
  • Flags provide standard 'help' output with default values and description.

The only drawback standard go flags have - is management problems when the number of flags used in your app becomes too large.

Iniflags elegantly solves this problem: just modify two lines in your main package and it magically gains support for reading flag values from ini file. Flags from ini files can be overriden by passing new values in command-line.

See also https://groups.google.com/forum/#!topic/golang-nuts/TByzyPgoAQE for details.

Solution 6 - Go

I have started using Gcfg which uses Ini-like files. It's simple - if you want something simple, this is a good choice.

Here's the loading code I am using currently, which has default settings and allows command line flags (not shown) that override some of my config:

package util

import (
	"code.google.com/p/gcfg"
)

type Config struct {
	Port int
	Verbose bool
	AccessLog string
	ErrorLog string
	DbDriver string
	DbConnection string
	DbTblPrefix string
}

type configFile struct {
	Server Config
}

const defaultConfig = `
	[server]
	port = 8000
	verbose = false
	accessLog = -
	errorLog  = -
	dbDriver     = mysql
	dbConnection = testuser:TestPasswd9@/test
	dbTblPrefix  =
`

func LoadConfiguration(cfgFile string, port int, verbose bool) Config {
	var err error
	var cfg configFile

	if cfgFile != "" {
		err = gcfg.ReadFileInto(&cfg, cfgFile)
	} else {
		err = gcfg.ReadStringInto(&cfg, defaultConfig)
	}

	PanicOnError(err)

   	if port != 0 {
        cfg.Server.Port = port
	}
	if verbose {
        cfg.Server.Verbose = true
    }

	return cfg.Server
}

Solution 7 - Go

have a look at [gonfig][1]

// load
config, _ := gonfig.FromJson(myJsonFile)
// read with defaults
host, _ := config.GetString("service/host", "localhost")
port, _ := config.GetInt("service/port", 80)
test, _ := config.GetBool("service/testing", false)
rate, _ := config.GetFloat("service/rate", 0.0)
// parse section into target structure
config.GetAs("service/template", &template)

[1]: https://github.com/creamdog/gonfig "gonfig"

Solution 8 - Go

https://github.com/spf13/viper and https://github.com/zpatrick/go-config are a pretty good libraries for configuration files.

Solution 9 - Go

Use toml like this article Reading config files the Go way

Solution 10 - Go

I wrote a simple ini config library in golang.

https://github.com/c4pt0r/cfg

goroutine-safe, easy to use

package cfg
import (
    "testing"
)

func TestCfg(t *testing.T) {
    c := NewCfg("test.ini")
    if err := c.Load() ; err != nil {
        t.Error(err)
    }
    c.WriteInt("hello", 42)
    c.WriteString("hello1", "World")

    v, err := c.ReadInt("hello", 0)
    if err != nil || v != 42 {
        t.Error(err)
    }

    v1, err := c.ReadString("hello1", "")
    if err != nil || v1 != "World" {
        t.Error(err)
    }

    if err := c.Save(); err != nil {
        t.Error(err)
    }
}

===================Update=======================

Recently I need an INI parser with section support, and I write a simple package:

github.com/c4pt0r/cfg

u can parse INI like using "flag" package:

package main

import (
    "log"
    "github.com/c4pt0r/ini"
)

var conf = ini.NewConf("test.ini")

var (
    v1 = conf.String("section1", "field1", "v1")
    v2 = conf.Int("section1", "field2", 0)
)

func main() {
    conf.Parse()

    log.Println(*v1, *v2)
}

Solution 11 - Go

You might also be interested in go-libucl, a set of Go bindings for UCL, the Universal Configuration Language. UCL is a bit like JSON, but with better support for humans: it supports comments and human-readable constructs like SI multipliers (10k, 40M, etc.) and has a little bit less boilerplate (e.g., quotes around keys). It's actually pretty close to the nginx configuration file format, if you're already familiar with that.

Solution 12 - Go

I agree with nemo and I wrote a little tool to make it all real easy.

bitbucket.org/gotamer/cfg is a json configuration package

  • You define your config items in your application as a struct.
  • A json config file template from your struct is saved on the first run
  • You can save runtime modifications to the config

See doc.go for an example

Solution 13 - Go

I tried JSON. It worked. But I hate having to create the struct of the exact fields and types I might be setting. To me that was a pain. I noticed it was the method used by all the configuration options I could find. Maybe my background in dynamic languages makes me blind to the benefits of such verboseness. I made a new simple config file format, and a more dynamic-ish lib for reading it out.

https://github.com/chrisftw/ezconf

I am pretty new to the Go world, so it might not be the Go way. But it works, it is pretty quick, and super simple to use.

Pros
  • Super simple
  • Less code
Cons
  • No Arrays or Map types
  • Very flat file format
  • Non-standard conf files
  • Does have a little convention built-in, which I now if frowned upon in general in Go community. (Looks for config file in the config directory)

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestiontheglauberView Question on Stackoverflow
Solution 1 - GonemoView Answer on Stackoverflow
Solution 2 - GoBurntSushi5View Answer on Stackoverflow
Solution 3 - GoMicahView Answer on Stackoverflow
Solution 4 - GoAsk Bjørn HansenView Answer on Stackoverflow
Solution 5 - GovalyalaView Answer on Stackoverflow
Solution 6 - GoRick-777View Answer on Stackoverflow
Solution 7 - GoChristian WestmanView Answer on Stackoverflow
Solution 8 - GosurfeurXView Answer on Stackoverflow
Solution 9 - GoherodotView Answer on Stackoverflow
Solution 10 - Goc4pt0rView Answer on Stackoverflow
Solution 11 - GotromboneheroView Answer on Stackoverflow
Solution 12 - GoRoboTamerView Answer on Stackoverflow
Solution 13 - GochrisftwView Answer on Stackoverflow