Umgang mit der Konfiguration in Go [geschlossen]

284

Ich bin neu in der Go-Programmierung und frage mich: Was ist die bevorzugte Methode zum Behandeln von Konfigurationsparametern für ein Go-Programm (die Art von Dingen , für die man in anderen Kontexten Eigenschaftendateien oder INI- Dateien verwenden könnte )?

theglauber
quelle
Ich habe auch einen Golang-Nuss-Faden gestartet, der einige zusätzliche Ideen enthält.
Theglauber
2
Ich neige dazu, Shell-Skripte und Umgebungsvariablen zu verwenden.
Rechtsfalte
3
Ich widmete einen ganzen Blog-Beitrag Persistent Application Configuration In Go, in dem ich anhand von Beispielen für zwei der beliebtesten Formate erklärte, wie dies zu tun ist: json und YAML. Die Beispiele sind produktionsbereit.
Upitau
Nur zur Veranschaulichung gibt es HCL von HashiCorp, das Kommentare unterstützt und JSON- und UCL-kompatibel ist. github.com/hashicorp/hcl
Kaveh Shahbazian

Antworten:

244

Das JSON- Format hat bei mir ganz gut funktioniert. Die Standardbibliothek bietet Methoden zum Schreiben der eingerückten Datenstruktur, sodass sie gut lesbar ist.

Siehe auch diesen Golang-Muttern-Faden .

Die Vorteile von JSON sind, dass es ziemlich einfach zu analysieren und von Menschen lesbar / bearbeitbar ist, während Semantik für Listen und Zuordnungen angeboten wird (was sehr praktisch sein kann), was bei vielen Konfigurationsparsern vom Typ ini nicht der Fall ist.

Anwendungsbeispiel:

conf.json :

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

Programm zum Lesen der Konfiguration

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]
nemo
quelle
6
Es scheint, dass JSON die am wenigsten schlechte der aktuellen Alternativen ist. Ich habe mich mit Go-Yaml befasst und es ist eine tapfere Anstrengung, aber ich habe den Mangel an Dokumentation als Hinweis darauf genommen, dass ich woanders suchen sollte. goini scheint eine einfache und unkomplizierte Bibliothek für den Umgang mit Windows- INI- Dateien zu sein. Ein neues Format namens TOML wurde vorgeschlagen, hat aber auch Probleme . An dieser Stelle würde ich mich an JSON oder ini halten .
Theglauber
6
YAML unterstützt Kommentare, wenn Sie überall in der Konfigurationsdatei Notizen hinzufügen möchten.
Ivan Black
42
Für diejenigen, die dies lesen und diesen Weg gehen, ist Folgendes zu beachten: JSONs fehlende Kommentare machen es für eine vom Menschen verwendbare Konfigurationsdatei (imo) ungeeignet. Es handelt sich um ein Datenaustauschformat. Wenn Sie nicht mehr in der Lage sind, hilfreiche / beschreibende Kommentare in Konfigurationsdateien zu schreiben, kann dies die Wartbarkeit beeinträchtigen ("Warum ist diese Einstellung aktiviert?", "Was macht sie?", "Was sind gültige Werte dafür?") ?" etc).
Darian Moody
6
Ahhh - Ich habe das in meinem Code versucht und vergessen, die Strukturattribute mit Großbuchstaben zu definieren (nicht exportiert) - das hat mich eine Stunde meines Lebens gekostet. Vielleicht begehen andere den gleichen Fehler> seien Sie gewarnt; D
JohnGalt
6
Sie sollten wahrscheinlich defer file.Close()nach dem Überprüfen offen err
Gabriel
97

Eine weitere Option ist die Verwendung von TOML , einem INI-ähnlichen Format, das von Tom Preston-Werner erstellt wurde. Ich habe dafür einen Go-Parser erstellt , der ausführlich getestet wird . Sie können es wie andere hier vorgeschlagene Optionen verwenden. Zum Beispiel, wenn Sie diese TOML-Daten in habensomething.toml

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

