Go | zap

日志库 —— Go Zap 入门 本文通过丰富的代码示例演示了 zap 的基本功能,读者可以跟随这些示例,学习如何使用 zap。 阅读详情

Go | zap

1. 简介

那些介绍、性能比较直接看参考中zap链接,这里只介绍该日志库用法,方便快速上手。

package main

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

func main() {
	logger, _ := zap.NewProduction()
	defer logger.Sync()

	logger.Info("hello world",
		zap.String("name", "yimt"),
	)

	// 可以将结构化日志转为fmt包形式
	sugar := logger.Sugar()
	sugar.Infof("name %s", "yimt")
}

输出

{"level":"info","ts":1684460836.884597,"caller":"hello-go/main.go:11","msg":"hello world","name":"yimt"}
{"level":"info","ts":1684460836.88468,"caller":"hello-go/main.go:17","msg":"name yimt"}

2. NewDevelopment & NewProduction区别

接下来通过查看NewDevelopment与NewProduction实现,简单了解下zap的配置,为后续学习zapcore.Core打下基础。

2.1. 实现

NewDevelopment

func NewDevelopment(options ...Option) (*Logger, error) {
	return NewDevelopmentConfig().Build(options...)
}
func NewDevelopmentConfig() Config {
	return Config{
		Level:            NewAtomicLevelAt(DebugLevel),
		Development:      true,
		Encoding:         "console",
		EncoderConfig:    NewDevelopmentEncoderConfig(),
		OutputPaths:      []string{"stderr"},
		ErrorOutputPaths: []string{"stderr"},
	}
}
func NewDevelopmentEncoderConfig() zapcore.EncoderConfig {
	return zapcore.EncoderConfig{
		// Keys can be anything except the empty string.
		TimeKey:        "T",
		LevelKey:       "L",
		NameKey:        "N",
		CallerKey:      "C",
		FunctionKey:    zapcore.OmitKey,
		MessageKey:     "M",
		StacktraceKey:  "S",
		LineEnding:     zapcore.DefaultLineEnding,
		EncodeLevel:    zapcore.CapitalLevelEncoder,
		EncodeTime:     zapcore.ISO8601TimeEncoder,
		EncodeDuration: zapcore.StringDurationEncoder,
		EncodeCaller:   zapcore.ShortCallerEncoder,
	}
}

NewProduction

func NewProduction(options ...Option) (*Logger, error) {
	return NewProductionConfig().Build(options...)
}
func NewProductionConfig() Config {
	return Config{
		Level:       NewAtomicLevelAt(InfoLevel),
		Development: false,
		Sampling: &SamplingConfig{
			Initial:    100,
			Thereafter: 100,
		},
		Encoding:         "json",
		EncoderConfig:    NewProductionEncoderConfig(),
		OutputPaths:      []string{"stderr"},
		ErrorOutputPaths: []string{"stderr"},
	}
}
func NewProductionEncoderConfig() zapcore.EncoderConfig {
	return zapcore.EncoderConfig{
		TimeKey:        "ts",
		LevelKey:       "level",
		NameKey:        "logger",
		CallerKey:      "caller",
		FunctionKey:    zapcore.OmitKey,
		MessageKey:     "msg",
		StacktraceKey:  "stacktrace",
		LineEnding:     zapcore.DefaultLineEnding,
		EncodeLevel:    zapcore.LowercaseLevelEncoder,
		EncodeTime:     zapcore.EpochTimeEncoder,
		EncodeDuration: zapcore.SecondsDurationEncoder,
		EncodeCaller:   zapcore.ShortCallerEncoder,
	}
}

2.2. 执行结果

NewDevelopment

func main() {
	logger, _ := zap.NewDevelopment()
	defer logger.Sync()

	logger.Info("hello world",
		zap.String("name", "yimt"),
	)
}

输出

2023-05-17T14:07:09.722+0800    INFO    hello-go/main.go:11     hello world     {"name": "yimt"}

NewProduction

