Golang-Vipper日志库的学习

1.简单介绍

Vipper日志库的学习
安装:

 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配置文件修改的hooks钩子函数

5201
Config file changed: /Users/codehope/remote-es-server-code/vipper-demo/application.yaml
11112

6.从io.Reader 读取配置

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]
}

【注意(version:viper@v1.9.0):从io.Reader读取 的话也需要设置配置文件的类型SetConfigType,不然有可能读出的值为nil

Vipper日志库的学习

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
}
本作品采用《CC 协议》,转载必须注明作者和本文链接
CunWang@Ch
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!