go语言实现log日志库()-go
go语言实现log日志库()
mylogger日志库结构
- mylogger
console.go
mylogger.go
myloggerfile.go - 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 }
————————
mylogger日志库结构
- mylogger
console.go
mylogger.go
myloggerfile.go - 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 }