代码改变世界

golang标准库log+第三方zerolog

2023-03-08 21:14  dribs  阅读(433)  评论(0编辑  收藏  举报
package main

import (
	"log"
	"os"
)

func main() {
	log.Printf("%s\n", "Printf") //2023/03/08 21:05:08 Printf
	log.Println("Println")
	log.Print("print")
	//log.Fatal("fatal")

	//log.Panicln("panicln")

	//自定义logger
	infologger := log.New(os.Stdout, "<Info>", 3|64) //3 LstdFlags 64 Lmsgprefix
	infologger.Println("this is test")  //    2023/03/08 21:05:08 <Info>this is test
	errlogger := log.New(os.Stderr, "<ERROR>", 3|64)
	errlogger.Println("this is err log test")

	//写日志文件
	f, err := os.OpenFile("e:/test.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, os.ModePerm)
	if err != nil {
		log.Panicln(err)
	}
	defer f.Close()
	logger := log.New(f, "<info>", log.LstdFlags)
	logger.Println("wirte file log test")

}

  

log包提供了一个缺省的Logger即std。std是小写的,包外不可见,所以提供了Default()方法返回std给 包外使用。

// 大约在源码log.go第90行
var std = New(os.Stderr, "", LstdFlags)
func Default() *Logger { return std }
const (
 Ldate         = 1 << iota // 1 当前时区日期: 2009/01/23
 Ltime                     // 2 当前时区时间: 01:23:23
 Lmicroseconds             // 4 微秒: 01:23:23.123123. assumes Ltime.
 Llongfile                 // 8 绝对路径和行号: /a/b/c/d.go:23
 Lshortfile                // 16 文件名和行号: d.go:23. overrides Llongfile
 LUTC                      // 32 使用UTC(GMT),而不是本地时区
 Lmsgprefix                // 64 默认前缀放行首,这个标记把前缀prefix放到消息
message之前
 LstdFlags     = Ldate | Ltime // 3 initial values for the standard
logger
)

  

 

zerolog

log模块太简陋了,实际使用并不方便。

logrus有日志级别、Hook机制、日志格式输出,很好用

zap是Uber的开源高性能日志库

zerolog更注重开发体验,高性能、有日志级别、链式API,json格式日志记录,号称0内存分配

官网 https://zerolog.io/

安装 go get -u github.com/rs/zerolog/log

package main

import (
	"errors"
	"fmt"
	"github.com/rs/zerolog"
	"github.com/rs/zerolog/log"
	"os"
)

func example1() {
	zerolog.SetGlobalLevel(zerolog.ErrorLevel) //设置全局的logger级别为error 3
	fmt.Println(zerolog.GlobalLevel())         //error
	//zerolog.SetGlobalLevel(zerolog.Disabled)   //相当于禁用所有logger,就没日志输出了

	log.Print("zerolog print string") // log.Debug().Msg("zerlog debug string")
	//log.Fatal().Msg("zerolog fatal string")
	//log.Panic().Msg("zerolog panic stirng")

	//logger 日志记录器级别
	fmt.Println(log.Logger)            //{{0xc000006020} -1 <nil> [123] [{}] false}
	fmt.Println(log.Logger.GetLevel()) //-1 trace 默认

	//child logger
	log1 := log.Logger.Level(zerolog.InfoLevel) //log1 := log.Logger.Level(1)
	fmt.Println(log1)                           //新建一个logger 级别为1 info级别的

	//消息级别
	log.Debug().Msg("defalut debug string") //logger的默认为trace -1 所以大于等于-1的都打印
	log.Error().Msg("defalut error string") //如果要输出成功,必须消息级别 >= max(自己的级别,glevel)
	log1.Debug().Msg("log1 debug string")
	log1.Info().Msg("log1 info string") //log1上面定义为info >=info才打印
	log1.Warn().Msg("log1 warn string")
	log1.Error().Msg("log1 err string") //如果gleve设置成error3 那么只能大于等于err级别的才打印

	err := errors.New("error test")
	log.Error().Err(err).Msg("haha")
	log.Error().Err(err).Send()
	//log.Panic().Err(err).Send()


}

//上下文
func example2() {
	zerolog.SetGlobalLevel(zerolog.InfoLevel)
	log.Info().Bool("Success", false).Str("Rea son", "File not found").Msg("文件没找到")
	log.Info().Str("Name", "Tom").Floats32("Scores", []float32{87.5, 90.59}).Send()
}

//错误日志
func example3() {
	zerolog.TimeFieldFormat = zerolog.TimeFormatUnix //自定义time字段时间的格式,时间戳
	//zerolog.ErrorFieldName = "err"                   //修改稿日志json中的缺省字段名error
	//错误日志
	err := errors.New("自定义错误")
	log.Error(). //错误级别消息
			Err(err). //err字段,错误消息内容
			Send()    //有错误消息了,message可以省略

	log.Fatal().Err(err).Send() //fatal 级别
}

//自定义logger
func example4() {
	zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
	logger := log.With(). //with 返回基于全局Logger的子logger
				Str("Name", "lihongxing").
				Caller(). //增加日志调用的位置信息字段
				Logger()  //返回logger

	logger.Info().Send() //{"level":"info","Name":"lihongxing","time":1678277947,"caller":"E:/disk/golang/zerolog包/main.go:73"}
	log.Info().Send()    //全局Logger    {"level":"info","time":1678277947}

	logger = zerolog.New(os.Stdout). //不基于全局Logger,重新构造
						With().Str("Name", "LIHX").
						Caller().                 //调用者信息,增加日志函数调用的位置信息字段
						Logger().                 //返回logger
						Level(zerolog.ErrorLevel) //重新定义Logger级别为error 3
	fmt.Println(logger.GetLevel()) //error
	logger.Info().Send()           //error级别不打印
	logger.Error().Send()          //{"level":"error","Name":"LIHX","caller":"E:/disk/golang/zerolog包/main.go:84"}
	log.Info().Send()              //{"level":"info","time":1678278590}   全局的Looger
}

//写日志文件
func example5() {
	zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
	f, err := os.OpenFile("e:/tt.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, os.ModePerm)
	if err != nil {
		log.Panic().Err(err).Send() //内部调用panic
	}
	defer f.Close()
	//如果只输出到文件可以去掉os.Stdout
	multi := zerolog.MultiLevelWriter(f, os.Stdout) //多分支写
	logger := zerolog.New(multi).With().Timestamp().Logger()
	logger.Info().Msg("日志分两路,写入日志和打印出控制台")

}

func main() {
	//example1()
	//example2()
	//example3()
	////源码全局logger的定义
	////var Logger = zerolog.New(os.Stderr).With().Timestamp().Logger()
	//zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
	////with创建一个全局Logger的子logger 这样就覆盖了全局logger
	//log.Logger = log.With().Str("Name", "li").Logger()
	//log.Info().Send()

	example4()
	//example5()
}