英文:
How to setup a golang app config according to the environment using yaml file
问题
我正在尝试设置一个配置结构体,以在我的应用程序中使用。
目前,我加载一个yaml文件并将其解码到我的配置结构体中。
config.yml
database_url: postgres://postgres:@localhost:5432/database_dev
config.go
import (
"os"
"gopkg.in/yaml.v2"
)
type AppConfig struct {
DatabaseUrl string `yaml:"database_url"`
}
func LoadConfig() *AppConfig {
appConfig := &AppConfig{}
file, _ := os.Open("config.yml")
defer f.Close()
decoder := yaml.NewDecoder(file)
decoder.Decode(config)
return appConfig
}
它运行得非常好,但现在我需要根据环境(测试、本地、生产等)设置不同的配置。
我想使用嵌套的yaml文件来声明环境变量。
config.yml
dev:
database_url: postgres://postgres:@localhost:5432/database_dev
test:
database_url: postgres://postgres:@localhost:5432/database_test
我希望在我的LoadConfig
函数中接收环境作为参数,并获取正确的配置。但我不知道如何做。
config.go
type configFile struct {
Dev struct { AppConfig }`yaml:"dev"`
Test struct { AppConfig }`yaml:"test"`
}
func LoadConfig(env string) *AppConfig {
appConfig := &AppConfig{}
configFile := &configFile{}
file, _ := os.Open("config.yml")
defer f.Close()
decoder := yaml.NewDecoder(file)
decoder.Decode(configFile)
// 在这里如何获取正确的结构体?
// config = configFile["env"]
// 它不起作用
// invalid operation: cannot index configFile (variable of type *configFile)
return appConfig
}
欢迎任何建议。
英文:
Im trying to setup a config struct to use through my application.
Currently I load a yaml file and decode it in my config struct.
config.yml
database_url: postgres://postgres:@localhost:5432/database_dev
config.go
import (
"os"
"gopkg.in/yaml.v2"
)
type AppConfig struct {
DatabaseUrl string `yaml:"database_url"`
}
func LoadConfig() *AppConfig {
appConfig := &AppConfig{}
file, _ := os.Open("config.yml")
defer f.Close()
decoder := yaml.NewDecoder(file)
decoder.Decode(config)
return appConfig
}
It works really fine, but now I need to setup different configuration according with the environment (test, local, production, etc.).
I thought that I could use a nested yaml file to declare the environments variables.
config.yml
dev:
database_url: postgres://postgres:@localhost:5432/database_dev
test:
database_url: postgres://postgres:@localhost:5432/database_test
I would like to receive the environment as a parameter in my LoadConfig
function, and get the correct configuration.
But I have no idea how to.
config.go
type configFile struct {
Dev struct { AppConfig }`yaml:"dev"`
Test struct { AppConfig }`yaml:"test"`
}
func LoadConfig(env string) *AppConfig {
appConfig := &AppConfig{}
configFile := &configFile{}
file, _ := os.Open("config.yml")
defer f.Close()
decoder := yaml.NewDecoder(file)
decoder.Decode(configFile)
// How to get the correct struct here ?
// config = configFile["env"]
// It doesn't works
// invalid operation: cannot index configFile (variable of type *configFile)
return appConfig
}
Any suggestion is welcome.
答案1
得分: 0
如果环境列表是任意的,那么你不需要在顶层使用struct
,而是需要使用map[string]AppConfig
。代码如下所示:
package main
import (
"fmt"
"os"
"gopkg.in/yaml.v2"
)
type (
AppConfig struct {
DatabaseUrl string `yaml:"database_url"`
}
ConfigFile map[string]*AppConfig
)
func LoadConfig(env string) (*AppConfig, error) {
configFile := ConfigFile{}
file, _ := os.Open("config.yml")
defer file.Close()
decoder := yaml.NewDecoder(file)
// 总是检查错误!
if err := decoder.Decode(&configFile); err != nil {
return nil, err
}
appConfig, ok := configFile[env]
if !ok {
return nil, fmt.Errorf("no such environment: %s", env)
}
return appConfig, nil
}
func main() {
appConfig, err := LoadConfig(os.Args[1])
if err != nil {
panic(err)
}
fmt.Printf("config: %+v\n", appConfig)
}
假设我们有你问题中提到的config.yml
文件,我们可以使用不同的环境运行上述示例,并查看所需的输出:
$ ./example test
config: &{DatabaseUrl:postgres://postgres:@localhost:5432/database_test}
$ ./example dev
config: &{DatabaseUrl:postgres://postgres:@localhost:5432/database_dev}
英文:
If the list of environments is arbitrary, then you don't want a struct
for the top level; you want a map[string]AppConfig
. That would look something like this:
package main
import (
"fmt"
"os"
"gopkg.in/yaml.v2"
)
type (
AppConfig struct {
DatabaseUrl string `yaml:"database_url"`
}
ConfigFile map[string]*AppConfig
)
func LoadConfig(env string) (*AppConfig, error) {
configFile := ConfigFile{}
file, _ := os.Open("config.yml")
defer file.Close()
decoder := yaml.NewDecoder(file)
// Always check for errors!
if err := decoder.Decode(&configFile); err != nil {
return nil, err
}
appConfig, ok := configFile[env]
if !ok {
return nil, fmt.Errorf("no such environment: %s", env)
}
return appConfig, nil
}
func main() {
appConfig, err := LoadConfig(os.Args[1])
if err != nil {
panic(err)
}
fmt.Printf("config: %+v\n", appConfig)
}
Assuming we have the config.yml
from your question, we can run the above example with different environments and see the desired output:
$ ./example test
config: &{DatabaseUrl:postgres://postgres:@localhost:5432/database_test}
$ ./example dev
config: &{DatabaseUrl:postgres://postgres:@localhost:5432/database_dev}
答案2
得分: 0
我认为除了设置一个配置文件之外,你还应该创建一个YML文件,并将服务器端口放在其中...
不幸的是,我经验不足,所以可能没有给出正确的答案。
英文:
I think furthermore setting up a config file ,you should create a YML file and put this the server port...
Unfortunately I am inexperienced Therefore, I may not have given the correct answer.
答案3
得分: 0
我认为一种方法是我们可以为不同的环境使用不同的配置文件。例如,在开发环境中,我们有config_dev.yaml
,在生产环境中,我们有config_prod.yaml
。
然后我们在引导脚本中指定环境变量。例如,我们通过export MyEnv=dev && ./my_app
来运行应用程序。在代码中,我们检查MyEnv
来决定使用哪个配置文件。在这种情况下,我们发现MyEnv
是dev
,所以我们使用config_dev.yaml
。
英文:
I think one way is that we can different config files for different environments. For example, in dev environment we have config_dev.yaml
, in production, we have config_prod.yaml
.
Then we specify environment variable in the bootstrap scripts. For example we run the app by export MyEnv=dev && ./my_app
. In the code, we check MyEnv
to decide which config file we would use. In this case, we found MyEnv is dev
so we use config_dev.yaml
.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论