func main() {
	logger, _ := zap.NewProduction()
	defer logger.Sync()

	logger.Info("hello world",
		zap.String("name", "yimt"),
	)
}

输出

{"level":"info","ts":1684303547.31098,"caller":"hello-go/main.go:11","msg":"hello world","name":"yimt"}

3. zapcore.Core接口

  • zapcore.NewCore(enc Encoder, ws WriteSyncer, enab LevelEnabler)
  • zapcore.NewNopCore()
  • zapcore.NewIncreaseLevelCore(core Core, level LevelEnabler) (Core, error)
  • zapcore.NewTee()

3.1. zapcore.NewCore(enc Encoder, ws WriteSyncer, enab LevelEnabler)

3.1.1. Encoder
  • zapcore.NewJSONEncoder(cfg EncoderConfig):以JSON形式编码。
  • zapcore.NewConsoleEncoder(cfg EncoderConfig):以console形式编码。

zapcore.EncoderConfig

主要用于配置日志编码,包括时间格式,日志键名,每条日志是否换行等。

  • zap.NewDevelopmentEncoderConfig()
  • zap.NewProductionEncoderConfig()
  • zapcore.EncoderConfig{}:可以自定义配置。

控制日志编码格式,正常控制台显示console形式编码,日志文件记录JSON形式编码。

3.1.2. zapcore.WriteSyncer
  • zapcore.AddSync(f):指定日志输出位置。

控制日志输出位置,主要有控制台和日志文件。

3.1.3. zapcore.LevelEnabler
  • zap.NewAtomicLevel():可以运行过程中线程安全的调节日志等级。
  • zap.LevelEnablerFunc:以回调形式控制日志等级。

用于控制日志等级。

3.1.4. 演示
package main

import (
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	"os"
)

func main() {
	core := zapcore.NewCore(zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig()), zapcore.AddSync(os.Stdout), zap.NewAtomicLevel())
	logger := zap.New(core)
	defer logger.Sync()

	logger.Info("hello world")
}

控制台输出

{"level":"info","ts":1684459049.47701,"msg":"hello world"}

3.2. zapcore.NewNopCore()

package main

import (
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
)

func main() {
	logger := zap.New(zapcore.NewNopCore())
	defer logger.Sync()

	logger.Info("hello world")
}

执行完什么都不会发生,可以直接看NewNopCore()内实现,上面Core所有功能都不处理。

type nopCore struct{}

// NewNopCore returns a no-op Core.
func NewNopCore() Core                                        { return nopCore{} }
func (nopCore) Enabled(Level) bool                            { return false }
func (n nopCore) With([]Field) Core                           { return n }
func (nopCore) Check(_ Entry, ce *CheckedEntry) *CheckedEntry { return ce }
func (nopCore) Write(Entry, []Field) error                    { return nil }
func (nopCore) Sync() error                                   { return nil }

3.3. zapcore.NewIncreaseLevelCore(core Core, level LevelEnabler) (Core, error)

实现

func NewIncreaseLevelCore(core Core, level LevelEnabler) (Core, error) {
	for l := _maxLevel; l >= _minLevel; l-- {
		if !core.Enabled(l) && level.Enabled(l) {
			return nil, fmt.Errorf("invalid increase level, as level %q is allowed by increased level, but not by existing core", l)
		}
	}

	return &levelFilterCore{core, level}, nil
}

直接在已有一个Core下降1个日志等级,以显示更多日志。

3.4. zapcore.NewTee()

上面示例都有一个问题,日志只能输出到一个Core。在有的时候我们需要日志以console形式输出到控制台,以json形式输出到日志文件时就用到了NewTee,可以将日志一次输入到多个Core处理。

package main

import (
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	"os"
)

