Comment gérer la configuration dans Go [fermé]

284

Je suis nouveau dans la programmation Go, et je me demande: quelle est la meilleure façon de gérer les paramètres de configuration d'un programme Go (le genre de choses que l'on pourrait utiliser pour les fichiers de propriétés ou les fichiers ini , dans d'autres contextes)?

theglauber
la source
J'ai également commencé un fil de noix de golang qui a quelques idées supplémentaires.
theglauber
2
J'ai tendance à utiliser des scripts shell et des variables d'environnement.
droite le
3
J'ai consacré un article de blog entier Persisting Application Configuration In Go où j'ai expliqué comment le faire avec des exemples pour les deux formats les plus populaires: json et YAML. Les exemples sont prêts pour la production.
upitau
Pour mémoire, il y a HCL de HashiCorp qui prend en charge les commentaires et est compatible JSON et UCL. github.com/hashicorp/hcl
Kaveh Shahbazian

Réponses:

244

Le format JSON a très bien fonctionné pour moi. La bibliothèque standard propose des méthodes pour écrire la structure de données en retrait, elle est donc assez lisible.

Voir aussi ce fil écrou golang .

Les avantages de JSON sont qu'il est assez simple à analyser et lisible / modifiable par l'homme tout en offrant une sémantique pour les listes et les mappages (qui peut devenir très pratique), ce qui n'est pas le cas avec de nombreux analyseurs de configuration de type ini.

Exemple d'utilisation:

conf.json :

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

Programme pour lire la configuration

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
la source
6
Il semble que JSON soit la moins mauvaise des alternatives actuelles. J'ai examiné go-yaml et c'est un vaillant effort, mais j'ai pris le manque de documentation comme une indication que je devrais chercher ailleurs. goini semble être une bibliothèque simple et facile pour gérer les fichiers ini de Windows . Un nouveau format appelé TOML a été proposé, mais il présente également des problèmes . À ce stade, je m'en tiendrai à JSON ou ini .
theglauber
6
YAML prend en charge les commentaires, si vous souhaitez ajouter des notes partout dans le fichier de configuration.
Ivan Black
43
Pour ceux qui lisent ceci et empruntent cette voie, méfiez-vous: le manque de commentaires de JSON le rend inapproprié pour un fichier de configuration utilisable par l'homme (imo). Il s'agit d'un format d'échange de données - la perte de la possibilité d'écrire des commentaires utiles / descriptifs dans les fichiers de configuration peut nuire à la maintenabilité («pourquoi ce paramètre est-il activé?», «Que fait-il?», «Quelles sont les valeurs valides pour celui-ci ?" etc).
Darian Moody
6
Ahhh - J'ai essayé cela dans mon code et j'ai oublié de définir les attributs struct avec des lettres majuscules (non exportées) - cela m'a coûté une heure de ma vie. Peut-être que d'autres commettent la même erreur> soyez averti; D
JohnGalt
6
Vous devriez probablement defer file.Close()après avoir vérifié l'erreur ouverte
Gabriel
97

Une autre option consiste à utiliser TOML , qui est un format de type INI créé par Tom Preston-Werner. J'ai construit un analyseur Go pour lui qui est largement testé . Vous pouvez l'utiliser comme les autres options proposées ici. Par exemple, si vous avez ces données TOML danssomething.toml

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

Ensuite, vous pouvez le charger dans votre programme Go avec quelque chose comme

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
la source
18
J'aime TOML car il me permet d'écrire des commentaires sur les nouvelles lignes ou à la fin d'un paramètre de configuration de ligne. Je ne peux pas faire ça avec JSON.
sergserg
Chaque mise à jour de la configuration nécessite une mise à jour du code, ce qui est très ennuyeux.
hywak
4
Chaque approche de la configuration le fait. Sinon, comment votre programme serait-il au courant de la nouvelle configuration?
BurntSushi5
@ BurntSushi5 peut-il y avoir des champs supplémentaires dans le fichier Toml dont le code ne se soucie pas? Je veux dire, une version plus récente du fichier de configuration peut-elle être utilisée avec une version plus ancienne du code? C'est correct dans mon cas d'ignorer les options de configuration inutilisées.
user1952500
2
je l'aime. Bon travail. Personnellement, je pense qu'il est plus facile pour les administrateurs ou les clients de modifier un fichier TOML qu'un JSON.
blndev
49

Viper est un système de gestion de configuration golang qui fonctionne avec JSON, YAML et TOML. Ça a l'air assez intéressant.

Michée
la source
1
Particulièrement viable pour les applications 12factor 12factor.net
DerKnorr
Utilisez gonfig pour la configuration JSON dans Go. github.com/eduardbcom/gonfig
Eduard Bondarenko
1
N'utilisez pas Viper, ce n'est pas thread-safe qui m'a presque viré.
igonejack
@igonejack Veuillez fournir un exemple où Viper vous a mordu?
Dr.eel
1
@ Dr.eel Essayez séparément viper.GetBool ("abc") et Viper.Set ("abc", false) dans différents goroutine.
igonejack
44

J'utilise généralement JSON pour des structures de données plus complexes. L'inconvénient est que vous vous retrouvez facilement avec un tas de code pour dire à l'utilisateur où était l'erreur, divers cas marginaux et ce qui ne l'est pas.

Pour la configuration de base (clés api, numéros de port, ...) j'ai eu beaucoup de chance avec le paquet gcfg . Il est basé sur le format git config.

