Jak obsługiwać konfigurację w Go [zamknięte]

284

Jestem nowy w programowaniu Go i zastanawiam się: jaki jest preferowany sposób obsługi parametrów konfiguracyjnych programu Go (rodzaj rzeczy, do których można użyć plików właściwości lub plików ini , w innych kontekstach)?

theglauber
źródło
Zacząłem też od wątku golang-nuts, który ma kilka dodatkowych pomysłów.
theglauber
2
Zwykle używam skryptów powłoki i zmiennych środowiskowych.
prawej strony
3
Poświęciłem cały post na blogu Trwała konfiguracja aplikacji w Go, gdzie wyjaśniłem, jak to zrobić, z przykładami dla dwóch najpopularniejszych formatów: json i YAML. Przykłady są gotowe do produkcji.
upitau
Dla przypomnienia istnieje HCL od HashiCorp, który obsługuje komentarze i jest kompatybilny z JSON i UCL. github.com/hashicorp/hcl
Kaveh

Odpowiedzi:

244

JSON Format pracował dla mnie całkiem dobrze. Standardowa biblioteka oferuje metody zapisywania wciętej struktury danych, dzięki czemu jest dość czytelna.

Zobacz także ten wątek golang-nuts .

Zaletą JSON jest to, że jest on dość prosty do parsowania i jest czytelny / edytowalny przez człowieka, oferując jednocześnie semantykę list i odwzorowań (które mogą się bardzo przydać), czego nie ma w przypadku wielu parserów konfiguracji typu ini.

Przykładowe użycie:

conf.json :

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

Program do odczytu konfiguracji

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
źródło
6
Wygląda na to, że JSON jest najmniejszą z obecnych alternatyw. Zajrzałem do go-yaml i jest to dzielny wysiłek, ale wziąłem brak dokumentacji jako wskazówkę, że powinienem szukać gdzie indziej. goini wydaje się być prostą i łatwą biblioteką do obsługi plików ini Windows . Zaproponowano nowy format o nazwie TOML, ale ma on również problemy . W tym momencie trzymałbym się JSON lub ini .
theglauber
6
YAML obsługuje komentarze, jeśli chcesz dodawać notatki wszędzie w pliku konfiguracyjnym.
Ivan Black
42
Dla osób czytających to i idących tą drogą, uwaga: brak komentarzy JSON sprawia, że ​​nie nadaje się on do pliku konfiguracyjnego nadającego się do użytku przez człowieka (imo). Jest to format wymiany danych - może się okazać, że utrata możliwości pisania pomocnych / opisowych komentarzy w plikach konfiguracyjnych może zaszkodzić łatwości konserwacji („dlaczego to ustawienie jest aktywowane?”, „Co to robi?”, „Jakie są dla niego prawidłowe wartości? ? ”itp.).
Darian Moody
6
Ahhh - próbowałem tego w swoim kodzie i zapomniałem zdefiniować atrybuty struktury dużymi literami (nie eksportowane) - kosztowało mnie to godzinę życia. Być może inni popełniają ten sam błąd> ostrzeżony; D
JohnGalt
6
Prawdopodobnie powinieneś defer file.Close()po sprawdzeniu open err
Gabriel
97

Inną opcją jest użycie TOML , który jest formatem INI stworzonym przez Toma Prestona-Wernera. I wbudowany parser go za to , że jest intensywnie testowany . Możesz używać go tak jak innych proponowanych tutaj opcji. Na przykład, jeśli masz te dane TOML wsomething.toml

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

Następnie możesz załadować go do swojego programu Go za pomocą czegoś takiego

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
źródło
18
Lubię TOML, ponieważ pozwala mi pisać komentarze na nowej linii lub na końcu ustawienia konfiguracji linii. Nie mogę tego zrobić z JSON.
sergserg
Każda aktualizacja konfiguracji wymaga aktualizacji w kodzie, co jest bardzo denerwujące.
hywak
4
Każde podejście do konfiguracji działa. Jak inaczej twój program wiedziałby o nowej konfiguracji?
BurntSushi5
@ BurntSushi5 czy w pliku Toml mogą znajdować się dodatkowe pola, których nie obchodzi kod? Mam na myśli, czy nowszej wersji pliku konfiguracyjnego można używać ze starszą wersją kodu? W moim przypadku można zignorować nieużywane opcje konfiguracji.
user1952500
2
lubię to. Dobra robota. Osobiście uważam, że administratorom lub klientom łatwiej jest zmienić plik TOML niż JSON.
blndev
49

Viper to system zarządzania konfiguracją Golang, który współpracuje z JSON, YAML i TOML. Wygląda całkiem interesująco.

Micheasz
źródło
1
Szczególnie przydatne w aplikacjach 12
czynnikowych
Użyj gonfig do konfiguracji JSON w Go. github.com/eduardbcom/gonfig
Eduard Bondarenko
1
Nie używaj Vipera, nie jest wątkowo bezpieczny, co prawie mnie zwolniło.
igonejack
@igonejack Podaj przykład, gdzie Viper cię ugryzł?
Dr.eel
1
@ Dr.eel Wypróbuj osobne viper.GetBool („abc”) i Viper.Set („abc”, false) w różnych goroutine.
igonejack
44

Zazwyczaj używam JSON do bardziej skomplikowanych struktur danych. Minusem jest to, że z łatwością dostajesz sporo kodu, aby poinformować użytkownika, gdzie był błąd, różne przypadki krawędzi i co nie.

Do podstawowej konfiguracji (klucze API, numery portów, ...) miałem bardzo dużo szczęścia z pakietem gcfg . Opiera się na formacie git config.

