Config file with cobra and viper
Asked Answered
R

1

9

Basic information: I have created a go application and used Cobra for it. Cobra uses Viper for command line parameters and flags.

I have a command listen with a flag bind and I want to configure it in a yaml file.

Code:

The init function of the listen command looks like this:

func init() {
    RootCmd.AddCommand(listenCmd)
    listenCmd.Flags().StringP("bind", "b", ":50051", "Provide bind definition")
    viper.BindPFlag("bind", listenCmd.Flags().Lookup("bind"))
}

Code of my application is at https://github.com/sascha-andres/go-logsink

Problem:

When I call the app with listen --bind "bla" the flag is set correctly to bla, but I have not found a way to achieve this using a YAML file located in my home directory.

Config files tried:

---

connect:
  bind: "bla"

and

---

bind: "bla"

In both cases the config file was found but the flag had not the expected value but the default value.

How do I have to write the config file to have the flag populated correctly?

Recess answered 10/1, 2017 at 20:56 Comment(5)
Sorry, I am unable to reproduce your problem: I tried with my yaml config file in /tmp and your code, and the bind param was correctly found and set to its config value. However, I noticed that the bind param must not be nested to be found, is that the case in your config ?Risteau
@T.Claverie I have currently the second version ( not nested ). I have pasted it at pastebin.com/7TcqrdgV. Updated question with link to the complete sourceRecess
Possible duplicate of why is cobra not reading my config fileTarbox
@Tarbox for your reference: this is 1 year 5 months old, the other one 1 year 2 months, no need to vote for close hereRecess
@Recess I know, but the other question is slightly more understandable, as it includes the problematic part - using variable bound to pflag instead of viper.GetString() - and this question only has a link to repository which no longer has the code in question.Tarbox
R
9

Ok, thanks for the additional information, It helped a lot !

Problem

The problem arises from the way you're retrieving the value of the flag. Here is what you currently have:

bind := cmd.Flag("bind").Value.String()
fmt.Printf("Binding definition provided: %s\n", bind)
server.Listen(bind)

When binding a flag with viper, it's actually viper that will hold the final value, according to this priorities:

1. If present, use the flag value
2. Else, use the value from the config file
3. Else, use the default flag value

Your problem is that you retrieve the flag value from the flag set of the command, and not from viper.

Behavior

Here is the code I tested:

bind := cmd.Flag("bind").Value.String()
fmt.Printf("Binding definition provided: %s\n", bind)
fmt.Printf("Binding definition provided from viper: %s\n", viper.GetString("bind"))

Without the bind config param:

$ go-logsink listen
Using config file: /xxx/.go-logsink.yaml
Binding definition provided: :50051
Binding definition provided from viper: :50051

With the bind config param set to "bla" (not nested, second config file):

$ go-logsink listen
Using config file: /xxx/.go-logsink.yaml
Binding definition provided: :50051
Binding definition provided from viper: bla

With the bind config param set to "bla" (not nested, second config file) and an explicit flag:

$ go-logsink listen --bind ":3333"
Using config file: /xxx/.go-logsink.yaml
Binding definition provided: :3333
Binding definition provided from viper: :3333

Bottomline : when binding your flags with viper, use viper to retrieve them.

Additional note : In your README, the proper way to generate grpc compatible code is by adding the grpc plugin to protobuf generation: protoc --go_out=plugins=grpc:. *.proto

Risteau answered 11/1, 2017 at 12:32 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.