Go语言中日志库demo

作者: ropon 分类: Go 发布时间: 2019-11-20 13:51
// logger.go
package logger

import "strings"

//日志库

//Loglevelmap 定义日志级别map
var Loglevelmap = map[string]int{
	"debug": 0,
	"info":  1,
	"warn":  2,
	"error": 3,
	"fatal": 4,
}

//Logger 是一个日志接口
type Logger interface {
	Debug(format string, args ...interface{})
	Info(format string, args ...interface{})
	Warn(format string, args ...interface{})
	Error(format string, args ...interface{})
	Fatal(format string, args ...interface{})
	Close()
}

// Getlevel 获取日志级别
func Getlevel(level string) int {
	//统一转成小写
	level = strings.ToLower(level)
	val, ok := Loglevelmap[level]
	if ok {
		return val
	}
	return 1
}

// file.go
package logger

import (
	"fmt"
	"os"
	"path"
	"time"
)

// FileLogger 日志结构体
type FileLogger struct {
	Level    string
	Filepath string
	Filename string
	file     *os.File
	errFile  *os.File
	maxSize  int64
	lastTime time.Time
}

// NewFileLogger 构造日志结构体函数
func NewFileLogger(Level, Filepath, Filename string) *FileLogger {
	FileObj := &FileLogger{
		Level:    Level,
		Filepath: Filepath,
		Filename: Filename,
		maxSize:  10 * 1024 * 1024,
		lastTime: time.Now(),
	}
	FileObj.initFile()
	return FileObj
}

