Zap日志解析

Config.yaml

zap:
level: 'info' #日志级别
format: 'console' #输出的级别,有console和json
prefix: '[catering]' #输出的前缀,[catering]xxxxxxxxxxx
director: 'log' #存放的文件夹
show-line: true #是否显示行号
encode-level: 'LowercaseColorLevelEncoder' #编码级别,目前支持四种LowercaseLevelEncoder,LowercaseColorLevelEncoder,CapitalLevelEncoder,CapitalColorLevelEncoder
stacktrace-key: 'stacktrace' #栈名
log-in-console: true #输出控制台

配置文件

package config

type Zap struct {
Level string `mapstructure:"level" json:"level" yaml:"level"` // 级别
Format string `mapstructure:"format" json:"format" yaml:"format"` // 输出
Prefix string `mapstructure:"prefix" json:"prefix" yaml:"prefix"` // 日志前缀
Director string `mapstructure:"director" json:"director" yaml:"director"` // 日志文件夹
ShowLine bool `mapstructure:"show-line" json:"showLine" yaml:"showLine"` // 显示行
EncodeLevel string `mapstructure:"encode-level" json:"encodeLevel" yaml:"encode-level"` // 编码级
StacktraceKey string `mapstructure:"stacktrace-key" json:"stacktraceKey" yaml:"stacktrace-key"` // 栈名
LogInConsole bool `mapstructure:"log-in-console" json:"logInConsole" yaml:"log-in-console"` // 输出控制台
}

初始化

func InitZap() {
cfg := global.Config.Zap //获取上述的配置文件 // 判断是否有Director文件夹
if ok, _ := pkg.PathExists(cfg.Director); !ok {
fmt.Printf("create %v directory\n", cfg.Director)
_ = os.Mkdir(cfg.Director, os.ModePerm)
} // zap.LevelEnablerFunc(func(lev zapcore.Level) bool 用来划分不同级别的输出
// 根据不同的级别输出到不同的日志文件 // 调试级别
debugPriority := zap.LevelEnablerFunc(func(lev zapcore.Level) bool {
return lev == zap.DebugLevel
})
// 日志级别
infoPriority := zap.LevelEnablerFunc(func(lev zapcore.Level) bool {
return lev == zap.InfoLevel
})
// 警告级别
warnPriority := zap.LevelEnablerFunc(func(lev zapcore.Level) bool {
return lev == zap.WarnLevel
})
// 错误级别
errorPriority := zap.LevelEnablerFunc(func(lev zapcore.Level) bool {
return lev >= zap.ErrorLevel
}) cores := [...]zapcore.Core{
getEncoderCore(fmt.Sprintf("./%s/server_debug.log", cfg.Director), debugPriority),
getEncoderCore(fmt.Sprintf("./%s/server_info.log", cfg.Director), infoPriority),
getEncoderCore(fmt.Sprintf("./%s/server_warn.log", cfg.Director), warnPriority),
getEncoderCore(fmt.Sprintf("./%s/server_error.log", cfg.Director), errorPriority),
} //zapcore.NewTee(cores ...zapcore.Core) zapcore.Core
//NewTee创建一个Core,将日志条目复制到两个或更多的底层Core中 logger := zap.New(zapcore.NewTee(cores[:]...)) //用文件名、行号和zap调用者的函数名注释每条消息
if cfg.ShowLine {
logger = logger.WithOptions(zap.AddCaller())
} //把初始化好的logger赋值到全局日志变量中
global.Log = logger
}

getEncoderCode函数

// getEncoderCore 获取Encoder的zapcore.Core
func getEncoderCore(fileName string, level zapcore.LevelEnabler) (core zapcore.Core) {
writer := pkg.GetWriteSyncer(fileName) // 使用file-rotatelogs进行日志分割
return zapcore.NewCore(getEncoder(), writer, level)
}

getEncoder函数

// getEncoder 获取zapcore.Encoder
func getEncoder() zapcore.Encoder {
//获取配置文件的输出格式,json or console
cfg := global.Config.Zap
if cfg.Format == "json" {
return zapcore.NewJSONEncoder(getEncoderConfig())
}
return zapcore.NewConsoleEncoder(getEncoderConfig())
}

getEncoderConfig函数

获取自定义的编码器的配置

