Skip to content

Viper

Adresse du dépôt : spf13/viper: Go configuration with fangs (github.com)

Adresse de la documentation : spf13/viper: Go configuration with fangs (github.com)

TIP

L'équipe officielle discute actuellement d'une transition vers Viper2, pour en savoir plus : Viper2

Installation

go get github.com/spf13/viper

Introduction

Viper est une solution complète de fichiers de configuration pour les applications Go, capable de gérer presque tous les types de besoins et formats de configuration, facilitant la gestion des fichiers de configuration de projet. Il possède les caractéristiques suivantes :

  • Définition de valeurs par défaut
  • Support des formats JSON, TOML, YAML, HCL, envfile, Java properties
  • Support de la surveillance en temps réel et du rechargement des fichiers de configuration
  • Support de la lecture depuis les variables d'environnement
  • Support de la lecture de configuration depuis des systèmes de configuration distants et surveillance des changements
  • Support de la lecture des indicateurs de ligne de commande
  • Support de la lecture depuis un tampon
  • Support de la définition explicite de valeurs

L'équipe officielle affirme que Viper peut répondre à tous les besoins de configuration d'applications. Les développeurs peuvent se concentrer sur la construction de l'application, laissant Viper gérer la configuration. De nombreux projets connus utilisent Viper

DANGER

Viper ne gère pas le chiffrement et le déchiffrement des fichiers de configuration, c'est-à-dire qu'il n'effectue aucun traitement de sécurité sur les fichiers de configuration.

Ordre de lecture

Viper utilise l'ordre de priorité suivant pour lire la configuration :

  1. Définition explicite de valeurs
  2. Indicateurs de ligne de commande
  3. Variables d'environnement
  4. Fichier de configuration
  5. Stockage clé-valeur
  6. Valeurs par défaut

TIP

Les clés dans la configuration Viper ne sont pas sensibles à la casse, les discussions futures pourraient rendre cela optionnel.

Valeurs par défaut

Un bon système de configuration devrait supporter la définition de valeurs par défaut. Bien que cela ne soit pas toujours nécessaire, cela s'avère très utile lorsqu'aucun fichier de configuration n'est défini. Voici un exemple :

go
viper.SetDefault("filePath","./dir/img/usr")
viper.SetDefault("root","123456")

Lecture des fichiers de configuration

Viper nécessite très peu de configuration pour savoir où chercher les fichiers de configuration. Viper supporte les fichiers JSON, TOML, YAML, HCL, INI, envfile et JavaProperties. Viper peut rechercher dans plusieurs chemins simultanément, mais une seule instance de Viper ne supporte actuellement qu'un seul fichier de configuration. Viper ne définit pas de chemin de recherche par défaut, laissant ce choix à l'application.

Voici un exemple d'utilisation de Viper pour lire un fichier de configuration. Il n'est pas nécessaire de spécifier un chemin complet, mais au moins un fichier de configuration doit être fourni.

go
func TestReadConfigFile(t *testing.T) {
   viper.SetConfigName("config.yml") // Lit le fichier de configuration nommé config, sans extension spécifique
   viper.SetConfigType("yaml")       // Lorsque l'extension n'est pas spécifiée, le type de fichier doit être précisé
   viper.AddConfigPath("./")         // Recherche dans le dossier courant
   viper.AddConfigPath("$HOME/")     // Utilise une variable
   viper.AddConfigPath(".")          // Recherche dans le répertoire de travail
   err := viper.ReadInConfig() // Lit la configuration
   if err != nil {
      log.Fatalln(err)
   }
}

Il est également possible de traiter séparément le cas où le fichier de configuration n'est pas trouvé

go
if err := viper.ReadInConfig(); err != nil {
  if _, ok := err.(viper.ConfigFileNotFoundError); ok {
    // Fichier de configuration non trouvé
  } else {
    // Autre type d'erreur
  }
}

Voici toutes les fonctions pour accéder à la configuration

  • Get(key string) : interface{}
  • GetBool(key string) : bool
  • GetFloat64(key string) : float64
  • GetInt(key string) : int
  • GetIntSlice(key string) : []int
  • GetString(key string) : string
  • GetStringMap(key string) : map[string]interface{}
  • GetStringMapString(key string) : map[string]string
  • GetStringSlice(key string) : []string
  • GetTime(key string) : time.Time
  • GetDuration(key string) : time.Duration
  • IsSet(key string) : bool
  • AllSettings() : map[string]interface{}

Pour accéder aux configurations imbriquées, utilisez le séparateur ., par exemple :

{
  "server":{
    "database":{
      "url": "mysql...."
    }
  }
}

Vous pouvez utiliser GetString("server.database.url") pour un accès imbriqué

Écriture des fichiers de configuration

Viper fournit une série de fonctions pour faciliter l'écriture de la configuration stockée en runtime dans des fichiers de configuration.

