您现在的位置是:首页 >学无止境 >golang标准库之log日志网站首页学无止境

golang标准库之log日志

qiao_qing 2024-06-14 17:19:17
简介golang标准库之log日志

一、log包简介

golang内置了log包,通过调用log包的函数,可以实现简单的日志打印功能。
log包还定义了Logger类型,提供了一些格式化输出的方法。也提供了一个预定义的“标准”logger,可以通过调用函数Print系列(Print|Printf|Println)、Fatal系列(Fatal|Fatalf|Fatalln)、和Panic系列(Panic|Panicf|Panicln)来使用,比自行创建一个logger对象更容易使用,它们会将日志信息打印到终端界面;

二、log包使用

2.1 log.Print/Println/Printf函数

仅打印日志。

package main

import (
	"log"
)

func main() {
	log.Print("Print: hello")              //直接打印
	log.Println("Println: hello pob")      //打印并换行
	log.Printf("Printf:hello %s", "alice") //格式化打印(可加变量)
}

运行结果

@deMacBook-Pro learning % go run go_package.go
2023/05/09 09:37:45 Print: hello
2023/05/09 09:37:45 Println: hello pob
2023/05/09 09:37:45 Printf:hello alice

Printf格式化输出,%(占位符)字母解析:

占位符说明举例输出
%v相应值的默认格式name := “张三”, fmt.Printf(“%v”, name)张三
%+v打印结构体时,会添加字段名Printf(“%+v”, people){Name:zhangsan}
%%字面上的百分号,并非值的占位符Printf(“%%”)%
%t布尔值 ,true 或 falsePrintf(“%t”, true)true
%d整数,十进制表示Printf(“%d”, 0x12)18
%s字符串和字节片(string类型或[]byte),输出字符串表示Printf(“%s”, []byte(“Go语言”))Go语言
%f打印float类型,默认宽度,默认精度log.Printf(“%.2f”, 11.222222)11.22

eg:

package main

import (
	"log"
)

func main() {
	type peplo struct {
		Name string
		Age  int
	}
	var ppp peplo
	ppp.Name = "lll"
	log.Printf("ppp %v", ppp)  //格式化打印(可加变量)
	log.Printf("ppp %+v", ppp) //打印结构体时,会添加字段名
	log.Printf("%d", 0x12)
	log.Printf("%.2f", 11.222222)
}

运行结果:

@deMacBook-Pro learning % go run go_package.go
2023/05/09 09:38:48 ppp {lll 0}
2023/05/09 09:38:48 ppp {Name:lll Age:0}
2023/05/09 09:38:48 18
2023/05/09 09:38:48 11.22

2.2 log.Panic/Panicf/Panicln函数

log.Panic/Panicf/Panicln函数会打印出日志并且抛出panic异常,需要注意的是在panic之后声明的代码将不会执行。

package main

import (
	"fmt"
	"log"
)

func main() {
	defer fmt.Println("发生了 panic错误!")
	log.Print("my log")
	log.Panic("my panic")
	fmt.Println("panic之后,未打印运行结束。。。")
}

运行结果:

@deMacBook-Pro learning % go run go_package.go
2023/05/09 09:47:33 my log
2023/05/09 09:47:33 my panic
发生了 panic错误!
panic: my panic

goroutine 1 [running]:
log.Panic({0xc000109f30?, 0x60?, 0x11378e0?})
        /usr/local/go/src/log/log.go:385 +0x65
main.main()
        /Users/gfy/Desktop/my_word/go_dir/src/learning/go_package.go:73 +0xc5
exit status 2

可见输出了log.Print和log.Panic中的内容,然后再panic之前的defer函数被调用并输出,而log.Panic之后的fmt.Println并没有被调用输出,可见log.Panic抛出panic异常之后的代码是不会被调用的。

log.Panicf/Panicln用法与Println/Printf函数类似,此处不再赘述。

2.3 log.Fatal/Fatalf/Fatalln函数

对于log.Fatal接口,会将日志内容打印输出,接着调用系统的os.Exit(1)接口,强制退出程序并返回状态1,但是有一点需要注意的是,由于直接调用系统os接口退出,defer函数不会调用。

package main

import (
	"fmt"
	"log"
)

