复盘日志库logrus框架

它是一个结构化、插件化的日志记录库。完全兼容 golang 标准库中的日志模块。它还内置了 2 种日志输出格式 JSONFormatter 和 TextFormatter,来定义输出的日志格式。
main函数基本配置如下

package main

import "logrustest/core"

// go get -u github.com/natefinch/lumberjack@v2
func main() {

    //fmt.Println(path.Join("logs", "app-%Y-%m-%d.log"))
    core.InitLogrus()
    core.Log.Println("Listening and serving HTTP on", 1, ":", 2)
    for i := 0; i < 10000000; i++ {
        core.Log.Info("日志内容:", 1212121) // 写入文件
    }

}

核心配置如下

package core

import (
    "fmt"
    rotatelogs "github.com/lestrrat-go/file-rotatelogs"
    "github.com/rifflock/lfshook"
    "github.com/sirupsen/logrus"
    "gopkg.in/natefinch/lumberjack.v2"
    "io"
    "logrustest/utils"
    "os"
    "path"
    "path/filepath"
    "time"
)

// Log 实例
var Log *logrus.Logger

// customFormatter 自定义日志
type customFormatter struct {
    logrus.TextFormatter
}

func (f *customFormatter) Format(entry *logrus.Entry) ([]byte, error) {
    var levelColor string
    var levelText string
    switch entry.Level {
    case logrus.DebugLevel:
        levelColor, levelText = "34", "DEBUG" // 蓝色
    case logrus.InfoLevel:
        levelColor, levelText = "36", "INFO " // 青色
    case logrus.WarnLevel:
        levelColor, levelText = "33", "WARN " // 黄色
    case logrus.ErrorLevel:
        levelColor, levelText = "31", "ERROR" // 红色
    case logrus.FatalLevel, logrus.PanicLevel:
        levelColor, levelText = "31", "FATAL" // 红色,更重要的错误
    default:
        levelColor, levelText = "0", "UNKNOWN" // 默认颜色
    }

    // 获取调用者信息
    var fileAndLine string
    if entry.HasCaller() {
        dir := filepath.Dir(entry.Caller.File)
        fileAndLine = fmt.Sprintf("%s/%s:%d", filepath.Base(dir), filepath.Base(entry.Caller.File), entry.Caller.Line)
    }

    // 组装格式化字符串
    msg := fmt.Sprintf("\033[1;%sm%s\033[0m \033[4;1;%sm[%s]\033[0m \033[1;%sm[%s]\033[0m %s\n",
        levelColor, levelText, // 日志级别,带颜色
        levelColor, entry.Time.Format("2006-01-02 15:04:05.9999"), // 时间戳,下划线加颜色
        levelColor, fileAndLine, // 文件名:行号,带颜色
        entry.Message, // 日志消息
    )
    return []byte(msg), nil
}

func InitLogrus() error {
    Log = logrus.New()
    // 设置在输出日志中添加文件名和方法信息:
    Log.SetReportCaller(true)
    // 设置日志格式 自定义
    //Log.SetFormatter(&customFormatter{logrus.TextFormatter{
    //  ForceColors:   true, // 设置日志格式为带颜色
    //  FullTimestamp: true, // 完整时间戳的文本格式
    //}})

    // 设置日志格式 json
    //Log.SetFormatter(&logrus.JSONFormatter{
    //  TimestampFormat: "2006-01-02 15:04:05", // 设置json里的日期输出格式
    //})

    // 设置日志格式 text
    Log.SetFormatter(&logrus.TextFormatter{
        TimestampFormat:           "2006-01-02 15:04:05",
        ForceColors:               true,
        EnvironmentOverrideColors: false,
        FullTimestamp:             true,
        DisableLevelTruncation:    true,
    })

    var logLevels = map[string]logrus.Level{
        "panic": logrus.PanicLevel,
        "fatal": logrus.FatalLevel,
        "error": logrus.ErrorLevel,
        "warn":  logrus.WarnLevel,
        "info":  logrus.InfoLevel,
        "debug": logrus.DebugLevel,
        "trace": logrus.TraceLevel,
    }

    // 加载配置中的 日志级别
    levelStr := "debug"
    if level, ok := logLevels[levelStr]; ok {
        // 设置输出警告级别
        Log.SetLevel(level)
    } else {
        Log.Error("Invalid log level in config, setting to default level")
        // 设置默认级别
        Log.SetLevel(logrus.InfoLevel)
    }

    // 判断是否有存储日志文件夹
    // logs 目录
    logPath := "logs"
    if ok, _ := utils.PathExists(logPath); !ok {
        // 不存在创建日志存储目录
        fmt.Printf("create %v directory\n", logPath)
        _ = os.Mkdir(logPath, os.ModePerm)
    }

    // 按照大小分割日志
    //logger := &lumberjack.Logger{
    //  Filename:   path + "/app.log",
    //  MaxSize:    1,    // 日志文件大小,单位是 MB
    //  MaxBackups: 3,    // 最大过期日志保留个数
    //  MaxAge:     28,   // 保留过期文件最大时间,单位 天
    //  Compress:   true, // 是否压缩日志,默认是不压缩。这里设置为true,压缩日志
    //}
    // logrus 设置日志的输出方式
    //Log.SetOutput(logger)

    // 按照日期分割日志
    //linkName := "latest_log"
    //fileWriter, err := rotatelogs.New(
    //  path.Join(logPath, "%Y-%m-%d-%H-%M.log"),
    //  rotatelogs.WithMaxAge(7*24*time.Hour),      // 日志最大保存时间
    //  rotatelogs.WithLinkName(linkName),          //生成软链,指向最新日志文件
    //  rotatelogs.WithRotationTime(time.Minute),   //最小为1分钟轮询。默认60s  低于1分钟就按1分钟来
    //  // rotatelogs.WithRotationCount(3),            //设置3份 大于3份 或到了清理时间 开始清理
    //  rotatelogs.WithRotationSize(100*1024*1024), //设置1MB大小,当大于这个容量时,创建新的日志文件
    //)
    //if err != nil {
    //  return err
    //}
    // logrus 设置日志的输出方式
    //Log.SetOutput(fileWriter)

    // 自定义勾子写法 按照大小分割
    //logFile := &lumberjack.Logger{
    //  Filename:   logPath + "/app.log",
    //  MaxSize:    1,     // 日志文件大小,单位是 MB
    //  MaxBackups: 5,     // 最大过期日志保留个数
    //  MaxAge:     28,    // 保留过期文件最大时间,单位 天
    //  Compress:   false, // 是否压缩日志,默认是不压缩。这里设置为true,压缩日志
    //}
    //Log.AddHook(&lumberjackHook{
    //  logger: logFile,
    //})
    ////logrus 设置日志的输出丢弃
    //Log.SetOutput(io.Discard)

    // 勾子写法 按照时间分割
    //fileSplitWriter := NewLfsFileDateHook("", 0)
    //Log.AddHook(fileSplitWriter)
    //Log.SetOutput(io.Discard)

    // 勾子写法 按照日志大小分割
    fileSplitWriter := NewLfsFileSizeHook("", 0)
    Log.AddHook(fileSplitWriter)
    Log.SetOutput(io.Discard) // 如果设置该选项则为终端不打印

    //Log.Println("Logrus设置完成...")
    return nil
}