func main() {
	f, err := os.Create("log.txt")
	if err != nil {
		panic(err)
	}
	// 日志已json形式输出文件
	outputFileCore := zapcore.NewCore(zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig()), zapcore.AddSync(f), zap.NewAtomicLevel())
	// 日志已console形式输出到控制台
	outputConsoleCore := zapcore.NewCore(zapcore.NewConsoleEncoder(zap.NewDevelopmentEncoderConfig()), zapcore.AddSync(os.Stdout), zap.NewAtomicLevel())
	tee := zapcore.NewTee(outputFileCore, outputConsoleCore)
	logger := zap.New(tee)
	defer logger.Sync()

	logger.Info("hello world")
}

log.txt

{"level":"info","ts":1684459649.253505,"msg":"hello world"}

控制台

2023-05-19T09:27:29.253+0800    INFO    hello world

4. 输出日志文件问题

上面示例虽然可以输出日志文件,但是还存在以下问题。

  1. 单个日志文件大小无法限制,单个日志文件过大最直观的麻烦是我们用文件编辑器打开经常未响应。
  2. 日志文件不会自己删除,在生产服务器可能会存在大量日志文件,占用硬盘空间。应该有不少人在MySQL的binlog日志文件上踩过坑吧。
  3. 旧日志压缩存储,节约硬盘空间。

下面就介绍lumberjack库,帮助我们自己管理日志文件,直接看下面示例就可以了。

package main

import (
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	"gopkg.in/natefinch/lumberjack.v2"
)

func main() {
	writeSyncer := zapcore.AddSync(&lumberjack.Logger{
		Filename:   "log.txt",
		MaxSize:    500, // megabytes
		MaxBackups: 3,
		MaxAge:     28,   //days
		Compress:   true, // disabled by default
	})
	core := zapcore.NewCore(zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig()), writeSyncer, zap.NewAtomicLevel())
	logger := zap.New(core)
	defer logger.Sync()

	logger.Info("hello world")
}

5. 最终示例

功能

  1. 同时输出控制台和日志文件
  2. 日志文件达到限制大小自动创建新日志文件。
  3. 自己删除过期日志。
  4. 旧日志文件自动压缩。
package main

import (
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	"gopkg.in/natefinch/lumberjack.v2"
	"os"
)

func main() {
	writeSyncer := zapcore.AddSync(&lumberjack.Logger{
		Filename:   "log.txt",
		MaxSize:    500, // megabytes
		MaxBackups: 3,
		MaxAge:     28,   //days
		Compress:   true, // disabled by default
	})
	// 日志已json形式输出文件
	outputFileCore := zapcore.NewCore(zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig()), writeSyncer, zap.NewAtomicLevel())
	// 日志已console形式输出到控制台
	outputConsoleCore := zapcore.NewCore(zapcore.NewConsoleEncoder(zap.NewDevelopmentEncoderConfig()), zapcore.AddSync(os.Stdout), zap.NewAtomicLevel())
	tee := zapcore.NewTee(outputFileCore, outputConsoleCore)
	logger := zap.New(tee)
	defer logger.Sync()

	logger.Info("hello world")
}

6. 参考

高性能日志库 Zap:Go 开发者的必备工具 在现代微服务架构中,日志不仅是系统运行状态的记录,更是调试、分析问题的重要手段。Go 语言中有不少优秀的日志库,其中 **Zap** 凭借其 **高性能** 和 **灵活性**,成为了众多开发者的首选工具。 本篇文章将详细介绍 Zap 的核心功能、优势及如何在项目中使用它来提高日志处理的效率。 阅读详情

相关推荐

Zap:Go 的高性能日志库

/ 配置日志级别、输出目标、时间格式等config.Level = zap.NewAtomicLevelAt(zap.DebugLevel) // 启用 Debug 级别config.OutputPaths = []string{"stdout", "/var/log/app.log"} // 输出到控制台和文件config.EncoderConfig.TimeKey = "timestamp" // 自定义时间字段名。

m0_66925868的博客 1424

go zap日志库的使用,以及封装。

