log包

Go标准库中有log包,提供了简单的日志功能。

输出  格式输出 换行输出 解释
log.Print() log.Printf() log.Println() 类似fmt.Print*
log.Fatal() log.Fatalf() log.Fatalln() 相当于log.Print* + os.Exit(1)
log.Panic() log.Panicf() log.Panicln() 相当于log.Print* + panic()

日志输出需要使用日志记录器Logger。 log包提供了一个缺省的Logger即std。std是小写的,包外不可见,所以提供了Default()方法返回std给包外使用。

 上表列出的方法底层都使用std.Output输出日志内容。而std本质上是使用了标准错误输出、无前缀、 LstdFlags标准标记的记录器Logger实例。

// 使用缺省Logger
log.Print("abcde\n")
log.Printf("%s\n", "abcd")
log.Println("abc")
log.Fatal("xyz") // 等价于 log.Print("xyz");os.Exit(1)
log.Panicln("Failed") // 等价于 log.Println("Failed");panic()

自定义Logger

// 自定义Logger
infoLogger := log.New(os.Stdout, "Info: ", log.LstdFlags|log.Lmsgprefix)
infoLogger.Println("这是一个普通消息") // 使用stdout输出
errLogger := log.New(os.Stderr, "Error: ", log.LstdFlags)
errLogger.Fatal("这是一个错误消息")

写日志文件

New方法签名 New(out io.Writer, prefix string, flag int) *Logger 中out参数提供Writer接口即可,那么就可以提供一个可写文件对象。

package main

import (
    "log"
    "os"
)

func main() {
    f, err := os.OpenFile("log/test.log", // os.Open为只读打开,OpenFile按照指定方式打开文件
        os.O_CREATE|os.O_RDONLY|os.O_APPEND,
        0644) // Unix permission bits
    if err != nil {
        log.Panicf("%v %v", "文件打开失败:", err)
    }
    defer f.Close()
    logger := log.New(f, "[INFO]", log.Ldate|log.Ltime)
    logger.Println("开始初始化。。。。")
}

 zerolog

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

  • logrus有日志级别、Hook机制、日志格式输出,很好用
  • zap是Uber的开源高性能日志库
  • zerolog更注重开发体验,高性能、有日志级别、链式API,json格式日志记录,号称0内存分配

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

 级别

zerolog提供以下级别(从高到底)

  • panic (zerolog.PanicLevel, 5)
  • fatal (zerolog.FatalLevel, 4)
  • error (zerolog.ErrorLevel, 3)
  • warn (zerolog.WarnLevel, 2)
  • info (zerolog.InfoLevel, 1)
  • debug (zerolog.DebugLevel, 0)
  • trace (zerolog.TraceLevel, -1)

级别有

  • gLevel全局级别
  1. zerolog.SetGlobalLevel(级别数字或常量) 来设置全局级别
  2. zerolog.GlobalLevel() 获取当前全局级别
  • 每个Logger的级别
  • 消息的级别
package main
import (
 "fmt"
 "github.com/rs/zerolog"
 "github.com/rs/zerolog/log"
)
func main() {
 fmt.Println("全局级别gLevel为", zerolog.GlobalLevel())
 fmt.Println("缺省logger的级别为", log.Logger.GetLevel())
 log1 := log.Level(zerolog.WarnLevel) // 创建一个子logger
 fmt.Println("log1级别为", log1.GetLevel())
 fmt.Println("~~~~~~~~~~~~~~~~~~~~~~~~~~~")
 log.Trace().Msg("缺省logger输出trace级别消息") // 输出
 log.Info().Msg("缺省logger输出info级别消息")   // 输出
 log.Warn().Msg("缺省logger输出warn级别消息")   // 输出
 log.Error().Msg("缺省logger输出error级别消息") // 输出
 log1.Debug().Msg("log1的Debug级别消息")     // 不能输出
    log1.Warn().Msg("log1的Warn级别消息")       // 输出
 log1.Error().Msg("log1的Error级别消息")     // 输出
}

因为有消息级别和Logger级别,因此使用缺省logger,全部可以输出日志消息,而log1使22行、23行输出了日志

而缺省Logger的级别是trace,任何消息级别都大于等于log1的级别,因此都可以输出。

