草庐IT

Golang Zap日志

小傅啊 2023-03-28 原文

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	info	E:/GoPath/project/go-catering/admin/initialize/router.go:32	use middleware logger
[catering]2022-03-17 17:36:42.201	info	E:/GoPath/project/go-catering/admin/initialize/router.go:36	use middleware cors
[catering]2022-03-17 17:36:42.201	info	E:/GoPath/project/go-catering/admin/initialize/router.go:38	register swagger handler
[catering]2022-03-17 17:36:42.225	info	E:/GoPath/project/go-catering/admin/initialize/router.go:104	router register success
[catering]2022-03-17 17:36:42.228	info	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	error	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	error	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	error	D:/goProject/src/catering/admin/pkg/app/request.go:13	UpNeedIntegration.Required.	{"message": "UpNeedIntegration Can not be empty"}

有关Golang Zap日志的更多相关文章

  1. ruby - Sinatra 中的全局救援和日志记录异常 - 2

    如何在出现异常时指定全局救援,如果您将Sinatra用于API或应用程序,您将如何处理日志记录? 最佳答案 404可以在not_found方法的帮助下处理,例如:not_founddo'Sitedoesnotexist.'end500s可以通过调用带有block的错误方法来处理,例如:errordo"Applicationerror.Plstrylater."end错误的详细信息可以通过request.env中的sinatra.error访问,如下所示:errordo'Anerroroccured:'+request.env['si

  2. ruby-on-rails - 使用 Ruby 标准 Logger 每天只创建一个日志 - 2

    我正在使用ruby​​标准记录器,我想要每天轮换一次,所以在我的代码中我有:Logger.new("#{$ROOT_PATH}/log/errors.log",'daily')它运行完美,但它创建了两个文件errors.log.20130217和errors.log.20130217.1。如何强制它每天只创建一个文件? 最佳答案 您的代码对于长时间运行的应用程序是正确的。发生的事情是您在给定的一天多次运行代码。第一次运行时,Ruby会创建一个日志文件“errors.log”。当日期改变时,Ruby将文件重命名为“errors.log

  3. ruby - Cucumber/Savon 省略或删除日志输出 - 2

    在运行Cucumber测试时,我得到(除了测试结果)大量调试/日志相关的输出形式:D,[2013-03-06T12:21:38.911829#49031]DEBUG--:SOAPrequest:D,[2013-03-06T12:21:38.911919#49031]DEBUG--:Pragma:no-cache,SOAPAction:"",Content-Type:text/xml;charset=UTF-8,Content-Length:1592W,[2013-03-06T12:21:38.912360#49031]WARN--:HTTPIexecutesHTTPPOSTusingt

  4. ruby-on-rails - faraday如何设置日志级别 - 2

    我最近将我的http客户端切换到faraday,一切都按预期工作。我有以下代码来创建连接:@connection=Faraday.new(:url=>base_url)do|faraday|faraday.useCustim::Middlewarefaraday.request:url_encoded#form-encodePOSTparamsfaraday.request:jsonfaraday.response:json,:content_type=>/\bjson$/faraday.response:loggerfaraday.adapterFaraday.default_ada

  5. 网站日志分析软件--让网站日志分析工作变得更简单 - 2

    网站的日志分析,是seo优化不可忽视的一门功课,但网站越大,每天产生的日志就越大,大站一天都可以产生几个G的网站日志,如果光靠肉眼去分析,那可能看到猴年马月都看不完,因此借助网站日志分析工具去分析网站日志,那将会使网站日志分析工作变得更简单。下面推荐两款网站日志分析软件。第一款:逆火网站日志分析器逆火网站日志分析器是一款功能全面的网站服务器日志分析软件。通过分析网站的日志文件,不仅能够精准的知道网站的访问量、网站的访问来源,网站的广告点击,访客的地区统计,搜索引擎关键字查询等,还能够一次性分析多个网站的日志文件,让你轻松管理网站。逆火网站日志分析器下载地址:https://pan.baidu.

  6. ruby - 如何更改 Sinatra 中的日志级别 - 2

    我正在使用此代码在我的Sinatra应用程序中启用日志记录:log_file=File.new('my_log_file.log',"a")$stdout.reopen(log_file)$stderr.reopen(log_file)$stdout.sync=true$stderr.sync=true实际的日志记录是使用:logger.debug("Startingcall.Params=#{params.inspect}")事实证明,只有INFO或更高级别的日志消息被记录,而DEBUG消息没有被记录。我正在寻找一种将日志级别设置为DEBUG的方法。 最佳

  7. ruby - 带有 grep 远程日志文件的 tail - 2

    我有这段代码来跟踪远程日志文件:defdo_tail(session,file)session.open_channeldo|channel|channel.on_datado|ch,data|puts"[#{file}]->#{data}"endchannel.exec"tail-f#{file}"endNet::SSH.start("host","user",:password=>"passwd")do|session|do_tailsession,"/path_to_log/file.log"session.loop我只想在file.log中检索带有ERROR字符串的行,我正在尝

  8. Ruby 守护进程日志轮换 - 2

    当我为Daemons(1.1.0)gem设置日志记录参数时,我将如何实现与此行类似的行为?logger=Logger.new('foo.log',10,1024000)守护进程选项:options={:ARGV=>['start'],:dir_mode=>:normal,:dir=>log_dir,:multiple=>false,:ontop=>false:mode=>:exec,:backtrace=>true,:log_output=>true} 最佳答案 不幸的是,Daemonsgem不使用Logger。它将STDOUT和S

  9. ruby-on-rails - 在 Rails 应用程序的前端获取实时日志 - 2

    在Rails3.x应用程序中,我正在使用net::ssh并向远程pc运行一些命令。我想向用户的浏览器显示实时日志。比如,如果两个命令在net中运行::ssh执行即echo"Hello",echo"Bye"被传递然后"Hello"应该在执行后立即显示在浏览器中。这是代码我在ruby​​onrails应用程序中使用ssh连接和运行命令Net::SSH.start(@servers['local'],@machine_name,:password=>@machine_pwd,:timeout=>30)do|ssh|ssh.open_channeldo|channel|channel.requ

  10. ruby - gem 应该在哪里存储日志文件? - 2

    我正在构建一个应该输出日志文件的ruby​​gem。将日志文件存储在哪里是一个好习惯?我正在从我正在构建的Rails网站中提取此功能,我可以在那里简单地登录到log/目录。 最佳答案 理想情况下,使路径可配置(.rc文件、交换机、rails/rack配置等)。如果它是一个Rack中间件,添加在构造函数的参数中指定它的可能性。如果没有提供日志路径,回退到检测日志目录。(我依稀记得它是Rails中的config.paths['log'],但如果可以的话,请确保config在你的gem中使用之前确实指向某些东西在Rails之外使用。)如果

随机推荐