package config import ( "os" "github.com/coroot/coroot-node-agent/flags" klog "github.com/sirupsen/logrus" "github.com/spf13/viper" ) // shouldUpdateConfig 判断是否应该更新配置 // 热更新时,如果配置项通过命令行参数或环境变量设置,则不更新 func shouldUpdateConfig(configKey, envKey1, envKey2 string, currentValue, configValue, defaultValue string, isHotReload bool) bool { // 检查环境变量(无论是初始加载还是热更新) if os.Getenv(envKey1) != "" || os.Getenv(envKey2) != "" { if isHotReload { klog.Debugf("[config] Skipping %s update (set via environment variable)", configKey) } return false } // 检查当前值是否与默认值不同 // 如果不同,说明是通过命令行参数设置的(因为 kingpin.Parse() 已经处理了命令行参数) // 无论是初始加载还是热更新,都不应该被配置文件覆盖 if currentValue != defaultValue { if isHotReload { klog.Debugf("[config] Skipping %s update (set via command line: %s)", configKey, currentValue) } else { klog.Debugf("[config] Skipping %s update from config file (set via command line: %s)", configKey, currentValue) } return false } // 当前值等于默认值,说明没有通过命令行参数设置,可以更新 return true } // applyConfig 应用配置到 flags // isHotReload: true 表示热更新,false 表示初始加载 // 热更新时不会覆盖通过命令行参数或环境变量设置的配置项 // 注意:ConfigServer 和 DataServer 的最高优先级是 common.ini(如果 RunInOmniagent 为 true),不受此函数影响 func applyConfig(v *viper.Viper, isHotReload bool) { klog.Infof("═══════════════════════════════════════════════════════════════") if isHotReload { klog.Infof("🔄 [CONFIG] Starting hot reload configuration...") } else { klog.Infof("📋 [CONFIG] Starting initial configuration load...") } klog.Infof("═══════════════════════════════════════════════════════════════") // Server 配置 // ConfigServer 和 DataServer 从 common.ini 加载(如果 RunInOmniagent 为 true) // 但是,无论是否在 RunInOmniagent 模式下,只要配置文件中的 config_server 发生改变,就更新 ProxyClient if v.IsSet("server.config_server") { newConfigServer := v.GetString("server.config_server") oldConfigServer := *flags.ConfigServer klog.Infof("📝 [CONFIG] server.config_server: config_file=%s, current=%s, flags_empty=%v", newConfigServer, oldConfigServer, *flags.ConfigServer == "") // 参考备份代码:只有当 *flags.ConfigServer == "" 时才从配置文件更新 if *flags.ConfigServer == "" && !*flags.RunInOmniagent { if newConfigServer != oldConfigServer { *flags.ConfigServer = newConfigServer klog.Infof("✅ [CONFIG] server.config_server UPDATED: %s -> %s", oldConfigServer, newConfigServer) // 更新 ProxyClient 的 endpoints updateProxyClientEndpoints(newConfigServer) } else { klog.Infof("⏭️ [CONFIG] server.config_server UNCHANGED: %s", newConfigServer) } } else if *flags.RunInOmniagent { // 在 RunInOmniagent 模式下,即使不更新 flags.ConfigServer(因为 common.ini 优先级更高), // 只要配置文件中的值改变了,也更新 ProxyClient if newConfigServer != oldConfigServer { klog.Infof("🔄 [CONFIG] server.config_server (RunInOmniagent mode): updating ProxyClient only: %s -> %s", oldConfigServer, newConfigServer) updateProxyClientEndpoints(newConfigServer) } else { klog.Infof("⏭️ [CONFIG] server.config_server (RunInOmniagent mode): no change, skipping") } } } if v.IsSet("server.data_server") { newDataServer := v.GetString("server.data_server") oldDataServer := *flags.DataServer klog.Infof("📝 [CONFIG] server.data_server: config_file=%s, current=%s, flags_empty=%v", newDataServer, oldDataServer, *flags.DataServer == "") // 参考备份代码:只有当 *flags.DataServer == "" 时才从配置文件更新 if *flags.DataServer == "" && !*flags.RunInOmniagent { if newDataServer != oldDataServer { *flags.DataServer = newDataServer klog.Infof("✅ [CONFIG] server.data_server UPDATED: %s -> %s", oldDataServer, newDataServer) } else { klog.Infof("⏭️ [CONFIG] server.data_server UNCHANGED: %s", newDataServer) } } else { klog.Infof("⏭️ [CONFIG] server.data_server SKIPPED (set via command line or RunInOmniagent mode)") } } if v.IsSet("server.server_prefix") { newVal := v.GetString("server.server_prefix") oldVal := *flags.ServerPrefix if newVal != oldVal { *flags.ServerPrefix = newVal klog.Infof("✅ [CONFIG] server.server_prefix UPDATED: %s -> %s", oldVal, newVal) } } if v.IsSet("server.license_key") { *flags.LicenseKey = v.GetString("server.license_key") } // Agent 配置 if v.IsSet("agent.disable_register_host") { newVal := v.GetBool("agent.disable_register_host") oldVal := *flags.DisableRegisterHost // 布尔值:检查环境变量,如果没有设置环境变量,则从配置文件更新 envSet := os.Getenv("EUSPACE_AGENT_DISABLE_REGISTER_HOST") != "" || os.Getenv("DISABLE_REG_HOST") != "" if !envSet { if newVal != oldVal { *flags.DisableRegisterHost = newVal klog.Infof("✅ [CONFIG] agent.disable_register_host UPDATED: %v -> %v", oldVal, newVal) } } else { klog.Infof("⏭️ [CONFIG] agent.disable_register_host SKIPPED (set via env)") } } if v.IsSet("agent.enable_license_check") { *flags.EnableLicenseCheck = v.GetBool("agent.enable_license_check") } if v.IsSet("agent.send_net_data") { *flags.SendNetData = v.GetBool("agent.send_net_data") } // Logging 配置 if v.IsSet("logging.log_level") { newLogLevel := v.GetString("logging.log_level") oldLogLevel := *flags.LogLevel klog.Infof("📝 [CONFIG] logging.log_level: config_file=%s, current=%s, flags_empty=%v", newLogLevel, oldLogLevel, *flags.LogLevel == "") // 参考备份代码:只有当 *flags.LogLevel == "" 时才从配置文件更新 flags if *flags.LogLevel == "" { if newLogLevel != oldLogLevel { *flags.LogLevel = newLogLevel klog.Infof("✅ [CONFIG] logging.log_level UPDATED (flags): %s -> %s", oldLogLevel, newLogLevel) } } else { klog.Infof("⏭️ [CONFIG] logging.log_level SKIPPED (set via command line: %s)", *flags.LogLevel) } // 使用统一的热更新机制:比较配置文件的新旧值,如果改变了就更新 logrus 级别 // 这样即使 *flags.LogLevel 是通过命令行设置的,配置文件改变时也能更新 logrus checkAndUpdateConfigValue("logging.log_level", newLogLevel, isHotReload, func() { // 初始加载时,如果 flags.LogLevel 为空,也要设置 logrus 级别 if !isHotReload && *flags.LogLevel == "" { updateLogLevel(newLogLevel) } else if isHotReload { // 热更新时,无论 flags 是否更新,都更新 logrus 级别 updateLogLevel(newLogLevel) } }) } if v.IsSet("logging.console_log") { *flags.ConsoleLog = v.GetBool("logging.console_log") } }