Skip to content

Viper

Repository-Adresse: spf13/viper: Go configuration with fangs (github.com)

Dokumentations-Adresse: spf13/viper: Go configuration with fangs (github.com)

TIP

Die offizielle Seite diskutiert derzeit den Übergang zu Viper2. Weitere Informationen finden Sie unter: Viper2

Installation

go get github.com/spf13/viper

Einführung

Viper ist eine vollständige Konfigurationsdatei-Lösung für Go-Anwendungen. Es kann fast alle Arten von Konfigurationsanforderungen und -formaten verarbeiten und erleichtert die Verwaltung von Projektkonfigurationsdateien. Es verfügt über folgende Funktionen:

  • Standardwerteinstellung
  • Unterstützte Formate: JSON, TOML, YAML, HCL, envfile, Java properties
  • Echtzeit-Überwachung und Neuladen von Konfigurationsdateien
  • Lesen aus Umgebungsvariablen
  • Lesen von Konfigurationen aus Remote-Konfigurationssystemen und Überwachen von Änderungen
  • Lesen von Kommandozeilen-Flags
  • Lesen aus Puffern
  • Explizites Setzen von Werten

Offiziell behauptet Viper, alle Anforderungen an Anwendungskonfigurationen erfüllen zu können. Entwickler müssen sich nur auf den Bau der Anwendung konzentrieren, während Viper die Konfigurationsverwaltung übernimmt. Viele bekannte Projekte verwenden Viper:

DANGER

Viper ist nicht für die Ver- und Entschlüsselung von Konfigurationsdateien verantwortlich, d.h. es führt keine Sicherheitsbehandlungen für Konfigurationsdateien durch.

Lesereihenfolge

Viper verwendet folgende Priorität zum Lesen der Konfiguration:

  1. Explizit gesetzte Werte
  2. Kommandozeilen-Flags
  3. Umgebungsvariablen
  4. Konfigurationsdateien
  5. Schlüsselwert-Speicher
  6. Standardwerte

TIP

Die Schlüssel in der Viper-Konfiguration unterscheiden nicht zwischen Groß- und Kleinschreibung. In zukünftigen Diskussionen könnte dies optional gemacht werden.

Standardwerte

Ein gutes Konfigurationssystem sollte die Einstellung von Standardwerten unterstützen. Obwohl dies nicht immer notwendig ist, ist es sehr nützlich, wenn keine Konfigurationsdatei gesetzt ist. Hier ist ein Beispiel:

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

Lesen von Konfigurationsdateien

Viper benötigt nur sehr wenig Konfiguration, um zu wissen, wo nach Konfigurationsdateien gesucht werden soll. Viper unterstützt JSON-, TOML-, YAML-, HCL-, INI-, envfile- und JavaProperties-Dateien. Viper kann mehrere Pfade gleichzeitig durchsuchen, aber derzeit unterstützt eine einzelne Viper-Instanz nur eine einzelne Konfigurationsdatei. Viper setzt keinen Standardpfad für die Konfigurationssuche und überlässt die Standardentscheidung der Anwendung.

Hier ist ein Beispiel für die Verwendung von Viper zum Lesen einer Konfigurationsdatei. Es ist nicht notwendig, einen vollständigen Pfad anzugeben, aber beim Verwenden sollte mindestens eine Konfigurationsdatei bereitgestellt werden.

go
func TestReadConfigFile(t *testing.T) {
   viper.SetConfigName("config.yml") // Liest eine Konfigurationsdatei namens config, ohne bestimmte Dateierweiterung
   viper.SetConfigType("yaml")       // Wenn keine bestimmte Dateierweiterung gesetzt ist, muss der Dateityp angegeben werden
   viper.AddConfigPath("./")         // Suche im aktuellen Ordner
   viper.AddConfigPath("$HOME/")     // Verwende Variable
   viper.AddConfigPath(".")          // Suche im Arbeitsverzeichnis
   err := viper.ReadInConfig() // Konfiguration lesen
   if err != nil {
      log.Fatalln(err)
   }
}

Es kann auch separat der Fall behandelt werden, dass die Konfigurationsdatei nicht gefunden wurde:

go
if err := viper.ReadInConfig(); err != nil {
  if _, ok := err.(viper.ConfigFileNotFoundError); ok {
    // Konfigurationsdatei nicht gefunden
  } else {
    // Andere Arten von Fehlern
  }
}

Hier sind alle Funktionen zum Zugriff auf die Konfiguration:

  • 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{}

Beim Zugriff auf verschachtelte Konfigurationen wird der .-Trennzeichen verwendet, zum Beispiel:

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

Kann über GetString("server.database.url") auf die Verschachtelung zugegriffen werden.

Schreiben von Konfigurationsdateien