Dann können Sie es mit so etwas in Ihr Go-Programm laden

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
}
BurntSushi5
quelle
18
Ich mag TOML, weil ich damit Kommentare zu Zeilenumbrüchen oder am Ende einer Zeilenkonfigurationseinstellung schreiben kann. Mit JSON kann ich das nicht machen.
Serggserg
Jedes Konfigurationsupdate erfordert eine Aktualisierung des Codes, was sehr ärgerlich ist.
Hywak
4
Jeder Ansatz zur Konfiguration funktioniert. Wie sonst würde Ihr Programm von der neuen Konfiguration erfahren?
BurntSushi5
@ BurntSushi5 Kann es zusätzliche Felder in der Toml-Datei geben, die dem Code egal sind? Ich meine, kann eine neuere Version der Konfigurationsdatei mit einer älteren Codeversion verwendet werden? In meinem Fall ist es in Ordnung, nicht verwendete Konfigurationsoptionen zu ignorieren.
user1952500
2
ich mag das. Gute Arbeit. Persönlich denke ich, dass es für Administratoren oder Kunden einfacher ist, eine TOML-Datei zu ändern als einen JSON.
Blndev
49

Viper ist ein Golang-Konfigurationsmanagementsystem, das mit JSON, YAML und TOML zusammenarbeitet. Es sieht ziemlich interessant aus.

Micah
quelle
1
Besonders geeignet für 12factor-Anwendungen 12factor.net
DerKnorr
Verwenden Sie gonfig für die JSON-Konfiguration in Go. github.com/eduardbcom/gonfig
Eduard Bondarenko
1
Benutze keine Viper, sie ist nicht threadsicher, was mich fast gefeuert hätte.
Igonejack
@igonejack Bitte geben Sie ein Beispiel an, wo Viper Sie gebissen hat.
Dr.eel
1
@ Dr.eel Versuchen Sie, viper.GetBool ("abc") und Viper.Set ("abc", false) in verschiedenen Goroutinen zu trennen.
Igonejack
44

Normalerweise verwende ich JSON für kompliziertere Datenstrukturen. Der Nachteil ist, dass Sie leicht eine Menge Code erhalten, um dem Benutzer mitzuteilen, wo der Fehler war, verschiedene Randfälle und was nicht.

Für die Basiskonfiguration (API-Schlüssel, Portnummern, ...) hatte ich sehr viel Glück mit dem gcfg- Paket. Es basiert auf dem Git-Konfigurationsformat.

Aus der Dokumentation:

Beispielkonfiguration:

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

Und der Code, der zum Lesen benötigt wird:

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

Es werden auch Slice-Werte unterstützt, sodass Sie die mehrfache Angabe eines Schlüssels und andere nützliche Funktionen wie diese zulassen können.

Fragen Sie Bjørn Hansen
quelle
4
Der ursprüngliche Autor von gcfg hat das Projekt abgebrochen und einen weiteren verwandten Sconf gestartet .
iwat
39

Verwenden Sie einfach Standard- Go-Flags mit Iniflags .

Standard-Go-Flags bieten folgende Vorteile:

  • Idiomatisch.
  • Einfach zu verwenden. Flags können einfach hinzugefügt und auf beliebige Pakete verteilt werden, die Ihr Projekt verwendet.
  • Flags unterstützen sofort Standardwerte und Beschreibungen.
  • Flags bieten eine Standard-Hilfeausgabe mit Standardwerten und einer Beschreibung.

Der einzige Nachteil, den Standard-Go-Flags haben, sind Verwaltungsprobleme, wenn die Anzahl der in Ihrer App verwendeten Flags zu groß wird.

Iniflags löst dieses Problem auf elegante Weise: Ändern Sie einfach zwei Zeilen in Ihrem Hauptpaket, und das Lesen von Flag-Werten aus der INI-Datei wird auf magische Weise unterstützt. Flags aus INI-Dateien können überschrieben werden, indem neue Werte in der Befehlszeile übergeben werden.

Weitere Informationen finden Sie unter https://groups.google.com/forum/#!topic/golang-nuts/TByzyPgoAQE .

