如何在Go中处理配置

huangapple go评论82阅读模式
英文:

How to handle configuration in Go

问题

什么是处理Go程序的配置参数的首选方法(在其他情境中可能会使用属性文件或ini文件的东西)?

英文:

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)?

答案1

得分: 273

JSON 格式对我来说非常有效。标准库提供了将数据结构缩进写入的方法,因此非常易读。

另请参阅golang-nuts线程

JSON的好处是它相当简单解析和人类可读/可编辑,同时提供了列表和映射的语义(这可能非常方便),而许多ini类型的配置解析器则不具备这种功能。

示例用法:

conf.json:

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

读取配置的程序

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) // 输出: [UserA, UserB]
英文:

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]

答案2

得分: 112

另一个选择是使用TOML,这是由Tom Preston-Werner创建的类似INI的格式。我为它构建了一个Go解析器,并进行了广泛的测试。您可以像其他在这里提出的选项一样使用它。例如,如果您有这个TOML数据在something.toml中:

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

然后您可以像这样将其加载到您的Go程序中:

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 {
    // 处理错误
}
英文:

Another option is to use TOML, which is an INI-like format created by Tom Preston-Werner. I built a Go parser for it that is extensively tested. 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

答案3

得分: 62

Viper是一个与JSON、YAML和TOML一起使用的Go语言配置管理系统。它看起来非常有趣。

英文:

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

答案4

得分: 51

我通常使用JSON来处理更复杂的数据结构。缺点是你很容易就会得到一堆代码,用来告诉用户错误出现在哪里,各种边界情况等等。

对于基本配置(API密钥,端口号等),我使用gcfg包非常好用。它基于git配置格式。

从文档中可以看到:

示例配置:

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

Go结构体:

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

读取配置文件所需的代码:

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

它还支持切片值,因此您可以允许多次指定一个键和其他一些很好的功能。

英文:

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.

答案5

得分: 46

只需使用标准的go flagsiniflags

go flags

import "flag"
var nFlag = flag.Int("n", 1234, "flag n的帮助信息")

iniflags

package main

import (
	"flag"
	...
	"github.com/vharitonsky/iniflags"
	...
)

var (
	flag1 = flag.String("flag1", "default1", "描述1")
	...
	flagN = flag.Int("flagN", 123, "描述N")
)

func main() {
	iniflags.Parse()  // 使用iniflags.Parse()代替flag.Parse()
}

标准的go flags具有以下优点:

  • 符合惯用法。
  • 使用简单。可以轻松地在项目使用的任意包中添加和分散标志。
  • 标志具有默认值和描述的开箱即用的支持。
  • 标志提供带有默认值和描述的标准“帮助”输出。

标准的go flags唯一的缺点是,在应用程序中使用的标志数量过多时会出现管理问题。

Iniflags优雅地解决了这个问题:只需修改主包中的两行代码,它就会神奇地支持从ini文件中读取标志值。可以通过在命令行中传递新值来覆盖ini文件中的标志值。

有关详细信息,请参阅https://groups.google.com/forum/#!topic/golang-nuts/TByzyPgoAQE。

英文:

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.

答案6

得分: 13

我已经开始使用Gcfg,它使用类似Ini的文件。它很简单 - 如果你想要简单的东西,这是一个不错的选择。

这是我目前正在使用的加载代码,它具有默认设置,并允许命令行标志(未显示)覆盖一些配置:

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
}
英文:

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
}

答案7

得分: 12

看一下gonfig

// 加载
config, _ := gonfig.FromJson(myJsonFile)
// 带默认值读取
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)
// 将部分解析到目标结构体中
config.GetAs("service/template", &template)
英文:

have a look at gonfig

// 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"

答案8

得分: 10

https://github.com/spf13/viperhttps://github.com/zpatrick/go-config 是用于配置文件的相当不错的库。

英文:

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

答案9

得分: 7

使用toml就像这篇文章以Go的方式读取配置文件中所示。

英文:

Use toml like this article Reading config files the Go way

答案10

得分: 5

我在golang中编写了一个简单的ini配置库。

https://github.com/c4pt0r/cfg

支持goroutine安全,易于使用

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)
    }
}

===================更新=======================

最近我需要一个支持分节的INI解析器,于是我写了一个简单的包:

github.com/c4pt0r/cfg

你可以像使用“flag”包一样解析INI:

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)
}
英文:

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)
}

答案11

得分: 4

你可能也对go-libucl感兴趣,它是用于UCL(通用配置语言)的Go绑定集。UCL有点像JSON,但对人类的支持更好:它支持注释和可读性更强的结构,如SI倍增器(10k、40M等),并且有一些较少的样板代码(例如,键周围的引号)。如果你已经熟悉nginx的配置文件格式,它实际上与之非常接近。

英文:

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.

答案12

得分: 2

我同意nemo的观点,并且我写了一个小工具来使这一切变得非常容易。

bitbucket.org/gotamer/cfg 是一个json配置包

  • 你可以在你的应用程序中将配置项定义为一个结构体。
  • 在第一次运行时,会将结构体转换为一个json配置文件模板进行保存。
  • 你可以保存运行时对配置的修改。

请参考doc.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

答案13

得分: 1

我尝试了JSON。它有效。但是我讨厌不得不创建可能设置的确切字段和类型的结构。对我来说,那是一种痛苦。我注意到这是我能找到的所有配置选项使用的方法。也许我在动态语言方面的背景使我对这种冗长的好处视而不见。我创建了一种新的简单配置文件格式,并为其编写了一个更具动态性的库来读取它。

https://github.com/chrisftw/ezconf

我对Go世界还不太熟悉,所以可能不是Go的方式。但它有效,速度相当快,使用起来非常简单。

优点

  • 非常简单
  • 代码量少

缺点

  • 没有数组或映射类型
  • 非常扁平的文件格式
  • 非标准的配置文件
  • 确实有一些内置的约定,这在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)

huangapple
  • 本文由 发表于 2013年5月9日 23:41:12
  • 转载请务必保留本文链接:https://go.coder-hub.com/16465705.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定