Go语言中日志库demo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
// logger.go
package logger

import "strings"

//日志库

//Loglevelmap 定义日志级别map
var Loglevelmap = map[string]int{
"debug": 0,
"info": 1,
"warn": 2,
"error": 3,
"fatal": 4,
}

//Logger 是一个日志接口
type Logger interface {
Debug(format string, args ...interface{})
Info(format string, args ...interface{})
Warn(format string, args ...interface{})
Error(format string, args ...interface{})
Fatal(format string, args ...interface{})
Close()
}

// Getlevel 获取日志级别
func Getlevel(level string) int {
//统一转成小写
level = strings.ToLower(level)
val, ok := Loglevelmap[level]
if ok {
return val
}
return 1
}

// file.go
package logger

import (
"fmt"
"os"
"path"
"time"
)

// FileLogger 日志结构体
type FileLogger struct {
Level string
Filepath string
Filename string
file *os.File
errFile *os.File
maxSize int64
lastTime time.Time
}

// NewFileLogger 构造日志结构体函数
func NewFileLogger(Level, Filepath, Filename string) *FileLogger {
FileObj := &FileLogger{
Level: Level,
Filepath: Filepath,
Filename: Filename,
maxSize: 10 * 1024 * 1024,
lastTime: time.Now(),
}
FileObj.initFile()
return FileObj
}

