Go语言日志log和zaplog

发布于:2024-05-20 ⋅ 阅读:(164) ⋅ 点赞:(0)

一、Log

1.1 logger基本使用

Go语言内置的log包实现了简单的日志服务。本包也提供了一个预定义的“标准”logger,可以通过调用函数Print系列(Print|Printf|Println)、Fatal系列(Fatal|Fatalf|Fatalln)、和Panic系列(Panic|Panicf|Panicln)来使用,比自行创建一个logger对象更容易使用。

Fatal系列用于输出一条致命错误信息,并调用 os.Exit(1) 终止程序运行。这个函数会在打印完错误信息之后立即调用 os.Exit 退出程序。

package main

import (
	"log"
)

func main() {
	log.Println("卡卡西的日志")

	x := "鸣人"
	log.Printf("%s的日志\n", x)
	
	log.Fatalln("会触发fatal的日志")
	
	// 这里的代码不会被执行,因为程序已经在 log.Fatalln 后退出了
	log.Panicln("会触发panic的日志")
}
2024/05/16 23:03:24 卡卡西的日志
2024/05/16 23:03:24 鸣人的日志       
2024/05/16 23:03:24 会触发fatal的日志
exit status 1 

1.2 logger配置

基础的logger只提供日志的时间信息,如果需要获取更多的信息或者输出方式,可以通过进一步配置实现。

1.2.1 标准配置 log.SetFlags.SetFlags

  • log.SetFlags() 函数用于设置日志的输出格式
  • log.Flags() 函数来获取当前日志包的配置标志,并将其打印输出。

以下是 log 包中定义的一些常用选项:

  • log.Ldate:日期:2009/01/23
  • log.Ltime:时间:01:23:23
  • log.Lmicroseconds:微秒级时间:01:23:23.123123
  • log.Llongfile:文件名和行号:/a/b/c/d.go:23
  • log.Lshortfile:文件名和行号:d.go:23
  • log.LUTC:使用 UTC 时间

下面在记录日志之前先设置一下logger的输出选项:

package main

import (
	"fmt"
	"log"
)

func main() {
	log.SetFlags(log.Llongfile | log.Lmicroseconds | log.Ldate)
	log.Println("卡卡西的日志")

	flags := log.Flags()
	fmt.Println("Flags:", flags)
}

输出结果

2024/05/16 23:25:39.519510 d:/go/练习/main.go:10: 卡卡西的日志
Flags: 13

1.2.2 前缀配置 log.SetPrefix 和 log.Prefix

  • log.SetPrefix 用于设置日志输出的前缀,它接受一个字符串作为参数,这个字符串将会作为日志信息的前缀显示在每条日志的最前面。
  • log.Prefix 则是一个属性,用于获取当前日志输出的前缀。
func main() {
	log.SetPrefix("复制忍者:")
	log.Println("卡卡西")

	prefix := log.Prefix()
	fmt.Println(prefix)
}

输出结果是

复制忍者:2024/05/18 10:06:56 卡卡西
复制忍者:  

1.2.3 输出位置 log.SetOutput

log.SetOutput 用于设置日志输出的目标。这个函数接受一个 io.Writer 类型的参数,将日志输出到指定的 io.Writer 实现。

