go语言中的配置管理神器 --viper 一(一)

简介: go语言中的配置管理神器 --viper 一

viper

Viper是什么?

Viper 是 Go 应用程序的完整配置解决方案,包括 12-Factor 应用程序。它旨在在应用程序中工作,并可以处理所有类型的配置需求和格式。它支持:

  • 默认配置
  • 从 JSON, TOML, YAML, HCL 和 Java 属性配置文件读取数据
  • 实时查看和重新读取配置文件(可选)
  • 从环境变量中读取
  • 从远程配置系统(etcd 或 Consul)读取数据并监听变化
  • 从命令行参数读取
  • 从 buffer 中读取
  • 设置显式值

Viper 可以被认为是所有应用程序配置需求的注册表

Viper 使用以下优先级顺序。每个项目优先于其下方的项目:

  • explicit call to Set
  • flag
  • env
  • config
  • key/value store
  • default
  • Viper配置键不区分大小写。

建立默认值

viper.SetDefault("ContentDir", "content")
viper.SetDefault("LayoutDir", "layouts")
viper.SetDefault("Taxonomies", map[string]string{"tag": "tags", "category": "categories"})

读取配置文件

Viper 需要极少的配置让它知道去哪里查找配置文件。Viper 支持 JSON, TOML, YAML, HCL 和 Java 属性配置文件。Viper 可以搜索多个路径,但目前单个 Viper 实例仅 支持单个配置文件。Viper 不默认任何配置搜索路径,将默认决策留给应用程序。

viper.SetConfigName("config") // 配置文件的名字,不包括拓展名
viper.AddConfigPath("/etc/appname/")   // 添加配置文件的路径
viper.AddConfigPath("$HOME/.appname")  // 多次调用以添加多个搜索路径
viper.AddConfigPath(".")               // .代表当前项目的工作目录
err := viper.ReadInConfig() //查找读取配置文件
if err != nil { // Handle errors reading the config file
    panic(fmt.Errorf("Fatal error config file: %s \n", err))
}

监听和重新读取配置文件

Viper 支持在运行时让应用程序实时读取配置文件。

只需告诉 viper 实例 watchConfig 即可。你可以选择为 Viper 提供当每次发生更改时运行的函数。

确保在调用 WatchConfig() 之前添加所有的配置路径 ConfigPath

viper.WatchConfig()
viper.OnConfigChange(func(e fsnotify.Event) {
    fmt.Println("Config file changed:", e.Name)
})

从 io.Reader 读取配置

Viper 预定义了许多配置源,例如文件,环境变量,标志和远程 K/V 存储,但你不受它们的约束。你还可以实现自己的需要的配置源并将其提供给 viper。

viper.SetConfigType("yaml") // or viper.SetConfigType("YAML")
// any approach to require this configuration into your program.
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.Set("Verbose", true)
viper.Set("LogFile", LogFile)

注册和使用别名

别名允许多个键引用单个值

viper.RegisterAlias("loud", "Verbose")
viper.Set("verbose", true) 
viper.Set("loud", true)   
viper.GetBool("loud") // true
viper.GetBool("verbose") // true

使用环境变量

Viper 完全支持环境变量。这使得 12 factor 应用程序可以开箱即用。 五种方法可以帮助使用 ENV:

AutomaticEnv()
BindEnv(string...) : error
SetEnvPrefix(string)
SetEnvKeyReplacer(string...) *strings.Replacer
AllowEmptyEnvVar(bool)

在处理环境变量时,重要的是要认识到 Viper 将环境变量视为区分大小写的变量。

Viper 提供了一种机制来确保 ENV 变量是唯一的。通过使用 SetEnvPrefix,可以告诉 Viper 在读取环境变量时使用前缀。BindEnv 和 AutomaticEnv 都将使用此前缀。

BindEnv 需要一个或两个参数。第一个参数是键名,第二个是环境变量的名称。环境变量的名称区分大小写。如果未提供 ENV 变量名,则 Viper 将自动假设键名与 ENV 变量名称匹配, 但 ENV 变量为 IN ALL CAPS。 当明确提供ENV变量名称时,它不会自动添加前缀。

使用 ENV 变量时要认识到的一件重要事情是每次访问时都会读取该值。当调用 BindEnv 时,Viper不会修复该值。

