// 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)
}
}