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 }