Go 语言之自定义 zap 日志
zap 日志:https://github.com/uber-go/zap
一、日志写入文件
- zap.NewProduction、zap.NewDevelopment 是预设配置好的。
- zap.New 可自定义配置
zap.New源码
这是构造Logger最灵活的方式,但也是最冗长的方式。
对于典型的用例,高度固执己见的预设(NewProduction、NewDevelopment和NewExample)或Config结构体更方便。- // New constructs a new Logger from the provided zapcore.Core and Options. If
- // the passed zapcore.Core is nil, it falls back to using a no-op
- // implementation.
- //
- // This is the most flexible way to construct a Logger, but also the most
- // verbose. For typical use cases, the highly-opinionated presets
- // (NewProduction, NewDevelopment, and NewExample) or the Config struct are
- // more convenient.
- //
- // For sample code, see the package-level AdvancedConfiguration example.
- func New(core zapcore.Core, options ...Option) *Logger {
- if core == nil {
- return NewNop()
- }
- log := &Logger{
- core: core,
- errorOutput: zapcore.Lock(os.Stderr),
- addStack: zapcore.FatalLevel + 1,
- clock: zapcore.DefaultClock,
- }
- return log.WithOptions(options...)
- }
复制代码 zapcore.Core 源码
- // Core is a minimal, fast logger interface. It's designed for library authors
- // to wrap in a more user-friendly API.
- type Core interface {
- LevelEnabler
- // With adds structured context to the Core.
- With([]Field) Core
- // Check determines whether the supplied Entry should be logged (using the
- // embedded LevelEnabler and possibly some extra logic). If the entry
- // should be logged, the Core adds itself to the CheckedEntry and returns
- // the result.
- //
- // Callers must use Check before calling Write.
- Check(Entry, *CheckedEntry) *CheckedEntry
- // Write serializes the Entry and any Fields supplied at the log site and
- // writes them to their destination.
- //
- // If called, Write should always log the Entry and Fields; it should not
- // replicate the logic of Check.
- Write(Entry, []Field) error
- // Sync flushes buffered logs (if any).
- Sync() error
- }
复制代码 zapcore.AddSync(file) 源码解析
- func AddSync(w io.Writer) WriteSyncer {
- switch w := w.(type) {
- case WriteSyncer:
- return w
- default:
- return writerWrapper{w}
- }
- }
- type writerWrapper struct {
- io.Writer
- }
- func (w writerWrapper) Sync() error {
- return nil
- }
- type WriteSyncer interface {
- io.Writer
- Sync() error
- }
复制代码 日志级别
- // A Level is a logging priority. Higher levels are more important.
- type Level int8
- const (
- // DebugLevel logs are typically voluminous, and are usually disabled in
- // production.
- DebugLevel Level = iota - 1
- // InfoLevel is the default logging priority.
- InfoLevel
- // WarnLevel logs are more important than Info, but don't need individual
- // human review.
- WarnLevel
- // ErrorLevel logs are high-priority. If an application is running smoothly,
- // it shouldn't generate any error-level logs.
- ErrorLevel
- // DPanicLevel logs are particularly important errors. In development the
- // logger panics after writing the message.
- DPanicLevel
- // PanicLevel logs a message, then panics.
- PanicLevel
- // FatalLevel logs a message, then calls os.Exit(1).
- FatalLevel
- _minLevel = DebugLevel
- _maxLevel = FatalLevel
- // InvalidLevel is an invalid value for Level.
- //
- // Core implementations may panic if they see messages of this level.
- InvalidLevel = _maxLevel + 1
- )
复制代码 实操
- package main
- import (
- "go.uber.org/zap"
- "go.uber.org/zap/zapcore"
- "net/http"
- "os"
- )
- // 定义一个全局 logger 实例
- // Logger提供快速、分级、结构化的日志记录。所有方法对于并发使用都是安全的。
- // Logger是为每一微秒和每一个分配都很重要的上下文设计的,
- // 因此它的API有意倾向于性能和类型安全,而不是简便性。
- // 对于大多数应用程序,SugaredLogger在性能和人体工程学之间取得了更好的平衡。
- var logger *zap.Logger
- // SugaredLogger将基本的Logger功能封装在一个较慢但不那么冗长的API中。任何Logger都可以通过其Sugar方法转换为sugardlogger。
- //与Logger不同,SugaredLogger并不坚持结构化日志记录。对于每个日志级别,它公开了四个方法:
- // - methods named after the log level for log.Print-style logging
- // - methods ending in "w" for loosely-typed structured logging
- // - methods ending in "f" for log.Printf-style logging
- // - methods ending in "ln" for log.Println-style logging
- // For example, the methods for InfoLevel are:
- //
- // Info(...any) Print-style logging
- // Infow(...any) Structured logging (read as "info with")
- // Infof(string, ...any) Printf-style logging
- // Infoln(...any) Println-style logging
- var sugarLogger *zap.SugaredLogger
- func main() {
- // 初始化
- InitLogger()
- // Sync调用底层Core的Sync方法,刷新所有缓冲的日志条目。应用程序在退出之前应该注意调用Sync。
- // 在程序退出之前,把缓冲区里的日志刷到磁盘上
- defer logger.Sync()
- simpleHttpGet("www.baidu.com")
- simpleHttpGet("http://www.baidu.com")
- }
- func InitLogger() {
- writeSyncer := getLogWriter()
- encoder := getEncoder()
- // NewCore创建一个向WriteSyncer写入日志的Core。
- // A WriteSyncer is an io.Writer that can also flush any buffered data. Note
- // that *os.File (and thus, os.Stderr and os.Stdout) implement WriteSyncer.
- // LevelEnabler决定在记录消息时是否启用给定的日志级别。
- // Each concrete Level value implements a static LevelEnabler which returns
- // true for itself and all higher logging levels. For example WarnLevel.Enabled()
- // will return true for WarnLevel, ErrorLevel, DPanicLevel, PanicLevel, and
- // FatalLevel, but return false for InfoLevel and DebugLevel.
- core := zapcore.NewCore(encoder, writeSyncer, zapcore.DebugLevel)
- // New constructs a new Logger from the provided zapcore.Core and Options. If
- // the passed zapcore.Core is nil, it falls back to using a no-op
- // implementation.
- logger = zap.New(core)
- // Sugar封装了Logger,以提供更符合人体工程学的API,但速度略慢。糖化一个Logger的成本非常低,
- // 因此一个应用程序同时使用Loggers和SugaredLoggers是合理的,在性能敏感代码的边界上在它们之间进行转换。
- sugarLogger = logger.Sugar()
- }
- func getEncoder() zapcore.Encoder {
- // NewJSONEncoder创建了一个快速、低分配的JSON编码器。编码器适当地转义所有字段键和值。
- // NewProductionEncoderConfig returns an opinionated EncoderConfig for
- // production environments.
- return zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig())
- }
- func getLogWriter() zapcore.WriteSyncer {
- // Create创建或截断指定文件。如果文件已经存在,它将被截断。如果该文件不存在,则以模式0666(在umask之前)创建。
- // 如果成功,返回的File上的方法可以用于IO;关联的文件描述符模式为O_RDWR。如果有一个错误,它的类型将是PathError。
- file, _ := os.Create("./test.log")
- // AddSync converts an io.Writer to a WriteSyncer. It attempts to be
- // intelligent: if the concrete type of the io.Writer implements WriteSyncer,
- // we'll use the existing Sync method. If it doesn't, we'll add a no-op Sync.
- return zapcore.AddSync(file)
- }
- func simpleHttpGet(url string) {
- // Get向指定的URL发出Get命令。如果响应是以下重定向代码之一,则Get跟随重定向,最多可重定向10个:
- // 301 (Moved Permanently)
- // 302 (Found)
- // 303 (See Other)
- // 307 (Temporary Redirect)
- // 308 (Permanent Redirect)
- // Get is a wrapper around DefaultClient.Get.
- // 使用NewRequest和DefaultClient.Do来发出带有自定义头的请求。
- resp, err := http.Get(url)
- if err != nil {
- // Error在ErrorLevel记录消息。该消息包括在日志站点传递的任何字段,以及日志记录器上积累的任何字段。
- //logger.Error(
- // 错误使用fmt。以Sprint方式构造和记录消息。
- sugarLogger.Error(
- "Error fetching url..",
- zap.String("url", url), // 字符串用给定的键和值构造一个字段。
- zap.Error(err)) // // Error is shorthand for the common idiom NamedError("error", err).
- } else {
- // Info以infollevel记录消息。该消息包括在日志站点传递的任何字段,以及日志记录器上积累的任何字段。
- //logger.Info("Success..",
- // Info使用fmt。以Sprint方式构造和记录消息。
- sugarLogger.Info("Success..",
- zap.String("statusCode", resp.Status),
- zap.String("url", url))
- resp.Body.Close()
- }
- }
复制代码 运行
[code]Code/go/zap_demo via
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |