How to use golang viper Watchconfig & onConfigChange

huangapple go评论129阅读模式
英文:

How to use golang viper Watchconfig & onConfigChange

问题

我正在尝试使用golang的viper库读取我的应用程序配置,并希望始终读取最新的配置。请查看下面的代码:

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"))
}

当主程序运行时,我尝试更新配置,并期望看到"OnConfigChange"的日志消息,但从未显示出来。

你可以如何修复这个程序?

有人可以提供一个使用viper的WatchConfig和OnConfigChange方法读取最新配置的示例吗?

英文:

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

答案1

得分: 3

ymonad的评论是正确的,根据你的操作系统,你可能会遇到viper/fsnotify的问题。

例如,我在Mac OS X(Sierra)上运行了你的示例代码,并注意到你描述的相同症状:当配置文件位于/tmp时,viper的WatchConfig调用不会触发viper的OnConfigChange函数。

然而,当我将AddConfigPath更改为使用当前工作目录或我的主目录时,我确实能够看到来自你的OnConfigChange函数的日志。例如,尝试一下:

v.AddConfigPath("./")

我建议尝试不同的目录位置,看看这是否是viper/fsnotify的某种错误或限制。由于某种原因,在Mac OS X上,它似乎无法检测到/tmp目录中的更改,至少对于我的设置来说是这样。我在OS X上找不到关于/tmp的任何问题的提及,但是fsnotify的CONTRIBUTING.md提到了在Vagrant下的“共享”目录的限制,因此可能存在一些文件系统配置不会触发通知的情况:

> 注意:在共享文件夹中,fsnotify文件系统事件不会触发。测试通过使用/tmp目录来解决这个限制。

另外,你不需要通过goroutine不断调用WatchConfigOnConfigChange。你可以完全消除goroutine,并将相关行移到init函数中。

英文:

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.

huangapple
  • 本文由 发表于 2017年2月5日 07:33:22
  • 转载请务必保留本文链接:https://go.coder-hub.com/42046893.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定