gitee.com/hongliu9527/go-tools@v0.0.8/logger/logger.go (about)

     1  /*
     2   * @Author: hongliu
     3   * @Date: 2022-04-26 09:34:48
     4   * @LastEditors: hongliu
     5   * @LastEditTime: 2022-04-26 10:34:25
     6   * @FilePath: \go-tools\logger\logger.go
     7   * @Description: 封装日志
     8   *
     9   * Copyright (c) 2022 by 洪流, All Rights Reserved.
    10   */
    11  
    12  // 1. 支持日志信息输出到终端和日志文件(支持同时输出),默认终端输出
    13  //    1.1 支持日志文件容量限制
    14  //    1.2 支持日志文件切片(按天进行切分))
    15  //    1.3 支持设置最大保留天数
    16  //    1.4 保证系统升级时不会清除存在的日志
    17  //    1.5 当剩余磁盘空间少于日志文件容量[可选]
    18  //    1.6 终端输出时支持颜色
    19  // 2. 保证系统升级时不会清除日志系统配置
    20  // 3. 支持日志输出等级
    21  
    22  package logger
    23  
    24  import (
    25  	"fmt"
    26  	"path"
    27  	"runtime"
    28  	"strconv"
    29  	"time"
    30  
    31  	rotatelogs "github.com/lestrrat-go/file-rotatelogs"
    32  	"github.com/rifflock/lfshook"
    33  	"github.com/sirupsen/logrus"
    34  )
    35  
    36  // Logger 日志记录器类型封装
    37  var logger *logrus.Logger
    38  
    39  // fixFields 日志上报的固定信息域
    40  var fixFields = make(logrus.Fields, 0)
    41  
    42  // 模块初始化函数
    43  func init() {
    44  	logger = logrus.New()
    45  	logger = logrus.New()
    46  	logger.SetFormatter(&Formatter{
    47  		TimestampFormat: "2006-01-02 15:04:05.000", // 设置时间戳格式
    48  		NoFieldsColors:  false,                     // 设置单行所有内容都显示颜色
    49  	})
    50  }
    51  
    52  // LogConfig 日志配置
    53  type LogConfig struct {
    54  	AppName                string        // 应用程序名称
    55  	LogDir                 string        // 保存目录
    56  	IsSaveToFile           bool          // 是否保存日志文件
    57  	ConsoleLogLevel        string        // 终端日志等级
    58  	FileLogLevel           string        // 文件日志等级
    59  	RotationIntervalTime   time.Duration // 日志分割时间间隔
    60  	MaxRotationRemainCount uint          // 日志分割文件个数
    61  }
    62  
    63  // logDefaultConfig 默认日志配置
    64  var logDefaultConfig = LogConfig{
    65  	AppName:                "App",     // 默认日志文件以应用程序名称的前缀
    66  	LogDir:                 "./log",   // 默认日志保存目录为当前目录下log目录
    67  	IsSaveToFile:           true,      // 默认开启日志文件保存功能
    68  	ConsoleLogLevel:        "info",    // 默认设置日志命令行输出级别
    69  	FileLogLevel:           "info",    // 默认设置日志文件输出级别
    70  	RotationIntervalTime:   time.Hour, // 默认设置每隔1个小时切分一次日志文件
    71  	MaxRotationRemainCount: 24,        // 默认设置只保存24个小时的日志内容
    72  }
    73  
    74  // ChinaClock 中国时区时钟
    75  type ChinaClock struct{}
    76  
    77  // Now 查询当前时间
    78  func (t ChinaClock) Now() time.Time {
    79  	return time.Now().UTC().Add(8 * time.Hour)
    80  }
    81  
    82  // newLogFileHook 创建日志文件相关的钩子
    83  // 1. 支持日志文件分割
    84  func newLogFileHook(logDir string, logLevel logrus.Level) logrus.Hook {
    85  	writer, err := rotatelogs.New(
    86  		logDir+"/"+logDefaultConfig.AppName+"_%Y-%m-%d_%H.log",
    87  		rotatelogs.WithClock(ChinaClock{}),
    88  		rotatelogs.WithRotationTime(logDefaultConfig.RotationIntervalTime),    // 设置日志分割的时间
    89  		rotatelogs.WithRotationCount(logDefaultConfig.MaxRotationRemainCount), // 设置文件清理前最多保存的个数
    90  		// rotatelogs.WithMaxAge(time.Hour*24),        // 设置文件清理前的最长保存时间(WithMaxAge和WithRotationCount二者只能设置一个)
    91  	)
    92  
    93  	if err != nil {
    94  		logrus.Errorf("配置日志文件分割属性失败(%s)", err.Error())
    95  	}
    96  
    97  	writerMap := make(lfshook.WriterMap)
    98  	levels := []logrus.Level{
    99  		logrus.DebugLevel,
   100  		logrus.InfoLevel,
   101  		logrus.WarnLevel,
   102  		logrus.ErrorLevel,
   103  		logrus.FatalLevel,
   104  		logrus.PanicLevel,
   105  	}
   106  
   107  	for _, level := range levels {
   108  		if int(level) <= int(logLevel) {
   109  			writerMap[level] = writer
   110  		}
   111  	}
   112  
   113  	lfsHook := lfshook.NewHook(writerMap, &logrus.TextFormatter{
   114  		DisableColors:   true,
   115  		FullTimestamp:   true,
   116  		TimestampFormat: "2006-01-02 15:04:05.000",
   117  	})
   118  	return lfsHook
   119  }
   120  
   121  // SetAppName 设置日志文件名以对应的应用程序名称为前缀
   122  func SetAppName(appName string) {
   123  	logDefaultConfig.AppName = appName
   124  }
   125  
   126  // SetLogFileDir 设置日志文件目录
   127  func SetLogFileDir(dir string) error {
   128  	logDefaultConfig.LogDir = dir
   129  	return nil
   130  }
   131  
   132  // SetLogRotationTime 设置日志文件分割时长(NOTE: 最小有效时间间隔为小时)
   133  func SetLogRotationTime(duration time.Duration) {
   134  	logDefaultConfig.RotationIntervalTime = duration
   135  }
   136  
   137  // SetLogRotationMaxFileCount 设置日志文件分割最大个数
   138  func SetLogRotationMaxFileCount(fileCount uint) {
   139  	logDefaultConfig.MaxRotationRemainCount = fileCount
   140  }
   141  
   142  // SetFileLevel 设置日志文件输出等级
   143  func SetFileLevel(logLevel string) {
   144  	level, err := logrus.ParseLevel(logLevel)
   145  	if err != nil {
   146  		logrus.Errorf("输入的日志等级(%s)校验失败(%s)", logLevel, err.Error())
   147  		return
   148  	}
   149  
   150  	// 创建日志文件相关的钩子替换掉默认钩子从而实现日志文件保存功能
   151  	hooks := make(logrus.LevelHooks)
   152  	hooks.Add(newLogFileHook(logDefaultConfig.LogDir, level))
   153  	logger.ReplaceHooks(hooks)
   154  }
   155  
   156  // SetFixedFields 设置日志上报的固定信息域
   157  func SetFixedFields(fields logrus.Fields) {
   158  	fixFields = fields
   159  }
   160  
   161  // AddFixedField 增加日志上报的固定信息域
   162  func AddFixedField(key string, value interface{}) {
   163  	fixFields[key] = value
   164  }
   165  
   166  // SetConsoleLevel 设置日志终端输出等级
   167  func SetConsoleLevel(logLevel string) {
   168  	level, err := logrus.ParseLevel(logLevel)
   169  	if err != nil {
   170  		logrus.Errorf("输入的日志等级(%s)校验失败(%s)", logLevel, err.Error())
   171  		return
   172  	}
   173  
   174  	if logger != nil {
   175  		logger.SetLevel(level)
   176  	}
   177  }
   178  
   179  // Debug 输出Debug信息
   180  func Debug(format string, v ...interface{}) {
   181  	_, filepath, line, ok := runtime.Caller(1)
   182  	if ok {
   183  		format = "[" + path.Base(filepath) + ":" + strconv.Itoa(line) + "] " + format
   184  	}
   185  
   186  	now := time.Now().UTC().Add(8 * time.Hour)
   187  	if logger != nil {
   188  		if len(v) == 0 {
   189  			logger.WithTime(now).WithFields(fixFields).Debug(format)
   190  		} else {
   191  			logger.WithTime(now).WithFields(fixFields).Debugf(format, v...)
   192  		}
   193  	} else {
   194  		fmt.Println("日志记录器未创建")
   195  	}
   196  }
   197  
   198  // Info 输出Info信息
   199  func Info(format string, v ...interface{}) {
   200  	_, filepath, line, ok := runtime.Caller(1)
   201  	if ok {
   202  		format = "[" + path.Base(filepath) + ":" + strconv.Itoa(line) + "] " + format
   203  	}
   204  
   205  	now := time.Now().UTC().Add(8 * time.Hour)
   206  	if logger != nil {
   207  		if len(v) == 0 {
   208  			logger.WithTime(now).WithFields(fixFields).Info(format)
   209  		} else {
   210  			logger.WithTime(now).WithFields(fixFields).Infof(format, v...)
   211  		}
   212  	} else {
   213  		fmt.Println("日志记录器未创建")
   214  	}
   215  }
   216  
   217  // Warning 输出Warning信息
   218  func Warning(format string, v ...interface{}) {
   219  	_, filepath, line, ok := runtime.Caller(1)
   220  	if ok {
   221  		format = "[" + path.Base(filepath) + ":" + strconv.Itoa(line) + "] " + format
   222  	}
   223  
   224  	now := time.Now().UTC().Add(8 * time.Hour)
   225  	if logger != nil {
   226  		if len(v) == 0 {
   227  			logger.WithTime(now).WithFields(fixFields).Warn(format)
   228  		} else {
   229  			logger.WithTime(now).WithFields(fixFields).Warnf(format, v...)
   230  		}
   231  	} else {
   232  		fmt.Println("日志记录器未创建")
   233  	}
   234  }
   235  
   236  // Error 输出Error信息
   237  func Error(format string, v ...interface{}) {
   238  	_, filepath, line, ok := runtime.Caller(1)
   239  	if ok {
   240  		format = "[" + path.Base(filepath) + ":" + strconv.Itoa(line) + "] " + format
   241  	}
   242  
   243  	now := time.Now().UTC().Add(8 * time.Hour)
   244  	if logger != nil {
   245  		if len(v) == 0 {
   246  			logger.WithTime(now).WithFields(fixFields).Error(format)
   247  		} else {
   248  			logger.WithTime(now).WithFields(fixFields).Errorf(format, v...)
   249  		}
   250  	} else {
   251  		fmt.Println("日志记录器未创建")
   252  	}
   253  }
   254  
   255  // Fatal 输出Fatal信息
   256  func Fatal(format string, v ...interface{}) {
   257  	_, filepath, line, ok := runtime.Caller(1)
   258  	if ok {
   259  		format = "[" + path.Base(filepath) + ":" + strconv.Itoa(line) + "] " + format
   260  	}
   261  
   262  	now := time.Now().UTC().Add(8 * time.Hour)
   263  	if logger != nil {
   264  		if len(v) == 0 {
   265  			logger.WithTime(now).WithFields(fixFields).Fatal(format)
   266  		} else {
   267  			logger.WithTime(now).WithFields(fixFields).Fatalf(format, v...)
   268  		}
   269  	} else {
   270  		fmt.Println("日志记录器未创建")
   271  	}
   272  }