func main() {
	defer fmt.Println("defer函数不会调用。。。")
	log.Print("my log")
	log.Fatal("my fatal")
	fmt.Println("运行结束。。。")
}

运行结果:

gfy@GFYdeMacBook-Pro learning % go run go_package.go
2023/05/09 09:50:34 my log
2023/05/09 09:50:34 my fatal
exit status 1

可见并没有调用defer函数。
log.Fatalf/Fatalln用法与Println/Printf函数类似,此处不再赘述。

三 标准日志配置

默认情况下log只会打印出时间,但是实际情况下我们还需要获取文件名,行号等信息,log包提供给我们定制的接口。

log包提供两个标准log配置的相关方法:

方法说明
func Flags() int返回标准log输出配置
func SetFlags(flag int)返回标准log输出配置

3.1 flag参数

const (
    // 控制输出日志信息的细节,不能控制输出的顺序和格式。
    // 输出的日志在每一项后会有一个冒号分隔,例如2009/01/23 01:23:23.123123 /a/b/c/d.go:23: message
    Ldate         = 1 << iota     // 日期,2009/01/23
    Ltime                         // 时间,01:23:23
    Lmicroseconds                 // 微秒级别的时间,01:23:23.123123(用于增强Ltime位)
    Llongfile                     // 文件全路径名+行号,/a/b/c/d.go:23
    Lshortfile                    // 文件名+行号,d.go:23(会覆盖掉Llongfile)
    LUTC                          // 使用UTC时间
    LstdFlags     = Ldate | Ltime // 标准logger的初始值
)

3.2 标准日志配置示例

package main

import (
	"fmt"
	"log"
)

func main() {
	i := log.Flags()
	fmt.Printf("i: %v
", i)
	log.SetFlags(log.Ldate | log.Ltime | log.Llongfile)
	log.Print("my log")
}

运行结果:

gfy@GFYdeMacBook-Pro learning % go run go_package.go
i: 3
2023/05/09 10:21:44 /Users/gfy/Desktop/my_word/go_dir/src/learning/go_package.go:109: my log

四 日志前缀配置

log包提供两个日志前缀配置的相关函数

方法说明
func Prefix() string返回日志的前缀配置
func SetPrefix(prefix string)设置日志前缀
package main

import (
	"fmt"
	"log"
)

func main() {
	s := log.Prefix()
	fmt.Printf("s: %v
", log.Prefix())
	log.SetPrefix("[MyLog] ")
	s = log.Prefix()
	fmt.Printf("s: %v
", s)
	log.Print("my log...")
}

运行结果:

gfy@GFYdeMacBook-Pro learning % go run go_package.go
s: 
s: [MyLog] 
[MyLog] 2023/05/09 10:26:45 my log...

五 日志输出位置配置

前面介绍的都是将日志输出到控制台上,golang的log包还支持将日志输出到文件中,log包提供了func SetOutput(w io.Writer)函数,将日志输出到文件中。

package main

import (
	"log"
	"os"
)

func main() {
	f, err := os.OpenFile("a.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
	if err != nil {
		log.Panic("打开日志文件异常")
	}
	log.SetOutput(f)
	log.Print("my log...")
}

运行结果:

gfy@GFYdeMacBook-Pro learning % go run go_package.go
gfy@GFYdeMacBook-Pro learning % ls| grep a.log      
a.log
gfy@GFYdeMacBook-Pro learning % cat a.log           
2023/05/10 09:54:48 my log...

六 自定义logger

log包中提供了func New(out io.Writer, prefix string, flag int) *Logger函数来实现自定义logger。从效果上来看,就是标准日志配置、日志前缀配置、日志输出位置配置整合到一个函数中,使日志配置不在那么繁琐。

package main

import (
	"log"
	"os"
)

var logger *log.Logger

func init() {
	logFile, err := os.OpenFile("a.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
	if err != nil {
		log.Panic("打开日志文件异常")
	}
	logger = log.New(logFile, "[Mylog]", log.Ldate|log.Ltime|log.Lshortfile)
}

func main() {
	logger.Println("自定义logger")
}

运行结果:

gfy@GFYdeMacBook-Pro learning % go run go_package.go
gfy@GFYdeMacBook-Pro learning % cat a.log           
[Mylog]2023/05/10 10:06:36 go_package.go:170: 自定义logger
风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。