系列文章:
Golang基础语法补充
Golang-Vipper日志库的学习
1.简单介绍
安装:
go get github.com/spf13/viper
Viper 是 Go 应用程序的完整配置解决方案,它旨在在应用程序中工作,并且可以处理所有类型的配置需求和格式。
- 设置默认值
- 从 JSON、TOML、YAML、HCL、envfile 和 Java 属性配置文件中读取
- 实时观看和重新读取配置文件(可选)
- 从环境变量中读取
- 从远程配置系统(etcd 或 Consul)读取,并观察变化
- 从命令行标志读取
- 从缓冲区读取
- 设置显式值
Viper 可以被认为是满足您所有应用程序配置需求的注册表。
2.建立默认值
一个好的配置系统将支持默认值。键不需要默认值,但在未通过配置文件、环境变量、远程配置或标志设置键的情况下它很有用。
//如果没有从配置文件读到对应的配置,但是被使用了,就会去使用默认值
viper.SetDefault("ContentDir", "content")
viper.SetDefault("LayoutDir", "layouts")
viper.SetDefault("Taxonomies", map[string]string{"tag": "tags", "category": "categories"})
3.读取配置文件
Viper需要最小的配置,所以它知道在哪里寻找配置文件。Viper支持JSON, TOML, YAML, HCL, INI, envfile和Java Properties文件。Viper可以搜索多个路径,但目前一个Viper实例只支持一个配置文件。Viper不默认任何配置搜索路径,而是将默认决定权留给一个应用程序。(他不会约定你的配置文件应该放在哪里,也不会规定你用什么格式或者名称来规定你的配置文件,你可以自己决定,告诉它就好!)
viper.SetConfigName("config") // 配置文件的名称(不带扩展名)
viper.SetConfigType("yaml") // 如果配置文件名称中没有扩展名,则需要配置这一项
viper.AddConfigPath("/etc/appname/") // 添加viper去查找配置文件的路径(可以添加多个)
viper.AddConfigPath(".") // 可以选择在工作目录中寻找配置。
if err != nil { // 处理读取配置文件的错误
panic(fmt.Errorf("Fatal error config file: %w \n", err))
}
您可以处理找不到配置文件的特定情况,如下所示:
if err := viper.ReadInConfig(); err != nil {
if _, ok := err.(viper.ConfigFileNotFoundError); ok {
// 未找到配置文件;如果需要,忽略错误
} else {
// 找到了配置文件,但产生了另一个错误
}
}
// 找到并成功解析了配置文件
注意 [自 1.6 起]:您还可以拥有一个没有扩展名的文件并以编程方式指定格式。对于那些位于用户家中没有任何扩展名的配置文件,如 .bashrc
4.编写配置文件
从配置文件中读取很有用,但有时您希望存储在运行时所做的所有修改。为此,有一堆命令可用,每个命令都有自己的目的:
- WriteConfig - 将当前 viper 配置写入预定义路径(如果存在)将覆盖当前的配置文件;如果没有预定义路径,则会出错。
- SafeWriteConfig - 将当前 viper 配置写入预定义路径。如果存在,则不会覆盖当前的配置文件。如果没有预定义路径,则会出错。
- WriteConfigAs - 将当前 viper 配置写入给定的文件路径。将覆盖给定的文件(如果存在)。
- SafeWriteConfigAs - 将当前 viper 配置写入给定的文件路径。不会覆盖给定的文件(如果存在)。
5.查看和重新读取配置文件
Viper 支持让您的应用程序在运行时实时读取配置文件的能力。
需要重新启动服务器才能使配置生效的日子已经一去不复返了,viper 驱动的应用程序可以在运行时读取配置文件的更新,而不会错过任何一个节拍。
只需告诉 viper 实例 watchConfig。或者,您可以为 Viper 提供一个函数,以便在每次发生更改时运行。
原配置文件内容:
server:
port: 5201
代码示例:
package main
import (
"fmt"
"github.com/fsnotify/fsnotify"
"github.com/spf13/viper"
)
func main(){
viper.SetConfigName("application") //设置配置文件名称
viper.SetConfigType("yaml") //设置配置文件扩展名
viper.AddConfigPath(".") //设置配置文件path
err := viper.ReadInConfig() //读配置文件
beforeGet := viper.Get("server.port")
fmt.Println(beforeGet) // 5201
viper.OnConfigChange(func(fs fsnotify.Event) { //配置文件变更钩子函数
fmt.Println("Config file changed:", fs.Name)
})
viper.WatchConfig() //开启监听
if err != nil{
fmt.Printf("config file read err %d \n",err)
}
if writeErr:= viper.WriteConfig();writeErr!=nil{
fmt.Printf("write err %d \n",writeErr)
}
viper.Set("server.port",11112) //通过set去修改配置
afterGet := viper.Get("server.port")
fmt.Println(afterGet) // 11112
}
watchConfig
5201
Config file changed: /Users/codehope/remote-es-server-code/vipper-demo/application.yaml
11112
6.从 读取配置
package main
import (
"bytes"
"fmt"
"github.com/spf13/viper"
"os"
)
func main() {
viper.SetConfigType("yaml") // 这个也需要加上的,不然读取的是nil
fileBuf, err := os.ReadFile("./application.yaml")
if err != nil{
fmt.Println(err)
return
}
fmt.Println(string(fileBuf))
//fmt.Printf("%T",fileBuf)
err1 := viper.ReadConfig(bytes.NewBuffer(fileBuf))
if err1 != nil {
return
}
getName := viper.Get("name")
getServer := viper.Get("server")
fmt.Println(getName) //app-demo
fmt.Println(getServer) //map[port:5201]
}
SetConfigTypenil
7.配置覆盖
这些可能来自一个命令行标志,或来自你自己的应用逻辑。
package main
import (
"bytes"
"fmt"
"github.com/spf13/viper"
)
func main() {
viper.SetConfigType("yaml")
ioReadConfig := []byte(
`name: "app-demo"`)
err := viper.ReadConfig(bytes.NewBuffer(ioReadConfig))
if err != nil {
fmt.Println(err)
return
}
fmt.Println(viper.Get("name")) //app-demo
viper.Set("name","app-demo2")
fmt.Println(viper.Get("name")) //app-demo2
}
8.注册和使用别名
别名允许一个值被多个键所引用
package main
import (
"bytes"
"fmt"
"github.com/spf13/viper"
)
func main() {
viper.SetConfigType("yaml")
ioReadConfig := []byte(
`name: "app-demo"`)
err := viper.ReadConfig(bytes.NewBuffer(ioReadConfig))
if err != nil {
fmt.Println(err)
return
}
viper.RegisterAlias("t_name","name") //name配置起个别名叫t_name
fmt.Println(viper.Get("t_name")) //获取t_name的配置值,实际去拿的 name的值 -> app-demo
viper.Set("t_name","app_new_name") //设置t_name的新值,实际去设置 name的值
fmt.Println(viper.Get("name")) //验证是否通过别名修改成功 -> app_new_name
}
Golang学习
Golang第三方库
本作品采用《CC 协议》,转载必须注明作者和本文链接
CunWang@Ch