// getEncoderConfig 获取zapcore.EncoderConfig
func getEncoderConfig() (config zapcore.EncoderConfig) {
cfg := global.Config.Zap
config = zapcore.EncoderConfig{
MessageKey: "message",
LevelKey: "level",
TimeKey: "time",
NameKey: "logger",
CallerKey: "caller",
StacktraceKey: cfg.StacktraceKey, //栈名
LineEnding: zapcore.DefaultLineEnding, //默认的结尾\n
EncodeLevel: zapcore.LowercaseLevelEncoder, //小写字母输出
EncodeTime: CustomTimeEncoder, //自定义时间格式
EncodeDuration: zapcore.SecondsDurationEncoder, //编码间隔 s
EncodeCaller: zapcore.FullCallerEncoder, //控制打印的文件位置是绝对路径,ShortCallerEncoder 是相对路径
}
//根据配置文件重新配置编码颜色和字体
switch {
case cfg.EncodeLevel == "LowercaseLevelEncoder": // 小写编码器(默认)
config.EncodeLevel = zapcore.LowercaseLevelEncoder
case cfg.EncodeLevel == "LowercaseColorLevelEncoder": // 小写编码器带颜色
config.EncodeLevel = zapcore.LowercaseColorLevelEncoder
case cfg.EncodeLevel == "CapitalLevelEncoder": // 大写编码器
config.EncodeLevel = zapcore.CapitalLevelEncoder
case cfg.EncodeLevel == "CapitalColorLevelEncoder": // 大写编码器带颜色
config.EncodeLevel = zapcore.CapitalColorLevelEncoder
default:
config.EncodeLevel = zapcore.LowercaseLevelEncoder
}
return config
}

CustomTimeEncoder函数

用于自定义日志前缀的输出格式

// 自定义日志输出时间格式
// 输出格式为 prfix + 具体的时间日期
func CustomTimeEncoder(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
cfg := global.Config.Zap
enc.AppendString(t.Format(cfg.Prefix + "2006-01-02 15:04:05.000"))
}

pkg.GetWriteSyncer函数

用于切割文件,防止日志文件过大

func GetWriteSyncer(file string) zapcore.WriteSyncer {
lumberJackLogger := &lumberjack.Logger{
Filename: file, // 日志文件的位置
MaxSize: 10, // 在进行切割之前,日志文件的最大大小(以MB为单位)
MaxBackups: 200, // 保留旧文件的最大个数
MaxAge: 30, // 保留旧文件的最大天数
Compress: true, // 是否压缩/归档旧文件
} if global.Config.Zap.LogInConsole {
return zapcore.NewMultiWriteSyncer(zapcore.AddSync(os.Stdout), zapcore.AddSync(lumberJackLogger))
}
return zapcore.AddSync(lumberJackLogger)
}

用法

伪代码,切勿直接粘贴复制

package global

var log *zap.Logger
package main

import (
"catering/initialize"
"catering/global"
) func main() {
initialize.InitZap()
global.log.Info("test")
}

打印日志示例

log
├── server_error.log
├── server_info.log

server_info.log