Valyala
quelle
Ich habe angefangen, Flags für ein Projekt zu verwenden, an dem ich gearbeitet habe (mein erstes Golang-Projekt von Grund auf neu), aber ich frage mich, wie ich mit Dingen wie Tests umgehen soll. Dies ist beispielsweise ein API-Client, und ich würde gerne Flags verwenden, aber es scheint, als würde dies meine Tests überkomplizieren ( go testlässt mich keine Flags weitergeben), während eine Konfigurationsdatei dies nicht tun würde.
Zachaysan
Das Setzen von Flaggen aus Tests ist einfach:*FlagName = value
Steven Soroka
9
wäre sehr hilfreich, wenn es hier detaillierten Beispielcode gäbe, der ein funktionierendes Beispiel zeigt :)
zero_cool
Keine gute Idee, wenn Sie die Konfiguration mit anderen Anwendungen teilen müssen, die in einer anderen Sprache geschrieben sind.
Kirzilla
würde vorschlagen, pflags anstelle von Flags zu verwenden. pflags verwendet den Posix-Standard
Fjolnir Dvorak
12

Ich habe angefangen, Gcfg zu verwenden, das Ini-ähnliche Dateien verwendet. Es ist einfach - wenn Sie etwas Einfaches wollen, ist dies eine gute Wahl.

Hier ist der Ladecode, den ich derzeit verwende, der Standardeinstellungen hat und Befehlszeilenflags (nicht gezeigt) zulässt, die einige meiner Konfigurationen überschreiben:

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
}
Rick-777
quelle
2
Ist das nicht genau das, was Ask bereits erwähnt hat?
Nemo
8

schau dir gonfig an

// 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)
Christian Westman
quelle
Dieser ist gut, da ich nicht die gesamte Konfigurationsstruktur in go
thanhpk
5

Ich habe eine einfache Ini-Konfigurationsbibliothek in Golang geschrieben.

https://github.com/c4pt0r/cfg

Goroutine-sicher, einfach zu bedienen

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 ======================

Vor kurzem brauche ich einen INI-Parser mit Abschnittsunterstützung und schreibe ein einfaches Paket:

github.com/c4pt0r/cfg

Sie können INI wie mit dem "Flag" -Paket analysieren:

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)
}
c4pt0r
quelle
4

Vielleicht interessiert Sie auch go-libucl , eine Reihe von Go-Bindungen für UCL, die universelle Konfigurationssprache. UCL ist ein bisschen wie JSON, aber mit besserer Unterstützung für Menschen: Es unterstützt Kommentare und lesbare Konstrukte wie SI-Multiplikatoren (10k, 40M usw.) und hat ein bisschen weniger Boilerplate (z. B. Anführungszeichen um Schlüssel). Es kommt dem Format der Nginx-Konfigurationsdatei ziemlich nahe, wenn Sie damit bereits vertraut sind.

Posaunist
quelle
2

Ich stimme nemo zu und habe ein kleines Tool geschrieben, um alles wirklich einfach zu machen.

bitbucket.org/gotamer/cfg ist ein JSON- Konfigurationspaket

  • Sie definieren Ihre Konfigurationselemente in Ihrer Anwendung als Struktur.
  • Eine json-Konfigurationsdateivorlage aus Ihrer Struktur wird beim ersten Ausführen gespeichert
  • Sie können Laufzeitänderungen an der Konfiguration speichern

Ein Beispiel finden Sie unter doc.go

RoboTamer
quelle
1

Ich habe JSON ausprobiert. Es funktionierte. Aber ich hasse es, die Struktur der genauen Felder und Typen erstellen zu müssen, die ich möglicherweise einstelle. Für mich war das ein Schmerz. Ich bemerkte, dass dies die Methode war, die von allen Konfigurationsoptionen verwendet wurde, die ich finden konnte. Vielleicht macht mich mein Hintergrund in dynamischen Sprachen blind für die Vorteile einer solchen Ausführlichkeit. Ich habe ein neues einfaches Konfigurationsdateiformat und eine dynamischere Bibliothek zum Auslesen erstellt.

https://github.com/chrisftw/ezconf

Ich bin ziemlich neu in der Go-Welt, daher ist es möglicherweise nicht der Go-Weg. Aber es funktioniert, es ist ziemlich schnell und super einfach zu bedienen.

Vorteile

  • Super einfach
  • Weniger Code

Nachteile

  • Keine Arrays oder Map-Typen
  • Sehr flaches Dateiformat
  • Nicht standardmäßige conf-Dateien
  • Hat eine kleine Konvention eingebaut, die ich jetzt in der Go-Community generell verpönt habe. (Sucht nach Konfigurationsdatei im Konfigurationsverzeichnis)
chrisftw
quelle