golang通过文件环境变量和命令行标志快速配置应用的插件库config的使用

Golang通过文件、环境变量和命令行标志快速配置应用的插件库config使用

特性

  • 声明式定义配置的方式
  • 只需一行代码即可从文件、环境变量或命令行参数读取配置
  • 支持验证功能

示例

config是一个支持从文件、环境变量和命令行参数读取配置到结构体的包。你只需要声明一个配置结构体并调用Read方法。

package main

import (
	"fmt"

	"github.com/num30/config"
)

type Config struct {
	DB        Database `default:{}`
	DebugMode bool     `flag:"debug" usage:"enable verbose debug logging"`
}

type Database struct {
	Host     string `default:"localhost" validate:"required"`
	Password string `validate:"required" envvar:"DB_PASS"`
	DbName   string `default:"mydb"`
	Username string `default:"root"`
	Port     int    `default:"5432"`
}

func main() {
	var conf Config
	err := config.NewConfReader("myconf").Read(&conf)
	if err != nil {
		panic(err)
	}

	fmt.Printf("Config %+v", conf)
}

当你想改变应用的数据库主机时,可以通过3种方式实现:

  1. 在home目录创建配置文件myconf.yaml
db:
   host: "localhost"
  1. 设置环境变量,如DB_HOST=localhost

  2. 设置命令行参数,如--db.host=localhost

安装

go get github.com/num30/config

设置配置值

ConfReader按照以下顺序合并来自三个来源的值:

  1. 文件
  2. 环境变量
  3. 命令行参数

在文件中设置的相同键会被环境变量覆盖,而命令行参数具有最高优先级。但是,你可以在文件中设置一个键,在环境变量或命令行参数中设置其他键,这些将被合并。

配置文件

名称

ConfReader将使用配置名称属性来搜索具有该名称的配置文件。

位置

默认情况下,配置读取器将在home或当前目录中搜索配置文件。你可以通过使用NewConfReader("myconf").WithSearchDirs("/etc/conf")来覆盖此行为。

引用字段

字段名称从以小写字母开头的驼峰式转换为小写下划线式。例如,如果在代码中你将值引用为DB.DbName,那么它将转换为:

db:
   dbName: "mydb"

格式

配置文件类型可以是任何viper支持的类型:JSON、TOML、YAML、HCL、INI、envfile和Java Properties文件。

环境变量

要通过环境变量设置标志,请将所有字母大写并用’_‘替换路径中的’.’。例如:app.Server.Port -> APP_SERVER_PORT

你可以为环境变量设置前缀。例如NewConfReader("myconf").WithPrefix("MYAPP")将搜索类似MYAPP_DB_HOST的环境变量

可以在结构体标签envvar中设置环境变量名称。例如:

Password string `envvar:"DB_PASS"`

将使用环境变量DB_PASS的值来配置Password字段。

命令行参数

要通过命令行参数设置配置字段,你需要传递以--为前缀的参数和小写的带路径的字段名。如--db.host=localhost

布尔值可以通过仅传递标志名称来设置,如--verbose

你可以通过在字段上使用标签flag:"name"来覆盖标志的名称。例如:

type Config struct {		
	DebugMode             bool `flag:"debug"`
}

你可以通过调用myapp --debug来设置标志

验证

你可以通过使用validate标签来验证配置结构体的字段。例如:

type Config struct {		
    Host           string `validate:"required"`
}

常见问题

  • 如何为切片设置值? 如果我们有这样的结构体:
type SliceConf struct {
    Slice []string
}

那么我们可以通过以下方式为切片设置值:

  • 环境变量 export SLICE="a,b"
  • 命令行参数 myapp --slice", "a", "--slice", "b"
  • 配置文件 slice: [ "a", "b"]

贡献

我们喜欢帮助!通过fork仓库并打开pull request或创建issue来贡献。

致谢

这个包基于Viper 特别感谢:

  • enviper使环境变量与viper一起工作
  • defaults使默认值与结构体一起工作

更多关于golang通过文件环境变量和命令行标志快速配置应用的插件库config的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang通过文件环境变量和命令行标志快速配置应用的插件库config的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Golang 配置管理:使用 config 插件库

