之前工作中写golang项目的时候,一直都是用别人封装好的日志包,这里尝试自行去实现一个简单封装的日志包,当然,是基于golang自带的log包去封装了。
1.自带log包的基本使用
这里先看自带的log包中日志对象的定义:
1 | // A Logger represents an active logging object that generates lines of |
从这里可以看出,log个人对象最重要的是包含一个io.Writer 类型的属性out, 只要是实现了io.Writer这个interface定义的Write()方法的对象,就可以声明为一个io.Writer类型的对象了。
在log包中, 有两个主要的方法去对Logger对象的out属性赋值,一个是直接调用New()方法创建一个Logger对象;另外一个便是调用SetOutput()方法对一个Logger对象的out属性进行赋值。
1 | func New(out io.Writer, prefix string, flag int) *Logger { |
os.File对象实现了io.Writer接口对应的方法,故而可以赋值给Logger的out属性,常见的os.File有很多
os.Stdin / os.Stdout / os.Stderr 这三个os.File类型的对象分别对应系统的三个标准输出
1 | // file.go |
这里我们的目标是要把日志输出到文件中,所以选择去调用 os.OpenFile()主动创建一个文件描述符,整体的代码如下
1 | // demo1.go |
2.简单封装一个支持日志级别的日志包(v1)
功能说明:
- 支持info,warn,err三种日志级别,运行过程中忽略低级别日志打印
- 三种级别日志写入同一个日志文件中
- 日志打印信息中显示文件名和行号
- 不考虑日志文件rolling和缓冲区
具体实现:
1 | // 工程目录 |
main.go1
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
28package main
import (
log "elog/log/v1"
)
var logger *log.ELog
func initLogger() {
logPath := "./logs"
logFile := "1.log"
logLevel := log.InfoLevel
logger = log.NewLogger(logLevel, logPath, logFile)
}
func main() {
initLogger()
logger.Info("hello info")
test()
}
func test() {
logger.Info("hello info test", "kkkkkk")
logger.Warn("hello waring", "warn1", ",warn2")
logger.Err("hello err", "err1", "error2")
}
log/v1/log.go :
1 | package v1 |
额外说明:
- ELog代表了一个需要被实例化的日志对象,其中包含三个表示不同等级日志处理的属性
- ELog.Info() 通过手动调用runtime.Caller获取文件名和行号,后标准化输出,ELog.Warn()函数直接使用log.logger.Output()函数指明调用者的文件名和行号。 查看log.logger.Output代码可以看到,内部也是通过调用runtime.Caller获取文件名和行号。 log包通过log.Lshortfile , log.Llongfile 这两个flag来去问打印文件名的完整路径或者短文件名。
- ELog提供了Close()函数,去关闭已经打开的文件描述符,因为对应同一个文件描述符,故只需要关闭一次
… 下一篇接着实现一个支持rolling的日志封装