新增配置调试功能:支持输出完整配置项与环境变量覆盖详情,调整 cron.daily_spec 默认值

This commit is contained in:
2026-01-28 09:08:26 +08:00
parent 3c1f29e4ef
commit 9ec9a2ba91
4 changed files with 95 additions and 2 deletions

View File

@@ -19,7 +19,7 @@ api:
cron:
enabled: true
daily_spec: "0 10 * * *"
daily_spec: "20 8-23/4 * * *"
retention:
days: 0

View File

@@ -36,6 +36,20 @@ func Init(webFS embed.FS, configPath string) *gin.Engine {
// 2. 初始化日志
util.InitLogger(cfg.Log)
// 以 debug 级别输出配置加载详情和环境变量覆盖情况
util.Logger.Debug("Configuration loading details",
zap.String("config_file", config.GetRawViper().ConfigFileUsed()),
)
envOverrides := config.GetEnvOverrides()
if len(envOverrides) > 0 {
for _, override := range envOverrides {
util.Logger.Debug("Environment variable override applied", zap.String("detail", override))
}
} else {
util.Logger.Debug("No environment variable overrides detected")
}
util.Logger.Debug("Full effective configuration:\n" + config.GetFormattedSettings())
// 输出配置信息
util.Logger.Info("Application configuration loaded")
util.Logger.Info("├─ Config file", zap.String("path", config.GetRawViper().ConfigFileUsed()))

View File

@@ -3,6 +3,7 @@ package config
import (
"fmt"
"os"
"sort"
"strings"
"sync"
"time"
@@ -156,7 +157,7 @@ func Init(configPath string) error {
v.SetDefault("log.db_log_level", "info")
v.SetDefault("api.mode", "local")
v.SetDefault("cron.enabled", true)
v.SetDefault("cron.daily_spec", "0 10 * * *")
v.SetDefault("cron.daily_spec", "20 8-23/4 * * *")
v.SetDefault("retention.days", 0)
v.SetDefault("db.type", "sqlite")
v.SetDefault("db.dsn", "data/bing_paper.db")
@@ -254,6 +255,38 @@ func GetRawViper() *viper.Viper {
return v
}
// GetAllSettings 返回所有生效配置项
func GetAllSettings() map[string]interface{} {
return v.AllSettings()
}
// GetFormattedSettings 以 key: value 形式返回所有配置项的字符串
func GetFormattedSettings() string {
keys := v.AllKeys()
sort.Strings(keys)
var sb strings.Builder
for _, k := range keys {
sb.WriteString(fmt.Sprintf("%s: %v\n", k, v.Get(k)))
}
return sb.String()
}
// GetEnvOverrides 返回环境变量覆盖详情(已排序)
func GetEnvOverrides() []string {
var overrides []string
keys := v.AllKeys()
sort.Strings(keys)
for _, key := range keys {
// 根据 viper 的配置生成对应的环境变量名
// Prefix: BINGPAPER, KeyReplacer: . -> _
envKey := strings.ToUpper(fmt.Sprintf("BINGPAPER_%s", strings.ReplaceAll(key, ".", "_")))
if val, ok := os.LookupEnv(envKey); ok {
overrides = append(overrides, fmt.Sprintf("%s: %s=%s", key, envKey, val))
}
}
return overrides
}
func GetTokenTTL() time.Duration {
ttl, err := time.ParseDuration(GetConfig().Token.DefaultTTL)
if err != nil {

View File

@@ -1,6 +1,9 @@
package config
import (
"fmt"
"os"
"strings"
"testing"
)
@@ -19,3 +22,46 @@ func TestDefaultConfig(t *testing.T) {
t.Errorf("Expected DB type sqlite, got %s", cfg.DB.Type)
}
}
func TestDebugFunctions(t *testing.T) {
// 设置一个环境变量
os.Setenv("BINGPAPER_SERVER_PORT", "9999")
defer os.Unsetenv("BINGPAPER_SERVER_PORT")
err := Init("")
if err != nil {
t.Fatalf("Failed to init config: %v", err)
}
settings := GetAllSettings()
serverCfg, ok := settings["server"].(map[string]interface{})
if !ok {
t.Fatalf("Expected server config map, got %v", settings["server"])
}
// Viper numbers in AllSettings are often int
portValue := serverCfg["port"]
// 允许不同的数字类型,因为 viper 内部实现可能变化
portStr := fmt.Sprintf("%v", portValue)
if portStr != "9999" {
t.Errorf("Expected port 9999 in settings, got %v (%T)", portValue, portValue)
}
overrides := GetEnvOverrides()
found := false
for _, o := range overrides {
if strings.Contains(o, "server.port") && strings.Contains(o, "9999") {
found = true
break
}
}
if !found {
t.Errorf("Expected server.port override in %v", overrides)
}
// 验证格式化输出
formatted := GetFormattedSettings()
if !strings.Contains(formatted, "server.port: 9999") {
t.Errorf("Expected formatted settings to contain server.port: 9999, got %s", formatted)
}
}