参考zap日志的基本使用(go必会知识*)一张图项目在开发阶段,如果出现问题,一般会去查看日志,来定位问题,这是非常有效的,上线后更加需要日志那么我们需要怎么样的日志呢?能打印最基本的信息,例如调用的文件,函数名称,行号,日志时间等支持不同的日志级别,例如: info、debug、error 等能够将记录的日志保存在文件里面,并且可以根据时间或者文件大小来切割日志文件,而zap就完全满足了,他非常的高效,并且是结构化的,分级的go日志库。如果不想将日志信息打印在终端,那么可以自定义配置,使用。.......

weixin_48536164的博客 5056

golang常用库之-日志框架包 zap库、go-log 库、golong 日志框架选型 logrus还是uber zap?

在 Go 项目开发中,我们可以通过修改一些优秀的开源日志包,来实现项目的日志包。Go 生态中有很多优秀的开源日志包,例如标准库 log 包、glog、logrus、zap、seelog、zerolog、log15、apex/log、go-logging 等。其中,用得比较多的是标准库 log 包、glog、logrus 和 zap。

西京刀客 2065

Go语言日志库zap

Go语言日志库zap

YIYIYI 2278

golang日志框架zap

zap是uber开源的Go高性能日志库 封装 package log import ( "os" "go.uber.org/zap" "go.uber.org/zap/zapcore" ) var ( logger *zap.Logger automicLevel = zap.NewAtomicLevelAt(zapcore.InfoLevel) ) func ini...

风格色的博客 1875

Golang zap 日志库快速使用

在go项目中,日志记录是必不可少的一部分,可以帮助开发者调试和排查问题以及为系统的运行状况提供数据。本文介绍了go业内非常流行的zap日志库,同时结合Lumberjack实现日志的切割和归档。

clearloe的博客 806

golang 日志库ZAP[uber-go zap]详解

zap 是 uber 开源的 Go 高性能日志库,支持不同的日志级别, 能够打印基本信息等,但不支持日志的分割,这里我们可以使用 lumberjack 也是 zap 官方推荐用于日志分割,结合这两个库我们就可以实现以下功能的日志机制:

nbplus_007的博客 1909

双参数威布尔分布(Weibull分布)参数计算(根据故障数据,求双参数威布尔分布的参数详细步骤)

根据故障数据求威布尔分布参数步骤 根据众多文献研究,设备故障数据大多服从指数分布、威布尔分布或对数正态分布。其中威布尔分布较为常用,本文主要介绍威布尔分布的简单应用,并根据某设备故障数据为例简单介绍威布尔分布参数的计算方法。 参考文献11参考文献22 1.双参数威布尔分布的概率密度函数、概率分布函数、可靠度函数: 2.预处理故障数据 将故障数据按时间排序,假设设备分别在以下时间点失效:11.1 、23.5、58.4……则将此时间从小到大排序。并计算中位秩。中位秩的计算公式如下: 其中i表示第几个数据,n

biaochengxiaobai的博客 4万+

golang扩展 日志库ZAP[uber-go zap]切割 natefinch-lumberjack

因为 zap 本身不支持切割归档日志文件,为了添加日志切割归档功能,我们将使用第三方库 lumberjack 来实现。

nbplus_007的博客 1034

保姆级教程:在Android车机上从零配置USB Gadget,搞定CarPlay有线连接

本文详细介绍了在Android车机上从零配置USB Gadget以实现CarPlay有线连接的完整实践指南。涵盖内核驱动开发、Android系统配置及用户空间通信架构,帮助开发者深入理解USB子系统和iAP2协议栈,实现稳定可靠的CarPlay有线连接功能。

weixin_30621711的博客 472

深度可分离卷积(DepthwiseSeparableConvolution):Depthwise卷积与Pointwise卷积

深度可分离卷积不用多说,在轻量级网络架构方面是一个绕不开的话题,只要接触深度学习多多少少会接触。深度可分离卷积即DepthwiseSeparableConvolution,该卷积将一个常规卷积过程划分成两个完成Depthwise卷积和Pointwise卷积,在保证输出一样时,计算量大大降低。首先来看,一个常规卷积是怎么实现的。其示意图如果我们从通道数变换的角度来看,卷积就是将3通道的tensor变为了4通道的tensor,我们来看看深度可分离卷积是怎么实现通道的变化的。...