Viper bietet eine Reihe von Funktionen, um Entwicklern das Schreiben von Laufzeitkonfigurationen in Konfigurationsdateien zu erleichtern.

go
// WriteConfig schreibt die Konfiguration in die ursprüngliche Konfigurationsdatei, Fehler wenn nicht vorhanden, überschreibt wenn vorhanden
func WriteConfig() error { return v.WriteConfig() }

// SafeWriteConfig schreibt die Konfiguration sicher in die ursprüngliche Konfigurationsdatei, erstellt wenn nicht vorhanden, überschreibt nicht wenn vorhanden
func SafeWriteConfig() error { return v.SafeWriteConfig() }

// WriteConfigAs schreibt die aktuelle Konfiguration in die angegebene Datei, Fehler wenn Datei nicht vorhanden, überschreibt wenn vorhanden
func WriteConfigAs(filename string) error { return v.WriteConfigAs(filename) }

// SafeWriteConfigAs Wenn die angegebene Datei existiert, wird die ursprüngliche Konfigurationsdatei nicht überschrieben, gibt Fehler zurück wenn Datei existiert
func SafeWriteConfigAs(filename string) error { return v.SafeWriteConfigAs(filename) }

Hier sind einige Beispiele:

go
func TestWritingConfig(t *testing.T) {
   viper.WriteConfig() // Schreibt Konfiguration in die ursprüngliche Konfigurationsdatei, diese sollten zuvor durch 'viper.AddConfigPath()' und 'viper.SetConfigName' definiert sein
   viper.SafeWriteConfig()
   viper.WriteConfigAs("/path/to/my/.config")
   viper.SafeWriteConfigAs("/path/to/my/.config") // Gibt Fehler zurück, da die angegebene Datei existiert
   viper.SafeWriteConfigAs("/path/to/my/.other_config")
}

Überwachung und Neuladen der Konfiguration

Viper ermöglicht es Anwendungen, zur Laufzeit dynamisch eine Konfigurationsdatei zu lesen, d.h. ohne Neustart der Anwendung werden aktualisierte Konfigurationen wirksam, ohne ein einziges Änderungsdetail zu verpassen. Sie müssen lediglich der Viper-Instanz mitteilen, die Konfigurationsänderungen zu überwachen, oder Sie können eine Funktion bereitstellen, die bei jeder Änderung ausgeführt wird.

go
func TestWatchingConfig(t *testing.T) {
  viper.OnConfigChange(func(e fsnotify.Event) {
    fmt.Println("Konfigurationsdatei wurde geändert:", e.Name)
  })
  viper.WatchConfig()
}

Aliase

go
func TestAliases(t *testing.T) {
   viper.RegisterAlias("a", "b")
   viper.Set("a", 1)
   viper.Set("b", 2) // Wird die Konfiguration von a überschreiben
   fmt.Println(viper.GetInt("a"))
}

Extrahieren von Unterstrukturen

Zuvor wurde erwähnt, dass über den .-Trennzeichen auf verschachtelte Konfigurationen zugegriffen werden kann. Tatsächlich kann auch die Funktion viper.Sub() verwendet werden, um Unterstrukturen zu extrahieren. Der Rückgabewert ist eine Viper-Instanz, wie im folgenden Beispiel:

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 { // Gibt nil zurück wenn nicht vorhanden
  panic("cache1 Konfiguration existiert nicht")
}

Festlegen des Verschachtelungstrennzeichens

Wenn der angegebene Schlüssel . enthält, muss ein anderes Trennzeichen manuell festgelegt werden, um Fehlinterpretationen zu vermeiden, zum Beispiel:

go
viper.KeyDelimiter("/") // Setzt das Trennzeichen auf /

Deserialisierung

Viper bietet zwei Funktionen, um die Konfiguration in eine Struktur oder Map zu deserialisieren, was ebenfalls verschachtelte Strukturen unterstützt:

  • 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("Kann nicht in Struktur deserialisieren, %v", err)
}

Serialisierung

Serialisiert die aktuelle Konfiguration in einen String in einem bestimmten Format, um sie in einer Konfigurationsdatei zu speichern. Normalerweise werden JSON, TOML, YAML, HCL, envfile und Java properties unterstützt.

TIP

Viper unterstützt auch benutzerdefinierte Serialisierungsformate: 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("Kann Konfiguration nicht als YAML serialisieren: %v", err)
  }
  return string(bs)
}

Mehrere Instanzen

Normalerweise reicht die von Viper bereitgestellte globale Instanz aus. Da jedoch eine Instanz nur eine Konfigurationsdatei abbilden kann, können Sie mehrere Instanzen selbst erstellen, um weitere Operationen durchzuführen, zum Beispiel:

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

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

//...

Golang by www.golangdev.cn edit