go语言实现log日志库
mylogger日志库结构
- mylogger
- console.go
- mylogger.go
- myloggerfile.go
日志库实现
console.go:
1 package mylogger 2 3 import ( 4 "fmt" 5 "time" 6 ) 7 8 // Logger对象的构造函数 9 func NewLogger(nowLevel string) *Logger { 10 myLevel, err := strToLoglever(nowLevel) 11 if err != nil { 12 panic(err) 13 } 14 return &Logger{Level: myLevel} 15 } 16 17 func (l Logger) enable(loglever Loglever) bool { 18 return loglever >= l.Level 19 } 20 21 func printLog(level Loglever, msg string, args ...interface{}) { 22 now := time.Now() 23 logtime := now.Format("2006-01-02 15:04:05") 24 fileName, funcName, lineNumber := getInfo(3) 25 msg = fmt.Sprintf(msg, args...) 26 fmt.Printf("[%s] [%s] [%s:%s:%d] %s\n", logtime, logleverToStr(level), fileName, funcName, lineNumber, msg) 27 } 28 29 func (l Logger) Debug(msg string, args ...interface{}) { 30 if l.enable(DEBUG) { 31 printLog(DEBUG, msg, args...) 32 } 33 } 34 35 func (l Logger) Info(msg string, args ...interface{}) { 36 if l.enable(INFO) { 37 printLog(INFO, msg, args...) 38 } 39 } 40 41 func (l Logger) Warning(msg string, args ...interface{}) { 42 if l.enable(WARNING) { 43 printLog(WARNING, msg, args...) 44 } 45 } 46 47 func (l Logger) Error(msg string, args ...interface{}) { 48 if l.enable(ERROR) { 49 printLog(ERROR, msg, args...) 50 } 51 } 52 53 func (l Logger) Falta(msg string, args ...interface{}) { 54 if l.enable(FALTA) { 55 printLog(FALTA, msg, args...) 56 } 57 }
mylogger.go:
1 package mylogger 2 3 import ( 4 "errors" 5 "fmt" 6 "path" 7 "runtime" 8 "strings" 9 ) 10 11 type Loglever uint16 12 13 type Logger struct { 14 Level Loglever 15 } 16 17 const ( 18 UNKNOW Loglever = iota 19 DEBUG 20 INFO 21 WARNING 22 ERROR 23 FALTA 24 ) 25 26 // 将字符串的日志级别转换成Loglever类型 27 // 将字符串类型的日志级别转成数字, 方便进行比较 28 func strToLoglever(lever string) (Loglever, error) { 29 lever = strings.ToUpper(lever) 30 switch lever { 31 case "DEBUG": 32 return DEBUG, nil 33 case "INFO": 34 return INFO, nil 35 case "WARNING": 36 return WARNING, nil 37 case "ERROR": 38 return ERROR, nil 39 case "FALTA": 40 return FALTA, nil 41 default: 42 err := errors.New("日志级别错误") 43 return UNKNOW, err 44 } 45 } 46 47 // 将Loglever对象转换成string类型 48 func logleverToStr(level Loglever) string { 49 switch level { 50 case DEBUG: 51 return "DEBUG" 52 case INFO: 53 return "INFO" 54 case WARNING: 55 return "WARNING" 56 case ERROR: 57 return "ERROR" 58 case FALTA: 59 return "FALTA" 60 default: 61 return "ERROR" 62 } 63 } 64 65 // 获取调用函数名、行号、文件名信息 66 func getInfo(n int) (fileName string, funcName string, lineNumber int) { 67 pc, file, line, ok := runtime.Caller(n) 68 if !ok { 69 fmt.Println("runtime caller failed.") 70 return 71 } 72 funcName = runtime.FuncForPC(pc).Name() 73 fileName = path.Base(file) 74 lineNumber = line 75 return 76 } 77 78 type MyLogger interface { 79 Debug(msg string, args ...interface{}) 80 Info(msg string, args ...interface{}) 81 Warning(msg string, args ...interface{}) 82 Error(msg string, args ...interface{}) 83 Falta(msg string, args ...interface{}) 84 }
myloggerfile.go:
1 package mylogger 2 3 /* 4 异步记录日志到文件中 5 */ 6 7 import ( 8 "errors" 9 "fmt" 10 "os" 11 "path" 12 "time" 13 ) 14 15 type FileLogger struct { 16 level Loglever 17 logFileName string // 日志文件的文件名 18 logFilePath string // 日志文件的路径 19 logMaxSize int64 // 日志文件的最大大小 20 fileObj *os.File // 日志文件的文件句柄 21 errFileObj *os.File // 错误日志文件的文件句柄 22 writeChan chan *Message // 存放Message结构体指针的通道 23 } 24 25 // Message 存放日志信息的结构体 26 type Message struct { 27 level Loglever 28 nowTime string 29 fileName string 30 funcName string 31 lineNumber int 32 msg string 33 } 34 35 // 构造函数,构建FileLogger结构体并返回 36 func NewFileLogger(level, logFileName, logFilePath string, logMaxSize int64) *FileLogger { 37 lv, err := strToLoglever(level) 38 if err != nil { 39 panic(err) 40 } 41 logger := &FileLogger{ 42 level: lv, 43 logFileName: logFileName, 44 logFilePath: logFilePath, 45 logMaxSize: logMaxSize, 46 writeChan: make(chan *Message, 5000), 47 } 48 // 初始化,将日志文件和错误日志文件的文件句柄传入FileLogger结构体 49 logger.initFileOpen() 50 return logger 51 } 52 53 // 初始化日志文件和错误日志文件的文件句柄 54 func (f *FileLogger) initFileOpen() error { 55 fileName := path.Join(f.logFilePath, f.logFileName) 56 logFile, err := os.OpenFile(fileName, os.O_APPEND|os.O_CREATE|os.O_RDWR, 0644) 57 if err != nil { 58 return errors.New("open log file error") 59 } 60 errLogFile, err := os.OpenFile(fileName+".err", os.O_APPEND|os.O_CREATE|os.O_RDWR, 0644) 61 if err != nil { 62 return errors.New("open err log file error") 63 } 64 f.fileObj = logFile 65 f.errFileObj = errLogFile 66 67 // 启动goroutine去异步写日志到文件中 68 go f.backendLog() 69 70 return nil 71 } 72 73 func (f *FileLogger) enable(loglevel Loglever) bool { 74 return loglevel >= f.level 75 } 76 77 // 检查日志文件大小 78 func (f *FileLogger) autoLogFileSplit(fileObj *os.File) (*os.File, error) { 79 fileInfo, err := fileObj.Stat() 80 if err != nil { 81 fmt.Println("get file info failed: ", err) 82 return nil, err 83 } 84 // 如果当前的日志大小超过定义的最大日志大小,则进行日志文件切割 85 if fileInfo.Size() >= f.logMaxSize { 86 LogName := path.Join(f.logFilePath, fileInfo.Name()) 87 nowTime := time.Now().Format("20060102150405000") 88 newLogName := fmt.Sprintf("%s.%s.bak", LogName, nowTime) 89 90 // 关闭正在写入的文件 91 fileObj.Close() 92 // 对当前文件进行重命名后备份 93 os.Rename(LogName, newLogName) 94 // 返回新打开的文件句柄 95 newFileObj, err := os.OpenFile(LogName, os.O_APPEND|os.O_CREATE|os.O_RDWR, 0644) 96 if err != nil { 97 fmt.Println("open new log file error: ", err) 98 return nil, err 99 } 100 return newFileObj, nil 101 } 102 return fileObj, nil 103 } 104 105 // 从writeChan通道中获取日志对象,然后记录到文件中 106 func (f *FileLogger) backendLog() { 107 for { 108 // 从通道中获取message对象, 如果通道中没有数据陷入阻塞,则休息500毫秒 109 select { 110 case job := <-f.writeChan: 111 // 日志文件自动切割 112 FileObj, err := f.autoLogFileSplit(f.fileObj) 113 if err != nil { 114 fmt.Println("split file error") 115 return 116 } 117 f.fileObj = FileObj 118 // 将内容输出到对应的日志文件和错误日志文件中 119 fmt.Fprintf(f.fileObj, "%s %s [%s %s %d] %s\n", job.nowTime, logleverToStr(job.level), job.fileName, job.funcName, job.lineNumber, job.msg) 120 if job.level >= ERROR { 121 // 日志文件自动切割 122 FileObj, err := f.autoLogFileSplit(f.errFileObj) 123 if err != nil { 124 fmt.Println("split file error") 125 return 126 } 127 f.errFileObj = FileObj 128 fmt.Fprintf(f.errFileObj, "%s %s [%s %s %d] %s\n", job.nowTime, logleverToStr(job.level), job.fileName, job.funcName, job.lineNumber, job.msg) 129 } 130 default: 131 time.Sleep(time.Millisecond * 500) 132 } 133 134 } 135 } 136 137 // 记录日志到文件中 138 func (f *FileLogger) log(lv Loglever, msg string, args ...interface{}) { 139 if f.enable(lv) { 140 now := time.Now() 141 date := now.Format("2006-01-02 15:04:05") 142 fileName, funcName, lineNumber := getInfo(3) 143 msg = fmt.Sprintf(msg, args...) 144 145 // 构建存放job信息的对象,放入writeChan通道中 146 newJob := &Message{ 147 level: lv, 148 nowTime: date, 149 fileName: fileName, 150 funcName: funcName, 151 lineNumber: lineNumber, 152 msg: msg, 153 } 154 // 尝试往writeChan通道中放对象,如果通道满了放不下,则丢弃数据 155 select { 156 case f.writeChan <- newJob: 157 default: 158 } 159 } 160 } 161 162 func (f *FileLogger) Debug(msg string, args ...interface{}) { 163 f.log(DEBUG, msg, args...) 164 } 165 166 func (f *FileLogger) Info(msg string, args ...interface{}) { 167 f.log(INFO, msg, args...) 168 } 169 170 func (f *FileLogger) Warning(msg string, args ...interface{}) { 171 f.log(WARNING, msg, args...) 172 } 173 174 func (f *FileLogger) Error(msg string, args ...interface{}) { 175 f.log(ERROR, msg, args...) 176 } 177 178 func (f *FileLogger) Falta(msg string, args ...interface{}) { 179 f.log(FALTA, msg, args...) 180 }
日志库的调用:
1 package main 2 3 import "gogogo/10-mylogger/02-logger/mylogger" 4 5 var logger mylogger.MyLogger 6 7 func main() { 8 logger = mylogger.NewLogger("Warning") 9 // for { 10 // logger.Debug("这是Debug日志") 11 // logger.Info("这是Info日志") 12 // logger.Warning("这是Warning日志") 13 // myname := "hgzerowzh" 14 // myage := 18 15 // logger.Error("这是Error日志, my name is %s, my age is %d", myname, myage) 16 // logger.Falta("这是Falta日志") 17 // time.Sleep(2 * time.Second) 18 19 // logger.Debug("这是Debug日志") 20 // logger.Info("这是Info日志") 21 // logger.Warning("这是Warning日志") 22 // myName := "hgzerowzh" 23 // myAge := 18 24 // logger.Error("这是Error日志, my name is %s, my age is %d", myName, myAge) 25 // logger.Falta("这是Falta日志") 26 // time.Sleep(2 * time.Second) 27 // } 28 29 logger = mylogger.NewFileLogger("Warning", "mylogger.log", "./", 20000*1024) 30 for { 31 logger.Debug("这是Debug日志") 32 logger.Info("这是Info日志") 33 logger.Warning("这是Warning日志") 34 myname := "hgzerowzh" 35 myage := 18 36 logger.Error("这是Error日志, my name is %s, my age is %d", myname, myage) 37 logger.Falta("这是Falta日志") 38 // time.Sleep(2 * time.Second) 39 } 40 }