Come gestire la configurazione in Go [chiuso]


284

Sono nuovo nella programmazione Go e mi chiedo: qual è il modo preferito di gestire i parametri di configurazione per un programma Go (il tipo di cose per cui si potrebbero usare i file delle proprietà o i file ini , in altri contesti)?


Ho anche iniziato un thread di noci di Golang che ha alcune idee aggiuntive.
theglauber,

2
Tendo a usare script di shell e variabili di ambiente.
destra

3
Ho dedicato un intero post sul blog Persisting Application Configuration In Go, dove ho spiegato come farlo con esempi per due formati più popolari: json e YAML. Gli esempi sono pronti per la produzione.
upitau,

Solo per la cronaca c'è HCL di HashiCorp che supporta i commenti ed è compatibile con JSON e UCL. github.com/hashicorp/hcl
Kaveh Shahbazian

Risposte:


244

Il formato JSON ha funzionato abbastanza bene per me. La libreria standard offre metodi per scrivere la struttura dei dati rientrata, quindi è abbastanza leggibile.

Vedi anche questa discussione sulle noci di Golang .

I vantaggi di JSON sono che è abbastanza semplice da analizzare e leggibile / modificabile dall'uomo mentre offre semantica per elenchi e mappature (che possono diventare abbastanza utili), il che non è il caso di molti parser di configurazione di tipo ini.

Esempio di utilizzo:

conf.json :

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

Programma per leggere la configurazione

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
Sembra che JSON sia la meno cattiva delle attuali alternative. Ho esaminato il go-yaml ed è uno sforzo coraggioso, ma ho preso la mancanza di documentazione come un'indicazione che dovrei cercare altrove. goini sembra essere una libreria semplice e facile da gestire ini file di Windows . È stato proposto un nuovo formato chiamato TOML, ma presenta anche problemi . A questo punto mi atterrei a JSON o INI .
theglauber,

6
YAML supporta i commenti, se si desidera aggiungere note ovunque nel file di configurazione.
Ivan Black,

43
Per coloro che leggono questo e seguono questa strada, attenzione: la mancanza di commenti di JSON lo rende inadatto per un file di configurazione utilizzabile dall'uomo (imo). È un formato di interscambio di dati: potresti perdere la possibilità di scrivere commenti utili / descrittivi nei file di configurazione e compromettere la manutenibilità ("perché questa impostazione è attivata?", "Cosa fa?", "Quali sono i valori validi per essa ?" eccetera).
Darian Moody,

6
Ahhh - l'ho provato nel mio codice e ho dimenticato di definire gli attributi struct con lettere maiuscole (non esportate) - questo mi è costato un'ora della mia vita. Forse altri commettono lo stesso errore> attenzione: D
JohnGalt

6
Probabilmente dovresti defer file.Close()dopo aver verificato open err
Gabriel

97

Un'altra opzione è usare TOML , che è un formato simile a INI creato da Tom Preston-Werner. Ho creato un parser Go per questo che è ampiamente testato . Puoi usarlo come altre opzioni proposte qui. Ad esempio, se si dispone di questi dati TOML insomething.toml

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

Quindi puoi caricarlo nel tuo programma Go con qualcosa di simile

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
Mi piace TOML perché mi consente di scrivere commenti su newline o alla fine di un'impostazione di configurazione di riga. Non posso farlo con JSON.
sergserg,

Ogni aggiornamento di configurazione richiede l'aggiornamento nel codice che è molto fastidioso.
hywak,

4
Ogni approccio alla configurazione lo fa. In quale altro modo il tuo programma sarebbe a conoscenza della nuova configurazione?
BurntSushi5,

@ BurntSushi5 ci possono essere campi aggiuntivi nel file Toml che non interessano al codice? Voglio dire, è possibile utilizzare una versione più recente del file di configurazione con una versione precedente del codice? Va bene nel mio caso ignorare le opzioni di configurazione non utilizzate.
user1952500

2
mi piace. Buon lavoro. Personalmente penso che sia più facile per gli amministratori o i clienti cambiare un file TOML che un JSON.
blndev,

49

Viper è un sistema di gestione della configurazione Golang che funziona con JSON, YAML e TOML. Sembra piuttosto interessante.


1
Particolarmente praticabile per le applicazioni 12factor 12factor.net
DerKnorr,

Usa gonfig per la configurazione JSON in Go. github.com/eduardbcom/gonfig
Eduard Bondarenko il

1
Non usare Viper, non è thread-safe che mi ha quasi licenziato.
igonejack,

@igonejack Fornisci un esempio dove ti ha morso Viper?
Dr.eel,

1
@ Dr.eel Prova a separare viper.GetBool ("abc") e Viper.Set ("abc", false) in diverse goroutine.
igonejack,

44

Di solito uso JSON per strutture di dati più complicate. Il rovescio della medaglia è che si finisce facilmente con un mucchio di codice per dire all'utente dove si trovava l'errore, vari casi limite e cosa no.

Per la configurazione di base (chiavi API, numeri di porta, ...) ho avuto molta fortuna con il pacchetto gcfg . Si basa sul formato di configurazione git.