func (f *FileLogger) initFile() {
	logName := path.Join(f.Filepath, f.Filename)
	fileObj, err := os.OpenFile(logName, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
	if err != nil {
		panic(fmt.Errorf("打开日志文件%s异常, 报错:%v", logName, err))
	}
	f.file = fileObj
	errLogName := fmt.Sprintf("err_%s", logName)
	errFileObj, err := os.OpenFile(errLogName, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
	if err != nil {
		panic(fmt.Errorf("打开日志文件%s异常, 报错:%v", errLogName, err))
	}
	f.errFile = errFileObj
}

//再次封装写日志函数
func (f *FileLogger) wLog(logLevel string, format string, args ...interface{}) {
	if Getlevel(f.Level) > Getlevel(logLevel) {
		return
	}
	// 按大小拆分日志
	// f.file = f.checkSplitLog(f.file)
	f.checkSplitLog()
	msgInfo := fmt.Sprintf(format, args...)
	nowStr := time.Now().Format("2006-01-02 15:04:05.000")
	funcName, fileName, line := getCallerInfo(3)
	logMsg := fmt.Sprintf("[%s] [%s] [%s:%s] %d %s", nowStr, logLevel, fileName, funcName, line, msgInfo)
	_, _ = fmt.Fprintln(f.file, logMsg)
	if Getlevel(logLevel) >= Getlevel("ERROR") {
		// 按大小拆分时需要
		// f.errFile = f.checkSplitLog(f.errFile)
		_, _ = fmt.Fprintln(f.errFile, logMsg)
	}
}

//日志拆分
func (f *FileLogger) checkSplitLog() {
	// 按大小拆分
	// fileInfo, _ := file.Stat()
	// fileSize := fileInfo.Size()
	// if fileSize < f.maxSize {
	// 	return file
	// }
	// 按时间拆分
	timeD := time.Now().Sub(f.lastTime).Minutes()
	if timeD >= 1 {
		fileName := f.file.Name()
		backupName := fmt.Sprintf("%s_bak%v", fileName, time.Now().Unix())
		_ = f.file.Close()
		_ = os.Rename(fileName, backupName)
		fileObj, err := os.OpenFile(fileName, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
		if err != nil {
			panic(fmt.Errorf("打开日志文件%s异常, 报错:%v", fileName, err))
		}

		errFileName := f.errFile.Name()
		errBackupName := fmt.Sprintf("%s_bak%v", errFileName, time.Now().Unix())
		_ = f.errFile.Close()
		_ = os.Rename(errFileName, errBackupName)
		errFileObj, err := os.OpenFile(errFileName, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
		if err != nil {
			panic(fmt.Errorf("打开日志文件%s异常, 报错:%v", errFileName, err))
		}
		// 将当前时间复制给上次拆分时间
		f.lastTime = time.Now()
		f.file = fileObj
		f.errFile = errFileObj
	}
}

// Debug 调试日志
func (f *FileLogger) Debug(format string, args ...interface{}) {
	f.wLog("DEBUG", format, args...)
}

// Info 一般日志
func (f *FileLogger) Info(format string, args ...interface{}) {
	f.wLog("INFO", format, args...)
}

// Warn 警告日志
func (f *FileLogger) Warn(format string, args ...interface{}) {
	f.wLog("WARN", format, args...)
}

// Error 错误日志
func (f *FileLogger) Error(format string, args ...interface{}) {
	f.wLog("ERROR", format, args...)
}

// Fatal 严重错误日志
func (f *FileLogger) Fatal(format string, args ...interface{}) {
	f.wLog("FATAL", format, args...)
}

// Close 关闭文件句柄
func (f *FileLogger) Close() {
	_ = f.file.Close()
	_ = f.errFile.Close()
}

// utils.go
package logger

import (
	"path"
	"runtime"
)

func getCallerInfo(skip int) (funcName, fileName string, line int) {
	pc, fileName, line, ok := runtime.Caller(skip)
	if !ok {
		panic("获取程序信息失败")
	}
	funcName = path.Base(runtime.FuncForPC(pc).Name())
	fileName = path.Base(fileName)
	return
}

// console.go
package logger

import (
	"fmt"
	"os"
	"time"
)

// ConsoleLogger 终端结构体
type ConsoleLogger struct {
	Level string
}

// NewConsoleLogger 构造终端结构体函数
func NewConsoleLogger(Level string) *ConsoleLogger {
	ConsoleObj := &ConsoleLogger{
		Level: Level,
	}
	return ConsoleObj
}

//再次封装写日志函数
func (f *ConsoleLogger) wLog(logLevel string, format string, args ...interface{}) {
	if Getlevel(f.Level) > Getlevel(logLevel) {
		return
	}
	msgInfo := fmt.Sprintf(format, args...)
	nowStr := time.Now().Format("2006-01-02 15:04:05.000")
	funcName, fileName, line := getCallerInfo(3)
	logMsg := fmt.Sprintf("[%s] [%s] [%s:%s] %d %s", nowStr, logLevel, fileName, funcName, line, msgInfo)
	_, _ = fmt.Fprintln(os.Stdout, logMsg)
}

// Debug 调试日志
func (f *ConsoleLogger) Debug(format string, args ...interface{}) {
	f.wLog("DEBUG", format, args...)
}

// Info 一般日志
func (f *ConsoleLogger) Info(format string, args ...interface{}) {
	f.wLog("INFO", format, args...)
}

// Warn 警告日志
func (f *ConsoleLogger) Warn(format string, args ...interface{}) {
	f.wLog("WARN", format, args...)
}

// Error 错误日志
func (f *ConsoleLogger) Error(format string, args ...interface{}) {
	f.wLog("ERROR", format, args...)
}

// Fatal 严重错误日志
func (f *ConsoleLogger) Fatal(format string, args ...interface{}) {
	f.wLog("FATAL", format, args...)
}

// Close 终端不需要关闭
func (f *ConsoleLogger) Close() {

}

// 使用方法
package main

import (
	"time"

	logger "ropon.top/day04/1logger"
)

// blog测试项目

//定义全局变量log 接口
var log logger.Logger

func main() {
	//往文件中写日志
	//log = logger.NewFileLogger("Debug", "./", "blog.log")
	//往终端写日志
	log = logger.NewConsoleLogger("Info")
	defer log.Close()
	for i := 0; i < 10; i++ {
		x := 100
		log.Debug("这是一条Debug信息,调试程序而已")
		log.Info("这是一条Info信息,测试记录变量值%d", x)
		log.Error("这是一条Error信息,天啦程序奔溃")
		log.Fatal("这是一条Fatal信息,哇程序出错啦")
		time.Sleep(time.Second * 10)
	}
}

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!