Shaw0xyz 发表于 2024-5-19 14:19:05

Go 统一日志处理

本帖最后由 Shaw0xyz 于 2024-5-19 14:20 编辑

在现代应用开发中,日志处理是非常重要的一环。统一的日志处理不仅可以帮助我们更好地调试和监控应用,还可以为后期的维护提供有力的支持。本文将介绍如何在Go语言项目中实现统一的日志处理,涵盖日志库的选择、配置和使用。


为什么需要统一日志处理?

- 调试方便:通过统一的日志格式和级别,方便快速定位问题。
- 监控便捷:统一的日志输出方便接入监控系统(如ELK、Prometheus)。
- 维护简单:一致的日志管理方式降低了代码复杂度,提升可维护性。

日志库的选择

Go语言有多种日志库可以选择,常用的有标准库`log`、`logrus`、`zap`等。本文将重点介绍如何使用`zap`库,因为它具有高性能、结构化日志等优点,非常适合生产环境。

安装zap库

首先,使用以下命令安装`zap`库:

go get -u go.uber.org/zap
初始化日志器

在项目中创建一个独立的日志管理包`logger`,并在其中初始化`zap`日志器:

// logger/logger.go
package logger

import (
    "go.uber.org/zap"
    "go.uber.org/zap/zapcore"
    "os"
)

var Logger *zap.Logger

func InitLogger() {
    config := zap.Config{
      Encoding:         "json",
      Level:            zap.NewAtomicLevelAt(zap.InfoLevel),
      OutputPaths:      []string{"stdout", "./logs/app.log"},
      ErrorOutputPaths: []string{"stderr"},
      EncoderConfig: zapcore.EncoderConfig{
            TimeKey:      "time",
            LevelKey:       "level",
            NameKey:      "logger",
            CallerKey:      "caller",
            MessageKey:   "msg",
            StacktraceKey:"stacktrace",
            LineEnding:   zapcore.DefaultLineEnding,
            EncodeLevel:    zapcore.LowercaseLevelEncoder,
            EncodeTime:   zapcore.ISO8601TimeEncoder,
            EncodeDuration: zapcore.StringDurationEncoder,
            EncodeCaller:   zapcore.ShortCallerEncoder,
      },
    }

    var err error
    Logger, err = config.Build()
    if err != nil {
      panic(err)
    }
    defer Logger.Sync()
}
以上代码配置了`zap`日志器,将日志输出到控制台和文件,并使用JSON格式进行日志编码。

配置日志级别

日志级别在日志处理中非常重要,常见的级别有:Debug、Info、Warn、Error和Fatal。可以根据项目需求设置不同的日志级别。

在初始化`zap`日志器时,我们通过`zap.NewAtomicLevelAt`函数设置了日志级别为`InfoLevel`,即只有Info及以上级别的日志会被记录。如果需要在运行时动态调整日志级别,可以使用以下代码:

func SetLogLevel(level zapcore.Level) {
    atomicLevel := zap.NewAtomicLevel()
    atomicLevel.SetLevel(level)
    Logger = Logger.WithOptions(zap.WrapCore(func(core zapcore.Core) zapcore.Core {
      return core.With([]zapcore.CoreOption{
            zapcore.AddSync(os.Stdout),
            zapcore.AddSync(&lumberjack.Logger{
                Filename:   "./logs/app.log",
                MaxSize:    100, // megabytes
                MaxBackups: 3,
                MaxAge:   28, // days
            }),
      }...)
    }))
}
通过调用`SetLogLevel`函数,可以动态调整日志级别。

使用日志器

在项目的其他部分使用日志器时,可以通过`logger.Logger`进行日志记录。例如:

// main.go
package main

import (
    "myproject/logger"
)

func main() {
    logger.InitLogger()

    logger.Logger.Info("This is an info message")
    logger.Logger.Warn("This is a warning message")
    logger.Logger.Error("This is an error message")
}

这样,日志将统一按照指定的格式和级别输出。

高级功能

结构化日志

`zap`支持结构化日志,可以非常方便地记录带有上下文信息的日志。例如:

logger.Logger.Info("User logged in",
    zap.String("username", "johndoe"),
    zap.Int("userID", 123),
    zap.Time("loginTime", time.Now()))
这样输出的日志更易于解析和分析。

日志轮转

日志文件可能会随着时间增长而变大,我们可以使用`lumberjack`库来实现日志轮转。需要安装`lumberjack`库:

go get -u gopkg.in/natefinch/lumberjack.v2
并在`logger/logger.go`中进行如下修改:

import "gopkg.in/natefinch/lumberjack.v2"

// 在InitLogger中设置lumberjack日志轮转
config.OutputPaths = []string{"stdout", "./logs/app.log"}
config.ErrorOutputPaths = []string{"stderr"}
config.EncoderConfig = zapcore.EncoderConfig{
    ...
}
logWriter := zapcore.AddSync(&lumberjack.Logger{
    Filename:   "./logs/app.log",
    MaxSize:    100, // megabytes
    MaxBackups: 3,
    MaxAge:   28, // days
})
core := zapcore.NewCore(
    zapcore.NewJSONEncoder(config.EncoderConfig),
    zapcore.NewMultiWriteSyncer(logWriter, zapcore.AddSync(os.Stdout)),
    zap.NewAtomicLevelAt(zap.InfoLevel),
)
Logger = zap.New(core)

以上配置实现了日志文件轮转,每个日志文件最大100MB,最多保留3个备份,日志文件保存时间为28天。

结语

通过上述步骤,我们成功在Go项目中实现了统一的日志处理。使用`zap`日志库不仅可以提升日志记录的性能,还能让日志更加结构化和易于管理。

页: [1]
查看完整版本: Go 统一日志处理