GoLang 异步日志库实现

GoLang 异步日志库实现

  • 公共的方法
type LogLevel uint8

const (
	L_DEBUG LogLevel = iota
	L_WARNING
	L_ERROR
)

func getLogLevel(level LogLevel) string {
	switch level {
	case L_DEBUG:
		return "DEBUG"
	case L_WARNING:
		return "WARNING"
	case L_ERROR:
		return "ERROR"
	default:
		return "nil"
	}
}

func getLogInfo(skip int) (fileName, funcName string, l int) {
	pc, file, line, ok := runtime.Caller(skip)
	if !ok {
		fmt.Println("runtime.Caller Error")
		return
	}
	fileName = path.Base(file)
	funcName = runtime.FuncForPC(pc).Name()
	l = line
	return
}
  • 结构体方法
    使用结构体指针作为通道传输信息,而不使用string字符串传递可以节省性能开销
    在该程序中使用select语句中的defult可以避免因接收不了通道的信息而阻塞正常程序的运行
type FileLogger struct {
	level         LogLevel
	logFilePath   string
	logFileName   string
	maxFileSize   int64
	fileWriter    *os.File
	errFileWriter *os.File
	logChan       chan *logPack
}
type logPack struct {
	level    LogLevel
	time     string
	fileName string
	funcName string
	line     int
	msg      string
	file     *os.File
}

func NewFileLogger(level LogLevel, path, name string, maxSize int64) *FileLogger {
	logger := &FileLogger{
		level:       level,
		logFilePath: path,
		logFileName: name,
		maxFileSize: maxSize,
		logChan:     make(chan *logPack, 50000),
	}
	logger.initWriter()
	go logger.writeLog()
	return logger
}

func (f *FileLogger) Debug(format string, a ...any) {
	f.createInfo(L_DEBUG, format, a...)
}
func (f *FileLogger) Warning(format string, a ...any) {
	f.createInfo(L_WARNING, format, a...)
}
func (f *FileLogger) Error(format string, a ...any) {
	f.createInfo(L_ERROR, format, a...)
}
func (f *FileLogger) createInfo(targetLogLevel LogLevel, format string, a ...any) {
	if f.level <= targetLogLevel {
		f.makeAndWriteInfo(f.fileWriter, targetLogLevel, format, a...)
	}
	//当错误等级大于等于ERROR时,需要将错误单独写到一个文件中去
	if targetLogLevel >= L_ERROR {
		f.makeAndWriteInfo(f.errFileWriter, targetLogLevel, format, a...)
	}
}
func (f *FileLogger) makeAndWriteInfo(file *os.File, targetLogLevel LogLevel, format string, a ...any) {
	msg := fmt.Sprintf(format, a...)
	fileName, funcName, line := getLogInfo(4)
	pack := &logPack{
		level:    targetLogLevel,
		time:     time.Now().Format("2006-01-02 15:04:05"),
		fileName: fileName,
		funcName: funcName,
		line:     line,
		msg:      msg,
		file:     file,
	}
	select {
	case f.logChan <- pack:
	default:
	}
}
func (f *FileLogger) checkSize(file *os.File) bool {
	fileInfo, err := file.Stat()
	if err != nil {
		fmt.Println(err)
		panic("checkSize Error:")
	}
	size := fileInfo.Size()
	return size >= f.maxFileSize
}
func (f *FileLogger) writeLog() {
	for true {
		select {
		case pack := <-f.logChan:
			file := pack.file
			if f.checkSize(file) {
				//需要切割

				//1.关闭旧的文件写入
				oldPath := path.Join(f.logFilePath, file.Name())
				newPath := oldPath + ".ok" + strconv.FormatInt(time.Now().UnixNano(), 10)
				err := file.Close()
				if err != nil {
					fmt.Println(err)
					return
				}
				//2.重命名旧的文件
				err = os.Rename(oldPath, newPath)
				if err != nil {
					fmt.Println(err)
					return
				}
				//3.创建新的文件写入
				newFile, err := os.OpenFile(oldPath, os.O_WRONLY|os.O_CREATE|os.O_APPEND, os.ModePerm)
				if err != nil {
					fmt.Println(err)
					return
				}
				//4.设置新的file
				if *file == *f.fileWriter {
					f.fileWriter = newFile
				} else {
					f.errFileWriter = newFile
				}
			}
			_, err := fmt.Fprintf(file, "[%s][%s][%s:%s:%d]:%s\n",
				getLogLevel(pack.level),
				pack.time,
				pack.fileName,
				pack.funcName,
				pack.line,
				pack.msg)
			if err != nil {
				fmt.Println(err)
				return
			}
		default:
			time.Sleep(time.Millisecond * 500)
		}
	}
}
func (f *FileLogger) initWriter() {
	p := path.Join(f.logFilePath, f.logFileName)
	file, err := os.OpenFile(p, os.O_WRONLY|os.O_CREATE|os.O_APPEND, os.ModePerm)
	if err != nil {
		fmt.Println(err)
		return
	}
	errFile, err := os.OpenFile(p+".err", os.O_WRONLY|os.O_CREATE|os.O_APPEND, os.ModePerm)
	if err != nil {
		fmt.Println(err)
		return
	}
	f.fileWriter = file
	f.errFileWriter = errFile
}
func (f *FileLogger) Close() {
	err := f.fileWriter.Close()
	if err != nil {
		fmt.Println(err)
	}
	err = f.errFileWriter.Close()
	if err != nil {
		fmt.Println(err)
	}
	f.fileWriter = nil
	f.errFileWriter = nil
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值