如何在Go中处理配置

the*_*ber 281 configuration-files go

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

nem*_*emo 241

JSON格式为我工作得很好.标准库提供了以缩进方式编写数据结构的方法,因此它非常易读.

另见这个golang-nuts线程.

JSON的好处是,在为列表和映射提供语义(这可能变得非常方便)时,解析和人类可读/可编辑相当简单,而许多ini类型的配置解析器则不然.

用法示例:

conf.json:

{
    "Users": ["UserA","UserB"],
    "Groups": ["GroupA"]
}
Run Code Online (Sandbox Code Playgroud)

程序读取配置

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]
Run Code Online (Sandbox Code Playgroud)

  • 对于阅读此内容并沿着该路线行进的人,请注意:JSON缺少注释使其不适合人类可用的配置文件(imo).它是一种数据交换格式 - 您可能会发现丢失在配置文件中编写有用/描述性注释的能力会损害可维护性("为什么激活此设置?","它做什么?","它的有效值是什么?" ?"等等. (37认同)
  • 似乎JSON是当前替代品中最不好的.我调查了go-yaml这是一个英勇的努力,但我缺乏文档作为我应该寻找其他地方的迹象.[goini](https://github.com/glacjay/goini)似乎是一个简单易用的库来处理Windows _ini_文件.已经提出了一种名为TOML的新格式,但它[有问题](https://news.ycombinator.com/item?id=5272634).此时我会坚持使用JSON或_ini_. (6认同)
  • 如果要在配置文件中的任何位置添加注释,YAML支持注释. (6认同)
  • 你可能应该在检查打开err后推迟file.Close()` (6认同)
  • 啊 - 我在我的代码中尝试过,忘了用大写字母定义结构属性(不导出) - 这花了我一生的时间.也许其他人犯同样的错误>被警告; D. (5认同)
  • @theglauber Yaml在可读性方面非常适合配置文件但不易出错(例如,制表符与空格)并且似乎很难解析.很像XML,除了它甚至不提供可读性:).但是,如果您对Yaml感兴趣,可能需要使用[go-yaml](http://code.google.com/p/goyaml/). (2认同)
  • @theglauber,理论上,yaml是[json的超集](http://yaml.org/spec/1.2/spec.html#id2759572). (2认同)
  • 延迟file.Close()!! (2认同)
  • 如果需要向 json 文件添加注释,只需将它们添加为 field:desc 条目,并在导入时忽略它。例如,您可以有一个名为 {notes:["note1","note2"]} 的字段 (2认同)

Bur*_*hi5 94

另一种选择是使用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
Run Code Online (Sandbox Code Playgroud)

然后你可以把它加载到你的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
}
Run Code Online (Sandbox Code Playgroud)

  • 我喜欢TOML,因为它允许我在换行符或行配置设置结束时写注释.我不能用JSON做到这一点. (18认同)
  • 配置的每一种方法都有.你的程序怎么会知道新的配置? (3认同)
  • 我喜欢。辛苦了 我个人认为管理员或客户更改TOML文件比JSON更容易。 (2认同)

Mic*_*cah 47

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

  • 您的配置可能应该在程序开始时加载,然后将值传递给您的依赖项。在单独的 goroutine 中加载配置可能是错误的方法。我永远不会期望配置加载库可以安全地并发使用。 (5认同)
  • 不要使用 Viper,它不是线程安全的,这几乎解雇了我。 (3认同)
  • 特别适用于 12factor 应用程序 https://12factor.net/ (2认同)

Ask*_*sen 44

我通常使用JSON来处理更复杂的数据结构.缺点是你很容易得到一堆代码来告诉用户错误的位置,各种边缘情况以及什么不是.

对于基本配置(api键,端口号,......)我对gcfg包非常好运.它基于git配置格式.

从文档:

示例配置:

; Comment line
[section]
name = value # Another comment
flag # implicit value for bool is true
Run Code Online (Sandbox Code Playgroud)

结构:

type Config struct {
    Section struct {
            Name string
            Flag bool
    }
}
Run Code Online (Sandbox Code Playgroud)

并且代码需要阅读它:

var cfg Config
err := gcfg.ReadFileInto(&cfg, "myconfig.gcfg")
Run Code Online (Sandbox Code Playgroud)

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

  • [gcfg](https://code.google.com/p/gcfg/)的原作者停止了该项目并启动了另一个相关的[sconf](https://github.com/sconf/sconf). (2认同)

val*_*ala 39

只需使用带有iniflags的标准go标志.

标准手旗有以下好处:

  • 成语.
  • 使用方便.标志可以轻松添加并分散到项目使用的任意包中.
  • 标志具有对默认值和描述的开箱即用支持.
  • 标志提供带有默认值和描述的标准"帮助"输出.

标准go标志的唯一缺点是 - 当您的应用程序中使用的标志数量变得太大时,管理问题.

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

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

  • 如果这里有详细的示例代码显示一个工作示例:)会非常有用:) (9认同)

Ric*_*777 12

我已经开始使用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
}
Run Code Online (Sandbox Code Playgroud)

  • 这不是Ask提到的吗? (2认同)

Chr*_*man 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)
Run Code Online (Sandbox Code Playgroud)


sur*_*urX 7

https://github.com/spf13/viperhttps://github.com/zpatrick/go-config是一个非常好的配置文件库.

  • Viper + Cobra是一个强大的组合. (3认同)

c4p*_*t0r 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)
    }
}
Run Code Online (Sandbox Code Playgroud)

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

最近,我需要具有部分支持的INI解析器,并且编写了一个简单的程序包:

github.com/c4pt0r/cfg
Run Code Online (Sandbox Code Playgroud)

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