duangou6446 2019-09-09 10:32
浏览 25
已采纳

如何在配置文件中更改值不提供该值

I want to do some watch when env variable/ config property value is changed I’ve found viper which should support this scenario but didn't able to make it work. I see that the OnConfigChange is called but the value from config is not taken from the config when it change. The config is loaded successfully

I’ve created a sample to demonstrate the issue.

File cfg.go

go/src/myproj/configuration/cfg.go

package configuration

import (
   "fmt"
   "os"
   "strings"

   "github.com/fsnotify/fsnotify"
   "github.com/sirupsen/logrus"
   "github.com/spf13/viper"
)

const (
   varLogLevel     = "log"
   varPathToConfig = "config.file"
)

type Configuration struct {
   v *viper.Viper
}

func New() *Configuration {
   c := Configuration{
      v: viper.New(),
   }

   c.v.SetDefault(varPathToConfig, "./config.yaml")
   c.v.SetDefault(varLogLevel, "info")
   c.v.AutomaticEnv()
   c.v.SetConfigFile(c.GetPathToConfig())
   err := c.v.ReadInConfig() // Find and read the config file
   logrus.WithField("path", c.GetPathToConfig()).Warn("loading config")
   // just use the default value(s) if the config file was not found
   if _, ok := err.(*os.PathError); ok {
      logrus.Warnf("no config file '%s' not found. Using default values", c.GetPathToConfig())
   } else if err != nil { // Handle other errors that occurred while reading the config file
      panic(fmt.Errorf("fatal error while reading the config file: %s", err))
   }
   setLogLevel(c.GetLogLevel())
   // monitor the changes in the config file
   c.v.WatchConfig()
   c.v.OnConfigChange(func(e fsnotify.Event) {
      logrus.WithField("file", e.Name).Warn("Config file changed")
      setLogLevel(c.GetLogLevel())
   })
   return &c
}

// GetLogLevel returns the log level
func (c *Configuration) GetLogLevel() string {
   s := c.v.GetString(varLogLevel)
   return s
}

// GetPathToConfig returns the path to the config file
func (c *Configuration) GetPathToConfig() string {
   return c.v.GetString(varPathToConfig)
}

func setLogLevel(logLevel string) {
   logrus.WithField("level", logLevel).Warn("setting log level")
   level, err := logrus.ParseLevel(logLevel)
   if err != nil {
      logrus.WithField("level", logLevel).Fatalf("failed to start: %s", err.Error())
   }
   logrus.SetLevel(level)
}

And I create some sample web-application server to make the program running in background (to be able to change the config and see wheatear something is changed )

go/src/myproj

package main

import (
   "fmt"
   "net/http"
   "myproj/configuration"
)

func main() {

   cfg := configuration.New()
   fmt.Println(cfg)

   http.HandleFunc("/", HelloServer)
   http.ListenAndServe(":8080", nil)
}

func HelloServer(w http.ResponseWriter, r *http.Request) {
   fmt.Fprintf(w, "Hello, %s!", r.URL.Path[1:])
}

The problem is that the function GetLogLevel() bring the old value and not read the value from config ?

This is the sample of config-file (I've put it sibling to the main.go file under the root project folder

This is the project structure

go/src/myproj
  - main.go
  - configuration #folder
  -- cfg.go
  - config.yaml
data:
  config.yaml: 'log: debug'

when I change it from info to debug (or other option) I see that the event watch was raised but it not fetch the new value (like debug). Any idea?

update when I change the configfile like @Tom suggested I was able to see that the log was change but not the level, it stay on warn

This is the logs , I still see the warn

WARN[0000] loading config                                path=./config.yaml
WARN[0000] setting log level                             fields.level=info
&{0xc00012e300}
WARN[0008] Config file changed                           file=config.yaml
WARN[0008] setting log level                             fields.level=error
WARN[0020] Config file changed                           file=config.yaml
WARN[0020] setting log level                             fields.level=debug
WARN[0060] Config file changed                           file=config.yaml
WARN[0060] setting log level                             fields.level=warn

  • 写回答

1条回答 默认 最新

  • doubao6936 2019-09-09 12:12
    关注

    There is nothing wrong with your code as far as I can see since fsnotify truly does trigger. So the culprit has to be in parsing. The first call to setLogLevel(c.GetLogLevel()) outside your onConfigChange callback returns an incorrect value. Change the contents of your yaml file to just

    log: 'level'
    

    and all should be working as desired.

    The logrus package supports the following levels (as of the time of writing) in order: Panic, Fatal, Error, Warn, Info, Debug, and Trace. The corresponding methods are: logrus.Panic(), logrus.Fatal(), logrus.Warn(), logrus.Info(), logrus.Debug(), and logrus.Trace().

    For example, if the current level is set to Warn, the call logrus.Warn("boo!") shall output boo!. However, calling logrus.Info("boo!") will show nothing.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥50 三种调度算法报错 有实例
  • ¥15 关于#python#的问题,请各位专家解答!
  • ¥200 询问:python实现大地主题正反算的程序设计,有偿
  • ¥15 smptlib使用465端口发送邮件失败
  • ¥200 总是报错,能帮助用python实现程序实现高斯正反算吗?有偿
  • ¥15 对于squad数据集的基于bert模型的微调
  • ¥15 为什么我运行这个网络会出现以下报错?CRNN神经网络
  • ¥20 steam下载游戏占用内存
  • ¥15 CST保存项目时失败
  • ¥20 java在应用程序里获取不到扬声器设备