feat(config): 增加配置文件热重载功能并优化日志输出
This commit is contained in:
parent
1a146d4bfb
commit
d944a913eb
4 changed files with 90 additions and 21 deletions
|
@ -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
1
go.mod
|
@ -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
2
go.sum
|
@ -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
12
main.go
|
@ -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) {
|
||||||
|
|
Loading…
Reference in a new issue