读取和设置环境变量
发布者:admin 发表于:417天前 阅读数:613 评论:0

除了读取文件和命令行传递参数外,环境变量是另一个向应用传递参数的方式。本文将简单探讨如何获取和操作基本的环境变量,然后我们一起来看看如何结合第三方库https://github.com/kelseyhightower/envconfig(Star 1741)来使用。

我们将构建一个可以通过JSON或环境变量读取配置的应用程序。下一章节将进一步探索其他替代格式,包括TOML和YAML。

实践

1.创建config.go:

package envvar

import (
    "encoding/json"
    "os"

    "github.com/kelseyhightower/envconfig"
    "github.com/pkg/errors"
)

// LoadConfig将从存储在路径中的json文件中选择加载文件,
// 然后根据envconfig struct标记覆盖这些值。
// envPrefix是我们为环境变量添加的前缀。
func LoadConfig(path, envPrefix string, config interface{}) error {
    if path != "" {
        err := LoadFile(path, config)
        if err != nil {
            return errors.Wrap(err, "error loading config from file")
        }
    }

    // envconfig.Process根据环境变量填充指定的结构
    err := envconfig.Process(envPrefix, config)
    return errors.Wrap(err, "error loading config from env")
}

// LoadFile 解析一个json文件并填充到config中
func LoadFile(path string, config interface{}) error {
    configFile, err := os.Open(path)
    if err != nil {
        return errors.Wrap(err, "failed to read config file")
    }
    defer configFile.Close()

    decoder := json.NewDecoder(configFile)
    if err = decoder.Decode(config); err != nil {
        return errors.Wrap(err, "failed to decode config file")
    }
    return nil
}

2.创建main.go:

package main

import (
    "bytes"
    "fmt"
    "io/ioutil"
    "os"

    "myConcurrency/chapter2/envvar"
)

// Config 将保存我们从json文件和环境变量中捕获的配置
type Config struct {
    Version string `json:"version" required:"true"`
    IsSafe  bool   `json:"is_safe" default:"true"`
    Secret  string `json:"secret"`
}

func main() {
    var err error

    // 建立一个临时json配置文件
    tf, err := ioutil.TempFile("", "tmp")
    if err != nil {
        panic(err)
    }
    defer tf.Close()
    defer os.Remove(tf.Name())

    // json 配置文件的内容
    secrets := `{
        "secret": "so so secret"
    }`

    if _, err = tf.Write(bytes.NewBufferString(secrets).Bytes()); err != nil {
        panic(err)
    }

    // 向环境变量中添加变量及对应值
    if err = os.Setenv("EXAMPLE_VERSION", "1.0.0"); err != nil {
        panic(err)
    }
    if err = os.Setenv("EXAMPLE_ISSAFE", "false"); err != nil {
        panic(err)
    }

    c := Config{}
    // 从文件中读取配置参数
    if err = envvar.LoadConfig(tf.Name(), "EXAMPLE", &c); err != nil {
        panic(err)
    }

    fmt.Println("secrets file contains =", secrets)

    // 获取环境变量参数及对应值
    fmt.Println("EXAMPLE_VERSION =", os.Getenv("EXAMPLE_VERSION"))
    fmt.Println("EXAMPLE_ISSAFE =", os.Getenv("EXAMPLE_ISSAFE"))

    // c既保存了json配置文件的参数也保存了环境变量的参数 我们将其打印
    fmt.Printf("Final Config: %#v\n", c)

}

3.运行main.go,这会输出:

secrets file contains = {
"secret": "so so secret"
}
EXAMPLE_VERSION = 1.0.0
EXAMPLE_ISSAFE = false
Final Config: main.Config{Version:"1.0.0", IsSafe:false,
Secret:"so so secret"}

说明

使用os包可以很容易的设置和读取环境变量。第三方库envconfig使用结构体tag将环境变量映射给结构体的方式很巧妙,有兴趣可以阅读其源码。

LoadConfig函数可以从各种来源获取配置信息,而不会产生大量开销或太多额外的依赖关系值得借鉴。

另外,请注意错误的处理。在此章节中使用errors.Wrap来生成错误,以便我们可以在不丢失原始错误信息的情况下注释错误。有关详细信息,请参阅第4章“错误处理“