package main
import (
 "fmt"
 "github.com/rs/zerolog"
 "github.com/rs/zerolog/log"
)
func main() {
 zerolog.SetGlobalLevel(zerolog.ErrorLevel) // 调高全局级别
 fmt.Println("全局级别gLevel为", zerolog.GlobalLevel())
 fmt.Println("缺省logger的级别为", log.Logger.GetLevel())
 log1 := log.Level(zerolog.WarnLevel) // 创建一个子logger
 fmt.Println("log1级别为", log1.GetLevel())
 fmt.Println("~~~~~~~~~~~~~~~~~~~~~~~~~~~")
 log.Trace().Msg("缺省logger输出trace级别消息") // 不能输出
 log.Info().Msg("缺省logger输出info级别消息")   // 不能输出
 log.Warn().Msg("缺省logger输出warn级别消息")   // 不能输出
 log.Error().Msg("缺省logger输出error级别消息") // 输出
 log1.Debug().Msg("log1的Debug级别消息")     // 不能输出
 log1.Warn().Msg("log1的Warn级别消息")       // 不能输出
 log1.Error().Msg("log1的Error级别消息")     // 输出
}

缺省logger和log1都只有error级别的输出,说明将gLevel调整到error级别后,所有logger输出消息都必 须大于等于gLevel。

zerolog.SetGlobalLevel()设置的是全局变量gLevel,它影响所有Logger。

日志消息是否能够输出,应当满足下面的要求 消息级别 >= max(gLevel, 当前logger级别)

上下文

zerolog是以Json对象格式输出的,还可以自定义一些键值对字段增加到上下文中以输出。

zerolog.SetGlobalLevel(zerolog.InfoLevel)
log.Info().Bool("Success", false).Str("Reason", "File Not Found").Msg("文件没
找到")
log.Info().Str("Name", "Tom").Floats32("Scores", []float32{87.5, 90, 
59}).Send()
// Send is equivalent to calling Msg("")

错误日志

package main
import (
 "errors"
 "github.com/rs/zerolog"
 "github.com/rs/zerolog/log" // 全局logger
)
func main() {
 zerolog.TimeFieldFormat = zerolog.TimeFormatUnix // 自定义time字段时间的格
式,TimeFormatUnix时间戳
 // zerolog.ErrorFieldName = "err" // 修改日志Json中的缺省字段名error
 // 错误日志
 err := errors.New("自定义的错误")
 log.Error(). // 错误级别消息
 Err(err). // err字段,错误消息内容
 Send()    // 有错误消息了,message可以省略
 log.Fatal(). // fatal级别
 Err(err).
 Send()
}

全局Logger

// 全局Logger定义如下
var Logger = zerolog.New(os.Stderr).With().Timestamp().Logger()

可以覆盖全局Logger

// 全局日期格式
zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
zerolog.TimeFieldFormat = "2006/01/02 15:04:05 -0700"
// With()创建一个全局Logger的子logger
log.Logger = log.With().Str("Name", "Cabel").Logger() // 覆盖了全局Logger
log.Info().Send() // {"level":"info","Name":"Cabel","time":1223947070}

自定义Logger

zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
logger := log.With(). // With()返回基于全局Logger的子logger
 Str("School", "Mg").
 Caller(). // 增加日志调用的位置信息字段
 Logger()  // 返回Logger
logger.Info().Send() // {"level":"info","School":"Mg","time":1223947070}
log.Info().Send()    // {"level":"info","time":1223947070} 全局Logger
zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
logger := zerolog.New(os.Stdout). // 不基于全局Logger,重新构造了一个Logger
 With().Str("School", "Mg").
 Caller().                 // 调用者信息:增加日志函数调用的位置信息字段
 Logger().                 // 返回Logger
 Level(zerolog.ErrorLevel) // 重新定义Logger级别为3 error,返回Logger
fmt.Println(logger.GetLevel())
logger.Info().Send() // {"level":"info","School":"Mg","time":1223947070} 
logger.Error().Send()
log.Info().Send() // {"level":"info","time":1223947070} 全局Logger

写日志文件

package main
import (
 "os"
 "github.com/rs/zerolog"
 "github.com/rs/zerolog/log" // 全局logger
)
func main() {
 zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
 f, err := os.OpenFile("o:/my.log", os.O_CREATE|os.O_APPEND, os.ModePerm)
 if err != nil {
 log.Panic().Err(err).Send() // 内部调用panic
 }
 defer f.Close()
    
 multi := zerolog.MultiLevelWriter(f, os.Stdout) // 多分支写
    // Timestamp()为这个全新的Logger增加时间戳输出
 logger := zerolog.New(multi).With().Timestamp().Logger()
 logger.Info().Msg("日志兵分两路,去控制台stdout,还去日志文件")
}

如果只输出到文件可以使用 zerolog.New(f).With().Timestamp().Logger()

 

posted on 2023-07-21 17:59  自然洒脱  阅读(63)  评论(0编辑  收藏  举报