Cómo manejar la configuración en Ir [cerrado]


284

Soy nuevo en la programación de Go y me pregunto: ¿cuál es la forma preferida de manejar los parámetros de configuración para un programa Go (el tipo de cosas para las que uno podría usar archivos de propiedades o archivos ini , en otros contextos)?


También comencé un hilo de nueces de golang que tiene algunas ideas adicionales.
theglauber

2
Tiendo a usar scripts de shell y variables de entorno.
derecha el

3
Dediqué toda una publicación de blog Persisting Application Configuration In Go donde expliqué cómo hacerlo con ejemplos para los dos formatos más populares: json y YAML. Los ejemplos están listos para la producción.
upitau

Solo para el registro hay HCL de HashiCorp que admite comentarios y es compatible con JSON y UCL. github.com/hashicorp/hcl
Kaveh Shahbazian

Respuestas:


244

El formato JSON me funcionó bastante bien. La biblioteca estándar ofrece métodos para escribir la estructura de datos con sangría, por lo que es bastante legible.

Vea también este hilo de nueces de golang .

Los beneficios de JSON son que es bastante simple de analizar y que se puede leer / editar por humanos, al tiempo que ofrece semántica para listas y mapeos (que puede ser bastante útil), que no es el caso con muchos analizadores de configuración de tipo ini.

Ejemplo de uso:

conf.json :

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

Programa para leer la configuración

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]

66
Parece que JSON es la menos mala de las alternativas actuales. Miré en go-yaml y es un esfuerzo valiente, pero tomé la falta de documentación como una indicación de que debería buscar en otro lado. Goini parece ser una biblioteca simple y fácil de manejar archivos ini de Windows . Se ha propuesto un nuevo formato llamado TOML, pero también tiene problemas . En este punto, me quedaría con JSON o ini .
theglauber

66
YAML admite comentarios, si desea agregar notas en todas partes en el archivo de configuración.
Ivan Black

42
Para aquellos que lean esto y sigan ese camino, tengan cuidado: la falta de comentarios de JSON lo hace inadecuado para un archivo de configuración utilizable por humanos (imo). Es un formato de intercambio de datos: es posible que perder la capacidad de escribir comentarios útiles / descriptivos en los archivos de configuración pueda dañar la capacidad de mantenimiento ("¿por qué está activada esta configuración?", "¿Qué hace?", "¿Cuáles son los valores válidos para ella? ? ", etc.)
Darian Moody

66
Ahhh, lo intenté en mi código y olvidé definir los atributos de la estructura con letras mayúsculas (no exportadas), esto me costó una hora de mi vida. Tal vez otros cometan el mismo error> se advirtió; D
JohnGalt

66
Probablemente deberías defer file.Close()después de comprobar abrir err
Gabriel

97

Otra opción es usar TOML , que es un formato similar a INI creado por Tom Preston-Werner. Yo construí un analizador Vaya para él que está ampliamente probado . Puede usarlo como otras opciones propuestas aquí. Por ejemplo, si tiene estos datos TOML ensomething.toml

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

Luego puede cargarlo en su programa Go con algo como

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
Me gusta TOML porque me permite escribir comentarios en líneas nuevas o al final de una configuración de configuración de línea. No puedo hacer eso con JSON.
sergserg

Cada actualización de configuración requiere una actualización en el código, lo que es muy molesto.
hywak

44
Cada acercamiento a la configuración lo hace. ¿De qué otra manera su programa estaría al tanto de la nueva configuración?
BurntSushi5

@ BurntSushi5 ¿puede haber campos adicionales en el archivo Toml que no le importen al código? Quiero decir, ¿se puede usar una versión más nueva del archivo de configuración con una versión anterior del código? Está bien en mi caso ignorar las opciones de configuración no utilizadas.
user1952500

2
me gusta. Buen trabajo. Personalmente, creo que es más fácil para los administradores o clientes cambiar un archivo TOML que un JSON.
blndev

49

Viper es un sistema de gestión de configuración de golang que funciona con JSON, YAML y TOML. Se ve muy interesante.


1
Especialmente viable para aplicaciones de 12
DerKnorr

Use gonfig para la configuración JSON en Go. github.com/eduardbcom/gonfig
Eduard Bondarenko

1
No use Viper, no es seguro para subprocesos, lo que casi me despide.
igonejack

@igonejack Por favor, proporcione un ejemplo donde Viper te mordió?
Dr.eel

1
@ Dr.eel Intente separar viper.GetBool ("abc") y Viper.Set ("abc", falso) en diferentes goroutine.
igonejack

44

Usualmente uso JSON para estructuras de datos más complicadas. La desventaja es que fácilmente terminas con un montón de código para decirle al usuario dónde estuvo el error, varios casos extremos y qué no.

Para la configuración básica (claves API, números de puerto, ...) he tenido muy buena suerte con el gcfg paquete . Se basa en el formato de configuración de git.

