feat(config): 增加配置文件热重载功能并优化日志输出

This commit is contained in:
liyp 2024-11-30 23:24:05 +08:00
parent 1a146d4bfb
commit d944a913eb
4 changed files with 90 additions and 21 deletions

View file

@ -5,35 +5,55 @@ import (
"os" "os"
"reflect" "reflect"
"sync" "sync"
"time"
"github.com/BurntSushi/toml" "github.com/BurntSushi/toml"
"github.com/fsnotify/fsnotify"
"github.com/sirupsen/logrus"
) )
var ( var (
config map[string]interface{} config map[string]interface{}
mu sync.RWMutex mu sync.RWMutex
once sync.Once
) )
// loadConfig 加载配置文件 // loadConfig 加载配置文件
func loadConfig() error { func loadConfig() error {
// mu.Lock()
// defer mu.Unlock()
_, err := toml.DecodeFile("config.toml", &config) _, err := toml.DecodeFile("config.toml", &config)
if err != nil {
logrus.Errorf("Failed to decode config file: %v", err)
}
return err return err
} }
// GetConfig 获取配置,使用 sync.Once 确保只加载一次 // GetConfig 获取配置
func GetConfig() map[string]interface{} { func GetConfig() map[string]interface{} {
once.Do(func() { // mu.RLock()
mu.Lock()
defer mu.Unlock()
if err := loadConfig(); err != nil { if err := loadConfig(); err != nil {
fmt.Printf("加载配置文件失败: %v\n", err) fmt.Printf("加载配置文件失败: %v\n", err)
os.Exit(1) os.Exit(1)
} }
})
return config return config
} }
// ReloadConfig 重新加载配置文件
func ReloadConfig() error {
mu.Lock()
defer mu.Unlock()
if err := loadConfig(); err != nil {
logrus.Errorf("failed to reload config: %v", err)
return err
}
logrus.Infof("Config reloaded successfully:%v", config)
return nil
}
// GetConfigValue 获取配置值 // GetConfigValue 获取配置值
func GetConfigValue(key string) interface{} { func GetConfigValue(key string) interface{} {
mu.RLock() mu.RLock()
@ -41,13 +61,6 @@ func GetConfigValue(key string) interface{} {
return config[key] return config[key]
} }
// ReloadConfig 重新加载配置文件
func ReloadConfig() error {
mu.Lock()
defer mu.Unlock()
return loadConfig()
}
// ModifyConfig 修改配置并写回文件 // ModifyConfig 修改配置并写回文件
func ModifyConfig(key string, value interface{}) error { func ModifyConfig(key string, value interface{}) error {
mu.Lock() mu.Lock()
@ -88,3 +101,52 @@ func PrintConfig(m map[string]interface{}, indent string) {
} }
} }
} }
// 监听配置文件变化
func WatchConfig(filepath string) {
watcher, err := fsnotify.NewWatcher()
if err != nil {
logrus.Fatalf("Failed to create watcher: %v", err)
}
defer watcher.Close()
err = watcher.Add(filepath)
if err != nil {
logrus.Fatalf("Failed to add file to watcher: %v", err)
}
var debounceTimer *time.Timer
for {
select {
case event, ok := <-watcher.Events:
if !ok {
return
}
if event.Op&(fsnotify.Write|fsnotify.Rename) != 0 {
if debounceTimer != nil {
debounceTimer.Stop()
}
debounceTimer = time.AfterFunc(500*time.Millisecond, func() {
logrus.Info("Config file changed, reloading...")
go func() {
if err := ReloadConfig(); err != nil {
logrus.Errorf("Failed to reload config: %v", err)
}
}()
})
}
case err, ok := <-watcher.Errors:
if !ok {
return
}
logrus.Errorf("Watcher error: %v", err)
}
}
}
// 启动监听配置文件的协程
func StartWatching(filepath string) {
go WatchConfig(filepath)
}

1
go.mod
View file

@ -57,6 +57,7 @@ require (
require ( require (
github.com/PuerkitoBio/goquery v1.9.2 github.com/PuerkitoBio/goquery v1.9.2
github.com/andybalholm/brotli v1.1.0 github.com/andybalholm/brotli v1.1.0
github.com/fsnotify/fsnotify v1.8.0
github.com/gin-gonic/gin v1.10.0 github.com/gin-gonic/gin v1.10.0
github.com/go-redis/redis/v8 v8.11.5 github.com/go-redis/redis/v8 v8.11.5
github.com/imroc/req/v3 v3.44.0 github.com/imroc/req/v3 v3.44.0

2
go.sum
View file

@ -26,6 +26,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M=
github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=

12
main.go
View file

@ -123,10 +123,9 @@ func main() {
logrus.Fatalf("Failed to initialize app: %v", err) logrus.Fatalf("Failed to initialize app: %v", err)
} }
cfg := config.GetConfig() cfg := config.GetConfig()
APIURL, ok := cfg["APIURL"].(string)
if !ok { // 启动文件监听
logrus.Fatalf("加载配置失败!") config.StartWatching("config.toml")
}
// config.PrintConfig(cfg, "") // config.PrintConfig(cfg, "")
// 在 App 初始化后统一使用 app.Logger // 在 App 初始化后统一使用 app.Logger
@ -134,6 +133,11 @@ func main() {
app.Logger.Fatalf("Failed to initialize database: %v", err) app.Logger.Fatalf("Failed to initialize database: %v", err)
} }
APIURL, ok := cfg["APIURL"].(string)
if !ok {
logrus.Fatalf("加载配置失败!")
}
gin.SetMode(gin.ReleaseMode) gin.SetMode(gin.ReleaseMode)
r := gin.Default() r := gin.Default()
r.POST("/", func(c *gin.Context) { r.POST("/", func(c *gin.Context) {