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日志库的主要内容,如果未能解决你的问题,请参考以下文章

go语言标准库之log

go语言碎片整理之标准库log

go语言碎片整理之标准库log

Go语言系列之标准库log

Go语言系列之标准库log

Go语言开发Go语言常用标准库一