github.com/spf 13/viper go viperパッケージ紹介

13152 ワード


Viperとは?
Viperは、12-Factorアプリケーションを含むGoアプリケーションの完全な構成ソリューションです.アプリケーションで作業し、すべてのタイプの構成要件とフォーマットを処理できるようにします.以下をサポートします.
  • デフォルト値
  • を設定
  • JSON,TOML,YAML,HCL,Javaプロパティプロファイルから
  • を読み込む
  • プロファイルをリアルタイムで表示/再読み込み(オプション)
  • 環境変数から
  • を読み出す.
  • リモート構成システム(etcdまたはConsul)から読み出し、変化
  • を観察する.
  • コマンドラインフラグから
  • を読み出す.
  • バッファから読み出す
  • .
  • 明示的な値
  • を設定する.
    Viperは、すべてのアプリケーション構成に必要なレジストリとみなすことができる.
    なぜViperを選んだのですか?
    現代のアプリケーションを構築する場合は、プロファイルのフォーマットを心配する必要はありません.素晴らしいソフトウェアの構築に専念したいです.Viperはこのために助けを提供しています.
    Viperは次のことをしました.
  • JSON、TOML、YAML、HCLまたはJava属性フォーマットで検索し、デモンストレーションプロファイルをロードします.
  • は、異なる構成オプションのデフォルト値を設定するメカニズムを提供する.
  • は、コマンドラインフラグによって指定されたオプションの上書き値を設定するメカニズムを提供する.
  • は、既存のコードを破壊することなく、パラメータの名前を簡単に変更する別名システムを提供します.
  • は、ユーザがコマンドラインまたはプロファイルをデフォルト値と同じ時間に提供することを容易に区別することができる.

  • Viperは以下の優先順位を使用します.各アイテムは、下のアイテムよりも優先されます.
     
    Viperを使用したデフォルトの設定
  • explicit call to Set
  • flag
  • env
  • config
  • key/value store
  • default
  • viper.SetDefault("ContentDir", "content")
    viper.SetDefault("LayoutDir", "layouts")
    viper.SetDefault("Taxonomies", map[string]string{"tag": "tags", "category": "categories"})

    Viper読み出しプロファイル
    Viperは最小限の構成が必要なので、プロファイルをどこで検索するか知っています.ViperはJSON、TOML、YAML、HCL、Java Propertiesファイルをサポートします.Viperは複数のパスを検索できますが、現在、単一のViperインスタンスでは単一のプロファイルのみがサポートされています.Viperはデフォルトで検索パスを使用するのではなく、デフォルト値の決定をアプリケーションに適用します.
    以下に、Viperを使用してプロファイルを検索および読み込みする方法の例を示します.特定のパスは必要ありませんが、予想されるプロファイルの場所に少なくとも1つのパスを指定してください.
     
    viper.SetConfigName("config") // name of config file (without extension)
    viper.AddConfigPath("/etc/appname/")   // path to look for the config file in
    viper.AddConfigPath("$HOME/.appname")  // call multiple times to add many search paths
    viper.AddConfigPath(".")               // optionally look for config in the working directory
    err := viper.ReadInConfig() // Find and read the config file
    if err != nil { // Handle errors reading the config file
    	panic(fmt.Errorf("Fatal error config file: %s 
    ", err)) }

    プロファイルのリスニングと再読み込み
    Viperは、実行時にアプリケーションにプロファイルをリアルタイムで読み込むことをサポートします.
    構成が有効になるまでサーバを再起動する必要があります.viperドライバのアプリケーションは、実行時に構成ファイルの更新を読み取ることができ、ビートを逃さないようにします.
    viperインスタンスwatchConfigを教えるだけです.変更が発生するたびに実行される機能をViperに提供するオプションがあります.
    呼び出し前にすべてのconfigPath WatchConfig()が追加されていることを確認します.
    viper.WatchConfig()
    viper.OnConfigChange(func(e fsnotify.Event) {
    	fmt.Println("Config file changed:", e.Name)
    })

    io.Reader読み取り構成
    Viperは、ファイル、環境変数、フラグ、リモートK/Vストレージなど、多くの構成ソースを事前に定義していますが、それらの制約を受けません.また、独自の必須構成ソースを実装し、viperに提供することもできます.
    viper.SetConfigType("yaml") //  viper.SetConfigType(“YAML”)
    //               
    var yamlExample = []byte(`
    Hacker: true
    name: steve
    hobbies:
    - skateboarding
    - snowboarding
    - go
    clothing:
      jacket: leather
      trousers: denim
    age: 35
    eyes : brown
    beard: true
    `)
    
    viper.ReadConfig(bytes.NewBuffer(yamlExample))
    
    viper.Get("name")

    Viper構成値の設定と上書き
    viper.Set("Verbose", true)
    viper.Set("LogFile", LogFile)

    Viper別名の登録と使用
    エイリアスでは、複数のキーが単一の値を参照できます.
    viper.RegisterAlias("loud", "Verbose")
    viper.Set("verbose", true) // same result as next line
    viper.Set("loud", true)   // same result as prior line
    
    viper.GetBool("loud") // true
    viper.GetBool("verbose") // true

    Viper環境変数の使用
    Viperは環境変数を完全にサポートしています.ENVを使用するには、次の4つの方法があります.
    AutomaticEnv()
    BindEnv(string...) : error
    SetEnvPrefix(string)
    SetEnvKeyReplacer(string...) *strings.Replacer
    BindEnvには1つまたは2つのパラメータが必要です.1番目のパラメータはキー名で、2番目は環境変数の名前です.環境変数の名前は大文字と小文字を区別します.ENV変数名が指定されていない場合、Viperは鍵名がENV変数名と一致すると自動的に仮定しますが、ENV変数はIN ALL CAPSです.ENV変数名を明示的に指定すると、接頭辞は自動的に追加されません.
    ENV変数を使用するときに認識すべき重要なことは、アクセスするたびに値が読み出されることです.この値は、BindEnv呼び出し時には修復されません.AutomaticEnvは、特に強力なヘルパーSetEnvPrefixと結合されている.呼び出されると、Viperは、viper.Getリクエストの発行時に環境変数をチェックします.次のルールが適用されます.環境変数が大文字のキーと一致し、EnvPrefix接頭辞でチェックされます.SetEnvKeyReplacerでは、strings.Replacerオブジェクトを使用してEnvキーをある程度書き換えることができます.このオプションは、-呼び出しでいくつかのコンテンツを使用または使用する場合に便利ですが、環境変数にGet()セパレータを使用する場合に便利です.使用例_を参照してください.viper_test.go
    SetEnvPrefix("spf")  //     
    BindEnv("id")
    os.Setenv("SPF_ID", "13") //          
    id := Get("id") // 13

    flagの使用
    Viperはflagにバインドできます.ENV のように、バインドメソッドを呼び出すと、この値は設定されません.これは、BindEnv関数でバインドすることもできます.
    単一のフラグの場合、init()メソッドはこの機能を提供する.
    serverCmd.Flags().Int("port", 1138, "Port to run Application server on")
    viper.BindPFlag("port", serverCmd.Flags().Lookup("port"))

    既存のpflags(pflag.FlagSet)のセットをバインドすることもできます.
    pflag.Int("flagname", 1234, "help message for flagname")
    
    pflag.Parse()
    viper.BindPFlags(pflag.CommandLine)
    
    i := viper.GetInt("flagname") 

     
    Viperでpflagを使用すると、標準ライブラリでフラグパッケージを使用する他のパッケージは除外されません.pflagパケットは、これらのフラグをインポートすることによって、フラグパケットとして定義されたフラグを処理することができる.これは、AddGoFlagSet()というpflagパッケージが提供する便利な関数を呼び出すことによって実現される.
    package main
    import (
    	"flag"
    	"github.com/spf13/pflag"
    )
    func main() {
    
    	// using standard library "flag" package
    	flag.Int("flagname", 1234, "help message for flagname")
    
    	pflag.CommandLine.AddGoFlagSet(flag.CommandLine)
    	pflag.Parse()
    	viper.BindPFlags(pflag.CommandLine)
    
    	i := viper.GetInt("flagname") // retrieve value from viper
    
    	...
    }

    flagインタフェース
    使用しない場合、Viperは2つのGoインタフェースを提供し、他のフラグシステムBindPFlag()をバインドします.Pflagsはフラグを表します.このインタフェースを実装する方法について、非常に簡単な例です.
    type myFlag struct {}
     func  (f  myFlag)HasChanged()bool { return  false }
     func  (f  myFlag)Name()string { return  “ my-flag-name ” }
     func  (f  myFlag)ValueString()string { return  “ my -flag-value “ }
     func  (f  myFlag)ValueType()string { return  “ string ” }

    flagがこのインタフェースを実装すると、Viperにバインドするように伝えることができます.
    viper.BindFlagValue("my-flag-name", myFlag{})

    リモートkey/valueストレージ
    Viperでリモートサポートを有効にするには、FlagValueパッケージに空白のインポートを行います.
    import _ "github.com/spf13/viper/remote"

    Viperは、etcdやConsulなどのkey/valueに格納されているパス検索の構成文字列(JSON、TOML、YAML、HCLなど)を読み込みます.これらの値はデフォルト値よりも優先されますが、ディスク、フラグ、または環境変数から取得された構成値で上書きされます.
    Viperはcryptを使用してK/Vストレージから構成を取得します.これは、暗号化された構成値を格納し、正しいgpgキーループがある場合に自動的に復号できることを意味します.暗号化はオプションです.
    リモート構成とローカル構成を組み合わせて使用するか、独立して使用できます.viper/remoteには、K/Vストレージ領域に構成を格納するコマンドラインヘルプがあります.crypthttp://127.0.0.1:4001上のデフォルトはetcdです.
    $ go get github.com/xordataexchange/crypt/bin/crypt 
    $ crypt set -plaintext /config/hugo.json /Users/hugo/settings/config.json

    値が設定されていることを確認します.
    $ crypt get -plaintext /config/hugo.json

    リモートkey/valueストレージの例-暗号化されていません
    viper.AddRemoteProvider("etcd", "http://127.0.0.1:4001","/config/hugo.json")
    viper.SetConfigType("json") //             ,       “json”,“toml”,“yaml”,“yml”,“properties”,“props”,“prop”
    err := viper.ReadRemoteConfig()

    リモートkey/valueストレージの例-暗号化
    viper.AddSecureRemoteProvider("etcd","http://127.0.0.1:4001","/config/hugo.json","/etc/secrets/mykeyring.gpg")
    viper.SetConfigType("json") //             ,       “json”,“toml”,“yaml”,“yml”,“properties”,“props”,“prop” 
    err := viper.ReadRemoteConfig()

    etcdの変更を傍受-暗号化されていません
    //  ,         viper  
    var runtime_viper = viper.New()
    
    runtime_viper.AddRemoteProvider("etcd", "http://127.0.0.1:4001", "/config/hugo.yml")
    runtime_viper.SetConfigType("yaml")
    
    //            
    err := runtime_viper.ReadRemoteConfig()
    
    //    
    runtime_viper.Unmarshal(&runtime_conf)
    
    //     goroutine         
    go func(){
    	for {
    	    time.Sleep(time.Second * 5) //        
    	    err := runtime_viper.WatchRemoteConfig()
    	    if err != nil {
    	        log.Errorf("unable to read remote config: %v", err)
    	        continue
    	    }
    
    	    //                  。        
            //            
    	    runtime_viper.Unmarshal(&runtime_conf)
    	}
    }()

    Viper取得値
    Viperでは、値のタイプに応じて値を取得する方法がいくつかあります.次の機能と方法があります.
    Get(key string) : interface{}
    GetBool(key string) : bool
    GetFloat64(key string) : float64
    GetInt(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{}

    見つからない場合は、Get関数ごとにゼロ値が返されます.cryptメソッドは、所与の鍵が存在するかどうかを検査する.
    例:
    viper.GetString("logfile") // case-insensitive Setting & Getting
    if viper.GetBool("verbose") {
        fmt.Println("verbose enabled")
    }

    ネストへのアクセス
    アクセサメソッドは、深層ネストキーのフォーマットパスも受け入れます.たとえば、次のJSONファイルがロードされている場合:
    {
        "host": {
            "address": "localhost",
            "port": 5799
        },
        "datastore": {
            "metric": {
                "host": "127.0.0.1",
                "port": 3099
            },
            "warehouse": {
                "host": "198.0.0.1",
                "port": 2112
            }
        }
    }

    Viperは、IsSet()で区切られたキーパスを渡すことによって、ネストされたフィールドにアクセスすることができる.
    GetString("datastore.metric.host") // (returns "127.0.0.1")

    これは上に確立された優先規則に合致する.検索パスは、残りの構成レジストリが見つかるまで中級接続されます.
    たとえば、このプロファイルが指定されている場合、.およびdatastore.metric.hostは既に定義されています(上書きできます).また、datastore.metric.portがデフォルトで定義されている場合、Viperもそれを見つけます.
    ただし、即時値datastore.metric.protocolを使用して上書きすると(フラグ、環境変数、datastore.metricメソッド、...)、すべてのサブキーSet()は未定義になり、より優先度の高い構成レベルで「マスク」されます.
    最後に、区切られたキーパスに一致するキーがある場合は、その値が返されます.たとえば
    {
        "datastore.metric.host": "0.0.0.0",
        "host": {
            "address": "localhost",
            "port": 5799
        },
        "datastore": {
            "metric": {
                "host": "127.0.0.1",
                "port": 3099
            },
            "warehouse": {
                "host": "198.0.0.1",
                "port": 2112
            }
        }
    }
    
    GetString("datastore.metric.host") // returns "0.0.0.0"

    sub-treeの抽出
    たとえば
    app:
      cache1:
        max-items: 100
        item-size: 64
      cache2:
        max-items: 200
        item-size: 80
    
    #   
    
    subv := viper.Sub("app.cache1")
    
    #subv 
    
    max-items:100 
    item-size:64

    仮定
    func NewCache(cfg *Viper) *Cache {...}

    フォーマットされた構成情報に基づいてキャッシュdatastore.metricが作成される.この2つのキャッシュを簡単に作成できます.
    cfg1 := viper.Sub("app.cache1")
    cache1 := NewCache(cfg1)
    
    cfg2 := viper.Sub("app.cache2")
    cache2 := NewCache(cfg2)

    遍歴する
    また、Unmarshaling allまたはstruct、mapなどの特定の値を選択することもできます.
    これには2つの方法があります.
    Unmarshal(rawVal interface{}) : error
    UnmarshalKey(key string, rawVal interface{}) : error

    例:
    type config struct {
    	Port int
    	Name string
    	PathMap string `mapstructure:"path_map"`
    }
    
    var C config
    
    err := Unmarshal(&C)
    if err != nil {
    	t.Fatalf("unable to decode into struct, %v", err)
    }

    文字列に変換
    viperに保存されているすべての設定をファイルに書き込むのではなく文字列に変更する必要がある場合があります.好きなフォーマットのmarshallerと返される構成subvを使用できます.
    import (
        yaml "gopkg.in/yaml.v2"
        // ...
    ) 
    
    func yamlStringSettings() string {
        c := viper.AllSettings()
    	bs, err := yaml.Marshal(c)
    	if err != nil {
            t.Fatalf("unable to marshal config to YAML: %v", err)
        }
    	return string(bs)
    }

    Viper or Vipers?
    Viperはいつでも利用できます.Viperの使用を開始するには、構成や初期化は必要ありません.ほとんどのアプリケーションでは、単一の中央リポジトリを使用して構成する必要があるため、viperパッケージではこの機能が提供されています.独身者に似ています
    上記のすべての例では、viperを使用する単一の方法を示した.
    複数のViperを使用
    また、アプリケーションで使用するために多くの異なるviperを作成することもできます.それぞれに独自の構成と価値観があります.それぞれ異なるプロファイル、キー値格納等から読み取ることができる.viperパッケージがサポートするすべての機能はviper上のメソッドにミラーされます.
    たとえば
    x := viper.New()
    y := viper.New()
    
    x.SetDefault("ContentDir", "content")
    y.SetDefault("ContentDir", "foobar")

    マルチviperを使用すると、ユーザーは異なるviperを追跡できます.