点击蓝字关注我吧
什么是日志,简单来说就是记录,在程序中日志担任着重要的作用,利用日志信息,我们可以很轻易发现程序的运行状况,一个输出格式化很好的也可以很轻易的进行数据分析。那么Golang中对日志怎么操作呢?
我们先从一个简单的例子入门:
结果如下
上面的例子中首先是SetFlags()这个函数是对log包的个性化定制,用它定制出我们想看到的输出日志后的格式。Pintln()和Printf()用法和fmt包的是一模一样,这里不在介绍。现在让我们看看log包为我们提供的定制化flag吧
const (
Ldate = 1 << iota //日期
Ltime //时间
Lmicroseconds //毫秒
Llongfile //绝对路径和行号
Lshortfile //文件和行号
LUTC //日期时间转为0时区的
LstdFlags = Ldate | Ltime //Go提供的标准抬头信息
)
现在是不是觉得log包是不是很方便,相比较我们平时使用的fmt在控制台输出,不仅能看到时间,还能看到日志记录的行号,大大提高我们在众多代码中找一行代码的效率。
当然也有其他的需求,比如在日志记录中想表明这个日志的来源在哪个服务下呢?log包都为我们很好的解决了。如下:
输出结果:
log包使用设置前缀的方法实现这一个功能。
仍然有一种场景,日志有很多类型,又该如何区分它们呢?我们想放一段源码作为了解:
func Println(v ...interface{}) {
std.Output(2, fmt.Sprintln(v...))
}
func Fatalln(v ...interface{}) {
std.Output(2, fmt.Sprintln(v...))
os.Exit(1)
}
func Panicln(v ...interface{}) {
s := fmt.Sprintln(v...)
std.Output(2, s)
panic(s)
}
我们可以轻松的看出,log包在输出的时候主要不同的是OutPut()这个函数,那么调用该方法的std又是什么呢,再来看段源码:
func New(out io.Writer, prefix string, flag int) *Logger {
return &Logger{out: out, prefix: prefix, flag: flag}
}
var std = New(os.Stderr, "", LstdFlags)
原来std是一个&Logger{},从上面的代码中可以看出属性中有一个io.Writer的接口,该接口就是log的输出设备,Go中给出的输出设备如下:
这三种设备分别代表了输入、输出、和警告错误信息。下面就是OutPut函数了,具体的代码如下:
这段代码可以很方便的就能看到日志的输出保证了并发时的线程安全。
知道了以上log日志输出的原理后,有没有发现豁然开朗,那么我们又该如何利用这一点去定制化我们自己的日志呢?这里只做简单的提示,有兴趣的可以尝试:
定义一个日志结构体代表不同级别的日志,level表示水平。
type Logger struct {
level int
err *log.Logger
warn *log.Logger
info *log.Logger
debug *log.Logger
}
然后用log自己的New()函数获得不同级别的日志:
Info = log.New(os.Stdout,"Info:",log.Ldate | log.Ltime | log.Lshortfile)
Warning = log.New(os.Stdout,"Warning:",log.Ldate | log.Ltime | log.Lshortfile)
Error = log.New(io.MultiWriter(os.Stderr,errfile),"Error:",log.Ldate | log.Ltime | log.Lshortfile)
当然我们也可以自定义这些函数来满足自己的需求