Dalla documentazione:

Configurazione di esempio:

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

Vai strutt:

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

E il codice necessario per leggerlo:

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

Supporta anche i valori di sezione, quindi puoi consentire di specificare una chiave più volte e altre belle funzioni come questa.


4
L'autore originale di gcfg ha interrotto il progetto e ne ha iniziato un'altra sconfitta .
Iwat,

39

Usa solo go-flag standard con iniflags .

I go-flag standard offrono i seguenti vantaggi:

  • Idiomatico.
  • Facile da usare. Le bandiere possono essere facilmente aggiunte e sparse tra i pacchetti arbitrari utilizzati dal progetto.
  • I flag hanno un supporto immediato per i valori e la descrizione predefiniti.
  • I flag forniscono un output standard di "guida" con valori e descrizione predefiniti.

L'unico svantaggio di go go standard presenta: sono i problemi di gestione quando il numero di flag utilizzati nella tua app diventa troppo grande.

Iniflags risolve elegantemente questo problema: basta modificare due righe nel pacchetto principale e ottiene magicamente supporto per la lettura dei valori dei flag dal file ini. I flag dei file ini possono essere sostituiti passando nuovi valori nella riga di comando.

Vedi anche https://groups.google.com/forum/#!topic/golang-nuts/TByzyPgoAQE per i dettagli.


Ho iniziato a usare le bandiere per un progetto a cui stavo lavorando (il mio primo progetto Golang da zero), ma mi chiedo come gestire cose come i test? Ad esempio, questo è un client API e mi piacerebbe usare i flag, ma sembra che complicherebbe eccessivamente i miei test ( go testnon mi lascia passare i flag) mentre un file di configurazione non lo farebbe.
Zachaysan,

impostare le bandiere dai test è facile:*FlagName = value
Steven Soroka,

9
sarebbe molto utile se qui ci fosse un codice di esempio dettagliato che mostra un esempio funzionante :)
zero_cool

Non è una buona idea quando è necessario condividere la configurazione con altre applicazioni scritte in altre lingue.
Kirzilla,

suggerirei di usare pflags invece di flags. pflags sta usando lo standard
posix

12

Ho iniziato a usare Gcfg che utilizza file simili a Ini. È semplice: se vuoi qualcosa di semplice, questa è una buona scelta.

Ecco il codice di caricamento che sto utilizzando attualmente, che ha le impostazioni predefinite e consente i flag della riga di comando (non mostrati) che sostituiscono alcune delle mie configurazioni:

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
Non è esattamente quello che Ask ha già menzionato?
nemo,

8

dai un'occhiata 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)

Questo è buono, dal momento che non devo ridefinire l'intera struttura di configurazione in go
thanhpk



5

Ho scritto una semplice libreria di configurazione in Golang.

https://github.com/c4pt0r/cfg

goroutine-sicuro, facile da usare

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

=================== Aggiornamento =======================

Di recente ho bisogno di un parser INI con supporto di sezione e scrivo un pacchetto semplice:

github.com/c4pt0r/cfg

puoi analizzare INI come usare il pacchetto "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

Potresti anche essere interessato a go-libucl , una serie di collegamenti Go per UCL, Universal Configuration Language. UCL è un po 'come JSON, ma con un migliore supporto per l'uomo: supporta commenti e costrutti leggibili dall'uomo come moltiplicatori SI (10k, 40M, ecc.) E ha un po' meno plateplate (ad esempio, virgolette attorno alle chiavi). In realtà è abbastanza vicino al formato del file di configurazione nginx, se lo conosci già.


2

Sono d'accordo con nemo e ho scritto un piccolo strumento per rendere tutto molto semplice.

bitbucket.org/gotamer/cfg è un pacchetto di configurazione json

  • Definisci i tuoi elementi di configurazione nella tua applicazione come una struttura.
  • Un modello di file di configurazione json dalla struttura viene salvato alla prima esecuzione
  • È possibile salvare le modifiche di runtime nella configurazione

Vedi doc.go per un esempio


1

Ho provato JSON. Ha funzionato. Ma odio dover creare la struttura dei campi e dei tipi esatti che potrei impostare. Per me è stato un dolore. Ho notato che era il metodo utilizzato da tutte le opzioni di configurazione che sono riuscito a trovare. Forse il mio background in linguaggi dinamici mi rende cieco ai benefici di tale verbosità. Ho creato un nuovo formato di file di configurazione semplice e una lib più dinamica per leggerlo.

https://github.com/chrisftw/ezconf

Sono abbastanza nuovo nel mondo Go, quindi potrebbe non essere il modo Go. Ma funziona, è abbastanza veloce e super semplice da usare.

Professionisti

  • Super semplice
  • Meno codice

Contro

  • Nessun array o tipi di mappa
  • Formato file molto piatto
  • File di configurazione non standard
  • Ha una piccola convenzione incorporata, che ora ho disapprovato in generale nella comunità Go. (Cerca il file di configurazione nella directory di configurazione)
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.