Go 语言之 zap 日志库简单使用

这篇具有很好参考价值的文章主要介绍了Go 语言之 zap 日志库简单使用。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Go 语言之 zap 日志库简单使用

默认的 Go log

log:https://pkg.go.dev/log

package main

import (
	"log"
	"os"
)

func init() {
	log.SetPrefix("LOG: ") // 设置前缀

	f, err := os.OpenFile("./log.log", os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
	if err != nil {
		log.Fatalf("open log file failed with error: %v", err)
	}
	log.SetOutput(f) // 设置输出

	log.SetFlags(log.Ldate | log.Ltime | log.Lmicroseconds | log.Llongfile)

	// const (
	// 	Ldate         = 1 << iota // 1 << 0 = 000000001 = 1
	// 	Ltime                     // 1 << 1 = 000000010 = 2
	// 	Lmicroseconds             // 1 << 2 = 000000100 = 4
	// 	Llongfile                 // 1 << 3 = 000001000 = 8
	// 	Lshortfile                // 1 << 4 = 000010000 = 16
	// 	...
	// )
}

func main() {
	log.Println("1234")

	// log.Fatalln("1234")

	// log.Panicln("1234")

	// log.Panic("1234")
	// log.Panicf("1234, %d", 5678)
}

log 包是一个简单的日志包。

Package log implements a simple logging package. It defines a type, Logger, with methods for formatting output. It also has a predefined 'standard' Logger accessible through helper functions Print[f|ln], Fatal[f|ln], and Panic[f|ln], which are easier to use than creating a Logger manually. That logger writes to standard error and prints the date and time of each logged message. Every log message is output on a separate line: if the message being printed does not end in a newline, the logger will add one. The Fatal functions call os.Exit(1) after writing the log message. The Panic functions call panic after writing the log message.

uber-go zap

log:https://pkg.go.dev/log

github zap:https://github.com/uber-go/zap

pkg zap:https://pkg.go.dev/go.uber.org/zap#section-readme

Blazing fast, structured, leveled logging in Go.

安装

go get -u go.uber.org/zap

在性能良好但不是关键的上下文中,使用 SugaredLogger。它比其他结构化日志包快4-10倍,包括结构化和 printf 风格的 API。

logger, _ := zap.NewProduction()
defer logger.Sync() // flushes buffer, if any
sugar := logger.Sugar()
sugar.Infow("failed to fetch URL",
  // Structured context as loosely typed key-value pairs.
  "url", url,
  "attempt", 3,
  "backoff", time.Second,
)
sugar.Infof("Failed to fetch URL: %s", url)

当性能和类型安全至关重要时,请使用Logger。它甚至比SugaredLogger 更快,分配也少得多,但它只支持结构化日志记录。

logger, _ := zap.NewProduction()
defer logger.Sync()
logger.Info("failed to fetch URL",
  // Structured context as strongly typed Field values.
  zap.String("url", url),
  zap.Int("attempt", 3),
  zap.Duration("backoff", time.Second),
)

zap文档:https://pkg.go.dev/go.uber.org/zap#section-readme

Logger 简单使用

package main

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

// 定义一个全局 logger 实例
// Logger提供快速、分级、结构化的日志记录。所有方法对于并发使用都是安全的。
// Logger是为每一微秒和每一个分配都很重要的上下文设计的,
// 因此它的API有意倾向于性能和类型安全,而不是简便性。
// 对于大多数应用程序,SugaredLogger在性能和人体工程学之间取得了更好的平衡。
var logger *zap.Logger

func main() {
	// 初始化
	InitLogger()
	// Sync调用底层Core的Sync方法,刷新所有缓冲的日志条目。应用程序在退出之前应该注意调用Sync。
	// 在程序退出之前,把缓冲区里的日志刷到磁盘上
	defer logger.Sync()
	simpleHttpGet("www.baidu.com")
	simpleHttpGet("http://www.baidu.com")
}

func InitLogger() {
	// NewProduction构建了一个合理的生产Logger,它将infollevel及以上的日志以JSON的形式写入标准错误。
	// It's a shortcut for NewProductionConfig().Build(...Option).
	logger, _ = zap.NewProduction()
}

func simpleHttpGet(url string) {
	// Get向指定的URL发出Get命令。如果响应是以下重定向代码之一,则Get跟随重定向,最多可重定向10个:
	//	301 (Moved Permanently)
	//	302 (Found)
	//	303 (See Other)
	//	307 (Temporary Redirect)
	//	308 (Permanent Redirect)
	// Get is a wrapper around DefaultClient.Get.
	// 使用NewRequest和DefaultClient.Do来发出带有自定义头的请求。
	resp, err := http.Get(url)
	if err != nil {
		// Error在ErrorLevel记录消息。该消息包括在日志站点传递的任何字段,以及日志记录器上积累的任何字段。
		logger.Error(
			"Error fetching url..",
			zap.String("url", url), // 字符串用给定的键和值构造一个字段。
			zap.Error(err))         // // Error is shorthand for the common idiom NamedError("error", err).
	} else {
		// Info以infollevel记录消息。该消息包括在日志站点传递的任何字段,以及日志记录器上积累的任何字段。
		logger.Info("Success..",
			zap.String("statusCode", resp.Status),
			zap.String("url", url))
		resp.Body.Close()
	}
}

运行

Code/go/zap_demo via 🐹 v1.20.3 via 🅒 base took 11.0s 
➜ go run main.go 
{"level":"error","ts":1686929392.121357,"caller":"zap_demo/main.go:42","msg":"Error fetching url..","url":"www.google.com","error":"Get \"www.google.com\": unsupported protocol scheme \"\"","stacktrace":"main.simpleHttpGet\n\t/Users/qiaopengjun/Code/go/zap_demo/main.go:42\nmain.main\n\t/Users/qiaopengjun/Code/go/zap_demo/main.go:21\nruntime.main\n\t/usr/local/go/src/runtime/proc.go:250"}
{"level":"error","ts":1686929422.123222,"caller":"zap_demo/main.go:42","msg":"Error fetching url..","url":"http://www.google.com","error":"Get \"http://www.google.com\": dial tcp 103.252.115.59:80: i/o timeout","stacktrace":"main.simpleHttpGet\n\t/Users/qiaopengjun/Code/go/zap_demo/main.go:42\nmain.main\n\t/Users/qiaopengjun/Code/go/zap_demo/main.go:22\nruntime.main\n\t/usr/local/go/src/runtime/proc.go:250"}

Code/go/zap_demo via 🐹 v1.20.3 via 🅒 base took 30.3s 
➜ go run main.go
{"level":"error","ts":1686929534.4672909,"caller":"zap_demo/main.go:42","msg":"Error fetching url..","url":"www.baidu.com","error":"Get \"www.baidu.com\": unsupported protocol scheme \"\"","stacktrace":"main.simpleHttpGet\n\t/Users/qiaopengjun/Code/go/zap_demo/main.go:42\nmain.main\n\t/Users/qiaopengjun/Code/go/zap_demo/main.go:21\nruntime.main\n\t/usr/local/go/src/runtime/proc.go:250"}
{"level":"info","ts":1686929535.561184,"caller":"zap_demo/main.go:47","msg":"Success..","statusCode":"200 OK","url":"http://www.baidu.com"}

Code/go/zap_demo via 🐹 v1.20.3 via 🅒 base 
➜ 

源码

// Level reports the minimum enabled level for this logger.
//
// For NopLoggers, this is [zapcore.InvalidLevel].
func (log *Logger) Level() zapcore.Level {
	return zapcore.LevelOf(log.core)
}

// Check returns a CheckedEntry if logging a message at the specified level
// is enabled. It's a completely optional optimization; in high-performance
// applications, Check can help avoid allocating a slice to hold fields.
func (log *Logger) Check(lvl zapcore.Level, msg string) *zapcore.CheckedEntry {
	return log.check(lvl, msg)
}

// Log logs a message at the specified level. The message includes any fields
// passed at the log site, as well as any fields accumulated on the logger.
func (log *Logger) Log(lvl zapcore.Level, msg string, fields ...Field) {
	if ce := log.check(lvl, msg); ce != nil {
		ce.Write(fields...)
	}
}

// Debug logs a message at DebugLevel. The message includes any fields passed
// at the log site, as well as any fields accumulated on the logger.
func (log *Logger) Debug(msg string, fields ...Field) {
	if ce := log.check(DebugLevel, msg); ce != nil {
		ce.Write(fields...)
	}
}

// Info logs a message at InfoLevel. The message includes any fields passed
// at the log site, as well as any fields accumulated on the logger.
func (log *Logger) Info(msg string, fields ...Field) {
	if ce := log.check(InfoLevel, msg); ce != nil {
		ce.Write(fields...)
	}
}

// Warn logs a message at WarnLevel. The message includes any fields passed
// at the log site, as well as any fields accumulated on the logger.
func (log *Logger) Warn(msg string, fields ...Field) {
	if ce := log.check(WarnLevel, msg); ce != nil {
		ce.Write(fields...)
	}
}

// Error logs a message at ErrorLevel. The message includes any fields passed
// at the log site, as well as any fields accumulated on the logger.
func (log *Logger) Error(msg string, fields ...Field) {
	if ce := log.check(ErrorLevel, msg); ce != nil {
		ce.Write(fields...)
	}
}

// DPanic logs a message at DPanicLevel. The message includes any fields
// passed at the log site, as well as any fields accumulated on the logger.
//
// If the logger is in development mode, it then panics (DPanic means
// "development panic"). This is useful for catching errors that are
// recoverable, but shouldn't ever happen.
func (log *Logger) DPanic(msg string, fields ...Field) {
	if ce := log.check(DPanicLevel, msg); ce != nil {
		ce.Write(fields...)
	}
}

// Panic logs a message at PanicLevel. The message includes any fields passed
// at the log site, as well as any fields accumulated on the logger.
//
// The logger then panics, even if logging at PanicLevel is disabled.
func (log *Logger) Panic(msg string, fields ...Field) {
	if ce := log.check(PanicLevel, msg); ce != nil {
		ce.Write(fields...)
	}
}

// Fatal logs a message at FatalLevel. The message includes any fields passed
// at the log site, as well as any fields accumulated on the logger.
//
// The logger then calls os.Exit(1), even if logging at FatalLevel is
// disabled.
func (log *Logger) Fatal(msg string, fields ...Field) {
	if ce := log.check(FatalLevel, msg); ce != nil {
		ce.Write(fields...)
	}
}

每个zapcore.Field其实就是一组键值对参数。

// Field is an alias for Field. Aliasing this type dramatically
// improves the navigability of this package's API documentation.
type Field = zapcore.Field

输出的是 JSON 格式的日志

SugaredLogger 简单使用

NewProduction

package main

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

// 定义一个全局 logger 实例
// Logger提供快速、分级、结构化的日志记录。所有方法对于并发使用都是安全的。
// Logger是为每一微秒和每一个分配都很重要的上下文设计的,
// 因此它的API有意倾向于性能和类型安全,而不是简便性。
// 对于大多数应用程序,SugaredLogger在性能和人体工程学之间取得了更好的平衡。
var logger *zap.Logger

var sugarLogger *zap.SugaredLogger

func main() {
	// 初始化
	InitLogger()
	// Sync调用底层Core的Sync方法,刷新所有缓冲的日志条目。应用程序在退出之前应该注意调用Sync。
	// 在程序退出之前,把缓冲区里的日志刷到磁盘上
	defer logger.Sync()
	simpleHttpGet("www.baidu.com")
	simpleHttpGet("http://www.baidu.com")
}

func InitLogger() {
	// NewProduction构建了一个合理的生产Logger,它将infollevel及以上的日志以JSON的形式写入标准错误。
	// It's a shortcut for NewProductionConfig().Build(...Option).
	logger, _ = zap.NewProduction()
	sugarLogger = logger.Sugar()
}

func simpleHttpGet(url string) {
	// Get向指定的URL发出Get命令。如果响应是以下重定向代码之一,则Get跟随重定向,最多可重定向10个:
	//	301 (Moved Permanently)
	//	302 (Found)
	//	303 (See Other)
	//	307 (Temporary Redirect)
	//	308 (Permanent Redirect)
	// Get is a wrapper around DefaultClient.Get.
	// 使用NewRequest和DefaultClient.Do来发出带有自定义头的请求。
	resp, err := http.Get(url)
	if err != nil {
		// Error在ErrorLevel记录消息。该消息包括在日志站点传递的任何字段,以及日志记录器上积累的任何字段。
		//logger.Error(
		sugarLogger.Error(
			"Error fetching url..",
			zap.String("url", url), // 字符串用给定的键和值构造一个字段。
			zap.Error(err))         // // Error is shorthand for the common idiom NamedError("error", err).
	} else {
		// Info以infollevel记录消息。该消息包括在日志站点传递的任何字段,以及日志记录器上积累的任何字段。
		//logger.Info("Success..",
		sugarLogger.Info("Success..",
			zap.String("statusCode", resp.Status),
			zap.String("url", url))
		resp.Body.Close()
	}
}

运行

Code/go/zap_demo via 🐹 v1.20.3 via 🅒 base 
➜ go run main.go
{"level":"error","ts":1686930454.798492,"caller":"zap_demo/main.go:47","msg":"Error fetching url..{url 15 0 www.baidu.com <nil>} {error 26 0  Get \"www.baidu.com\": unsupported protocol scheme \"\"}","stacktrace":"main.simpleHttpGet\n\t/Users/qiaopengjun/Code/go/zap_demo/main.go:47\nmain.main\n\t/Users/qiaopengjun/Code/go/zap_demo/main.go:23\nruntime.main\n\t/usr/local/go/src/runtime/proc.go:250"}
{"level":"info","ts":1686930454.83406,"caller":"zap_demo/main.go:54","msg":"Success..{statusCode 15 0 200 OK <nil>} {url 15 0 http://www.baidu.com <nil>}"}

Code/go/zap_demo via 🐹 v1.20.3 via 🅒 base 
➜ 

NewDevelopment

package main

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

// 定义一个全局 logger 实例
// Logger提供快速、分级、结构化的日志记录。所有方法对于并发使用都是安全的。
// Logger是为每一微秒和每一个分配都很重要的上下文设计的,
// 因此它的API有意倾向于性能和类型安全,而不是简便性。
// 对于大多数应用程序,SugaredLogger在性能和人体工程学之间取得了更好的平衡。
var logger *zap.Logger

// SugaredLogger将基本的Logger功能封装在一个较慢但不那么冗长的API中。任何Logger都可以通过其Sugar方法转换为sugardlogger。
//与Logger不同,SugaredLogger并不坚持结构化日志记录。对于每个日志级别,它公开了四个方法:
//   - methods named after the log level for log.Print-style logging
//   - methods ending in "w" for loosely-typed structured logging
//   - methods ending in "f" for log.Printf-style logging
//   - methods ending in "ln" for log.Println-style logging

// For example, the methods for InfoLevel are:
//
//	Info(...any)           Print-style logging
//	Infow(...any)          Structured logging (read as "info with")
//	Infof(string, ...any)  Printf-style logging
//	Infoln(...any)         Println-style logging
var sugarLogger *zap.SugaredLogger

func main() {
	// 初始化
	InitLogger()
	// Sync调用底层Core的Sync方法,刷新所有缓冲的日志条目。应用程序在退出之前应该注意调用Sync。
	// 在程序退出之前,把缓冲区里的日志刷到磁盘上
	defer logger.Sync()
	simpleHttpGet("www.baidu.com")
	simpleHttpGet("http://www.baidu.com")
}

func InitLogger() {
	// NewProduction构建了一个合理的生产Logger,它将infollevel及以上的日志以JSON的形式写入标准错误。
	// It's a shortcut for NewProductionConfig().Build(...Option).
	//logger, _ = zap.NewProduction()
	// NewDevelopment构建一个开发日志,它以一种人性化的格式将DebugLevel及以上的日志写入标准错误。
	logger, _ = zap.NewDevelopment()
	// Sugar封装了Logger,以提供更符合人体工程学的API,但速度略慢。糖化一个Logger的成本非常低,
	// 因此一个应用程序同时使用Logger和sugaredlogger是合理的,在性能敏感代码的边界上在它们之间进行转换。
	sugarLogger = logger.Sugar()
}

func simpleHttpGet(url string) {
	// Get向指定的URL发出Get命令。如果响应是以下重定向代码之一,则Get跟随重定向,最多可重定向10个:
	//	301 (Moved Permanently)
	//	302 (Found)
	//	303 (See Other)
	//	307 (Temporary Redirect)
	//	308 (Permanent Redirect)
	// Get is a wrapper around DefaultClient.Get.
	// 使用NewRequest和DefaultClient.Do来发出带有自定义头的请求。
	resp, err := http.Get(url)
	if err != nil {
		// Error在ErrorLevel记录消息。该消息包括在日志站点传递的任何字段,以及日志记录器上积累的任何字段。
		//logger.Error(
		
		// 错误使用fmt。以Sprint方式构造和记录消息。
		sugarLogger.Error(
			"Error fetching url..",
			zap.String("url", url), // 字符串用给定的键和值构造一个字段。
			zap.Error(err))         // // Error is shorthand for the common idiom NamedError("error", err).
	} else {
		// Info以infollevel记录消息。该消息包括在日志站点传递的任何字段,以及日志记录器上积累的任何字段。
		//logger.Info("Success..",
		
		// Info使用fmt。以Sprint方式构造和记录消息。
		sugarLogger.Info("Success..",
			zap.String("statusCode", resp.Status),
			zap.String("url", url))
		resp.Body.Close()
	}
}

运行文章来源地址https://www.toymoban.com/news/detail-487319.html

Code/go/zap_demo via 🐹 v1.20.3 via 🅒 base 
➜ go run main.go
2023-06-16T23:52:00.384+0800    ERROR   zap_demo/main.go:48     Error fetching url..{url 15 0 www.baidu.com <nil>} {error 26 0  Get "www.baidu.com": unsupported protocol scheme ""}
main.simpleHttpGet
        /Users/qiaopengjun/Code/go/zap_demo/main.go:48
main.main
        /Users/qiaopengjun/Code/go/zap_demo/main.go:23
runtime.main
        /usr/local/go/src/runtime/proc.go:250
2023-06-16T23:52:00.439+0800    INFO    zap_demo/main.go:55     Success..{statusCode 15 0 200 OK <nil>} {url 15 0 http://www.baidu.com <nil>}

Code/go/zap_demo via 🐹 v1.20.3 via 🅒 base 
➜ 

到了这里,关于Go 语言之 zap 日志库简单使用的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Go | zap

    那些介绍、性能比较直接看参考中zap链接,这里只介绍该日志库用法,方便快速上手。 输出 接下来通过查看 NewDevelopment 与 NewProduction 实现,简单了解下zap的配置,为后续学习 zapcore.Core 打下基础。 2.1. 实现 NewDevelopment NewProduction 2.2. 执行结果 NewDevelopment 输出 NewProduction 输出

    2024年02月05日
    浏览(22)
  • Go语言之反射(反射的简单使用,原理)

    1.什么是反射 Go语言中,反射的机制就是在运行的时候,可以获取到其变量的类型和值,且可以对其类型和值进行检查,对其值进行修改。 即在不知道具体的类型的情况下,可以用反射机制来查看变量类型、更新变量的值。 Go中反射主要涉及到两个概念:Type和Value。对所有的

    2023年04月25日
    浏览(26)
  • 【设计模式】使用 go 语言实现简单工厂模式

    最近在看《大话设计模式》,这本书通过对话形式讲解设计模式的使用场景,有兴趣的可以去看一下。 第一篇讲的是 简单工厂模式 ,要求输入两个数和运算符号,得到运行结果。 这个需求不难,难就难在类要怎么设计,才能达到可复用、维护性强、可拓展和灵活性高。 运

    2024年02月05日
    浏览(32)
  • GO语言使用最简单的UI方案govcl

    接触go语言有一两年时间了。 之前用Qt和C#写过桌面程序,C#会被别人扒皮,极度不爽;Qt默认要带一堆dll,或者静态编译要自己弄或者找库,有的库还缺这缺那,很难编译成功。 如果C# winform可以编译成二进制原生exe的话,给人感觉是开发效率最好的。 C#有nuget可以用别人的库

    2024年02月15日
    浏览(23)
  • 使用Go语言编写简单的HTTP服务器

    在Go语言中,我们可以使用标准库中的\\\"net/http\\\"包来编写HTTP服务器。下面是一个简单的示例,展示了如何使用Go编写一个基本的HTTP服务器。 go 复制代码 package  main import  ( \\\"fmt\\\"   \\\"net/http\\\"   ) func   main ()  { // 创建一个处理器函数,处理所有对根路径的请求 handler := func (w http.

    2024年01月24日
    浏览(36)
  • Golang一日一库之 日志库 zap

    在开发过程中 会使用到日志库去记录错误的日志,尤其是golang中 有无穷无尽的error 如果不记录,当你的代码出错,就无从排错了。 zap 是开源的 Go 高性能日志库 主要有以下特点: 支持不同的日志级别 能够打印基本信息等但不支持日志的分割 但是可以使用 lumberjack 也是 za

    2023年04月12日
    浏览(35)
  • Go语言使用net/http实现简单登录验证和文件上传功能

         最近再看Go语言web编程,go语言搭建Web服务器,既可以用go原生的net/http包,也可以用gin/fasthttp/fiber等这些Web框架。本博客使用net/http模块编写了一个简单的登录验证和文件上传的功能,在此做个简单记录。 目录 1.文件目录结构 2.编译运行 3.用户登录  4.文件上传 5.mime/m

    2024年02月11日
    浏览(34)
  • 使用go语言、Python脚本搭建一个简单的chatgpt服务网站。

    前言 研0在暑假想提升一下自己,自学了go语言编程和机器学习相关学习,但是一味学习理论,终究是枯燥的,于是自己弄点小项目做。 在这之前,建议您需要掌握以下两个技巧,我在这里不赘述了 一个openAI账号,并申请了KEY(b站有教程) 魔法的method(自己摸索哈~网上应该

    2024年02月11日
    浏览(44)
  • go语言日志收集系统

    完整项目的GitHub地址 1. 项目背景 a. 每个系统都有日志,当系统出现问题时,需要通过日志解决问题 b. 当系统机器比较少时,登陆到服务器上查看即可满足 c. 当系统机器规模巨大,登陆到机器上查看几乎不现实 2. 解决方案 a. 把机器上的日志实时收集,统一的存储到中心系统

    2023年04月08日
    浏览(27)
  • Gin框架原生方式切割日志,Go语言原生日志切割

    目录 摘要 痛点 正文 1.分析 io.Writer 接口 2.实现 io.Writer 接口 3.将它作为原生输出 4.将它作为 Gin 框架的输出 自定义一个日志输出,将go语言和gin框架的日志自动按天拆分。本文通过实现io.Writer接口的方式,替换原生和gin框架的默认Writer,并植入了自定义的逻辑。该示例只讲述

    2024年02月09日
    浏览(33)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包