func main() {
	file, err := os.OpenFile("logfile.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
	if err != nil {
		log.Fatal("Failed to open logfile.log", err)
	}
	defer file.Close()

	log.SetOutput(file)
	log.SetFlags(log.Llongfile | log.Lmicroseconds | log.Ldate)
	log.Println("卡卡西")
	log.SetPrefix("复制忍者:")
}

1.3 logger对象创建

log.New 用于创建一个新的 Logger 对象。这个函数接受三个参数:一个实现了 io.Writer 接口的目标输出流、一个用于添加前缀的字符串、以及一个用于指定日志属性的标志选项。

func main() {
	// 创建一个新的 Logger 对象,将日志输出到标准错误输出,并添加前缀 "ERROR: "
	logger := log.New(os.Stderr, "ERROR: ", log.LstdFlags)

	// 使用新创建的 Logger 对象输出日志
	logger.Println("This is an error message.")
}

输出结果

ERROR: 2024/05/18 10:27:40 This is an error message.

二、第三方日志库 Zap

注意:Zap并不是Go的标准库,而是为了解决Go内置log库功能有限的问题,所引入的第三方日志库。在此处介绍Zap是为了方便与log库进行对比学习。

  • Zap的优点:快、结构化,分日志级别。

Zap 日志库提供了两种类型的日志记录器:Sugared LoggerLogger。它们分别适用于不同的日志记录场景。

  1. Sugared Logger:

    • Sugared Logger 提供了结构化和格式化的日志记录功能,支持使用类似 Printf 风格的方法记录日志。
    • 它使用了结构化的上下文字段,可以方便地记录关键-值对形式的日志信息。
    • Sugared Logger 适合用于一般的日志记录需求,提供了更直观、易用的 API。
  2. Logger:

    • Logger 提供了更底层的、零分配(zero-allocation)的日志记录功能,适用于高性能、高吞吐量的日志记录需求。
    • 它的 API 相对更加简洁,不支持结构化的上下文字段,但在性能方面有优势。
    • Logger 适合用于需要尽量减少内存分配和提升性能的场景。

根据具体的需求和场景,可以选择使用 Zap 提供的 Sugared Logger 或 Logger 来实现相应的日志记录功能。

2.1 Logger

  1. 调用zap.NewProduction()或者zap.NewDevelopment()或者zap.Example()创建了一个 Zap 日志记录器
  2. 通过Logger调用Info/Error等
  3. 程序结束前调用 logger.Sync() 来确保所有日志都被输出

zap.NewProduction():会配置 Logger 以适应生产环境的需求,例如默认会将日志输出到标准错误输出,并且会禁用堆栈跟踪等详细的调试信息,以减少对性能的影响。适合用于生产环境中记录稳定运行日志的场景。
zap.NewDevelopment():会配置 Logger 以便于开发过程中更好地跟踪和调试日志,例如会输出更详细的调试信息和堆栈跟踪。适合用于开发和调试过程中辅助定位问题、跟踪日志的场景。
zap.Example():是一个示例方法,提供了一个简单的例子,演示了如何创建 Logger 实例、记录不同级别的日志、以及如何添加结构化的上下文字段等操作。

下面通过简单的http get介绍logger的用法

package main

import (
	"net/http"
	"go.uber.org/zap"
)

var logger *zap.Logger

// 初始化日志记录器
func InitLogger() {
	logger, _ = zap.NewProduction()
}

// 发送 HTTP GET 请求
func httpGet(url string){
	resp, err := http.Get(url)
	if err != nil {
		// 如果请求中出现错误,记录错误日志
		logger.Error(
			"Error fetching url: ",
			zap.String("url",url),
			zap.Error(err))
	} else {
		// 如果请求成功,记录成功日志
		logger.Info(
			"Success: ",
			zap.String("statusCode", resp.Status),
			zap.String("url", url))
		resp.Body.Close()
	}
}

func main() {
	InitLogger()

	// 使用了 defer 关键字来延迟执行 logger.Sync(),以确保在程序退出前执行同步操作
	defer logger.Sync()

	httpGet("https://blog.csdn.net/Ricardo2/article/details/134253323")
	httpGet("www.google.com")
}

输出结果

{"level":"info","ts":1716001211.442937,"caller":"练习/main.go:26","msg":"Success: ","statusCode":"403 Forbidden","url":"https://blog.csdn.net/Ricardo2/article/details/134253323"}
{"level":"error","ts":1716001211.443463,"caller":"练习/main.go:20","msg":"Error fetching url: ","url":"www.google.com","error":"Get \"www.google.com\": unsupported protocol scheme \"\"","stacktrace":"main.httpGet\n\td:/go/练习/main.go:20\nmain.main\n\td:/go/练习/main.go:41\nruntime.main\n\tE:/goland/src/runtime/proc.go:250"}

2.2 SugaredLogger

大部分的实现基本都相同。
惟一的区别是,我们通过logger.Sugar()方法来获取一个SugaredLogger。

package main

import (
	"net/http"
	"go.uber.org/zap"
)

var sugarLogger *zap.SugaredLogger

// 初始化日志记录器
func InitLogger() {
	logger, _ := zap.NewProduction()
	sugarLogger = logger.Sugar()
}

// 发送 HTTP GET 请求
func httpGet(url string){
	sugarLogger.Debugf("Trying to grt request for %s", url)
	resp, err := http.Get(url)
	if err != nil {
		// 如果请求中出现错误,记录错误日志
		sugarLogger.Error(
			"Error fetching url: ",
			zap.String("url",url),
			zap.Error(err))
	} else {
		// 如果请求成功,记录成功日志
		sugarLogger.Info(
			"Success: ",
			zap.String("statusCode", resp.Status),
			zap.String("url", url))
		resp.Body.Close()
	}
}

func main() {
	InitLogger()

	// 使用了 defer 关键字来延迟执行 logger.Sync(),以确保在程序退出前执行同步操作
	defer sugarLogger.Sync()

	httpGet("https://blog.csdn.net/Ricardo2/article/details/134253323")
	httpGet("www.google.com")
}

输出结果

{"level":"info","ts":1716001865.691326,"caller":"练习/main.go:28","msg":"Success: {statusCode 15 0 403 Forbidden <nil>} {url 15 0 https://blog.csdn.net/Ricardo2/article/details/134253323 <nil>}"}
{"level":"error","ts":1716001865.6924412,"caller":"练习/main.go:22","msg":"Error fetching url: {url 15 0 www.google.com <nil>} {error 26 0  Get \"www.google.com\": unsupported protocol scheme \"\"}","stacktrace":"main.httpGet\n\td:/go/练习/main.go:22\nmain.main\n\td:/go/练习/main.go:43\nruntime.main\n\tE:/goland/src/runtime/proc.go:250"}

2.3 日志级别

Zap 日志库支持以下几种日志级别,可以根据不同的需求来选择合适的级别记录日志:

  • Debug:
    用于记录调试过程中的详细信息,通常在开发和调试阶段使用。
    使用 logger.Debug() 方法记录 Debug 级别的日志。
  • Info:
    用于记录程序运行过程中的一般信息,例如启动信息、关键事件等。
    使用 logger.Info() 方法记录 Info 级别的日志。
  • Warn:
    用于记录可能出现问题但不会影响程序正常运行的警告信息,例如参数使用不当、潜在的问题等。
    使用 logger.Warn() 方法记录 Warn 级别的日志。
  • Error:
    用于记录程序中的错误信息,例如异常、错误状态等。
    使用 logger.Error() 方法记录 Error 级别的日志。
  • DPanic:
    用于记录严重的错误,会导致程序进入恐慌状态的错误。
    使用 logger.DPanic() 方法记录 DPanic 级别的日志。
  • Panic:
    用于记录导致程序无法继续正常运行的错误,记录后会触发程序 panic。
    使用 logger.Panic() 方法记录 Panic 级别的日志。
  • Fatal:
    用于记录导致程序无法继续运行的严重错误,记录后会触发程序退出。
    使用 logger.Fatal() 方法记录 Fatal 级别的日志。

对C++或者Golang编程技术感兴趣的朋友请点击这里:零声学院课程


网站公告

今日签到

点亮在社区的每一天
去签到