De la documentation:

Exemple de configuration:

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

Allez struct:

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

Et le code nécessaire pour le lire:

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

Il prend également en charge les valeurs de tranche, vous pouvez donc permettre de spécifier plusieurs fois une clé et d'autres fonctionnalités intéressantes comme celle-ci.

Poser une question à Bjørn Hansen
la source
4
L'auteur original de gcfg a interrompu le projet et a commencé un autre sconf connexe .
iwat
39

Utilisez simplement des drapeaux go standard avec des iniflags .

Les drapeaux go standard ont les avantages suivants:

  • Idiomatique.
  • Facile à utiliser. Les indicateurs peuvent être facilement ajoutés et dispersés dans des packages arbitraires utilisés par votre projet.
  • Les indicateurs ont une prise en charge prête à l'emploi pour les valeurs et la description par défaut.
  • Les indicateurs fournissent une sortie d'aide standard avec des valeurs et une description par défaut.

Le seul inconvénient des drapeaux go standard est: les problèmes de gestion lorsque le nombre de drapeaux utilisés dans votre application devient trop important.

Iniflags résout ce problème avec élégance: il suffit de modifier deux lignes dans votre package principal et il prend comme par magie la prise en charge de la lecture des valeurs d'indicateur à partir du fichier ini. Les indicateurs des fichiers ini peuvent être remplacés en passant de nouvelles valeurs en ligne de commande.

Voir également https://groups.google.com/forum/#!topic/golang-nuts/TByzyPgoAQE pour plus de détails.

valyala
la source
J'ai commencé à utiliser des indicateurs pour un projet sur lequel je travaillais (mon premier projet golang à partir de zéro), mais je me demande comment gérer des choses comme les tests? Par exemple, il s'agit d'un client api, et j'aimerais utiliser des indicateurs, mais il semble que cela compliquerait trop mes tests ( go testne me laisse pas passer les indicateurs), contrairement à un fichier de configuration.
zachaysan
définir des drapeaux à partir des tests est facile:*FlagName = value
Steven Soroka
9
serait très utile s'il y avait un exemple de code détaillé ici montrant un exemple de travail :)
zero_cool
Ce n'est pas une bonne idée lorsque vous devez partager la configuration avec d'autres éléments d'application écrits dans une autre langue.
Kirzilla
suggérerait d'utiliser pflags au lieu de flags. pflags utilise la norme posix
Fjolnir Dvorak
12

J'ai commencé à utiliser Gcfg qui utilise des fichiers de type Ini. C'est simple - si vous voulez quelque chose de simple, c'est un bon choix.

Voici le code de chargement que j'utilise actuellement, qui a des paramètres par défaut et permet des indicateurs de ligne de commande (non affichés) qui remplacent une partie de ma configuration:

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
la source
2
N'est-ce pas exactement ce que Ask a déjà mentionné?
nemo
8

jetez un oeil à 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
la source
Celui-ci est bon, car je n'ai pas à redéfinir toute la structure de la configuration dans go
thanhpk
5

J'ai écrit une simple bibliothèque de configuration ini dans golang.

https://github.com/c4pt0r/cfg

sans danger pour la goroutine, facile à utiliser

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

=================== Mise à jour ========================

Récemment, j'ai besoin d'un analyseur INI avec support de section, et j'écris un package simple:

github.com/c4pt0r/cfg

vous pouvez analyser INI comme utiliser le package "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
la source
4

Vous pourriez également être intéressé par go-libucl , un ensemble de liaisons Go pour UCL, Universal Configuration Language. UCL est un peu comme JSON, mais avec un meilleur support pour les humains: il prend en charge les commentaires et les constructions lisibles par l'homme comme les multiplicateurs SI (10k, 40M, etc.) et a un peu moins de passe-partout (par exemple, les guillemets autour des clés). Il est en fait assez proche du format de fichier de configuration nginx, si vous le connaissez déjà.

trombonehero
la source
2

Je suis d'accord avec nemo et j'ai écrit un petit outil pour que tout soit vraiment simple.

bitbucket.org/gotamer/cfg est un package de configuration json

  • Vous définissez vos éléments de configuration dans votre application comme une structure.
  • Un modèle de fichier de configuration json de votre structure est enregistré lors de la première exécution
  • Vous pouvez enregistrer les modifications d'exécution de la configuration

Voir doc.go pour un exemple

RoboTamer
la source
1

J'ai essayé JSON. Ça a marché. Mais je déteste devoir créer la structure des champs et types exacts que je pourrais définir. Pour moi, c'était une douleur. J'ai remarqué que c'était la méthode utilisée par toutes les options de configuration que je pouvais trouver. Peut-être que mon expérience dans les langues dynamiques me rend aveugle aux avantages d'une telle verbosité. J'ai fait un nouveau format de fichier de configuration simple, et une bibliothèque plus dynamique pour le lire.

https://github.com/chrisftw/ezconf

Je suis assez nouveau dans le monde du Go, donc ce n'est peut-être pas le chemin du Go. Mais cela fonctionne, il est assez rapide et super simple à utiliser.

Avantages

  • Super simple
  • Moins de code

Les inconvénients

  • Aucun tableau ni type de carte
  • Format de fichier très plat
  • Fichiers de conf non standard
  • A une petite convention intégrée, que je désapprouve maintenant en général dans la communauté Go. (Recherche le fichier de configuration dans le répertoire de configuration)
chrisftw
la source