github.com/spf 13/viper go viperパッケージ紹介
13152 ワード
Viperとは?
Viperは、12-Factorアプリケーションを含むGoアプリケーションの完全な構成ソリューションです.アプリケーションで作業し、すべてのタイプの構成要件とフォーマットを処理できるようにします.以下をサポートします.
Viperは、すべてのアプリケーション構成に必要なレジストリとみなすことができる.
なぜViperを選んだのですか?
現代のアプリケーションを構築する場合は、プロファイルのフォーマットを心配する必要はありません.素晴らしいソフトウェアの構築に専念したいです.Viperはこのために助けを提供しています.
Viperは次のことをしました.
Viperは以下の優先順位を使用します.各アイテムは、下のアイテムよりも優先されます.
Viperを使用したデフォルトの設定
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ストレージ領域に構成を格納するコマンドラインヘルプがあります.crypt
http://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を追跡できます.