xu.hyj 1万+

【GO】24.golang 日志库 zap

下载库 go get go.uber.org/zap 快速开始代码 package main import ( "go.uber.org/zap" "time" ) func main() { url := "http://www.google.com" //print format log loggerDev, _ := zap.NewDevelopme...

chen_peng7的博客 1040

应急响应靶场练习Linux-web-2

本次应急响应靶机采用的是知攻善防实验室的Linux-2应急响应靶机靶机下载地址为:相关账户密码: root/Inch@957821.(第一个为大写的i,记住要带最后的点.)1.该攻击者的IP为192.168.20.12.攻击方式应该是通过/index.php?user-app-register上传了一个webshell,然后使用蚁剑管理webshell之后再次上传version2.php进行提权.3.攻击者修改了phpmyadmin数据库的管理员密码。

tddkett的博客 2800

Golang zap框架应用(一)——根据日志级别将日志存储到不同文件中

目标功能: 根据日志级别进行不同文件存储 将error以下级别添加到info.log文件中 将error及以上添加到error.log文件中 下载: go get -u go.uber.org/zap github源码:https://github.com/uber-go/zap func main() { logger,err := getLogger("D:/log...

skh2015java的博客 5413

联邦学习中的差分隐私保护详解及python实现

随着数据隐私法规(如 GDPR、CCPA)日益严格,传统将数据集中到云端训练模型的方式面临合规与安全风险。联邦学习通过让各客户端保留本地数据,仅共享模型更新,缓解了数据流动带来的隐私风险。但模型更新仍可能泄露个体信息。为进一步保障隐私,可在本地更新中引入差分隐私(DP)机制,通过向梯度或模型更新中注入随机噪声,防止反向推断原始数据citeturn0search9。

闲人编程的博客 1919

[27] cuda 应用之 核函数实现图像通道变换

[27] cuda 应用之 核函数实现图像通道变换

yohnyang的博客 201

Golang 日志框架 Zap 入坑指南

文章目录简介CaseCase 1: Hello WorldCase 2: SugaredLoggercase 3: 定制化 SugaredLogger 简介 众所周知,Zap 是个很 nb 的日志框架,作为入门篇,本文主要用几个例子来直观地感受下 Zap 写出来的日志长什么样,符不符合我们的需求(主要是审美需求),性能什么的我们攒钱不 care。 以下栗子由浅入深,循序渐进,大部分栗子可以直接 copy 运行。 Case Case 1: Hello World Zap 的 Hello World 代码大

祈晴小义 6128

红绿灯背后的数学:如何用Java算出“黄金绿灯时间“?

本文探讨了城市交通信号灯配时优化的数学原理与Java实现方法。文章首先分析了信号灯配时不合理导致的交通问题,指出精确计算绿灯时长的重要性。核心内容包括:1)基于M/M/1排队模型建立车流量数学模型,通过优化算法最小化总等待时间;2)使用Java实现信号灯优化控制器,采用梯度下降法动态调整绿灯时长。文中提供了完整的Java代码实现,包括信号灯控制器基类和优化控制器类,采用原子类保证线程安全,并详细解释了关键算法原理和实现细节。该方案可为城市智能交通系统提供理论支持和技术实现参考。

墨夶的博客 1345

go zap 高性能日志

日志在整个工程实践中的重要性不言而喻,在选择日志组件的时候也有多方面的考量。详细、正确和及时的反馈是必不可少的,但是整个性能表现是否也是必要考虑的点呢?在长期的实践中发现有的日志组件对于计算资源的消耗十分巨大,这将导致整个服务成本的居高不下。此文从设计原理深度分析了 zap 的设计与实现上的权衡,也希望整个的选择、考量的过程能给其他的技术团队在开发高性能的 Go 组件时带来一定的借鉴意义。日志作为整个代码行为的记录,是程序执行逻辑和异常最直接的反馈。对于整个系统来说,日志是至关重要的组成部分。

