如何在Go中处理配置


284

我是Go编程的新手,我想知道:处理Go程序的配置参数的首选方法是什么(在其他情况下,这种东西可能会使用属性文件或ini文件)?


我还启动了一个golang-nuts线程,其中包含一些其他想法。
2013年

2
我倾向于使用shell脚本和环境变量。
2015年

3
我在整篇博客文章Persisting Application Configuration In Go中专门介绍了如何使用两种最流行的格式(json和YAML)的示例进行说明。这些示例已准备就绪。
upitau

仅作记录,HashiCorp提供了HCL,它支持注释,并且与JSON和UCL兼容。github.com/hashicorp/hcl
Kaveh Shahbazian

Answers:


244

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) // output: [UserA, UserB]

6
看起来JSON是当前替代方法中最糟糕的。我调查了go-yaml,这是一个英勇的工作,但我认为缺乏文档说明我应该在其他地方使用。goini似乎是处理Windows ini文件的简单易用的库。已经提出了一种称为TOML的新格式,但是它也存在问题。在这一点上,我会坚持使用JSON或ini
13年

6
如果您想在配置文件中的任何地方添加注释,则YAML支持注释。
伊万·布莱克

42
对于那些阅读此书并沿这条路线走的人,请当心:JSON缺少注释使它不适用于人类可用的配置文件(imo)。它是一种数据交换格式-您可能会发现失去在配置文件中编写有用/描述性注释的能力会损害可维护性(“为什么激活此设置?”,“它会做什么?”,“什么是有效值”) ?”等)。
达里安·穆迪

6
啊-我在代码中尝试了此操作,却忘了用大写字母定义结构属性(不导出)-这花了我一个小时的时间。也许其他人也犯了同样的错误>被警告; D
JohnGalt

6
您可能应该defer file.Close()在检查过打开错误之后
Gabriel

97

另一种选择是使用TOML,它是Tom Preston-Werner创建的一种类似INI的格式。我专为一搏解析器广泛的测试。您可以像在此建议的其他选项一样使用它。例如,如果您有此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 {
    // handle error
}

18
我喜欢TOML,因为它使我可以在换行符或行设置设置的末尾写注释。我无法使用JSON做到这一点。
sergserg 2014年

每次配置更新都需要更新代码,这很烦人。
hywak

4
每种配置方法都可以。您的程序还如何知道新配置?
BurntSushi5

@ BurntSushi5 Toml文件中是否有代码不关心的其他字段?我的意思是,可以将较新版本的配置文件与较旧版本的代码一起使用吗?就我而言,可以忽略未使用的配置选项。
user1952500 '18

2
我喜欢。辛苦了 我个人认为管理员或客户更改TOML文件比JSON更容易。
blndev

49

Viper是可与JSON,YAML和TOML一起使用的golang配置管理系统。看起来很有趣。


1
特别适用于12factor应用程序12factor.net
DerKnorr

在Go中使用gonfig进行JSON配置。github.com/eduardbcom/gonfig
爱德华·邦达连科

1
不要使用Viper,它不是线程安全的,这几乎使我失望了。
igonejack

@igonejack请提供一个例子,说明Viper在哪里咬你?
Dr.eel

1
@ Dr.eel在不同的goroutine中尝试将viper.GetBool(“ abc”)和Viper.Set(“ abc”,false)分开。
igonejack

44

我通常将JSON用于更复杂的数据结构。不利的一面是,您很容易以一堆代码来告诉用户错误出在哪里,各种极端情况以及什么都不是。

对于基本配置(api键,端口号等),我对gcfg软件包非常满意。它基于git config格式。

从文档中:

样本配置:

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

转到struct:

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

和读取它所需的代码:

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

它还支持切片值,因此您可以允许多次指定键以及类似的其他好功能。


4
gcfg的原始作者中止了该项目,并启动了另一个相关的sconf
iwat 2015年

39

只需将标准go标志iniflags 一起使用即可

标准go标志具有以下优点:

  • 惯用的。
  • 易于使用。可以轻松添加标志并将其分散在项目使用的任意包中。
  • 标志具有默认值和说明的现成支持。
  • 标志提供带有默认值和描述的标准“帮助”输出。

标准go标志的唯一缺点是-当应用中使用的标志数量太大时,就会出现管理问题。

Iniflags很好地解决了这个问题:只需在主程序包中修改两行,即可神奇地获得从ini文件读取标志值的支持。可以通过在命令行中传递新值来覆盖ini文件中的标志。

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


我开始对我一直在从事的项目(我的第一个从头开始的golang项目)使用标志,但是我想知道如何处理测试之类的东西?例如,这是一个api客户端,我想使用标志,但是似乎go test配置文件不会使我的测试复杂化(不允许我传递标志)。
zachaysan,2015年

从测试设置标志很容易:*FlagName = value
史蒂文·索罗卡

9
如果这里有显示工作示例的详细示例代码,这将非常有帮助:)
zero_cool

当您需要与使用其他语言编写的其他应用程序共享配置时,这不是一个好主意。
Kirzilla

建议使用pflags而不是flags。pflags使用POSIX标准
Fjolnir Dvorak的

12

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

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

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
}

2
这难道不是问问已经提到的吗?
nemo

8

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

这个很好,因为我不必在go中重新定义整个配置结构
thanhpk



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

您可以像使用“标志”包那样解析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)
}

4

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


2

我同意nemo,并写了一个小工具来使一切变得简单。

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

  • 您可以在应用程序中将配置项定义为结构。
  • 您的结构中的json配置文件模板会在第一次运行时保存
  • 您可以将运行时修改保存到配置中

有关示例,请参见doc.go


1

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

https://github.com/chrisftw/ezconf

我对围棋世界还很陌生,因此可能不是围棋方式。但是它可以工作,非常快捷,而且使用起来超级简单。

优点

  • 超级简单
  • 更少的代码

缺点

  • 没有数组或地图类型
  • 非常平面的文件格式
  • 非标准配置文件
  • 确实有一些内置的约定,如果现在在Go社区中普遍不赞成,那么我现在不赞成这样做。(在config目录中查找配置文件)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.