0

I am trying to read my application configuration using golang viper and would like to read the latest config always. Please find my code below

config.go

package config

import (
    "github.com/spf13/viper"
    "log"
    "github.com/fsnotify/fsnotify"
    "time"
)

type Reader interface {
    GetAllKeys() []string
    Get(key string) interface{}
    GetBool(key string) bool
    GetString(key string) string
}

type viperConfigReader struct {
    viper *viper.Viper
}

var TestConfReader *viperConfigReader

func (v viperConfigReader) GetAllKeys() []string{
    return v.viper.AllKeys()
}

func (v viperConfigReader) Get(key string) interface{} {
    return v.viper.Get(key)
}

func (v viperConfigReader) GetBool(key string) bool {
    return v.viper.GetBool(key)
}

func (v viperConfigReader) GetString(key string) string {
    return v.viper.GetString(key)
}


func init() {
    v:= viper.New()
    v.SetConfigName("test")
    v.AddConfigPath("/tmp/")

    err := v.ReadInConfig()

    if err != nil {
        log.Panic("Not able to read configuration", err.Error())
    }

    TestConfReader = &viperConfigReader{
        viper: v,
    }

    go func() {
        for {
            time.Sleep(time.Second * 5)
            v.WatchConfig()
            v.OnConfigChange(func(e fsnotify.Event) {
                log.Println("config file changed", e.Name)
            })
        }
    }()
}

main.go

package main

import (
    "github.com/xxxx/xxxx/config"
    "log"
    "time"
)

func main() {

    conf := config.TestConfReader

    log.Println(conf.GetAllKeys())
    log.Println(conf.GetString("test1"))

    time.Sleep(20 * time.Second)

    log.Println(conf.GetString("test1"))
}

When the main program is running, I tried to update the config and expected to see OnConfigChange log message but it never showed up.

How can I fix this program ?.

Can someone provide an example of using viper watchconfig & onconfigchange methods to read the latest config

inari6
  • 401
  • 1
  • 9
  • 19
  • 2
    Your code works as expected and correctly triggers `OnConfigChange` in my Linux environment. You should write your OS, and maybe mount option of `/tmp/` to get help. – ymonad Feb 05 '17 at 00:30
  • Thanks for your quick response. I moved my config to current working directory and it worked. – inari6 Feb 06 '17 at 18:18

1 Answers1

3

The comment by ymonad is on the right track, depending on your OS you may be experiencing problems with viper/fsnotify.

For example, I ran your example code on Mac OS X (Sierra) and noticed the same symptom you described: when the config file is in /tmp the viper WatchConfig call was not causing the viper OnConfigChange function to be called.

However, when I change the AddConfigPath to use the current working directory or my home directory then I do see logging from your OnConfigChange function. For example, try:

v.AddConfigPath("./")

I'd recommend experimenting with different directory locations to see if this is some sort of viper/fsnotify bug or limitation. For some reason, it doesn't appear to detect changes from the /tmp directory on Mac OS X, at least, it doesn't for my setup. I couldn't find any mention of problems with /tmp on OS X, but the fsnotify CONTRIBUTING.md does mention limitations with "shared" directories under Vagrant so perhaps there are some filesystem configurations that do not trigger notifications:

Notice: fsnotify file system events won't trigger in shared folders. The tests get around this limitation by using the /tmp directory.

Also, you don't need to keep calling WatchConfig and OnConfigChange via your goroutine. You can eliminate the goroutine completely and just move the relevant lines into init.

Community
  • 1
  • 1
Drew MacInnis
  • 8,267
  • 1
  • 22
  • 18
  • Thanks for your quick response. In my mac, moved config to current working directory and it worked. I also moved WatchConfig & OnConfigChange to init function. – inari6 Feb 06 '17 at 18:19