daemon365的博客 2805

【自适应调制】自适应调制解调通信链路误码率matlab仿真与分析

BPSK中的B是“Binary”的意思,也就是有两个变化状态,比如说相位上的“+90°(代表1)、-90°(代表0)”,一个状态代表的就是一个比特。QPSK的“Q”是“Quadrature”的意思,有四个变化状态,如相位上的“+45°(代表00)、-45°(代表11)、+135°(代表10)、-135°(代表01)”,那么一个状态就代表两个比特的信息,如图2所示。同理8PSK的一个状态代表三个比特。但是功率资源并不是无限的,基站总的发射功率是一定的,为了充分利用所有的功率,采用的就是AMC技术。

FPGA/MATLAB学习教程/源码/项目合作开发 1831

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

【Go】Go zap 日志模块

详细介绍了Go当中的zap日志模块,包含zap的概念、快速入门、优雅实践,最后还进行了统一日志接口以及请求响应日志中间件的实战

weixin_62533201的博客 1218

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

golang高性能日志库zap

简介 zap是uber开源的Go高性能日志库 为什么选择Uber-go zap 在介绍Uber-go的zap包之前,让我们先看看Go语言提供的基本日志功能。Go语言提供的默认日志包是Go Logger:https://golang.org/pkg/log/ Go Logger的优势和劣势 优势: 它最大的优点是使用非常简单。我们可以设置任何io.Writer作为日志记录输出并向其发送要写入的日志。 劣势 仅限基本的日志级别 只有一个Print选项。不支持INFO/DEBUG等多个级别。 对于错误日志,它有

kuokay的博客 1173

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

学会使用golang zap日志库

go语言zap日志库的基本使用

2401_87046050的博客 1274

golang整合日志zap

和,这 3 个方法通过单个函数调用就可以构建一个日志计记录器,也可以简单配置Config 配置项源码// 动态改变日志级别,在运行时你可以安全改变日志级别// 将日志记录器设置为开发模式,在 WarnLevel 及以上级别日志会包含堆栈跟踪信息// 在日志中停止调用函数所在文件名、行数// 完全禁止自动堆栈跟踪。默认情况下,在 development 中,warnlevel及以上日志级别会自动捕获堆栈跟踪信息// 在 production 中,ErrorLevel 及以上也会自动捕获堆栈信息。

weixin_49132888的博客 1269

Go-zap日志框架

在很早之前的文章中,我们介绍过 Go 标准日志库log和结构化的日志库logrus。在热点函数中记录日志对日志库的执行性能有较高的要求,不能影响正常逻辑的执行时间。uber开源的日志库zap,对性能和内存分配做了极致的优化。zap用在日志性能和内存分配比较关键的地方。本文仅介绍了zap库的基本使用,子包zapcore中有更底层的接口,可以定制丰富多样的Logger。loglogrus。

weixin_37375983的博客 1648

一文带你入门golang中zap日志基本应用

关于golang中其他各种日志插件对比,这里不再赘述,直奔zap主题,啊哈哈,理论小结+实战,不扯淡,纯干货,嘎嘎,动起来。 目录 前言 使用小结 动手实战 基于zap+file-rotatelogs实现按天分隔日志 基于zap+lumberjack实现按天分隔日志 写在最后 前言 为什么选择zap: zap是非常快的、结构化的,分日志级别的Go日志库 它同时提供了结构化日志记录和printf风格的日志记录 以下是Zap发布的基准测试信息 记录一条消息和10个字段: P...

天天water的专栏 6634
上一篇: Go | 三索引切片
下一篇: Vue3 | Element Plus resetFields不生效
yimtcode
博客等级 码龄6年 205粉丝 140原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yimtcode

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值