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
| package mylogger
import (
"fmt"
"os"
"path"
"time"
)
// 往文件里写日志
// 定义 文件日志 的结构体
type FileLogger struct {
// 定义日志记录的级别
level Level
// 日志文件名称
filename string
// 日志文件路径
filepath string
// 文件句柄
file *os.File
errFile *os.File
// 日志大小
maxSize int64
}
// 文件日志的 构造函数 并初始化打开日志文件以及句柄
func NewFileLogger(levelStr, filename, filepath string, logSize int64) *FileLogger {
logLevel := parseLogLevel(levelStr)
fl := &FileLogger{
level: logLevel,
filename: filename,
filepath: filepath,
maxSize: logSize,
}
// 初始化 传入的文件名字以及路径打开文件
fl.initFile()
// 返回
return fl
}
// 初始化文件的句柄的方法
func (f *FileLogger) initFile() {
// 1. 拼接 日志文件 的路径
logName := path.Join(f.filepath, f.filename)
// 2. 打开文件,使用 os.OpenFile
fileObj, err := os.OpenFile(logName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
if err != nil {
panic(fmt.Errorf("打开文件 %s 失败, %v", logName, err))
}
// 3. 将文件句柄赋值给 FileLogger 结构体中的 f.file
f.file = fileObj
// 4. 错误日志
errLogName := fmt.Sprintf("%s.err", logName)
// 5. 打开错误日志文件
errFileObj, err := os.OpenFile(errLogName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
if err != nil {
panic(fmt.Errorf("打开文件 %s 失败, %v", errLogName, err))
}
// 6. 将文件句柄赋值给 FileLogger 结构体中的 f.errFile
f.errFile = errFileObj
}
func (f *FileLogger) checkSplit(file *os.File) bool {
// 获取当前日志文件的大小
fileInfo, _ := file.Stat()
fileSize := fileInfo.Size()
// 判断传入的文件大小
return fileSize >= f.maxSize
}
// 日志切割函数
func (f *FileLogger) splitLogFile(file *os.File) *os.File {
// 获取 文件的完整路劲
fileName := file.Name()
backupName := fmt.Sprintf("%s_%v.back", fileName, time.Now().Unix())
// 关闭原来的文件句柄
file.Close()
// 备份原来日志的文件
_ = os.Rename(fileName, backupName)
// 重新打开日志文件
fileObj, err := os.OpenFile(fileName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
if err != nil {
panic(fmt.Errorf("打开文件 %s 失败, %v", fileName, err))
}
return fileObj
}
// 日志记录功能函数
func (f *FileLogger) log(level Level, format string, args ...interface{}) {
// 获取 日志需要记录的信息
// 0. 判断日志的级别, 判断传入参数level的日志级别
if f.level > level {
return
}
// 1. fmt.Sprint 字符串拼接
msg := fmt.Sprintf(format, args...)
// 2. 定义 要写入日志的格式: ( [时间][文件:行号][函数名][日志级别] msg )
// 2.1 获取时间
nowStr := time.Now().Format("2006-01-02 15:04:05.000")
// 2.2 获取 文件,行号,函数名 等信息
fileName, link, funcName := getCallerInfo(3)
// 2.3 获取 用户传入的日志级别 字符串
logLevelStr := getLevelStr(level)
// 2.4 拼接成完整的日志信息
logMsg := fmt.Sprintf("[%s][%s:%d][%s][%s] %s",
nowStr, fileName, link, funcName, logLevelStr, msg)
// 检查判断是否需要切分日志
if f.checkSplit(f.file) {
f.file = f.splitLogFile(f.file)
}
// 3. fmt.Fprintf 写入 f.file 日志文件
_, err := fmt.Fprintln(f.file, logMsg)
if err != nil {
panic(fmt.Errorf("写入文件 %s 失败", f.filename))
}
// 4. 如果 level 等级是 error 或 fatal 级别还要写入 f.errFile 中
if level >= ErrorLevel {
if f.checkSplit(f.errFile) {
f.errFile = f.splitLogFile(f.errFile)
}
_, err := fmt.Fprintln(f.errFile, logMsg)
if err != nil {
panic(fmt.Errorf("写入文件 %s 失败", f.filename))
}
}
}
// Debug 日志级别的方法 args ...表示 一个或多个参数
func (f *FileLogger) Debug(format string, args ...interface{}) {
f.log(DebugLevel, format, args...)
}
// Info 日志级别的方法 args ...表示 一个或多个参数
func (f *FileLogger) Info(format string, args ...interface{}) {
f.log(InfoLevel, format, args...)
}
// Warning 日志级别的方法 args ...表示 一个或多个参数
func (f *FileLogger) Warning(format string, args ...interface{}) {
f.log(WarningLevel, format, args...)
}
// Warning 日志级别的方法 args ...表示 一个或多个参数
func (f *FileLogger) Error(format string, args ...interface{}) {
f.log(ErrorLevel, format, args...)
}
// Fatal 日志级别的方法 args ...表示 一个或多个参数
func (f *FileLogger) Fatal(format string, args ...interface{}) {
f.log(FatalLevel, format, args...)
}
// 关闭日志文件句柄的方法
func (f *FileLogger) Close() {
f.file.Close()
f.errFile.Close()
}
|