Z dokumentacji:

Przykładowa konfiguracja:

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

Przejdź do struktury:

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

I kod potrzebny do odczytania:

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

Obsługuje także wartości wycinków, dzięki czemu możesz pozwolić na wielokrotne określanie klucza i inne podobne funkcje.

Zapytaj Bjørna Hansena
źródło
4
Pierwotny autor gcfg przerwał projekt i uruchomił kolejny powiązany sconf .
iwat
39

Wystarczy użyć standardowych flag go z tagami iniflag .

Standardowe flagi go mają następujące zalety:

  • Idiomatyczny.
  • Łatwy w użyciu. Flagi można łatwo dodawać i rozrzucać między dowolnymi pakietami używanymi przez projekt.
  • Flagi mają gotową obsługę domyślnych wartości i opisu.
  • Flagi zapewniają standardowe wyjście „pomocy” z domyślnymi wartościami i opisem.

Jedyną wadą standardowych flag go są - problemy z zarządzaniem, gdy liczba flag używanych w aplikacji staje się zbyt duża.

Iniflags elegancko rozwiązuje ten problem: wystarczy zmodyfikować dwie linie w głównym pakiecie i uzyskuje magiczne wsparcie odczytu wartości flag z pliku ini. Flagi z plików ini można zastąpić, przekazując nowe wartości w wierszu polecenia.

Zobacz także https://groups.google.com/forum/#!topic/golang-nuts/TByzyPgoAQE, aby uzyskać szczegółowe informacje.

valyala
źródło
Zacząłem używać flag do projektu, nad którym pracowałem (mój pierwszy od podstaw projekt golang), ale zastanawiam się, jak radzić sobie z takimi rzeczami, jak testy? Na przykład jest to klient interfejsu API i chciałbym używać flag, ale wygląda na to, że skomplikowałoby to moje testowanie ( go testnie pozwala mi na przekazywanie flag), podczas gdy plik konfiguracyjny nie.
zachaysan
ustawianie flag z testów jest łatwe:*FlagName = value
Steven Soroka
9
byłby bardzo pomocny, gdyby był tutaj szczegółowy przykładowy kod pokazujący działający przykład :)
zero_cool
Nie jest to dobry pomysł, gdy trzeba współdzielić konfigurację z innymi aplikacjami napisanymi w innych językach.
Kirzilla
sugeruje użycie pflags zamiast flag. pflags używa standardu posix
Fjolnir Dvorak
12

Zacząłem używać Gcfg, który używa plików podobnych do Ini. To proste - jeśli chcesz czegoś prostego, to dobry wybór.

Oto kod ładujący, którego obecnie używam, który ma ustawienia domyślne i zezwala na flagi wiersza poleceń (nie pokazano), które zastępują niektóre ustawienia:

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
źródło
2
Czy to nie jest dokładnie to, o czym pytał już Ask?
nemo
8

spójrz na 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)
Christian Westman
źródło
Ten jest dobry, ponieważ nie muszę redefiniować całej struktury konfiguracji w go
thanhpk
5

Napisałem prostą bibliotekę konfiguracji ini w golang.

https://github.com/c4pt0r/cfg

bezpieczny dla goroutine, łatwy w użyciu

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

=================== Aktualizacja =======================

Ostatnio potrzebuję parsera INI z obsługą sekcji i piszę prosty pakiet:

github.com/c4pt0r/cfg

możesz parsować INI, np. używając pakietu „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)
}
c4pt0r
źródło
4

Możesz być także zainteresowany go-libucl , zestawem powiązań Go dla UCL, Universal Configuration Language. UCL jest trochę podobny do JSON, ale z lepszym wsparciem dla ludzi: obsługuje komentarze i konstrukcje czytelne dla człowieka, takie jak mnożniki SI (10k, 40M itp.), I ma nieco mniej płyt kotłowych (np. Cudzysłowy wokół klawiszy). W rzeczywistości jest całkiem zbliżony do formatu pliku konfiguracyjnego nginx, jeśli już go znasz.

puzon
źródło
2

Zgadzam się z nemo i napisałem małe narzędzie, aby wszystko było naprawdę łatwe.

bitbucket.org/gotamer/cfg to pakiet konfiguracyjny json

  • Definiujesz elementy konfiguracji w aplikacji jako struct.
  • Szablon pliku konfiguracyjnego json z Twojej struktury jest zapisywany przy pierwszym uruchomieniu
  • Możesz zapisać modyfikacje środowiska wykonawczego w konfiguracji

Przykład: doc.go

RoboTamer
źródło
1

Próbowałem JSON. Zadziałało. Ale nienawidzę konieczności tworzenia struktury dokładnych pól i typów, które mogę ustawić. Dla mnie to był ból. Zauważyłem, że była to metoda używana przez wszystkie opcje konfiguracji, jakie mogłem znaleźć. Być może moje doświadczenie w dynamicznych językach sprawia, że ​​jestem ślepy na zalety takiej gadatliwości. Stworzyłem nowy prosty format pliku konfiguracyjnego i bardziej dynamiczną bibliotekę do odczytu.

https://github.com/chrisftw/ezconf

Jestem całkiem nowy w świecie Go, więc może to nie być droga Go. Ale to działa, jest dość szybki i bardzo prosty w użyciu.

Plusy

  • Super proste
  • Mniej kodu

Cons

  • Brak typów tablic lub map
  • Bardzo płaski format pliku
  • Niestandardowe pliki conf
  • Ma wbudowaną małą konwencję, której teraz sprzeciwiam się ogólnie w społeczności Go. (Szuka pliku konfiguracyjnego w katalogu config)
chrisftw
źródło