Парсинг конфигов в Go с помощью Viper
11 декабря 2019
Редкая программа обходится без файла конфигурации. Даже если вы пишите простенький REST-сервис, то ему как минимум нужно знать, какой порт и на каком интерфейсе слушать, а также где искать PostgreSQL. Что уж говорить о более сложных приложениях. Для чтения конфигов в проектах на Go часто используют библиотеку spf13/viper.
Почему Viper? Потому что он умеет очень много всего:
- Поддерживаются форматы Yaml, Json, INI и другие;
- Параметры конфигурации можно переопределять через флаги;
- Также параметры можно задавать через переменные окружения, как это принято в Kubernetes;
- Viper умеет забирать параметры из etcd и Consul;
- Параметры можно менять на лету, что позволяет изменить поведение программы без перезапуска;
Другими словами, какие бы требования не предъявлялись к приложению, Viper почти наверняка сможет их удовлетворить. Вот все им и пользуются.
Все возможности библиотеки мы рассматривать не будем, так как их много и получится пересказ документации. Рассмотрим только самый базовый пример использования, который обычно и нужен:
customFormatter := new(log.TextFormatter)
customFormatter.TimestampFormat = "2006-01-02 15:04:05"
customFormatter.FullTimestamp = true
log.SetFormatter(customFormatter)
viper.AutomaticEnv()
viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
viper.SetEnvPrefix("restexample")
viper.SetDefault("loglevel", "debug")
viper.SetDefault("listen", "localhost:8080")
viper.SetDefault("db.url", "postgres://localhost")
if configPath != "" {
log.Infof("Parsing config: %s", configPath)
viper.SetConfigFile(configPath)
err := viper.ReadInConfig()
if err != nil {
log.Panicf("Unable to read config file: %s", err)
}
} else {
log.Infof("Config file is not specified.")
}
logLevelString := viper.GetString("loglevel")
logLevel, err := log.ParseLevel(logLevelString)
if err != nil {
log.Panicf("Unable to parse loglevel: %s", logLevelString)
}
log.SetLevel(logLevel)
log.Infof("Listen: %s", viper.GetString("listen"))
log.Infof("DB URL: %s", viper.GetString("db.url"))
}
Путь до файла конфигурации передается приложению при помощи обязательного флага --config
или его синонима -c
, как это ранее было описано в посте Парсинг флагов и аргументов в языке Go.
Пример файла конфигурации:
listen: 0.0.0.0:8080
db:
url: postgres://postgresql@localhost/restservice
Варианты запуска приложения:
Config file is not specified.
Listen: localhost:8080
DB URL: postgres://localhost
$ ./rest -c ./config.yaml
Parsing config: ./config.yaml
Listen: 0.0.0.0:8080
DB URL: postgres://restservice@localhost/restservice
$ RESTEXAMPLE_LISTEN=localhost:80 ./rest -c ./config.yaml
Parsing config: ./config.yaml
Listen: localhost:80
DB URL: postgres://restservice@localhost/restservice
$ RESTEXAMPLE_LISTEN=localhost:80 ./rest
Config file is not specified.
Listen: localhost:80
DB URL: postgres://localhost
В выводе опущены таймстемпы, так как они нам сейчас не интересны.
Первый вариант демонстрирует запуск без указания файла конфигурации и каких-либо переменных окружения. В этом случае используются параметры по умолчанию, указанные в коде. Если указать файл конфигурации, как во втором варианте, то параметры из файла перезатрут параметры по умолчанию. Наконец, третий и четвертый варианты запуска демонстрируют, что переменные окружения имеют приоритет как перед параметрами по умолчанию, так и перед параметрами из файла конфигурации.
Как видите, ничего сложного! Наиболее полную и актуальную информацию, как обычно, вы найдете в официальной документации.
Метки: Go.
Вы можете прислать свой комментарий мне на почту, или воспользоваться комментариями в Telegram-группе.