Введение
Предыдущая статьяВведениеcobraупоминается, когдаviper, Сегодня мы познакомим вас с этой библиотекой. viper — это конфигурационное решение с богатыми возможностями:
- Поддержка файлов конфигурации в различных форматах, таких как свойства JSON/TOML/YAML/HCL/envfile/Java;
- Вы можете настроить монитор для изменения файла конфигурации, автоматически загружать новую измененную конфигурацию;
- Из переменных среды и параметров командной строки
io.Reader
прочитать конфигурацию; - Чтение и мониторинг изменений из систем удаленной настройки, таких как etcd/Consul;
- Установленное значение ключа отображается в логике кода.
быстрый в использовании
Установить:
$ go get github.com/spf13/viper
использовать:
package main
import (
"fmt"
"log"
"github.com/spf13/viper"
)
func main() {
viper.SetConfigName("config")
viper.SetConfigType("toml")
viper.AddConfigPath(".")
viper.SetDefault("redis.port", 6381)
err := viper.ReadInConfig()
if err != nil {
log.Fatal("read config failed: %v", err)
}
fmt.Println(viper.Get("app_name"))
fmt.Println(viper.Get("log_level"))
fmt.Println("mysql ip: ", viper.Get("mysql.ip"))
fmt.Println("mysql port: ", viper.Get("mysql.port"))
fmt.Println("mysql user: ", viper.Get("mysql.user"))
fmt.Println("mysql password: ", viper.Get("mysql.password"))
fmt.Println("mysql database: ", viper.Get("mysql.database"))
fmt.Println("redis ip: ", viper.Get("redis.ip"))
fmt.Println("redis port: ", viper.Get("redis.port"))
}
прежде чем мы используемGo ежедневная библиотека go-iniКонфигурация, использованная в этой статье, изменена на формат toml. Синтаксис toml очень прост, см. краткое руководство.learn X in Y minutes.
app_name = "awesome web"
# possible values: DEBUG, INFO, WARNING, ERROR, FATAL
log_level = "DEBUG"
[mysql]
ip = "127.0.0.1"
port = 3306
user = "dj"
password = 123456
database = "awesome"
[redis]
ip = "127.0.0.1"
port = 7381
Использование Viper очень просто и требует минимальной настройки. установить имя файла (SetConfigName
), тип конфигурации (SetConfigType
) и путь поиска (AddConfigPath
), то звонитеReadInConfig
.
viper автоматически прочитает конфигурацию в соответствии с типом. вызывается при использованииviper.Get
метод получения значения ключа.
Скомпилируйте и запустите программу:
awesome web
DEBUG
mysql ip: 127.0.0.1
mysql port: 3306
mysql user: dj
mysql password: 123456
mysql database: awesome
redis ip: 127.0.0.1
redis port: 7381
Несколько замечаний:
- Не используйте суффикс при установке имени файла;
- Можно задать несколько путей поиска, и viper будет искать в соответствии с установленным порядком;
- VIPER используется при получении значения
section.key
, то есть передать имя вложенного ключа; - Значение по умолчанию можно назвать
viper.SetDefault
настраивать.
прочитать ключ
viper предоставляет несколько форм методов чтения. В приведенном выше примере мы видимGet
использование метода.Get
метод возвращаетinterface{}
стоимость, неудобно пользоваться.
GetType
Методы серии могут возвращать значение указанного типа.
где Тип может бытьBool/Float64/Int/String/Time/Duration/IntSlice/StringSlice
.
Но обратите внимание, чтоЕсли указанный ключ не существует или имеет неправильный тип,GetType
Метод возвращает нулевое значение соответствующего типа.
Если вы хотите определить, существует ли ключ, используйтеIsSet
метод.
Кроме того,GetStringMap
иGetStringMapString
Непосредственно используйте карту, чтобы вернуть все пары ключ-значение под ключом, первый возвращаетmap[string]interface{}
, последний возвращаетсяmap[string]string
.AllSettings
отmap[string]interface{}
Возвращает все настройки.
// 省略包名和 import 部分
func main() {
viper.SetConfigName("config")
viper.SetConfigType("toml")
viper.AddConfigPath(".")
err := viper.ReadInConfig()
if err != nil {
log.Fatal("read config failed: %v", err)
}
fmt.Println("protocols: ", viper.GetStringSlice("server.protocols"))
fmt.Println("ports: ", viper.GetIntSlice("server.ports"))
fmt.Println("timeout: ", viper.GetDuration("server.timeout"))
fmt.Println("mysql ip: ", viper.GetString("mysql.ip"))
fmt.Println("mysql port: ", viper.GetInt("mysql.port"))
if viper.IsSet("redis.port") {
fmt.Println("redis.port is set")
} else {
fmt.Println("redis.port is not set")
}
fmt.Println("mysql settings: ", viper.GetStringMap("mysql"))
fmt.Println("redis settings: ", viper.GetStringMap("redis"))
fmt.Println("all settings: ", viper.AllSettings())
}
Мы добавили в файл конфигурации config.tomlprotocols
иports
Конфигурация:
[server]
protocols = ["http", "https", "port"]
ports = [10000, 10001, 10002]
timeout = 3s
Скомпилируйте и запустите программу, вывод:
protocols: [http https port]
ports: [10000 10001 10002]
timeout: 3s
mysql ip: 127.0.0.1
mysql port: 3306
redis.port is set
mysql settings: map[database:awesome ip:127.0.0.1 password:123456 port:3306 user:dj]
redis settings: map[ip:127.0.0.1 port:7381]
all settings: map[app_name:awesome web log_level:DEBUG mysql:map[database:awesome ip:127.0.0.1 password:123456 port:3306 user:dj] redis:map[ip:127.0.0.1 port:7381] server:map[ports:[10000 10001 10002] protocols:[http https port]]]
Если вы настроитеredis.port
закомментировано, будет выведеноredis.port is not set
.
Как использовать его в примере вышеtime.Duration
Тип, пока этоtime.ParseDuration
Принятые форматы в порядке, например.3s
,2min
,1min30s
Ждать.
установить значение ключа
viper поддерживает настройки в нескольких местах, читаемые последовательно в следующем порядке:
- перечислить
Set
Настройки отображения; - параметры командной строки;
- переменные окружения;
- конфигурационный файл;
- По умолчанию.
viper.Set
Если ключ проходитviper.Set
Установите значение, тогда это значение имеет наивысший приоритет.
viper.Set("redis.port", 5381)
Если вы поместите приведенную выше строку кода в программу и запустите программу, выводredis.port
будет 5381.
параметры командной строки
Если ключ не проходитviper.Set
Отобразите значение параметра, затем fetch попытается прочитать параметры командной строки.
Если доступно, используйте его в первую очередь. viper использует библиотеку pflag для разбора опций.
мы первыеinit
Определите параметры в методе и вызовитеviper.BindPFlags
Привяжите параметры к конфигурации:
func init() {
pflag.Int("redis.port", 8381, "Redis port to connect")
// 绑定命令行
viper.BindPFlags(pflag.CommandLine)
}
Затем вmain
вызов в начале методаpflag.Parse
Варианты разбора.
Скомпилируйте и запустите программу:
$ ./main.exe --redis.port 9381
awesome web
DEBUG
mysql ip: 127.0.0.1
mysql port: 3306
mysql user: dj
mysql password: 123456
mysql database: awesome
redis ip: 127.0.0.1
redis port: 9381
Как не пройти мимо вариантов:
$ ./main.exe
awesome web
DEBUG
mysql ip: 127.0.0.1
mysql port: 3306
mysql user: dj
mysql password: 123456
mysql database: awesome
redis ip: 127.0.0.1
redis port: 7381
Обратите внимание, что параметры здесь не используются.redis.port
значение по умолчанию для .
Однако, если значение ключа недоступно с помощью приведенных ниже методов, верните значение параметра по умолчанию (если есть). Попробуйте закомментировать файл конфигурацииredis.port
Проверьте эффект.
переменная среды
Если значение ключа не получено ранее, он попытается прочитать его из переменной окружения. Мы можем связать их по одному или автоматически связать их все.
существуетinit
вызов методаAutomaticEnv
Метод связывает все переменные окружения:
func init() {
// 绑定环境变量
viper.AutomaticEnv()
}
Чтобы проверить успешность привязки, мыmain
Переменная окружения GOPATH выводится в методе:
func main() {
// 省略部分代码
fmt.Println("GOPATH: ", viper.Get("GOPATH"))
}
Через System -> Advanced Settings -> New Создайте новый файл с именемredis.port
переменная окружения со значением 10381.
запустить программу, вывестиredis.port
Значение равно 10381, и в выходных данных есть информация GOPATH.
Вы также можете привязать переменные среды по отдельности:
func init() {
// 绑定环境变量
viper.BindEnv("redis.port")
viper.BindEnv("go.path", "GOPATH")
}
func main() {
// 省略部分代码
fmt.Println("go path: ", viper.Get("go.path"))
}
перечислитьBindEnv
метод, если передается только один параметр, этот параметр представляет как имя ключа, так и имя переменной среды.
Если передаются два параметра, первый параметр представляет имя ключа, а второй параметр представляет имя переменной среды.
также черезviper.SetEnvPrefix
метод для установки префикса переменной среды, чтобы черезAutomaticEnv
и параметрBindEnv
связанные переменные окружения,
в настоящее время используетGet
, viper автоматически добавит этот префикс и найдет его в переменных окружения.
Если соответствующая переменная среды не существует, viper автоматически преобразует все имена ключей в верхний регистр и повторит поиск. Итак, используйте ключевое имяgopath
Переменные среды также могут быть прочитаныGOPATH
значение .
конфигурационный файл
Если ключ не может быть найден по предыдущим путям, viper попытается найти его в файле конфигурации.
Во избежание влияния переменных окружения нужно удалитьredis.port
эта переменная окружения.
Смотретьбыстрый в использованииВ примерах.
По умолчанию
вышебыстрый в использованииВ предыдущем разделе мы видели, как устанавливать значения по умолчанию, поэтому я не буду повторять их здесь.
чтение конфигурации
отio.Reader
читать в
вайпер поддерживает отio.Reader
Прочитайте конфигурацию в. Эта форма является гибкой, и источником может быть файл, строка, сгенерированная программой, или даже поток байтов, прочитанный из сетевого подключения.
package main
import (
"bytes"
"fmt"
"log"
"github.com/spf13/viper"
)
func main() {
viper.SetConfigType("toml")
tomlConfig := []byte(`
app_name = "awesome web"
# possible values: DEBUG, INFO, WARNING, ERROR, FATAL
log_level = "DEBUG"
[mysql]
ip = "127.0.0.1"
port = 3306
user = "dj"
password = 123456
database = "awesome"
[redis]
ip = "127.0.0.1"
port = 7381
`)
err := viper.ReadConfig(bytes.NewBuffer(tomlConfig))
if err != nil {
log.Fatal("read config failed: %v", err)
}
fmt.Println("redis port: ", viper.GetInt("redis.port"))
}
Unmarshal
поддержка вайпер настроитUnmarshal
в структуру и присваивать значения соответствующим полям в структуре.
package main
import (
"fmt"
"log"
"github.com/spf13/viper"
)
type Config struct {
AppName string
LogLevel string
MySQL MySQLConfig
Redis RedisConfig
}
type MySQLConfig struct {
IP string
Port int
User string
Password string
Database string
}
type RedisConfig struct {
IP string
Port int
}
func main() {
viper.SetConfigName("config")
viper.SetConfigType("toml")
viper.AddConfigPath(".")
err := viper.ReadInConfig()
if err != nil {
log.Fatal("read config failed: %v", err)
}
var c Config
viper.Unmarshal(&c)
fmt.Println(c.MySQL)
}
Компилируем, запускаем программу, выводим:
{127.0.0.1 3306 dj 123456 awesome}
сохранить конфигурацию
Иногда мы хотим сохранить конфигурацию, сгенерированную в программе, или внесенные изменения. viper предоставляет интерфейс!
-
WriteConfig
: Напишите текущую конфигурацию Viper до заранее определенного пути или вернуть ошибку, если нет предопределенного пути. перезаписать текущую конфигурацию; -
SafeWriteConfig
: Та же функция, что и выше, но если файл конфигурации существует, он не будет перезаписан; -
WriteConfigAs
: Сохраните конфигурацию по указанному пути, если файл существует, он будет перезаписан; -
SafeWriteConfigAs
: та же функция, что и выше, но если файл конфигурации общего доступа существует, он не будет перезаписан.
Далее мы программно генерируемconfig.toml
Конфигурация:
package main
import (
"log"
"github.com/spf13/viper"
)
func main() {
viper.SetConfigName("config")
viper.SetConfigType("toml")
viper.AddConfigPath(".")
viper.Set("app_name", "awesome web")
viper.Set("log_level", "DEBUG")
viper.Set("mysql.ip", "127.0.0.1")
viper.Set("mysql.port", 3306)
viper.Set("mysql.user", "root")
viper.Set("mysql.password", "123456")
viper.Set("mysql.database", "awesome")
viper.Set("redis.ip", "127.0.0.1")
viper.Set("redis.port", 6381)
err := viper.SafeWriteConfig()
if err != nil {
log.Fatal("write config failed: ", err)
}
}
Скомпилируйте и запустите программу, сгенерированные файлы выглядят следующим образом:
app_name = "awesome web"
log_level = "DEBUG"
[mysql]
database = "awesome"
ip = "127.0.0.1"
password = "123456"
port = 3306
user = "root"
[redis]
ip = "127.0.0.1"
port = 6381
Отслеживание изменений файлов
VIPER может контролировать модификации файлов и конфигурации горячей нагрузки. Таким образом, нет необходимости перезапустить сервер для конфигурации, чтобы вступить в силу.
package main
import (
"fmt"
"log"
"time"
"github.com/spf13/viper"
)
func main() {
viper.SetConfigName("config")
viper.SetConfigType("toml")
viper.AddConfigPath(".")
err := viper.ReadInConfig()
if err != nil {
log.Fatal("read config failed: %v", err)
}
viper.WatchConfig()
fmt.Println("redis port before sleep: ", viper.Get("redis.port"))
time.Sleep(time.Second * 10)
fmt.Println("redis port after sleep: ", viper.Get("redis.port"))
}
просто позвониviper.WatchConfig
, viper будет автоматически отслеживать изменения конфигурации. Если есть изменения, перезагрузите конфигурацию.
В приведенной выше программе мы сначала печатаемredis.port
значение, тоSleep
10 с. За это время изменить конфигурациюredis.port
значение ,Sleep
Распечатайте снова, когда закончите.
Discovery выводит измененное значение:
redis port before sleep: 7381
redis port after sleep: 73810
Кроме того, вы можете добавить обратный вызов для изменения конфигурации:
viper.OnConfigChange(func(e fsnotify.Event) {
fmt.Printf("Config file:%s Op:%s\n", e.Name, e.Op)
})
Этот обратный вызов будет выполняться при изменении файла.
использование гадюкиfsnotifyВ этой библиотеке реализована функция мониторинга модификаций файлов.
Полный пример кода см.GitHub.
Ссылаться на
- viperРепозиторий GitHub
я
Добро пожаловать, чтобы обратить внимание на мою общедоступную учетную запись WeChat [GoUpUp], учитесь вместе и добивайтесь прогресса вместе ~
Эта статья опубликована в блогеOpenWriteвыпуск!