/** * @Author: likun * @Title: todo * @Description: todo * @File: node_init * @Date: 2024-11-08 14:02:42 */ package node import ( "admin/lib/flags" "admin/lib/prom" "admin/lib/xlog" "admin/lib/xlog/handler" "encoding/json" "fmt" "github.com/rs/zerolog" "gopkg.in/yaml.v3" "io" "os" "time" ) // initialize 初始化app func (node *Node) initialize() { // 初始化节点启动参数,例如 ./app -a a -b b -c 123 must(node.initBootFlags()) // 初始化节点启动配置文件,例如config/app.yaml must(node.initBootConfig()) // 初始化逻辑 for _, j := range node.preInitFuncs { curErr := j.value.(Task)() if curErr != nil { err := fmt.Errorf("node run pre_initialize task(%s) return error:%v", j.key, curErr) panic(err) } } // 初始化程序日志系统 must(node.initLog()) // 初始化prometheus metrics、go pprof must(node.initTracer()) // 初始化逻辑 for _, j := range node.initFuncs { curErr := j.value.(Task)() if curErr != nil { err := fmt.Errorf("node run initialize task(%s) return error:%v", j.key, curErr) panic(err) } } return } func (node *Node) initBootFlags() error { var appBootFlags []interface{} for _, v := range node.adis { curApp := newApp(v.name, v.options...) node.apps = append(node.apps, curApp) if curApp.bootFlag == nil { continue } appBootFlags = append(appBootFlags, curApp.bootFlag) } // 解析启动参数 flags.ParseWithStructPointers(append([]interface{}{node.bootFlags.globalBootFlag, node.bootFlags.exBootFlag}, appBootFlags...)...) flagBin, _ := json.Marshal(node.bootFlags.globalBootFlag) xlog.Noticef("os args:%+v, parsed flags:%v", os.Args, string(flagBin)) // check if node.bootFlags.globalBootFlag.ServiceName == "" { if len(node.adis) > 1 { node.bootFlags.globalBootFlag.ServiceName = "all_in_one" } else { node.bootFlags.globalBootFlag.ServiceName = node.adis[0].name } } return nil } func (node *Node) initBootConfig() error { // 解析配置文件 if node.bootConfigFile.globalBootConfigFileContent != nil && node.bootFlags.globalBootFlag.BootConfig != "" { err := node.parseWithConfigFileContent(true) if err != nil { newErr := fmt.Errorf("parse With Config File Content is error:%v", err) return newErr } // 定时解析配置文件 ticker := time.NewTicker(time.Second * 3) go func() { for range ticker.C { // 解析配置文件 err = node.parseWithConfigFileContent(false) if err != nil { xlog.Errorf("parse With Config File Content is error:%v", err) continue } } }() } return nil } func (node *Node) initLog() error { logConfig := &LogBootConfig{} if node.bootConfigFile.globalBootConfigFileContent != nil { logConfig = node.bootConfigFile.globalBootConfigFileContent.GetLogConfig().Check() } var ( enableLogFile = logConfig.EnableFile enableLogStdout = logConfig.EnableStdout logDir = logConfig.LogDir logLevel = logConfig.LogLevel nodeId = node.bootFlags.globalBootFlag.NodeID serviceName = node.bootFlags.globalBootFlag.ServiceName maxLogFileBytesSize = logConfig.LogFileSize * 1024 * 1024 * 1024 maxLogRotateBackupCount = logConfig.LogFileRotateCount ) // 初始化日志系统 var logHandlers []io.Writer if !enableLogFile { // 没有指定日志输出目录,默认输出到控制台 logHandlers = append(logHandlers, os.Stdout) } else { // 指定日志输出目录 logHandler, err := handler.NewRotatingDayMaxFileHandler(logDir, serviceName, maxLogFileBytesSize, maxLogRotateBackupCount) if err != nil { newErr := fmt.Errorf("new xlog file handler with path [%v] name[%v] error:%v", logDir, serviceName, err) return newErr } logHandlers = append(logHandlers, logHandler) // 也指定输出到控制台 if enableLogStdout { logHandlers = append(logHandlers, os.Stdout) } } // 创建logger logLevelEnum := xlog.ParseLogLevelString(logLevel) xlog.NewGlobalLogger(logHandlers, logLevelEnum, func(l zerolog.Logger) zerolog.Logger { return l.With().Str("service", serviceName).Str("node_id", nodeId).Logger() }) return nil } func (node *Node) initTracer() error { node.tracer = prom.NewEngine(true) return nil } // 解析配置文件 func (node *Node) parseWithConfigFileContent(first bool) error { content, err := os.ReadFile(node.bootFlags.globalBootFlag.BootConfig) if err != nil { newErr := fmt.Errorf("load boot config file %v error:%v", node.bootFlags.globalBootFlag.BootConfig, err) return newErr } if node.bootConfigFile.globalBootConfigParser == nil { node.bootConfigFile.globalBootConfigParser = yaml.Unmarshal } oldContent, _ := json.Marshal(node.bootConfigFile.globalBootConfigFileContent) err = node.bootConfigFile.globalBootConfigParser(content, node.bootConfigFile.globalBootConfigFileContent) if err != nil { newErr := fmt.Errorf("load boot config file %v content %v ok, but parse content error:%v", node.bootFlags.globalBootFlag.BootConfig, string(content), err) return newErr } // 读取配置后设置一次日志等级 if !first { xlog.SetLogLevel(xlog.ParseLogLevelString(node.bootConfigFile.globalBootConfigFileContent.GetLogConfig().LogLevel)) } node.bootConfigFile.globalBootConfigFileContent.OnReload(first, string(oldContent)) return nil } func must(err error) { if err != nil { panic(err) } }