https://download.csdn.net/blog/column/12814461/143185986
Go
package main
import (
"fmt"
"net/http"
"os"
"path/filepath"
"time"
"github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"
"gopkg.in/natefinch/lumberjack.v2"
)
// 设置 Logger
func SetupLogger() *logrus.Logger {
logger := logrus.New()
logger.SetOutput(&lumberjack.Logger{
//Filename: "log/gin.log", // 这里自动生成的 文件和文本
Filename: generateLogFileName(),
MaxSize: 10, // MB
MaxBackups: 3,
MaxAge: 28, // days
Compress: true,
})
logger.SetFormatter(&logrus.TextFormatter{
FullTimestamp: true,
})
return logger
}
// 日志中间件
func LoggerMiddleware(logger *logrus.Logger) gin.HandlerFunc {
return func(c *gin.Context) {
logger.WithFields(logrus.Fields{
"method": c.Request.Method,
"path": c.Request.URL.Path,
}).Info("Request received")
c.Next() // 继续处理请求
logger.WithFields(logrus.Fields{
"status": c.Writer.Status(),
"method": c.Request.Method,
"path": c.Request.URL.Path,
}).Info("Response sent")
logger.Warning(logrus.Fields{
"status": c.Writer.Status(),
"method": c.Request.Method,
})
}
}
// generateLogFileName 生成日志文件名,格式为:app-YYYY-MM-DD.log
func generateLogFileName() string {
// 获取当前执行文件的路径
exePath, err := os.Executable()
if err != nil {
panic(err)
}
// 解析符号链接,如果当前程序是符号链接,则返回符号链接的目标路径
realPath, err := filepath.EvalSymlinks(exePath)
if err != nil {
panic(err)
}
//获取当前执行文件的不带后缀的文件名
appName := filepath.Base(realPath)
appName = appName[:len(appName)-len(filepath.Ext(appName))]
return fmt.Sprintf("logs/%s-%s.log", appName, time.Now().Format("2006-01-02"))
}
func main() {
r := gin.Default()
logger := SetupLogger()
r.Use(LoggerMiddleware(logger))
r.GET("/ping", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"message": "pong"})
})
r.Run(":8080")
}
夺新一代标准日志库slog
https://www.cnblogs.com/cheyunhua/p/18612100
https://blog.csdn.net/wick_light/article/details/140031724 // 多个 日志文件处理
Go
package main
import (
"gopkg.in/natefinch/lumberjack.v2"
"log/slog"
"os"
)
func main() {
// 配置 lumberjack 日志归档
lumberjackLogger := &lumberjack.Logger{
Filename: "./tmp/app.log", // 日志文件路径
MaxSize: 10, // 单个日志文件最大大小(单位:MB)
MaxBackups: 5, // 保留的旧日志文件个数
MaxAge: 30, // 保留的旧日志文件最大天数(单位:天)
Compress: true, // 是否压缩旧日志文件
}
handler := slog.NewJSONHandler(lumberjackLogger, &slog.HandlerOptions{
AddSource: true, // 如果设置为 true,日志输出中将包含源代码的位置(文件名和行号),默认值:false(不记录源位置)
Level: slog.LevelDebug,
})
// 第一种情况
// 使用默认日志记录器,此模式日志输出格式为text文本型,且不会输出Debug级别日志
//logger := slog.Default()
//第二种情况 日志级别控制:
//2. 日志级别控制
//slog 支持以下日志级别
//
//• slog.LevelDebug
//• slog.LevelInfo
//• slog.LevelWarn
//• slog.LevelError
//HandlerOptions 是 log/slog 提供的一种配置结构,用于自定义日志处理器的行为。通过配置 HandlerOptions,可以实现日志的源位置跟踪、日志级别动态调整,以及对日志属性的定制化处理,参数包括如下:
//
//• AddSource:启用源代码位置记录,便于定位日志位置
//• Level:控制日志级别,可静态或动态调整
//• ReplaceAttr:修改、移除或过滤属性,支持灵活的日志定制
//按照日志级别控制,并输出JSON格式
/*handler := slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
Level: slog.LevelDebug,
})
logger := slog.New(handler)
// 输出结构化日志
logger.Debug("This is a debug message")
logger.Info("Starting qkp platform log", "version", "v3.2.2")
logger.Warn("Low disk space", "remaining", "500MB")
logger.Error("Failed to connect to ETCD cluster", "error", "connection timeout")*/
// 第三种情况:
//3. 自定义日志处理器(Handler)
//slog.Handler 是日志输出的核心接口,允许自定义日志处理行为 内置处理器
//
//• slog.NewTextHandler: 以文本形式输出日志(默认格式)
//• slog.NewJSONHandler: 以 JSON 格式输出日志
// 第四种情况 4. 使用上下文记录器
//slog 支持通过上下文管理附加信息
/*handler := slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
Level: slog.LevelDebug,
})
logger := slog.New(handler).With("platform", "qkp", "version", "v3.2.2")
// 输出结构化日志
logger.Debug("This is a debug message")
logger.Info("Starting qkp platform log", "version", "v3.2.2")
logger.Warn("Low disk space", "remaining", "500MB")
logger.Error("Failed to connect to ETCD cluster", "error", "connection timeout")
*/
// 第五种: 5. 集成lumberjack进行日志切片和归档
// 配置 lumberjack 日志归档
/*lumberjackLogger :=&lumberjack.Logger{
Filename:"/tmp/app.log",// 日志文件路径
MaxSize:10,// 单个日志文件最大大小(单位:MB)
MaxBackups:5,// 保留的旧日志文件个数
MaxAge:30,// 保留的旧日志文件最大天数(单位:天)
Compress:true,// 是否压缩旧日志文件
}
handler := slog.NewJSONHandler(lumberjackLogger,&slog.HandlerOptions{
AddSource:true,// 如果设置为 true,日志输出中将包含源代码的位置(文件名和行号),默认值:false(不记录源位置)
Level: slog.LevelDebug,
})
logger := slog.New(handler).With("platform","qkp","version","v3.2.2")
// 输出结构化日志
logger.Debug("This is a debug message")
logger.Info("Starting qkp platform log","version","v3.2.2")
logger.Warn("Low disk space","remaining","500MB")
logger.Error("Failed to connect to ETCD cluster","error","connection timeout")
在/tmp目录下查询app.log日志
*/
// 第七种 :6. 结合归档日志级别以及替换关键字格式化日志
// 配置 lumberjack 日志归档
/*lumberjackLogger :=&lumberjack.Logger{
Filename:"/tmp/app.log",// 日志文件路径
MaxSize:10,// 单个日志文件最大大小(单位:MB)
MaxBackups:5,// 保留的旧日志文件个数
MaxAge:30,// 保留的旧日志文件最大天数(单位:天)
Compress:true,// 是否压缩旧日志文件
}
handler := slog.NewJSONHandler(lumberjackLogger,&slog.HandlerOptions{
AddSource:true,// 如果设置为 true,日志输出中将包含源代码的位置(文件名和行号),默认值:false(不记录源位置)
Level: slog.LevelDebug,
ReplaceAttr:func(groups []string, a slog.Attr) slog.Attr{
// 替换关键字platform 的值从qkp变成kubernetes
if a.Key=="platform"{
return slog.Attr{Key: a.Key,Value: slog.StringValue("kubernetes")}
}
return a
},
})
logger := slog.New(handler).With("platform","qkp","version","v3.2.2")
// 输出结构化日志
logger.Debug("This is a debug message")
logger.Info("Starting qkp platform log","version","v3.2.2")
logger.Warn("Low disk space","remaining","500MB")
logger.Error("Failed to connect to ETCD cluster","error","connection timeout")
}
*/
logger := slog.New(handler).With("platform", "qkp", "version", "v3.2.2")
// 输出结构化日志
logger.Debug("This is a debug message")
logger.Info("Starting qkp platform log", "version", "v3.2.2")
logger.Warn("Low disk space", "remaining", "500MB")
logger.Error("Failed to connect to ETCD cluster", "error", "connection timeout")
}
日志分隔:
Go
package main
import (
"os"
"github.com/sirupsen/logrus"
"gopkg.in/natefinch/lumberjack.v2"
)
func main() {
// 配置 lumberjack 用于 info 级别的日志
infoLogger := &lumberjack.Logger{
Filename: "info.log",
MaxSize: 500,
MaxBackups: 3,
MaxAge: 28,
Compress: true,
}
// 配置 lumberjack 用于 error 级别的日志
errorLogger := &lumberjack.Logger{
Filename: "error.log",
MaxSize: 500,
MaxBackups: 3,
MaxAge: 28,
Compress: true,
}
// 创建 logrus 的实例
logger := logrus.New()
// 设置 info 级别的日志输出目标
logger.SetLevel(logrus.InfoLevel)
logger.SetOutput(infoLogger)
// 设置 error 级别的日志输出目标
logger.AddHook(&errorHook{writer: errorLogger})
// 使用 logrus 记录日志
logger.Info("This is an info message")
logger.Error("This is an error message")
}
// errorHook 是一个自定义的 logrus 钩子,用于将 error 级别的日志输出到指定的 writer
type errorHook struct {
writer *lumberjack.Logger
}
// Fire 方法会在每次记录日志时被调用
func (h *errorHook) Fire(entry *logrus.Entry) error {
if entry.Level <= logrus.ErrorLevel {
line, err := entry.String()
if err != nil {
return err
}
h.writer.Write([]byte(line))
}
return nil
}
// Levels 方法返回需要处理的日志级别
func (h *errorHook) Levels() []logrus.Level {
return []logrus.Level{
logrus.ErrorLevel,
logrus.FatalLevel,
logrus.PanicLevel,
}
}