go语言实现log日志库
Posted Pray
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了go语言实现log日志库相关的知识,希望对你有一定的参考价值。
mylogger日志库结构
- mylogger
- console.go
- mylogger.go
- myloggerfile.go
日志库实现
console.go:
package mylogger import ( "fmt" "time" ) // Logger对象的构造函数 func NewLogger(nowLevel string) *Logger myLevel, err := strToLoglever(nowLevel) if err != nil panic(err) return &LoggerLevel: myLevel func (l Logger) enable(loglever Loglever) bool return loglever >= l.Level func printLog(level Loglever, msg string, args ...interface) now := time.Now() logtime := now.Format("2006-01-02 15:04:05") fileName, funcName, lineNumber := getInfo(3) msg = fmt.Sprintf(msg, args...) fmt.Printf("[%s] [%s] [%s:%s:%d] %s\\n", logtime, logleverToStr(level), fileName, funcName, lineNumber, msg) func (l Logger) Debug(msg string, args ...interface) if l.enable(DEBUG) printLog(DEBUG, msg, args...) func (l Logger) Info(msg string, args ...interface) if l.enable(INFO) printLog(INFO, msg, args...) func (l Logger) Warning(msg string, args ...interface) if l.enable(WARNING) printLog(WARNING, msg, args...) func (l Logger) Error(msg string, args ...interface) if l.enable(ERROR) printLog(ERROR, msg, args...) func (l Logger) Falta(msg string, args ...interface) if l.enable(FALTA) printLog(FALTA, msg, args...)
mylogger.go:
package mylogger import ( "errors" "fmt" "path" "runtime" "strings" ) type Loglever uint16 type Logger struct Level Loglever const ( UNKNOW Loglever = iota DEBUG INFO WARNING ERROR FALTA ) // 将字符串的日志级别转换成Loglever类型 // 将字符串类型的日志级别转成数字, 方便进行比较 func strToLoglever(lever string) (Loglever, error) lever = strings.ToUpper(lever) switch lever case "DEBUG": return DEBUG, nil case "INFO": return INFO, nil case "WARNING": return WARNING, nil case "ERROR": return ERROR, nil case "FALTA": return FALTA, nil default: err := errors.New("日志级别错误") return UNKNOW, err // 将Loglever对象转换成string类型 func logleverToStr(level Loglever) string switch level case DEBUG: return "DEBUG" case INFO: return "INFO" case WARNING: return "WARNING" case ERROR: return "ERROR" case FALTA: return "FALTA" default: return "ERROR" // 获取调用函数名、行号、文件名信息 func getInfo(n int) (fileName string, funcName string, lineNumber int) pc, file, line, ok := runtime.Caller(n) if !ok fmt.Println("runtime caller failed.") return funcName = runtime.FuncForPC(pc).Name() fileName = path.Base(file) lineNumber = line return type MyLogger interface Debug(msg string, args ...interface) Info(msg string, args ...interface) Warning(msg string, args ...interface) Error(msg string, args ...interface) Falta(msg string, args ...interface)
myloggerfile.go:
package mylogger /* 异步记录日志到文件中 */ import ( "errors" "fmt" "os" "path" "time" ) type FileLogger struct level Loglever logFileName string // 日志文件的文件名 logFilePath string // 日志文件的路径 logMaxSize int64 // 日志文件的最大大小 fileObj *os.File // 日志文件的文件句柄 errFileObj *os.File // 错误日志文件的文件句柄 writeChan chan *Message // 存放Message结构体指针的通道 // Message 存放日志信息的结构体 type Message struct level Loglever nowTime string fileName string funcName string lineNumber int msg string // 构造函数,构建FileLogger结构体并返回 func NewFileLogger(level, logFileName, logFilePath string, logMaxSize int64) *FileLogger lv, err := strToLoglever(level) if err != nil panic(err) logger := &FileLogger level: lv, logFileName: logFileName, logFilePath: logFilePath, logMaxSize: logMaxSize, writeChan: make(chan *Message, 5000), // 初始化,将日志文件和错误日志文件的文件句柄传入FileLogger结构体 logger.initFileOpen() return logger // 初始化日志文件和错误日志文件的文件句柄 func (f *FileLogger) initFileOpen() error fileName := path.Join(f.logFilePath, f.logFileName) logFile, err := os.OpenFile(fileName, os.O_APPEND|os.O_CREATE|os.O_RDWR, 0644) if err != nil return errors.New("open log file error") errLogFile, err := os.OpenFile(fileName+".err", os.O_APPEND|os.O_CREATE|os.O_RDWR, 0644) if err != nil return errors.New("open err log file error") f.fileObj = logFile f.errFileObj = errLogFile // 启动goroutine去异步写日志到文件中 go f.backendLog() return nil func (f *FileLogger) enable(loglevel Loglever) bool return loglevel >= f.level // 检查日志文件大小 func (f *FileLogger) autoLogFileSplit(fileObj *os.File) (*os.File, error) fileInfo, err := fileObj.Stat() if err != nil fmt.Println("get file info failed: ", err) return nil, err // 如果当前的日志大小超过定义的最大日志大小,则进行日志文件切割 if fileInfo.Size() >= f.logMaxSize LogName := path.Join(f.logFilePath, fileInfo.Name()) nowTime := time.Now().Format("20060102150405000") newLogName := fmt.Sprintf("%s.%s.bak", LogName, nowTime) // 关闭正在写入的文件 fileObj.Close() // 对当前文件进行重命名后备份 os.Rename(LogName, newLogName) // 返回新打开的文件句柄 newFileObj, err := os.OpenFile(LogName, os.O_APPEND|os.O_CREATE|os.O_RDWR, 0644) if err != nil fmt.Println("open new log file error: ", err) return nil, err return newFileObj, nil return fileObj, nil // 从writeChan通道中获取日志对象,然后记录到文件中 func (f *FileLogger) backendLog() for // 从通道中获取message对象, 如果通道中没有数据陷入阻塞,则休息500毫秒 select case job := <-f.writeChan: // 日志文件自动切割 FileObj, err := f.autoLogFileSplit(f.fileObj) if err != nil fmt.Println("split file error") return f.fileObj = FileObj // 将内容输出到对应的日志文件和错误日志文件中 fmt.Fprintf(f.fileObj, "%s %s [%s %s %d] %s\\n", job.nowTime, logleverToStr(job.level), job.fileName, job.funcName, job.lineNumber, job.msg) if job.level >= ERROR // 日志文件自动切割 FileObj, err := f.autoLogFileSplit(f.errFileObj) if err != nil fmt.Println("split file error") return f.errFileObj = FileObj fmt.Fprintf(f.errFileObj, "%s %s [%s %s %d] %s\\n", job.nowTime, logleverToStr(job.level), job.fileName, job.funcName, job.lineNumber, job.msg) default: time.Sleep(time.Millisecond * 500) // 记录日志到文件中 func (f *FileLogger) log(lv Loglever, msg string, args ...interface) if f.enable(lv) now := time.Now() date := now.Format("2006-01-02 15:04:05") fileName, funcName, lineNumber := getInfo(3) msg = fmt.Sprintf(msg, args...) // 构建存放job信息的对象,放入writeChan通道中 newJob := &Message level: lv, nowTime: date, fileName: fileName, funcName: funcName, lineNumber: lineNumber, msg: msg, // 尝试往writeChan通道中放对象,如果通道满了放不下,则丢弃数据 select case f.writeChan <- newJob: default: func (f *FileLogger) Debug(msg string, args ...interface) f.log(DEBUG, msg, args...) func (f *FileLogger) Info(msg string, args ...interface) f.log(INFO, msg, args...) func (f *FileLogger) Warning(msg string, args ...interface) f.log(WARNING, msg, args...) func (f *FileLogger) Error(msg string, args ...interface) f.log(ERROR, msg, args...) func (f *FileLogger) Falta(msg string, args ...interface) f.log(FALTA, msg, args...)
日志库的调用:
package main import "gogogo/10-mylogger/02-logger/mylogger" var logger mylogger.MyLogger func main() logger = mylogger.NewLogger("Warning") // for // logger.Debug("这是Debug日志") // logger.Info("这是Info日志") // logger.Warning("这是Warning日志") // myname := "hgzerowzh" // myage := 18 // logger.Error("这是Error日志, my name is %s, my age is %d", myname, myage) // logger.Falta("这是Falta日志") // time.Sleep(2 * time.Second) // logger.Debug("这是Debug日志") // logger.Info("这是Info日志") // logger.Warning("这是Warning日志") // myName := "hgzerowzh" // myAge := 18 // logger.Error("这是Error日志, my name is %s, my age is %d", myName, myAge) // logger.Falta("这是Falta日志") // time.Sleep(2 * time.Second) // logger = mylogger.NewFileLogger("Warning", "mylogger.log", "./", 20000*1024) for logger.Debug("这是Debug日志") logger.Info("这是Info日志") logger.Warning("这是Warning日志") myname := "hgzerowzh" myage := 18 logger.Error("这是Error日志, my name is %s, my age is %d", myname, myage) logger.Falta("这是Falta日志") // time.Sleep(2 * time.Second)
以上是关于go语言实现log日志库的主要内容,如果未能解决你的问题,请参考以下文章