// hook的方式写入文件 大小
type lumberjackHook struct {
    logger *lumberjack.Logger
}

// Levels 返回该钩子应用的日志级别
func (hook *lumberjackHook) Levels() []logrus.Level {
    return logrus.AllLevels
}

// Fire 处理每一条日志记录,并将日志写入 lumberjack 管理的文件
func (hook *lumberjackHook) Fire(entry *logrus.Entry) error {
    // 格式化日志内容
    line, err := entry.String()
    if err != nil {
        return err
    }
    // 将日志写入文件
    _, err = hook.logger.Write([]byte(line))
    return err
}

// NewLfsFileSizeHook hook的方式写入文件 大小
func NewLfsFileSizeHook(logName string, maxRemainCnt uint) logrus.Hook {
    logPath := "logs"
    writer := &lumberjack.Logger{
        Filename:   path.Join(logPath, "app.log"),
        MaxSize:    1,    // 日志文件大小,单位是 MB
        MaxBackups: 3,    // 最大过期日志保留个数
        MaxAge:     28,   // 保留过期文件最大时间,单位 天
        Compress:   true, // 是否压缩日志,默认是不压缩。这里设置为true,压缩日志
    }

    logrus.SetLevel(logrus.InfoLevel)
    lfsHook := lfshook.NewHook(lfshook.WriterMap{
        logrus.DebugLevel: writer,
        logrus.InfoLevel:  writer,
        logrus.WarnLevel:  writer,
        logrus.ErrorLevel: writer,
        logrus.FatalLevel: writer,
        logrus.PanicLevel: writer,
    }, &logrus.TextFormatter{DisableColors: true})

    return lfsHook
}

// NewLfsFileDateHook hook的方式写入文件 日期
func NewLfsFileDateHook(logName string, maxRemainCnt uint) logrus.Hook {
    logPath := "logs"
    linkName := "latest_log"
    writer, err := rotatelogs.New(
        path.Join(logPath, "app-%Y-%m-%d.log"),
        rotatelogs.WithMaxAge(7*24*time.Hour),    // 日志最大保存时间
        rotatelogs.WithLinkName(linkName),        //生成软链,指向最新日志文件
        rotatelogs.WithRotationTime(time.Minute), //最小为1分钟轮询。默认60s  低于1分钟就按1分钟来
        //rotatelogs.WithRotationCount(5),            //设置3份 大于3份 或到了清理时间 开始清理
        rotatelogs.WithRotationSize(100*1024*1024), //设置1MB大小,当大于这个容量时,创建新的日志文件
    )
    if err != nil {
        logrus.Panicf("日志文件配置错误,无法记录日志: %v", err)
    }
    logrus.SetLevel(logrus.InfoLevel)
    lfsHook := lfshook.NewHook(lfshook.WriterMap{
        logrus.DebugLevel: writer,
        logrus.InfoLevel:  writer,
        logrus.WarnLevel:  writer,
        logrus.ErrorLevel: writer,
        logrus.FatalLevel: writer,
        logrus.PanicLevel: writer,
    }, &logrus.TextFormatter{DisableColors: true})

    return lfsHook
}