[catering]2022-03-17 17:36:42.200	[34minfo[0m	E:/GoPath/project/go-catering/admin/initialize/router.go:32	use middleware logger
[catering]2022-03-17 17:36:42.201 [34minfo[0m E:/GoPath/project/go-catering/admin/initialize/router.go:36 use middleware cors
[catering]2022-03-17 17:36:42.201 [34minfo[0m E:/GoPath/project/go-catering/admin/initialize/router.go:38 register swagger handler
[catering]2022-03-17 17:36:42.225 [34minfo[0m E:/GoPath/project/go-catering/admin/initialize/router.go:104 router register success
[catering]2022-03-17 17:36:42.228 [34minfo[0m E:/GoPath/project/go-catering/admin/core/server.go:27 server run success on {"address": ":8888"}

server_error.log

[catering]2022-03-09 21:35:33.812	[31merror[0m	D:/goProject/src/catering/admin/pkg/app/request.go:13	Id.Required.	{"message": "Id Can not be empty"}
[catering]2022-03-09 21:35:33.813 [31merror[0m D:/goProject/src/catering/admin/pkg/app/request.go:13 LevelName.Required. {"message": "LevelName Can not be empty"}
[catering]2022-03-09 21:35:33.813 [31merror[0m D:/goProject/src/catering/admin/pkg/app/request.go:13 UpNeedIntegration.Required. {"message": "UpNeedIntegration Can not be empty"}

Golang Zap日志的更多相关文章

  1. golang中使用zap日志库

    1. 快速使用 package main import ( "go.uber.org/zap" "time" ) func main() { // 1. sug ...

  2. Go语言项目中使用zap日志库(翻译)

    本文先介绍了Go语言原生的日志库的使用,然后详细介绍了非常流行的Uber开源的zap日志库,同时介绍了如何搭配Lumberjack实现日志的切割和归档. 在Go语言项目中使用Uber-go的Zap L ...

  3. Go之Zap日志库集成Gin

    简介 在许多Go语言项目中,我们需要一个好的日志记录器能够提供下面这些功能: 1 . 能够将事件记录到文件中,而不是应用程序控制台; 2 . 日志切割-能够根据文件大小.时间或间隔等来切割日志文件; ...

  4. 在Go语言项目中使用Zap日志库

    在Go语言项目中使用Zap日志库 本文先介绍了Go语言原生的日志库的使用,然后详细介绍了非常流行的Uber开源的zap日志库,同时介绍了如何搭配Lumberjack实现日志的切割和归档. 在Go语言项 ...

  5. Golang的日志处理

    整个看了一圈下来,感觉Golang的日志包在管理多线程安全的情况下,提供了最小粒度的工具.并没有提供什么复杂的过滤器之类的生成. 实现了一个demo来记录一下日志分类日志打印等实现: package ...

  6. Golang 异常/日志处理

    1.xerrors 异常 xerrors 包是一个非常棒的设计,不同于往常语言如java/php,因为go的errors只是一个string类型的映射,所以内存占用空间很少.这在golang的核心库和 ...

  7. golang 写日志到syslog

    应用程序可以通过 UNIX domain sockets, UDP or TCP,向syslog守护进程发送日志.syslog守护进程可以在远端. 这样,就可以不用单独收集应用程序的日志了. gola ...

  8. golang第三方日志包seelog配置文件详解

    开发任何项目,都离不开日志,配好自己的项目日志输出,往往是开发项目的前提.在golang中,seelog应该是比较有名的日志处理包了,功能非常强大,seelog官方文档 一.seelog主要功能下面我 ...

  9. zap+日志分级分文件+按时间切割日志整合demo

    实现功能     info debug 级别的日志输出到 /path/log/demo.log     warn error .... 级别的日志输出到 /path/log/demo_error.lo ...

随机推荐

  1. 关于List、Set、Map接口讲解

    概述 List.Set接口都是继承于Collection主接口,而Map为独立接口 1.List接口下有ArrayList.Vector.LinkedList实现类 2.Set接口下有HashSet. ...

  2. bzoj5417/luoguP4770 [NOI2018]你的名字(后缀自动机+线段树合并)

    bzoj5417/luoguP4770 [NOI2018]你的名字(后缀自动机+线段树合并) bzoj Luogu 给出一个字符串 $ S $ 及 $ q $ 次询问,每次询问一个字符串 $ T $ ...

  3. XStream类对象把List<javaBean>()转成json数据

    [省市联动] Servlet端: XStream把list转成json数据 //JSONArray-->变成数组/集合[] //JSONObject-->变成简单的数据{name:ayee ...

  4. abstract的method是否可同时是static,是否可同时是native,是否可同时是synchronized?

    abstract的method 不可以是static的,因为抽象的方法是要被子类实现的,而static与子类扯不上关系! native方法表示该方法要用另外一种依赖平台的编程语言实现的,不存在着被子类 ...

  5. 解释内存中的栈(stack)、堆(heap)和方法区(method area)的用法?

    通常我们定义一个基本数据类型的变量,一个对象的引用,还有就是函数调用的现场保存都使用JVM中的栈空间:而通过new关键字和构造器创建的对象则放在堆空间,堆是垃圾收集器管理的主要区域,由于现在的垃圾收集 ...

  6. 为什么 Thread 类的 sleep()和 yield ()方法是静态的?

    Thread 类的 sleep()和 yield()方法将在当前正在执行的线程上运行.所以在其他处于等待状态的线程上调用这些方法是没有意义的.这就是为什么这些方法是静态的.它们可以在当前正在执行的线程 ...

  7. 说说对 SQL 语句优化有哪些方法?

    1.Where 子句中:where 表之间的连接必须写在其他 Where 条件之前,那些可 以过滤掉最大数量记录的条件必须写在 Where 子句的末尾.HAVING 最后. 2.用 EXISTS 替代 ...

  8. spring-boot-learning-MongoDB

    NoSQL可以极大提高互联网系统的性能,但是它有一些致命的缺陷,其中最为严重的就是计算功能卡分有限,例如,在一个10 万数据量的List 中,我只需要满足特定条件的元素在Red is 中,使用集合或者 ...

  9. SQLyog创建用户并授权的过程

    点击你要授权的数据库然后点击用户管理器 然后输入用户名和密码主机选localhost 然后点击创建,然后选择你创建的数据库全选 最后保存就可以了

  10. 百度移动统计调用api教程,少进坑(82001错误)

    相信很多小伙伴使用了百度统计,来查看自己应用使用的情况,但是会发现百度移动统计在官网没有api调用取数据的接口, 现在我就以自己成功调用api并且成功拿到数据,将这个步骤给大家参考,(末尾有调用移动统 ...