7.7 日志
golang 的log包使用起来挺简单,这里做一些简单介绍。
示例:
package main
import (
"log"
)
func main() {
arr := []int{1, 2}
log.Print("Print array ", arr, "\n")
log.Println("Println array", arr)
log.Printf("Printf array with item [%d,%d]\n", arr[0], arr[1])
}
结果:
2018/12/14 18:42:02 Print array [1 2] 2018/12/14 18:42:02 Println array [1 2] 2018/12/14 18:42:02 Printf array with item [1,2]
log.Fatal 、log.Fatalln、log.Fatalf
示例:
log.Fatal("Fatal array ", arr, "\n")
log.Fatalln("Fatalln array", arr)
log.Fatalf("Fatalf array with item [%d,%d]\n", arr[0], arr[1])
对于 log.Fatal 接口,会先将日志内容打印到标准输出,接着调用系统的 os.exit(1) 接口退出程序并返回状态 1 。
在实际开发中要慎重,它导致整个系统退出,且不执行defer。
示例
package main
import (
"fmt"
"log"
"net/http"
)
func sayHelloHandler(w http.ResponseWriter, r *http.Request) {
defer func() {
fmt.Println("--first--")
}()
log.Fatalln("test for defer Fatal")
}
func main() {
http.HandleFunc("/", sayHelloHandler) // 设置访问路由
log.Fatal(http.ListenAndServe(":8080", nil))
}
当访问 http://127.0.0.1:8080/ 后,http 服务停止了,且defer没有调用。
log.SetOutput
将日志写到指定文件中
示例
package main
import (
"log"
"os"
)
func main() {
// 按照所需读写权限创建文件
f, err := os.OpenFile("filename.log", os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
if err != nil {
log.Fatal(err)
}
// 完成后延迟关闭
defer f.Close()
//设置日志输出到 f
log.SetOutput(f)
//写入日志内容
log.Println("check to make sure it works")
}
查看生成日志文件filename.log 内容
2018/12/14 18:56:55 check to make sure it works
log.Logger、log.New
先自定义Logger类型, log.Logger提供了一个New方法用来创建对象:
func New(out io.Writer, prefix string, flag int) *Logger
该函数一共有三个参数:
(1)输出位置out,是一个io.Writer对象,该对象可以是一个文件也可以是实现了该接口的对象。通常我们可以用这个来指定日志输出到哪个文件。 (2)prefix 我们在前面已经看到,就是在日志内容前面的东西。我们可以将其置为 “[Info]” 、 “[Warning]”等来帮助区分日志级别。 (3) flags 是一个选项,显示日志开头的东西,可选的值有:
Ldate = 1 << iota // 形如 2009/01/23 的日期
Ltime // 形如 01:23:23 的时间
Lmicroseconds // 形如 01:23:23.123123 的时间
Llongfile // 全路径文件名和行号: /a/b/c/d.go:23
Lshortfile // 文件名和行号: d.go:23
LstdFlags = Ldate | Ltime // 日期和时间
package main
import (
"io"
"io/ioutil"
"log"
"os"
)
var (
Trace *log.Logger // 记录所有日志
Info *log.Logger // 重要的信息
Warning *log.Logger // 需要注意的信息
Error *log.Logger // 致命错误
)
func init() {
file, err := os.OpenFile("filename.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
if err != nil {
log.Fatalln(err)
}
Trace = log.New(ioutil.Discard, "TRACE: ", log.Ltime|log.Lshortfile)
Info = log.New(os.Stdout, "Info: ", log.Ltime|log.Lshortfile)
Warning = log.New(os.Stdout, "Warning: ", log.Ltime|log.Lshortfile)
Error = log.New(io.MultiWriter(file, os.Stderr), "Error", log.Ltime|log.Lshortfile)
}
func main() {
Trace.Println("trace")
Info.Println("info")
Warning.Println("warning")
Error.Println("Error")
}
细心的朋友可能发现执行多次程序输出日志的顺序会有变化,这个主要是 os.Stderr和os.Stdout输出的不同引起的,这两个虽然都是输出到终端,但在默认情况下,stdout是行缓冲的,它的输出会放在一个buffer里面,只有到换行的时候,才会输出到屏幕。而stderr是无缓冲的,会直接输出的。参考:http://blog.sina.com.cn/s/blog_912673ce01013qq9.html
日志库logrus
logrus是在Github中star最多的go日志库,功能强大,性能不错。
安装:
go get -u github.com/sirupsen/logrus
实例
package main
import (
"github.com/sirupsen/logrus"
"os"
)
// Create a new instance of the logger. You can have any number of instances.
var log = logrus.New()
func main() {
// The API for setting attributes is a little different than the package level
// exported logger. See Godoc.
log.Out = os.Stdout
//You could set this to any `io.Writer` such as a file
file, err := os.OpenFile("logrus.log", os.O_CREATE|os.O_WRONLY, 0666)
if err == nil {
log.Out = file
} else {
log.Info("Failed to log to file, using default stderr")
}
log.WithFields(logrus.Fields{
"animal": "walrus",
"size": 10,
}).Info("A group of walrus emerges from the ocean")
}
如果你对别的Go日志库感兴趣可以参考:
- https://www.ctolib.com/topics-123640.html
- https://github.com/search?l=Go&o=desc&q=log&s=stars&type=Repositories