使用 lumberjack 让 logrous 实现日志文件切割

 

logrus 的 hook 说明

hook 结构定义

type Hook struct {
	Writer    io.Writer    // hook 自己 io.Writer,可以将 logrous 的日志推送到这里 
	LogLevels []log.Level  // 触发 hook 的日志等级
}

  

接口函数

func (hook *Hook) Fire(entry *log.Entry) error

  自定义 hook 的核心。当满足条件的日志,触发了 hook 操作时,就会调用 Fire 函数。比如要实现将 logrus 的日志发送给 syslog,则可以在这里实现定义

func (hook *Hook) Levels() []log.Level

  定义 logrus 的哪些等级的日志会触发 hook 操作,也就是触发 Fire

使用  lumberjack 给  logrous 实现日志文件切割

lumberjack 是一个简单而有效的 Go 语言日志轮转库,它可以与标准库 log 或其他日志库(包括 logrus)结合使用来实现日志文件的切割。虽然 logrus 本身不直接支持日志轮转,但你可以通过编写一个自定义的钩子(hook)来将 lumberjack 集成到 logrus 中。

不过,通常不需要手动编写这样的钩子,因为社区可能已经提供了现成的解决方案。然而,在我最后的检查中,我没有找到一个直接集成 lumberjack 和 logrus 的官方或广泛认可的钩子库。但你可以按照以下步骤手动实现这一功能:

  1. 安装 logrus 和 lumberjack
  2. 创建一个自定义的 logrus 钩子,该钩子使用 lumberjack 来处理日志输出。
  3. 将这个钩子添加到 logrus 实例中。

下面是一个简单的示例,展示了如何实现这一过程:

 

package main

import (
	"github.com/sirupsen/logrus"
	"gopkg.in/natefinch/lumberjack.v2"
	"os"
)

// CustomHook 是一个自定义的 logrus 钩子,它使用 lumberjack 进行日志轮转。
type CustomHook struct {
	logger *lumberjack.Logger
}

// NewCustomHook 创建一个新的 CustomHook 实例。
func NewCustomHook(filename string, maxSize int, maxBackups int, maxAge int, compress bool) *CustomHook {
	return &CustomHook{
		logger: &lumberjack.Logger{
			Filename:   filename,
			MaxSize:    maxSize,   // MB
			MaxBackups: maxBackups,
			MaxAge:     maxAge,    // days
			Compress:   compress,
		},
	}
}

// Fire 是 logrus 钩子接口的一部分,当日志事件发生时会被调用。
func (hook *CustomHook) Fire(entry *logrus.Entry) error {
	// 将日志条目格式化为字符串并写入 lumberjack 日志记录器。
	line, err := entry.String()
	if err != nil {
		return err
	}
	_, err = hook.logger.Write([]byte(line + "\n"))
	return err
}

// Levels 定义了该钩子应该监听哪些日志级别。
func (hook *CustomHook) Levels() []logrus.Level {
	return logrus.AllLevels
}

func main() {
	// 创建一个自定义的 logrus 钩子,配置日志轮转参数。
	hook := NewCustomHook("logs/myapp.log", 10, 3, 28, true)

	// 配置 logrus 使用自定义钩子。
	logger := logrus.New()
	logger.Hooks.Add(hook)
	logger.SetFormatter(&logrus.TextFormatter{
		TimestampFormat: "2006-01-02 15:04:05",
		FullTimestamp:   true,
	})
	logger.SetLevel(logrus.DebugLevel)

	// 测试日志输出。
	logger.Info("This is an info message.")
	logger.Warn("This is a warning message.")
	logger.Error("This is an error message.")

	// 模拟一些工作以生成更多日志。
	for i := 0; i < 100; i++ {
		logger.Infof("This is log message %d\n", i)
		// 为了演示日志轮转,这里应该有一个延迟,但请注意在实际应用中不要阻塞主线程。
		// 使用 goroutine 或其他异步机制来生成日志可能更合适。
		// time.Sleep(time.Minute * 10) // 例如,每10分钟生成一条日志(这里为了演示而注释掉)。
	}

	// 注意:在实际应用中,通常不会在主函数中阻塞以等待日志生成。
	// 日志生成通常是由应用程序的其他部分(如处理请求的 goroutine)负责的。
	// 这里只是为了演示如何配置和使用 logrus 与 lumberjack。
}

  

重要提示:

  • 在上面的示例中,time.Sleep 被注释掉了,因为在实际应用中,你不应该在主函数中阻塞以等待日志生成。相反,你应该让应用程序的其他部分(如处理请求的 goroutine)负责生成日志。
  • 为了确保日志轮转正常工作,你的应用程序需要持续运行并生成足够的日志以触发轮转条件(如文件大小达到限制)。
  • 上面的代码示例是一个简单的演示,并没有处理所有可能的错误情况和边界条件。在生产环境中使用时,请确保添加适当的错误处理和日志记录。
  • 请注意,lumberjack 会在达到指定的文件大小限制时创建新的日志文件,并根据配置保留旧的文件。但是,它不会立即删除或压缩旧文件;这些操作会在下一次写入新日志时发生(如果配置了压缩)。

PS:

以上代码来自大模型结果。对我的项目而言,将 luberjack 当做 logrous 的 hook 后,logrous 会写一次日志,luberjack 也会写一次日志,这样就会造成一份日志写两次。因此需要将 Fire 重写成如下结果

func (hook *CustomHook) Fire(entry *logrus.Entry) error {
	// 触发 lumberjack 日志切割。
	_, err := hook.logger.Write([]byte(""))
	return err
}

  

posted @ 2024-12-18 10:31  dos_hello_world  阅读(50)  评论(0)    收藏  举报