De la documentación:

Configuración de muestra:

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

Y el código necesario para leerlo:

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

También admite valores de división, por lo que puede permitir especificar una clave varias veces y otras características agradables como esa.


44
El autor original de gcfg suspendió el proyecto y comenzó otro sconf relacionado .
iwat

39

Simplemente use las banderas de go estándar con iniflags .

Las banderas estándar go tienen los siguientes beneficios:

  • Idiomático.
  • Fácil de usar. Las banderas se pueden agregar y dispersar fácilmente en paquetes arbitrarios que utiliza su proyecto.
  • Los indicadores tienen compatibilidad inmediata con los valores y la descripción predeterminados.
  • Los indicadores proporcionan una salida de 'ayuda' estándar con valores y descripción predeterminados.

El único inconveniente que tienen las banderas de go estándar son los problemas de administración cuando la cantidad de banderas utilizadas en su aplicación es demasiado grande.

Iniflags resuelve este problema con elegancia: solo modifique dos líneas en su paquete principal y mágicamente obtendrá soporte para leer los valores del indicador desde el archivo ini. Las banderas de los archivos ini se pueden anular pasando nuevos valores en la línea de comandos.

Consulte también https://groups.google.com/forum/#!topic/golang-nuts/TByzyPgoAQE para más detalles.


Comencé a usar banderas para un proyecto en el que he estado trabajando (mi primer proyecto de Golang desde cero), pero me pregunto cómo manejar cosas como las pruebas. Por ejemplo, este es un cliente api, y me gustaría usar banderas, pero parece que complicaría demasiado mis pruebas ( go testno me deja pasar banderas) mientras que un archivo de configuración no lo haría.
zachaysan

configurar las banderas de las pruebas es fácil:*FlagName = value
Steven Soroka

9
sería muy útil si hubiera un código de ejemplo detallado aquí que muestre un ejemplo de trabajo :)
zero_cool

No es una buena idea cuando necesita compartir la configuración con otras aplicaciones escritas en otros idiomas.
Kirzilla

sugeriría usar pflags en lugar de banderas. pflags está utilizando el estándar posix
Fjolnir Dvorak

12

He empezado a usar Gcfg que usa archivos similares a Ini. Es simple: si quieres algo simple, esta es una buena opción.

Aquí está el código de carga que estoy usando actualmente, que tiene configuraciones predeterminadas y permite marcas de línea de comando (no mostradas) que anulan algunas de mis configuraciones:

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
¿No es esto exactamente lo que Ask ya mencionó?
nemo

8

echa un vistazo a 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)

Este es bueno, ya que no tengo que redefinir toda la estructura de configuración en go
thanhpk



5

Escribí una biblioteca simple de configuración ini en golang.

https://github.com/c4pt0r/cfg

seguro para la rutina, fácil de usar

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

=================== Actualización =======================

Recientemente necesito un analizador INI con soporte de sección, y escribo un paquete simple:

github.com/c4pt0r/cfg

puede analizar INI como si usara el paquete "flag":

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

También le puede interesar go-libucl , un conjunto de enlaces Go para UCL, el Lenguaje de configuración universal. UCL es un poco como JSON, pero con un mejor soporte para humanos: admite comentarios y construcciones legibles por humanos como multiplicadores SI (10k, 40M, etc.) y tiene un poco menos repetitivo (por ejemplo, comillas alrededor de las teclas). En realidad, está bastante cerca del formato de archivo de configuración nginx, si ya está familiarizado con eso.


2

Estoy de acuerdo con nemo y escribí una pequeña herramienta para que todo sea realmente fácil.

bitbucket.org/gotamer/cfg es un paquete de configuración json

  • Usted define sus elementos de configuración en su aplicación como una estructura.
  • Una plantilla de archivo de configuración json de su estructura se guarda en la primera ejecución
  • Puede guardar modificaciones de tiempo de ejecución en la configuración

Ver doc.go para un ejemplo


1

Intenté JSON. Funcionó. Pero odio tener que crear la estructura de los campos y tipos exactos que podría estar configurando. Para mí eso fue un dolor. Noté que era el método utilizado por todas las opciones de configuración que pude encontrar. Quizás mi experiencia en lenguajes dinámicos me deja ciego a los beneficios de tal verbosidad. Hice un nuevo formato de archivo de configuración simple y una biblioteca más dinámica para leerlo.

https://github.com/chrisftw/ezconf

Soy bastante nuevo en el mundo Go, por lo que podría no ser el camino Go. Pero funciona, es bastante rápido y súper simple de usar.

Pros

  • Super simple
  • Menos código

Contras

  • Sin matrices ni tipos de mapas
  • Formato de archivo muy plano
  • Archivos conf no estándar
  • Tiene una pequeña convención incorporada, que ahora estoy mal vista en general en la comunidad Go. (Busca el archivo de configuración en el directorio de configuración)
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.