在 Go 语言中,管理应用配置有多种方式,包括环境变量、命令行参数和配置文件等。下面我将介绍如何使用流行的 config 插件库来统一管理这些配置源。

安装 config 库

首先安装 config 库:

go get github.com/olebedev/config

基本使用示例

package main

import (
	"fmt"
	"log"
	"os"

	"github.com/olebedev/config"
)

type AppConfig struct {
	Server struct {
		Host string `json:"host"`
		Port int    `json:"port"`
	} `json:"server"`
	Database struct {
		URL      string `json:"url"`
		Username string `json:"username"`
		Password string `json:"password"`
	} `json:"database"`
	Debug bool `json:"debug"`
}

func main() {
	// 1. 从默认配置文件加载
	cfg, err := config.ParseYamlFile("config.yaml")
	if err != nil {
		log.Printf("Warning: %v, using default config", err)
		
		// 创建默认配置
		cfg, err = config.ParseYaml(`
server:
  host: localhost
  port: 8080
database:
  url: localhost:5432
  username: postgres
  password: postgres
debug: false
`)
		if err != nil {
			log.Fatal(err)
		}
	}

	// 2. 从环境变量覆盖配置
	if host := os.Getenv("APP_SERVER_HOST"); host != "" {
		cfg.Set("server.host", host)
	}
	if port := os.Getenv("APP_SERVER_PORT"); port != "" {
		cfg.Set("server.port", port)
	}

	// 3. 解析到结构体
	var appConfig AppConfig
	if err := cfg.Unmarshal(&appConfig); err != nil {
		log.Fatal(err)
	}

	fmt.Printf("Final config: %+v\n", appConfig)
}

支持多配置源的高级用法

下面是一个更完整的示例,支持 JSON/YAML 配置文件、环境变量和命令行参数:

package main

import (
	"flag"
	"fmt"
	"log"
	"os"

	"github.com/olebedev/config"
)

func main() {
	// 定义命令行参数
	configFile := flag.String("config", "config.yaml", "Path to config file")
	debug := flag.Bool("debug", false, "Enable debug mode")
	port := flag.Int("port", 0, "Server port")
	flag.Parse()

	// 尝试加载配置文件
	cfg, err := config.ParseYamlFile(*configFile)
	if err != nil {
		log.Printf("Warning: %v, using default config", err)
		cfg, _ = config.ParseYaml("") // 创建空配置
	}

	// 环境变量覆盖
	if envHost := os.Getenv("APP_HOST"); envHost != "" {
		cfg.Set("server.host", envHost)
	}
	if envPort := os.Getenv("APP_PORT"); envPort != "" {
		cfg.Set("server.port", envPort)
	}

	// 命令行参数覆盖(最高优先级)
	if *port > 0 {
		cfg.Set("server.port", *port)
	}
	if *debug {
		cfg.Set("debug", true)
	}

	// 获取配置值
	host, _ := cfg.String("server.host")
	portVal, _ := cfg.Int("server.port")
	debugVal, _ := cfg.Bool("debug")

	fmt.Printf("Server will run on %s:%d, debug mode: %v\n", 
		host, portVal, debugVal)
}

配置优先级

通常配置源的优先级如下(从低到高):

  1. 默认值(代码中硬编码)
  2. 配置文件(JSON/YAML)
  3. 环境变量
  4. 命令行参数

最佳实践

  1. 配置文件模板:提供一个 config.yaml.example 文件作为模板
  2. 环境变量命名:使用统一前缀如 APP_ 避免冲突
  3. 敏感信息:不要将密码等敏感信息提交到版本控制
  4. 配置验证:加载配置后验证必填项和格式

其他替代方案

除了 olebedev/config,还有其他流行的配置管理库:

  1. Viper:功能最全,支持多种配置格式和环境变量
  2. Koanf:轻量级,支持多种配置源和格式
  3. Envconfig:专注于环境变量到结构体的映射

选择哪个库取决于你的具体需求,对于简单应用,olebedev/config 已经足够;对于复杂需求,Viper 可能是更好的选择。

回到顶部