AutomaticEnv 是一个强大的帮手,特别是与 SetEnvPrefix 结合使用时。每当发出 viper.Get 请求时,Viper 都会检查环境变量。它将适用以下规则。 它将检查一个环境变量,其名称与大写的键匹配,如果设置了 EnvPrefix,则以它为前缀。

SetEnvKeyReplacer 允许你使用 strings.Replacer 对象来重写 Env 键。如果你想在 Get() 调用中使用 - 或者某些东西,但希望你的环境变量使用 _ 分隔符, 这是很有用的。使用它的一个例子可以在 viper_test.go 中找到。

默认情况下,空环境变量被视为未设置,并将回退到下一个配置源。要设置空环境变量,请使用 AllowEmptyEnv 方法。

SetEnvPrefix("spf") // 将自动大写
BindEnv("id")
os.Setenv("SPF_ID", "13") 
id := Get("id") // 13

用Flags

Viper 具有绑定到标志的能力。具体来说,Viper支持Cobra库中使用的Pflag。

与BindEnv类似,该值不是在调用绑定方法时设置的,而是在访问该方法时设置的。这意味着你可以根据需要尽早进行绑定,即使在init()函数中也是如此。

对于单个标志,BindPFlag()方法提供此功能。

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检索值

在 Viper 中使用 pflag 并不阻碍其他包中使用标准库中的 flag 包。pflag 包可以通过导入这些 flags 来处理flag包定义的flags。这是通过调用pflag包提供的便利函数AddGoFlagSet()来实现的。

例如:

package main
import (
  "flag"
  "github.com/spf13/pflag"
)
func main() {
  // 使用标准库 "flag" 包
  flag.Int("flagname", 1234, "help message for flagname")
  pflag.CommandLine.AddGoFlagSet(flag.CommandLine)
  pflag.Parse()
  viper.BindPFlags(pflag.CommandLine)
  i := viper.GetInt("flagname") // 从 viper 检索值
  ...
}

从Viper获取值

在Viper中,有几种方法可以根据值的类型获取值。存在以下功能和方法:

Get(key string) : interface{}
GetBool(key string) : bool
GetFloat64(key string) : float64
GetInt(key string) : int
GetIntSlice(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方法在找不到值的时候都会返回零值。为了检查给定的键是否存在,提供了IsSet()方法。

例如:

viper.GetString("logfile") // 不区分大小写的设置和获取
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可以通过传入.分隔的路径来访问嵌套字段:

GetString("datastore.metric.host") // (返回 "127.0.0.1")

如果存在与分隔的键路径匹配的键,则返回其值。例如:

{
    "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”) // 返回 “0.0.0.0”


go语言中的配置管理神器 --viper 一(二)https://developer.aliyun.com/article/1391730

目录
打赏
0
0
0
0
5
分享
相关文章
|
2天前
|
Go 语言入门指南:切片
Golang中的切片(Slice)是基于数组的动态序列,支持变长操作。它由指针、长度和容量三部分组成,底层引用一个连续的数组片段。切片提供灵活的增减元素功能,语法形式为`[]T`,其中T为元素类型。相比固定长度的数组,切片更常用,允许动态调整大小,并且多个切片可以共享同一底层数组。通过内置的`make`函数可创建指定长度和容量的切片。需要注意的是,切片不能直接比较,只能与`nil`比较,且空切片的长度为0。
Go 语言入门指南:切片
|
5天前
|
公司局域网管理系统里的 Go 语言 Bloom Filter 算法,太值得深挖了
本文探讨了如何利用 Go 语言中的 Bloom Filter 算法提升公司局域网管理系统的性能。Bloom Filter 是一种高效的空间节省型数据结构,适用于快速判断元素是否存在于集合中。文中通过具体代码示例展示了如何在 Go 中实现 Bloom Filter,并应用于局域网的 IP 访问控制,显著提高系统响应速度和安全性。随着网络规模扩大和技术进步,持续优化算法和结合其他安全技术将是企业维持网络竞争力的关键。
22 1
公司局域网管理系统里的 Go 语言 Bloom Filter 算法,太值得深挖了
eino — 基于go语言的大模型应用开发框架(二)
本文介绍了如何使用Eino框架实现一个基本的LLM(大语言模型)应用。Eino中的`ChatModel`接口提供了与不同大模型服务(如OpenAI、Ollama等)交互的统一方式,支持生成完整响应、流式响应和绑定工具等功能。`Generate`方法用于生成完整的模型响应,`Stream`方法以流式方式返回结果,`BindTools`方法为模型绑定工具。此外,还介绍了通过`Option`模式配置模型参数及模板功能,支持基于前端和用户自定义的角色及Prompt。目前主要聚焦于`ChatModel`的`Generate`方法,后续将继续深入学习。
48 6
eino — 基于go语言的大模型应用开发框架(一)
Eino 是一个受开源社区优秀LLM应用开发框架(如LangChain和LlamaIndex)启发的Go语言框架,强调简洁性、可扩展性和可靠性。它提供了易于复用的组件、强大的编排框架、简洁明了的API、最佳实践集合及实用的DevOps工具,支持快速构建和部署LLM应用。Eino不仅兼容多种模型库(如OpenAI、Ollama、Ark),还提供详细的官方文档和活跃的社区支持,便于开发者上手使用。
37 6
Go语言实战:错误处理和panic_recover之自定义错误类型
本文深入探讨了Go语言中的错误处理和panic/recover机制,涵盖错误处理的基本概念、自定义错误类型的定义、panic和recover的工作原理及应用场景。通过具体代码示例介绍了如何定义自定义错误类型、检查和处理错误值,并使用panic和recover处理运行时错误。文章还讨论了错误处理在实际开发中的应用,如网络编程、文件操作和并发编程,并推荐了一些学习资源。最后展望了未来Go语言在错误处理方面的优化方向。
Go语言的网络编程与TCP_UDP
Go语言由Google开发,旨在简单、高效和可扩展。本文深入探讨Go语言的网络编程,涵盖TCP/UDP的基本概念、核心算法(如滑动窗口、流量控制等)、最佳实践及应用场景。通过代码示例展示了TCP和UDP的实现,并讨论了其在HTTP、DNS等协议中的应用。最后,总结了Go语言网络编程的未来发展趋势与挑战,推荐了相关工具和资源。
探秘员工泄密行为防线:基于Go语言的布隆过滤器算法解析
在信息爆炸时代,员工泄密行为对企业构成重大威胁。本文聚焦布隆过滤器(Bloom Filter)这一高效数据结构,结合Go语言实现算法,帮助企业识别和预防泄密风险。通过构建正常操作“指纹库”,实时监测员工操作,快速筛查可疑行为。示例代码展示了如何利用布隆过滤器检测异常操作,并提出优化建议,如调整参数、结合日志分析系统等,全方位筑牢企业信息安全防线,守护核心竞争力。
员工上网行为监控中的Go语言算法:布隆过滤器的应用
在信息化高速发展的时代,企业上网行为监管至关重要。布隆过滤器作为一种高效、节省空间的概率性数据结构,适用于大规模URL查询与匹配,是实现精准上网行为管理的理想选择。本文探讨了布隆过滤器的原理及其优缺点,并展示了如何使用Go语言实现该算法,以提升企业网络管理效率和安全性。尽管存在误报等局限性,但合理配置下,布隆过滤器为企业提供了经济有效的解决方案。
99 8
员工上网行为监控中的Go语言算法:布隆过滤器的应用
|
12天前
|
【02】客户端服务端C语言-go语言-web端PHP语言整合内容发布-优雅草网络设备监控系统-2月12日优雅草简化Centos stream8安装zabbix7教程-本搭建教程非docker搭建教程-优雅草solution
【02】客户端服务端C语言-go语言-web端PHP语言整合内容发布-优雅草网络设备监控系统-2月12日优雅草简化Centos stream8安装zabbix7教程-本搭建教程非docker搭建教程-优雅草solution
64 20
|
18天前
|
Go语言入门:分支结构
本文介绍了Go语言中的条件语句,包括`if...else`、`if...else if`和`switch`结构,并通过多个练习详细解释了它们的用法。`if...else`用于简单的条件判断;`if...else if`处理多条件分支;`switch`则适用于基于不同值的选择逻辑。特别地,文章还介绍了`fallthrough`关键字,用于优化重复代码。通过实例如判断年龄、奇偶数、公交乘车及成绩等级等,帮助读者更好地理解和应用这些结构。
36 14

热门文章

最新文章

AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等