func (f *FileLogger) initFile() {
logName := path.Join(f.Filepath, f.Filename)
fileObj, err := os.OpenFile(logName, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
if err != nil {
panic(fmt.Errorf("打开日志文件%s异常, 报错:%v", logName, err))
}
f.file = fileObj
errLogName := fmt.Sprintf("err_%s", logName)
errFileObj, err := os.OpenFile(errLogName, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
if err != nil {
panic(fmt.Errorf("打开日志文件%s异常, 报错:%v", errLogName, err))
}
f.errFile = errFileObj
}

//再次封装写日志函数
func (f *FileLogger) wLog(logLevel string, format string, args ...interface{}) {
if Getlevel(f.Level) > Getlevel(logLevel) {
return
}
// 按大小拆分日志
// f.file = f.checkSplitLog(f.file)
f.checkSplitLog()
msgInfo := fmt.Sprintf(format, args...)
nowStr := time.Now().Format("2006-01-02 15:04:05.000")
funcName, fileName, line := getCallerInfo(3)
logMsg := fmt.Sprintf("[%s] [%s] [%s:%s] %d %s", nowStr, logLevel, fileName, funcName, line, msgInfo)
_, _ = fmt.Fprintln(f.file, logMsg)
if Getlevel(logLevel) >= Getlevel("ERROR") {
// 按大小拆分时需要
// f.errFile = f.checkSplitLog(f.errFile)
_, _ = fmt.Fprintln(f.errFile, logMsg)
}
}

//日志拆分
func (f *FileLogger) checkSplitLog() {
// 按大小拆分
// fileInfo, _ := file.Stat()
// fileSize := fileInfo.Size()
// if fileSize < f.maxSize {
// return file
// }
// 按时间拆分
timeD := time.Now().Sub(f.lastTime).Minutes()
if timeD >= 1 {
fileName := f.file.Name()
backupName := fmt.Sprintf("%s_bak%v", fileName, time.Now().Unix())
_ = f.file.Close()
_ = os.Rename(fileName, backupName)
fileObj, err := os.OpenFile(fileName, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
if err != nil {
panic(fmt.Errorf("打开日志文件%s异常, 报错:%v", fileName, err))
}

errFileName := f.errFile.Name()
errBackupName := fmt.Sprintf("%s_bak%v", errFileName, time.Now().Unix())
_ = f.errFile.Close()
_ = os.Rename(errFileName, errBackupName)
errFileObj, err := os.OpenFile(errFileName, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
if err != nil {
panic(fmt.Errorf("打开日志文件%s异常, 报错:%v", errFileName, err))
}
// 将当前时间复制给上次拆分时间
f.lastTime = time.Now()
f.file = fileObj
f.errFile = errFileObj
}
}

// Debug 调试日志
func (f *FileLogger) Debug(format string, args ...interface{}) {
f.wLog("DEBUG", format, args...)
}

// Info 一般日志
func (f *FileLogger) Info(format string, args ...interface{}) {
f.wLog("INFO", format, args...)
}

// Warn 警告日志
func (f *FileLogger) Warn(format string, args ...interface{}) {
f.wLog("WARN", format, args...)
}

// Error 错误日志
func (f *FileLogger) Error(format string, args ...interface{}) {
f.wLog("ERROR", format, args...)
}

// Fatal 严重错误日志
func (f *FileLogger) Fatal(format string, args ...interface{}) {
f.wLog("FATAL", format, args...)
}

// Close 关闭文件句柄
func (f *FileLogger) Close() {
_ = f.file.Close()
_ = f.errFile.Close()
}

// utils.go
package logger

import (
"path"
"runtime"
)

func getCallerInfo(skip int) (funcName, fileName string, line int) {
pc, fileName, line, ok := runtime.Caller(skip)
if !ok {
panic("获取程序信息失败")
}
funcName = path.Base(runtime.FuncForPC(pc).Name())
fileName = path.Base(fileName)
return
}

// console.go
package logger

import (
"fmt"
"os"
"time"
)

// ConsoleLogger 终端结构体
type ConsoleLogger struct {
Level string
}

// NewConsoleLogger 构造终端结构体函数
func NewConsoleLogger(Level string) *ConsoleLogger {
ConsoleObj := &ConsoleLogger{
Level: Level,
}
return ConsoleObj
}

//再次封装写日志函数
func (f *ConsoleLogger) wLog(logLevel string, format string, args ...interface{}) {
if Getlevel(f.Level) > Getlevel(logLevel) {
return
}
msgInfo := fmt.Sprintf(format, args...)
nowStr := time.Now().Format("2006-01-02 15:04:05.000")
funcName, fileName, line := getCallerInfo(3)
logMsg := fmt.Sprintf("[%s] [%s] [%s:%s] %d %s", nowStr, logLevel, fileName, funcName, line, msgInfo)
_, _ = fmt.Fprintln(os.Stdout, logMsg)
}

// Debug 调试日志
func (f *ConsoleLogger) Debug(format string, args ...interface{}) {
f.wLog("DEBUG", format, args...)
}

// Info 一般日志
func (f *ConsoleLogger) Info(format string, args ...interface{}) {
f.wLog("INFO", format, args...)
}

// Warn 警告日志
func (f *ConsoleLogger) Warn(format string, args ...interface{}) {
f.wLog("WARN", format, args...)
}

// Error 错误日志
func (f *ConsoleLogger) Error(format string, args ...interface{}) {
f.wLog("ERROR", format, args...)
}

// Fatal 严重错误日志
func (f *ConsoleLogger) Fatal(format string, args ...interface{}) {
f.wLog("FATAL", format, args...)
}

// Close 终端不需要关闭
func (f *ConsoleLogger) Close() {

}

// 使用方法
package main

import (
"time"

logger "ropon.top/day04/1logger"
)

// blog测试项目

//定义全局变量log 接口
var log logger.Logger

func main() {
//往文件中写日志
//log = logger.NewFileLogger("Debug", "./", "blog.log")
//往终端写日志
log = logger.NewConsoleLogger("Info")
defer log.Close()
for i := 0; i < 10; i++ {
x := 100
log.Debug("这是一条Debug信息,调试程序而已")
log.Info("这是一条Info信息,测试记录变量值%d", x)
log.Error("这是一条Error信息,天啦程序奔溃")
log.Fatal("这是一条Fatal信息,哇程序出错啦")
time.Sleep(time.Second * 10)
}
}