package config import ( "bytes" "fmt" "net" "os" "strings" "github.com/spf13/viper" "github.com/toolkits/pkg/file" "github.com/didi/nightingale/v5/backend" "github.com/didi/nightingale/v5/models" "github.com/didi/nightingale/v5/pkg/i18n" "github.com/didi/nightingale/v5/pkg/iconf" "github.com/didi/nightingale/v5/pkg/ilog" ) type ConfigStruct struct { Logger ilog.Config `yaml:"logger"` HTTP httpSection `yaml:"http"` RPC rpcSection `yaml:"rpc"` LDAP models.LdapSection `yaml:"ldap"` MySQL models.MysqlSection `yaml:"mysql"` Heartbeat heartbeatSection `yaml:"heartbeat"` I18N i18n.Config `yaml:"i18n"` Judge judgeSection `yaml:"judge"` Alert alertSection `yaml:"alert"` Trans transSection `yaml:"trans"` ContactKeys []contactKey `yaml:"contactKeys"` NotifyChannels []string `yaml:"notifyChannels"` Tpl tplSection `yaml:"tpl"` } type tplSection struct { AlertRulePath string `yaml:"alertRulePath"` DashboardPath string `yaml:"dashboardPath"` } type alertSection struct { NotifyScriptPath string `yaml:"notifyScriptPath"` NotifyScriptConcurrency int `yaml:"notifyScriptConcurrency"` MutedAlertPersist bool `yaml:"mutedAlertPersist"` } type transSection struct { Enable bool `yaml:"enable"` Backend backend.BackendSection `yaml:"backend"` } type judgeSection struct { ReadBatch int `yaml:"readBatch"` ConnTimeout int `yaml:"connTimeout"` CallTimeout int `yaml:"callTimeout"` WriterNum int `yaml:"writerNum"` ConnMax int `yaml:"connMax"` ConnIdle int `yaml:"connIdle"` } type heartbeatSection struct { IP string `yaml:"ip"` LocalAddr string `yaml:"-"` Interval int64 `yaml:"interval"` } type httpSection struct { Mode string `yaml:"mode"` Access bool `yaml:"access"` Listen string `yaml:"listen"` Pprof bool `yaml:"pprof"` CookieName string `yaml:"cookieName"` CookieDomain string `yaml:"cookieDomain"` CookieSecure bool `yaml:"cookieSecure"` CookieHttpOnly bool `yaml:"cookieHttpOnly"` CookieMaxAge int `yaml:"cookieMaxAge"` CookieSecret string `yaml:"cookieSecret"` CsrfSecret string `yaml:"csrfSecret"` } type rpcSection struct { Listen string `yaml:"listen"` } type contactKey struct { Label string `yaml:"label" json:"label"` Key string `yaml:"key" json:"key"` } var Config *ConfigStruct func Parse() error { ymlFile := iconf.GetYmlFile("server") if ymlFile == "" { return fmt.Errorf("configuration file of server not found") } bs, err := file.ReadBytes(ymlFile) if err != nil { return fmt.Errorf("cannot read yml[%s]: %v", ymlFile, err) } viper.SetConfigType("yaml") err = viper.ReadConfig(bytes.NewBuffer(bs)) if err != nil { return fmt.Errorf("cannot read yml[%s]: %v", ymlFile, err) } // default value settings viper.SetDefault("i18n.lang", "zh") viper.SetDefault("heartbeat.interval", 1000) viper.SetDefault("judge.readBatch", 2000) viper.SetDefault("judge.connTimeout", 2000) viper.SetDefault("judge.callTimeout", 5000) viper.SetDefault("judge.writerNum", 256) viper.SetDefault("judge.connMax", 2560) viper.SetDefault("judge.connIdle", 256) viper.SetDefault("alert.notifyScriptPath", "./etc/script/notify.py") viper.SetDefault("alert.notifyScriptConcurrency", 200) viper.SetDefault("alert.mutedAlertPersist", true) viper.SetDefault("trans.backend.prometheus.lookbackDeltaMinute", 2) viper.SetDefault("trans.backend.prometheus.maxConcurrentQuery", 30) viper.SetDefault("trans.backend.prometheus.maxSamples", 50000000) viper.SetDefault("trans.backend.prometheus.maxFetchAllSeriesLimitMinute", 5) viper.SetDefault("trans.backend.prometheus.slowLogRecordSecond", 3) viper.SetDefault("trans.backend.prometheus.defaultFetchSeriesQl", `{__name__=~"system.*"}`) viper.SetDefault("tpl.alertRulePath", "./etc/alert_rule") viper.SetDefault("tpl.dashboardPath", "./etc/dashboard") err = viper.Unmarshal(&Config) if err != nil { return fmt.Errorf("cannot read yml[%s]: %v", ymlFile, err) } fmt.Println("config.file:", ymlFile) if Config.Heartbeat.IP == "" { // auto detect Config.Heartbeat.IP = fmt.Sprint(GetOutboundIP()) if Config.Heartbeat.IP == "" { fmt.Println("heartbeat ip auto got is blank") os.Exit(1) } } // 用户在配置文件中指定了heartbeat.ip ,用于本机没有网络,下面的报错,那么需要将Config.Heartbeat.LocalAddr设置一下 // auto get outbound ip fail: dial udp 8.8.8.8:80: connect: network is unreachable port := strings.Split(Config.RPC.Listen, ":")[1] Config.Heartbeat.LocalAddr = Config.Heartbeat.IP + ":" + port // 正常情况肯定不是127.0.0.1,但是,如果就是单机部署,并且这个机器没有网络,比如本地调试并且本机没网的时候 // if Config.Heartbeat.IP == "127.0.0.1" { // fmt.Println("heartbeat ip is 127.0.0.1 and it is useless, so, exit") // os.Exit(1) // } fmt.Println("heartbeat.ip:", Config.Heartbeat.IP) fmt.Printf("heartbeat.interval: %dms\n", Config.Heartbeat.Interval) return nil } // Get preferred outbound ip of this machine func GetOutboundIP() net.IP { conn, err := net.Dial("udp", "8.8.8.8:80") if err != nil { fmt.Println("auto get outbound ip fail:", err) os.Exit(1) } defer conn.Close() localAddr := conn.LocalAddr().(*net.UDPAddr) return localAddr.IP }