Browse Source

refactor:修改日志文件按天创建新的

GTong 7 months ago
parent
commit
9d698bce67
4 changed files with 174 additions and 70 deletions
  1. 2 2
      config.toml
  2. 2 2
      internal/global/global.go
  3. 85 33
      internal/global/logs.go
  4. 85 33
      internal/module/capture/capture_log.go

+ 2 - 2
config.toml

@@ -9,8 +9,8 @@ oadb_db = "ECOLOGY2"
 oadb_user = "XUGU_LICENSE"
 oadb_password = "xugu@license2024"
 
-licdb_ip = "10.28.20.105"
-licdb_port = "5190"
+licdb_ip = "10.28.20.233"
+licdb_port = "5138"
 licdb_db = "license"
 licdb_user = "SYSDBA"
 licdb_password = "SYSDBA"

+ 2 - 2
internal/global/global.go

@@ -18,7 +18,7 @@ var Cfg *Config
 
 func InitDb() {
 	Cfg = LoadConfig("./config.toml")
-	fmt.Println("Cfg", Cfg)
+	fmt.Println("配置读取: ", Cfg)
 	licDbstr := fmt.Sprintf("IP=%s;DB=%s;User=%s;PWD=%s;Port=%s;AUTO_COMMIT=on;CHAR_SET=UTF8",
 		Cfg.Database.LicDBIP,
 		Cfg.Database.LicDBDb,
@@ -31,7 +31,7 @@ func InitDb() {
 		Cfg.Database.OADBUser,
 		Cfg.Database.OADBPass,
 		Cfg.Database.OADBPort)
-		
+
 	var err error
 	XuguDB, err = sql.Open("xugusql", licDbstr)
 	if err != nil {

+ 85 - 33
internal/global/logs.go

@@ -10,37 +10,39 @@ import (
 	"github.com/sirupsen/logrus"
 )
 
+// Logger 是全局的 logrus.Logger 实例,供其他包使用
 var Logger *logrus.Logger
 
 // Hook 结构体定义了一个日志钩子,用于将日志条目输出到指定的 Writer,并使用指定的 Formatter 格式化日志条目。
 // Level 字段是一个包含日志级别的切片,用于指定该钩子应处理的日志级别。
 type Hook struct {
-	Writer    io.Writer
-	Formatter logrus.Formatter
-	Level     []logrus.Level
+	Writer    io.Writer        // 日志输出的目标 Writer
+	Formatter logrus.Formatter // 日志的格式化器
+	Level     []logrus.Level   // 此钩子应处理的日志级别
 }
 
 // Fire 方法是 logrus.Hook 接口的实现。当日志条目符合钩子的日志级别时,
 // 这个方法会被调用。它首先使用 Formatter 将日志条目格式化为字节切片,
 // 然后将其写入 Writer。此版本增强了日志条目,添加了错误发生的文件名和行号。
 func (h *Hook) Fire(entry *logrus.Entry) error {
-	// 获取错误发生的文件名和行号
+	// 如果日志条目有调用者信息,则记录文件名和行号
 	if entry.HasCaller() {
 		entry.Data["file"] = fmt.Sprintf("%s:%d", entry.Caller.File, entry.Caller.Line)
 	}
 
+	// 使用 Formatter 格式化日志条目为字节切片
 	line, err := h.Formatter.Format(entry)
 	if err != nil {
-		return err
+		return err // 如果格式化出错,返回错误
 	}
-	h.Writer.Write(line)
+	h.Writer.Write(line) // 将格式化的日志条目写入 Writer
 	return nil
 }
 
 // Levels 方法返回该钩子支持的日志级别切片。
 // logrus 在写入日志时会调用这个方法来决定是否使用这个钩子。
 func (h *Hook) Levels() []logrus.Level {
-	return h.Level
+	return h.Level // 返回支持的日志级别
 }
 
 // newHook 函数用于创建一个新的 Hook 实例。它接收一个 Writer,
@@ -49,11 +51,13 @@ func (h *Hook) Levels() []logrus.Level {
 // 并返回该 Hook 实例。
 func newHook(writer io.Writer, formatter logrus.Formatter, level logrus.Level) *Hook {
 	var levels []logrus.Level
+	// 遍历 logrus 所有的日志级别,如果当前级别低于或等于指定的 level,添加到 levels 切片中
 	for _, l := range logrus.AllLevels {
 		if l <= level {
 			levels = append(levels, l)
 		}
 	}
+	// 返回新建的 Hook 实例
 	return &Hook{
 		Writer:    writer,
 		Formatter: formatter,
@@ -61,63 +65,111 @@ func newHook(writer io.Writer, formatter logrus.Formatter, level logrus.Level) *
 	}
 }
 
-// InitLogs 函数负责初始化 logrus.Logger 对象。它首先检查是否存在指定的日志目录(默认为 ./logs/)。
-// 如果目录不存在,它会创建该目录。
+// createLogFile 函数用于根据当前日期创建一个新的日志文件。
+// 它返回日志文件的文件叠指针、文件名和可能的错误信息。
+func createLogFile(logFilePath string) (*os.File, string, error) {
+	// 使用当前日期生成日志文件名,格式为 `log-YYYY-MM-DD-HH-MM-SS.log`
+	currentDate := time.Now().Format("2006-01-02-15-04-05")
+	logFileName := fmt.Sprintf("%s/log-%s.log", logFilePath, currentDate)
+
+	// 打开或创建日志文件,文件路径由 logFilePath 指定
+	logFile, err := os.OpenFile(logFileName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
+	return logFile, logFileName, err // 返回日志文件叠指针、文件名和可能的错误
+}
+
+// InitLogs 函数负责初始化 logrus.Logger 对象。它首先检查是否存在指定的日志目录。
+// 如果目录不存在,会创建该目录。
 func InitLogs(logFilePath string, logLevelStr string) *logrus.Logger {
-	//dir := "./logs/"
-	// 检查目录是否存在
+	// 检查日志目录是否存在
 	if _, err := os.Stat(logFilePath); os.IsNotExist(err) {
 		// 目录不存在,创建目录
 		err := os.MkdirAll(logFilePath, os.ModePerm)
 		if err != nil {
-			fmt.Println("Error creating directory:", err)
+			fmt.Println("Error creating directory:", err) // 打印创建目录失败的错误信息
 			return nil
 		}
-		fmt.Println("Directory created:", logFilePath)
+		fmt.Println("Directory created:", logFilePath) // 打印成功创建目录的信息
 	}
 
-	// 尝试将 logLevelStr 转换为 logrus.Level。如果转换失败,则默认使用 InfoLevel 级别。
+	// 将 logLevelStr 转换为 logrus.Level,失败时默认使用 InfoLevel
 	logLevel, err := logrus.ParseLevel(logLevelStr)
 	if err != nil {
 		logLevel = logrus.InfoLevel
-		log.Printf("Invalid log level: %s. Defaulting to info", logLevelStr)
+		log.Printf("Invalid log level: %s. Defaulting to info", logLevelStr) // 输出无效日志级别信息
 	}
 
-	// 初始化 Logger 实例,并将其输出设置为 io.Discard,即默认情况下不输出任何日志。
-	// 这是为了强制所有日志输出都通过钩子来处理。
+	// 初始化 Logger 实例,将输出设置为 io.Discard,以强制通过钩子处理所有日志输出
 	Logger = logrus.New()
-	Logger.SetOutput(io.Discard)
+	Logger.SetOutput(io.Discard) // 默认不输出任何日志
 
-	// 启用记录调用者信息,这样可以记录错误发生的位置(文件名和行号)
+	// 启用记录调用者信息(文件名和行号)
 	Logger.SetReportCaller(true)
 
-	// 使用当前日期生成日志文件名,格式为 `log-YYYY-MM-DD.log`
-	currentDate := time.Now().Format("2006-01-02")
-	logFileName := fmt.Sprintf("%s/log-%s.log", logFilePath, currentDate)
-
-	// 打开或创建日志文件。日志文件的路径由 logFilePath 参数指定。
-	logFile, err := os.OpenFile(logFileName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
+	// 使用 createLogFile 创建一个新的日志文件
+	logFile, logFileName, err := createLogFile(logFilePath)
 	if err != nil {
-		log.Printf("Failed to open log file: %s", logFileName)
-		panic(err)
+		log.Printf("Failed to open log file: %s", logFileName) // 打印文件打开失败的信息
+		panic(err)                                             // 触发 panic
 	}
 
-	// 添加一个新的 Hook,将日志输出到日志文件中,并使用 JSONFormatter 进行格式化
+	// 添加一个新的 Hook,将日志输出到日志文件中,并使用 JSONFormatter 进行格式化
 	Logger.AddHook(newHook(
 		logFile,
 		&logrus.JSONFormatter{},
 		logLevel,
 	))
 
-	// 添加另一个 Hook,将日志输出到标准错误输出(通常是控制台),
-	// 并使用 TextFormatter 格式化日志,显示完整时间戳并强制使用颜色。
+	// 添加一个 Hook,将日志输出到标准错误输出(控制台),使用 TextFormatter 格式化
 	Logger.AddHook(newHook(
 		os.Stderr,
 		&logrus.TextFormatter{
-			FullTimestamp: true,
-			ForceColors:   true,
+			FullTimestamp: true, // 显示完整时间戳
+			ForceColors:   true, // 强制使用颜色输出
 		},
 		logLevel,
 	))
-	return Logger
+
+	// 启动一个 goroutine,用于每天创建新的日志文件
+	go func() {
+		// 每 24 小时触发一次
+		ticker := time.NewTicker(24 * time.Hour)
+		defer ticker.Stop() // 停止 ticker
+
+		for {
+			<-ticker.C // 等待 ticker 触发
+
+			// 关闭当前日志文件
+			logFile.Close()
+
+			// 创建新的日志文件
+			newLogFile, newLogFileName, err := createLogFile(logFilePath)
+			if err != nil {
+				log.Printf("Failed to create new log file: %s", newLogFileName) // 打印创建失败信息
+				continue                                                        // 如果失败,跳过此次循环,等待下一次检查
+			}
+			logFile = newLogFile // 更新 logFile
+
+			// 清除所有旧的日志钩子
+			Logger.ReplaceHooks(make(logrus.LevelHooks))
+
+			// 添加新的文件输出 Hook
+			Logger.AddHook(newHook(
+				logFile,
+				&logrus.JSONFormatter{},
+				logLevel,
+			))
+
+			// 添加控制台输出 Hook
+			Logger.AddHook(newHook(
+				os.Stderr,
+				&logrus.TextFormatter{
+					FullTimestamp: true,
+					ForceColors:   true,
+				},
+				logLevel,
+			))
+		}
+	}()
+
+	return Logger // 返回初始化后的 Logger 实例
 }

+ 85 - 33
internal/module/capture/capture_log.go

@@ -10,37 +10,39 @@ import (
 	"github.com/sirupsen/logrus"
 )
 
+// Logger 是全局的 logrus.Logger 实例,供其他包使用
 var Logger *logrus.Logger
 
 // Hook 结构体定义了一个日志钩子,用于将日志条目输出到指定的 Writer,并使用指定的 Formatter 格式化日志条目。
 // Level 字段是一个包含日志级别的切片,用于指定该钩子应处理的日志级别。
 type Hook struct {
-	Writer    io.Writer
-	Formatter logrus.Formatter
-	Level     []logrus.Level
+	Writer    io.Writer        // 日志输出的目标 Writer
+	Formatter logrus.Formatter // 日志的格式化器
+	Level     []logrus.Level   // 此钩子应处理的日志级别
 }
 
 // Fire 方法是 logrus.Hook 接口的实现。当日志条目符合钩子的日志级别时,
 // 这个方法会被调用。它首先使用 Formatter 将日志条目格式化为字节切片,
 // 然后将其写入 Writer。此版本增强了日志条目,添加了错误发生的文件名和行号。
 func (h *Hook) Fire(entry *logrus.Entry) error {
-	// 获取错误发生的文件名和行号
+	// 如果日志条目有调用者信息,则记录文件名和行号
 	if entry.HasCaller() {
 		entry.Data["file"] = fmt.Sprintf("%s:%d", entry.Caller.File, entry.Caller.Line)
 	}
 
+	// 使用 Formatter 格式化日志条目为字节切片
 	line, err := h.Formatter.Format(entry)
 	if err != nil {
-		return err
+		return err // 如果格式化出错,返回错误
 	}
-	h.Writer.Write(line)
+	h.Writer.Write(line) // 将格式化的日志条目写入 Writer
 	return nil
 }
 
 // Levels 方法返回该钩子支持的日志级别切片。
 // logrus 在写入日志时会调用这个方法来决定是否使用这个钩子。
 func (h *Hook) Levels() []logrus.Level {
-	return h.Level
+	return h.Level // 返回支持的日志级别
 }
 
 // newHook 函数用于创建一个新的 Hook 实例。它接收一个 Writer,
@@ -49,11 +51,13 @@ func (h *Hook) Levels() []logrus.Level {
 // 并返回该 Hook 实例。
 func newHook(writer io.Writer, formatter logrus.Formatter, level logrus.Level) *Hook {
 	var levels []logrus.Level
+	// 遍历 logrus 所有的日志级别,如果当前级别低于或等于指定的 level,添加到 levels 切片中
 	for _, l := range logrus.AllLevels {
 		if l <= level {
 			levels = append(levels, l)
 		}
 	}
+	// 返回新建的 Hook 实例
 	return &Hook{
 		Writer:    writer,
 		Formatter: formatter,
@@ -61,63 +65,111 @@ func newHook(writer io.Writer, formatter logrus.Formatter, level logrus.Level) *
 	}
 }
 
-// InitLogs 函数负责初始化 logrus.Logger 对象。它首先检查是否存在指定的日志目录(默认为 ./logs/)。
-// 如果目录不存在,它会创建该目录。
+// createLogFile 函数用于根据当前日期创建一个新的日志文件。
+// 它返回日志文件的文件叠指针、文件名和可能的错误信息。
+func createLogFile(logFilePath string) (*os.File, string, error) {
+	// 使用当前日期生成日志文件名,格式为 `log-YYYY-MM-DD-HH-MM-SS.log`
+	currentDate := time.Now().Format("2006-01-02-15-04-05")
+	logFileName := fmt.Sprintf("%s/log-%s.log", logFilePath, currentDate)
+
+	// 打开或创建日志文件,文件路径由 logFilePath 指定
+	logFile, err := os.OpenFile(logFileName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
+	return logFile, logFileName, err // 返回日志文件叠指针、文件名和可能的错误
+}
+
+// InitLogs 函数负责初始化 logrus.Logger 对象。它首先检查是否存在指定的日志目录。
+// 如果目录不存在,会创建该目录。
 func InitLogs(logFilePath string, logLevelStr string) *logrus.Logger {
-	//dir := "./logs/"
-	// 检查目录是否存在
+	// 检查日志目录是否存在
 	if _, err := os.Stat(logFilePath); os.IsNotExist(err) {
 		// 目录不存在,创建目录
 		err := os.MkdirAll(logFilePath, os.ModePerm)
 		if err != nil {
-			fmt.Println("Error creating directory:", err)
+			fmt.Println("Error creating directory:", err) // 打印创建目录失败的错误信息
 			return nil
 		}
-		fmt.Println("Directory created:", logFilePath)
+		fmt.Println("Directory created:", logFilePath) // 打印成功创建目录的信息
 	}
 
-	// 尝试将 logLevelStr 转换为 logrus.Level。如果转换失败,则默认使用 InfoLevel 级别。
+	// 将 logLevelStr 转换为 logrus.Level,失败时默认使用 InfoLevel
 	logLevel, err := logrus.ParseLevel(logLevelStr)
 	if err != nil {
 		logLevel = logrus.InfoLevel
-		log.Printf("Invalid log level: %s. Defaulting to info", logLevelStr)
+		log.Printf("Invalid log level: %s. Defaulting to info", logLevelStr) // 输出无效日志级别信息
 	}
 
-	// 初始化 Logger 实例,并将其输出设置为 io.Discard,即默认情况下不输出任何日志。
-	// 这是为了强制所有日志输出都通过钩子来处理。
+	// 初始化 Logger 实例,将输出设置为 io.Discard,以强制通过钩子处理所有日志输出
 	Logger = logrus.New()
-	Logger.SetOutput(io.Discard)
+	Logger.SetOutput(io.Discard) // 默认不输出任何日志
 
-	// 启用记录调用者信息,这样可以记录错误发生的位置(文件名和行号)
+	// 启用记录调用者信息(文件名和行号)
 	Logger.SetReportCaller(true)
 
-	// 使用当前日期生成日志文件名,格式为 `log-YYYY-MM-DD.log`
-	currentDate := time.Now().Format("2006-01-02")
-	logFileName := fmt.Sprintf("%s/log-%s.log", logFilePath, currentDate)
-
-	// 打开或创建日志文件。日志文件的路径由 logFilePath 参数指定。
-	logFile, err := os.OpenFile(logFileName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
+	// 使用 createLogFile 创建一个新的日志文件
+	logFile, logFileName, err := createLogFile(logFilePath)
 	if err != nil {
-		log.Printf("Failed to open log file: %s", logFileName)
-		panic(err)
+		log.Printf("Failed to open log file: %s", logFileName) // 打印文件打开失败的信息
+		panic(err)                                             // 触发 panic
 	}
 
-	// 添加一个新的 Hook,将日志输出到日志文件中,并使用 JSONFormatter 进行格式化
+	// 添加一个新的 Hook,将日志输出到日志文件中,并使用 JSONFormatter 进行格式化
 	Logger.AddHook(newHook(
 		logFile,
 		&logrus.JSONFormatter{},
 		logLevel,
 	))
 
-	// 添加另一个 Hook,将日志输出到标准错误输出(通常是控制台),
-	// 并使用 TextFormatter 格式化日志,显示完整时间戳并强制使用颜色。
+	// 添加一个 Hook,将日志输出到标准错误输出(控制台),使用 TextFormatter 格式化
 	Logger.AddHook(newHook(
 		os.Stderr,
 		&logrus.TextFormatter{
-			FullTimestamp: true,
-			ForceColors:   true,
+			FullTimestamp: true, // 显示完整时间戳
+			ForceColors:   true, // 强制使用颜色输出
 		},
 		logLevel,
 	))
-	return Logger
+
+	// 启动一个 goroutine,用于每天创建新的日志文件
+	go func() {
+		// 每 24 小时触发一次
+		ticker := time.NewTicker(24 * time.Hour)
+		defer ticker.Stop() // 停止 ticker
+
+		for {
+			<-ticker.C // 等待 ticker 触发
+
+			// 关闭当前日志文件
+			logFile.Close()
+
+			// 创建新的日志文件
+			newLogFile, newLogFileName, err := createLogFile(logFilePath)
+			if err != nil {
+				log.Printf("Failed to create new log file: %s", newLogFileName) // 打印创建失败信息
+				continue                                                        // 如果失败,跳过此次循环,等待下一次检查
+			}
+			logFile = newLogFile // 更新 logFile
+
+			// 清除所有旧的日志钩子
+			Logger.ReplaceHooks(make(logrus.LevelHooks))
+
+			// 添加新的文件输出 Hook
+			Logger.AddHook(newHook(
+				logFile,
+				&logrus.JSONFormatter{},
+				logLevel,
+			))
+
+			// 添加控制台输出 Hook
+			Logger.AddHook(newHook(
+				os.Stderr,
+				&logrus.TextFormatter{
+					FullTimestamp: true,
+					ForceColors:   true,
+				},
+				logLevel,
+			))
+		}
+	}()
+
+	return Logger // 返回初始化后的 Logger 实例
 }