viper简介

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

  • 设置默认值
  • JSONTOMLYAMLHCLenvfileJava属性配置文件中读取
  • 实时观看和重新读取配置文件(可选)
  • 从环境变量中读取
  • 从远程配置系统(etcd 或 Consul)读取,并观察变化
  • 从命令行标志读取
  • 从缓冲区读取
  • 设置显式值

读取配置文件

app.yaml

1server:
2  host: 0.0.0.0
3  port: 9090
4log:
5  level: debug
6  format: json

main.go

创建配置文件结构体

 1var cfg Cfg
 2
 3type Cfg struct {
 4  Server Server `yaml:"server"`
 5  Log    Log    `yaml:"log"`
 6}
 7type Server struct {
 8  Host string `yaml:"host"`
 9  Port int    `yaml:"port"`
10}
11
12type Log struct {
13  Level  string `yaml:"level"`
14  Format string `yaml:"format"`
15}

使用viper读取配置文件并解析到结构体

 1func initConfig() {
 2  viper.AddConfigPath("./")
 3  viper.SetConfigName("apps")
 4  viper.SetConfigType("yaml")
 5  if err := viper.ReadInConfig(); err != nil {
 6    log.Fatalf("read config file failed, %v", err)
 7  }
 8  if err := viper.Unmarshal(&cfg); err != nil {
 9    log.Printf("unmarshal config file failed, %v", err)
10  }
11  log.Printf("%#v", cfg)
12}

设置日志相关参数

 1func initLog() {
 2  switch strings.ToLower(cfg.Log.Level) {
 3  case "panic":
 4    logrus.SetLevel(logrus.PanicLevel)
 5  case "fatal":
 6    logrus.SetLevel(logrus.FatalLevel)
 7  case "error":
 8    logrus.SetLevel(logrus.ErrorLevel)
 9  case "warn", "warning":
10    logrus.SetLevel(logrus.WarnLevel)
11  case "info":
12    logrus.SetLevel(logrus.InfoLevel)
13  case "debug":
14    logrus.SetLevel(logrus.DebugLevel)
15  case "trace":
16    logrus.SetLevel(logrus.TraceLevel)
17  default:
18    logrus.SetLevel(logrus.InfoLevel)
19  }
20  switch strings.ToLower(cfg.Log.Format) {
21  case "json":
22    logrus.SetFormatter(&logrus.JSONFormatter{})
23  case "text":
24    logrus.SetFormatter(&logrus.TextFormatter{})
25  default:
26    logrus.SetFormatter(&logrus.TextFormatter{})
27  }
28}

main函数

1func main() {
2  r := gin.Default()
3  logrus.Debug("i'm a debug log")
4  logrus.Info("i'm a info log")
5  logrus.Warn("i'm a warn log")
6  logrus.Error("i'm a error log")
7  r.Run(cfg.Server.Host + ":" + strconv.Itoa(cfg.Server.Port))
8}

运行

1go run main.go

输出结果

 12021/06/30 10:12:16 main.Cfg{Server:main.Server{Host:"0.0.0.0", Port:9090}, Log:main.Log{Level:"debug", Format:"json"}}
 2[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.
 3
 4[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
 5 - using env:   export GIN_MODE=release
 6 - using code:  gin.SetMode(gin.ReleaseMode)
 7
 8{"level":"debug","msg":"i'm a debug log","time":"2021-06-30T10:12:16+08:00"}
 9{"level":"info","msg":"i'm a info log","time":"2021-06-30T10:12:16+08:00"}
10{"level":"warning","msg":"i'm a warn log","time":"2021-06-30T10:12:16+08:00"}
11{"level":"error","msg":"i'm a error log","time":"2021-06-30T10:12:16+08:00"}
12[GIN-debug] Listening and serving HTTP on 0.0.0.0:9090

可以看到已经从配置文件读取到配置了。

从环境变量读取配置

1.修改initConfig函数,开启自动注入环境变量功能

在读取配置文件之前使用AutomaticEnv,并使用SetEnvKeyReplacer将".“替换为”" 注:如果是yaml字段有使用到"",可以替换成其他的,或者使用"__"

环境变量的格式为:SERVER_PORT

1...
2  viper.SetConfigType("yaml")
3  viper.AutomaticEnv()
4  replacer := strings.NewReplacer(".", "_")
5  viper.SetEnvKeyReplacer(replacer)
6  if err := viper.ReadInConfig(); err != nil {
7...

2.运行测试

1SERVER_PORT=10086 go run main.go
 12021/06/30 15:45:19 main.Cfg{Server:main.Server{Host:"", Port:10086}, Log:main.Log{Level:"debug", Format:"json"}}
 2[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.
 3
 4[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
 5 - using env:	export GIN_MODE=release
 6 - using code:	gin.SetMode(gin.ReleaseMode)
 7
 8{"level":"debug","msg":"i'm a debug log","time":"2021-06-30T15:45:19+08:00"}
 9{"level":"info","msg":"i'm a info log","time":"2021-06-30T15:45:19+08:00"}
10{"level":"warning","msg":"i'm a warn log","time":"2021-06-30T15:45:19+08:00"}
11{"level":"error","msg":"i'm a error log","time":"2021-06-30T15:45:19+08:00"}
12[GIN-debug] Listening and serving HTTP on :10086

看到端口已经自动变成10086了。

修改日志相关变量

1LOG_LEVEL=info LOG_FORMAT=text go run viper.go

可以看到日志级别和日志格式已经为环境变量指定的了。

 12021/06/30 15:46:50 main.Cfg{Server:main.Server{Host:"", Port:9090}, Log:main.Log{Level:"info", Format:"text"}}
 2[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.
 3
 4[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
 5 - using env:	export GIN_MODE=release
 6 - using code:	gin.SetMode(gin.ReleaseMode)
 7
 8INFO[0000] i'm a info log
 9WARN[0000] i'm a warn log
10ERRO[0000] i'm a error log
11[GIN-debug] Listening and serving HTTP on :9090