I'm using the excellent viper library from here: https://github.com/spf13/viper
I'm trying to read in a config file in hcl (although it could be a JSOn or YAML file as well) which looks like this:
interval = 10
statsd_prefix = "pinger"
group "dns" {
target_prefix = "ping"
target "dns" {
hosts = [
"dnsserver1",
"dnsserver2"
]
}
}
The code I have so far looks like this:
viper.SetConfigName("config")
viper.AddConfigPath(".")
err := viper.ReadInConfig()
if err != nil {
panic(fmt.Errorf("Fatal error config file: %s \n", err))
}
interval := viper.GetInt("interval")
prefix := viper.GetString("statsd_prefix")
groups := viper.GetStringMap("group")
fmt.Println(interval)
fmt.Println(prefix)
The big problem I'm having is with the group option. This can be multiple different groups.
It doesn't seem to work when I read it in using viper.GetStringMap
, so I used the standard viper.Get
function. The resulting structure looks like this when dumped:
([]map[string]interface {}) (len=1 cap=1) {
(map[string]interface {}) (len=1) {
(string) (len=3) "dns": ([]map[string]interface {}) (len=1 cap=2) {
(map[string]interface {}) (len=2) {
(string) (len=13) "target_prefix": (string) (len=4) "ping",
(string) (len=6) "target": ([]map[string]interface {}) (len=1 cap=1) {
(map[string]interface {}) (len=1) {
(string) (len=8) "dns": ([]map[string]interface {}) (len=1 cap=1) {
(map[string]interface {}) (len=1) {
(string) (len=5) "hosts": ([]interface {}) (len=2 cap=2) {
(string) (len=18) "dnsserver1",
(string) (len=18) "dnsserver2"
}
}
}
}
}
}
}
}
}
It seems to be of type slice when I use reflect. Do I need to cast it to a slice? How do I do that? Is there an easier way of managing a data structure like this?
I'm completely new to golang, so please go easy on me :)
Instead of call raw Get and then decide what exactly you get I'd suggest first describe your desired config structure, something like
type config struct {
interval int `mapstructure:"Interval"`
statsdPrefix string `mapstructure:"statsd_prefix"`
groups []group
}
type group struct {
group string `mapstructure:"group"`
targetPrefix string `mapstructure:"target_prefix"`
targets []target
}
type target struct {
target string `mapstructure:"target"`
hosts []string `mapstructure:"hosts"`
}
and than unmarshall(decode) in it
var C config
err := viper.Unmarshal(&C)
if err != nil {
t.Fatalf("unable to decode into struct, %v", err)
}
assuming decoder is smart enough to unmurshall in provided structure if it possible and meaningful.
The question is a bit older, but I figured since I stumbled upon this, somebody else might come here looking...
The primary issue in the original question is that this JSON notation defines a list, not a map:
hosts = [
"dnsserver1",
"dnsserver2"
]
So the simple solution in this case is not to use viper.GetStringMap("group")
, but instead viper.GetStringSlice("group")
.
A slice in GO is what most other programming languages refer to as an Array or a List.
So in this case, the Slice would then be ["dnsserver1", "dnsserver2"]
.
If you wanted to properly use the GetStringMap()
function of viper, you need a different format in your config file, namely a map format:
"hosts": {
"dnsserver1": "8.8.8.8",
"dnsserver2": "8.8.4.4"
}
This can then be parsed using viper.GetStringMap()
into a map[string]string
Structure, which looks like this: map["dnsserver1":"8.8.8.8" "dnsserver2":"8.8.4.4"]
.
You could then access the map at a given key, like map["dnsserver1"]
which would give you a string containing "8.8.8.8".
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With