go
// WriteConfig écrit la configuration dans le fichier de configuration original, retourne une erreur si inexistant, écrase s'il existe
func WriteConfig() error { return v.WriteConfig() }

// SafeWriteConfig écrit la configuration de manière sécurisée dans le fichier original, crée si inexistant, n'écrase pas s'il existe
func SafeWriteConfig() error { return v.SafeWriteConfig() }

// WriteConfigAs écrit la configuration actuelle dans le fichier spécifié, retourne une erreur si le fichier n'existe pas, écrase s'il existe
func WriteConfigAs(filename string) error { return v.WriteConfigAs(filename) }

// SafeWriteConfigAs si le fichier spécifié existe, n'écrasera pas le fichier de configuration original, retourne une erreur s'il existe
func SafeWriteConfigAs(filename string) error { return v.SafeWriteConfigAs(filename) }

Voici quelques exemples :

go
func TestWritingConfig(t *testing.T) {
   viper.WriteConfig() // Écrit la configuration dans le fichier original, ces fichiers doivent être définis au préalable par 'viper.AddConfigPath()' et 'viper.SetConfigName'
   viper.SafeWriteConfig()
   viper.WriteConfigAs("/path/to/my/.config")
   viper.SafeWriteConfigAs("/path/to/my/.config") // Retourne une erreur car le fichier spécifié existe
   viper.SafeWriteConfigAs("/path/to/my/.other_config")
}

Surveillance et rechargement de configuration

Viper permet aux applications de lire dynamiquement un fichier de configuration en runtime, c'est-à-dire sans redémarrer l'application pour que la configuration mise à jour prenne effet, sans manquer aucun détail de changement. Il suffit de dire à l'instance Viper de surveiller les changements de configuration, ou vous pouvez fournir une fonction à viper pour qu'elle s'exécute à chaque changement.

go
func TestWatchingConfig(t *testing.T) {
  viper.OnConfigChange(func(e fsnotify.Event) {
    fmt.Println("Le fichier de configuration a été modifié:", e.Name)
  })
  viper.WatchConfig()
}

Alias

go
func TestAliases(t *testing.T) {
   viper.RegisterAlias("a", "b")
   viper.Set("a", 1)
   viper.Set("b", 2) // Écrasera la configuration de a
   fmt.Println(viper.GetInt("a"))
}

Extraction de sous-structures

Nous avons mentionné précédemment l'accès aux configurations imbriquées via le séparateur .. Vous pouvez également utiliser la fonction viper.Sub() pour extraire une sous-structure. La valeur de retour est une instance Viper, comme dans l'exemple suivant :

yaml
cache:
  cache1:
    max-items: 100
    item-size: 64
  cache2:
    max-items: 200
    item-size: 80
go
cache1Config := viper.Sub("cache.cache1")
if cache1Config == nil { // Retourne nil si inexistant
  panic("La configuration cache1 n'existe pas")
}

Définition du séparateur d'imbrication

Lorsque vous souhaitez spécifier une clé contenant un ., vous devez manuellement spécifier un autre séparateur pour éviter les erreurs d'analyse, par exemple :

go
viper.KeyDelimiter("/") // Définit le séparateur sur /

Désérialisation

Viper fournit deux fonctions pour désérialiser la configuration dans une structure ou une map, supportant également les structures imbriquées :

  • Unmarshal(rawVal interface{}) : error
  • UnmarshalKey(key string, rawVal interface{}) : error
go
type config struct {
  Port int
  Name string
  PathMap string `mapstructure:"path_map"`
}

var C config

err := viper.Unmarshal(&C)
if err != nil {
  t.Fatalf("Impossible de désérialiser en structure, %v", err)
}

Sérialisation

Sérialise la configuration actuelle dans une chaîne selon un format spécifique pour l'enregistrer dans un fichier de configuration. Supporte généralement JSON, TOML, YAML, HCL, envfile, Java properties.

TIP

Viper supporte également les formats de sérialisation personnalisés, Decoding custom formats with Viper - Márk Sági-Kazár (sagikazarmark.hu)

go
import (
  yaml "gopkg.in/yaml.v2"
  // ...
)

func yamlStringSettings() string {
  c := viper.AllSettings()
  bs, err := yaml.Marshal(c)
  if err != nil {
    log.Fatalf("Impossible de sérialiser la configuration en YAML: %v", err)
  }
  return string(bs)
}

Instances multiples

En général, l'instance globale fournie par Viper est suffisante, mais comme une instance ne peut mapper qu'un seul fichier de configuration, vous pouvez créer plusieurs instances pour effectuer plus d'opérations, par exemple :

go
x := viper.New()
y := viper.New()

x.SetDefault("ContentDir", "content")
y.SetDefault("ContentDir", "foobar")

//...

Golang by www.golangdev.cn edit