千锋教育-做有情怀、有良心、有品质的职业教育机构

手机站
千锋教育

千锋学习站 | 随时随地免费学

千锋教育

扫一扫进入千锋手机站

领取全套视频
千锋教育

关注千锋学习站小程序
随时随地免费学习课程

当前位置:首页  >  技术干货  > 女性工程师分享Golang实现日志系统的经验

女性工程师分享Golang实现日志系统的经验

来源:千锋教育
发布人:xqq
时间: 2023-12-21 13:15:49 1703135749

女性工程师分享:Golang实现日志系统的经验

随着软件开发项目的逐渐复杂化,日志系统的作用也越发重要。日志系统不仅可以提供调试信息,还可以分析程序性能、监控系统运行状况。本文将向大家分享如何使用 Golang 实现一个高效、可扩展的日志系统。

1. 日志系统的需求分析

在实现日志系统之前,我们需要先明确日志系统的需求。

- 支持不同级别的日志记录,如 Debug、Info、Warning、Error、Critical 等;

- 支持将日志输出到控制台或者文件;

- 支持按照时间或者文件大小进行分割日志;

- 支持可配置化。

2. Golang 日志库的选择

在 Golang 中,有很多日志库可以选择。在本文中,我们选择使用 Zap 作为日志库,原因如下:

- Zap 是 Uber 开源的一个高性能日志库,支持多种日志级别、输出方式和分割策略等;

- Zap 采用了高效的无锁机制,并且对内存使用进行了优化,可以大大提高性能;

- Zap 支持多线程和多协程的并发输出,可以满足高并发场景的需求。

下面是使用 Zap 输出日志的示例代码:

package mainimport (    "go.uber.org/zap"    "go.uber.org/zap/zapcore")func main() {    logger, _ := zap.NewDevelopment(zap.AddStacktrace(zapcore.FatalLevel))    defer logger.Sync()    logger.Debug("Debug log")    logger.Info("Info log")    logger.Warn("Warn log")    logger.Error("Error log")    logger.Panic("Panic log")}

3. 日志系统的实现

在明确了需求并选择了日志库之后,我们就可以开始实现日志系统了。

3.1 日志级别

在日志系统中,不同级别的日志信息需要有不同的颜色或者标识符。我们可以使用颜色库 color 来设置不同级别的日志颜色,示例代码如下:

package loggerimport (    "fmt"    "log"    "os"    "github.com/fatih/color"    "go.uber.org/zap"    "go.uber.org/zap/zapcore")var (    logger *zap.Logger)// LogLevel 日志级别type LogLevel uint8const (    // DebugLevel 调试级别    DebugLevel LogLevel = iota    // InfoLevel 普通信息级别    InfoLevel    // WarnLevel 警告级别    WarnLevel    // ErrorLevel 错误级别    ErrorLevel    // PanicLevel 严重错误级别    PanicLevel)var levelColors = func(...interface{}) string{    color.New(color.FgHiCyan).SprintFunc(),    color.New(color.FgHiGreen).SprintFunc(),    color.New(color.FgHiYellow).SprintFunc(),    color.New(color.FgHiRed).SprintFunc(),    color.New(color.FgHiRed, color.Bold).SprintFunc(),}func levelColor(l LogLevel) func(...interface{}) string {    if l >= DebugLevel && l <= PanicLevel {        return levelColors    }    return color.New(color.Faint).SprintFunc()}func init() {    encoderConfig := zap.NewDevelopmentEncoderConfig()    encoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder    logger = zap.New(zapcore.NewCore(        zapcore.NewConsoleEncoder(encoderConfig),        zapcore.Lock(os.Stdout),        zap.NewAtomicLevelAt(zapcore.InfoLevel),    ))}// Debug debug级别日志func Debug(msg string, fields ...zap.Field) {    logger.Debug(msg, fields...)}// Info info级别日志func Info(msg string, fields ...zap.Field) {    logger.Info(msg, fields...)}// Warn warn级别日志func Warn(msg string, fields ...zap.Field) {    logger.Warn(msg, fields...)}// Error error级别日志func Error(msg string, fields ...zap.Field) {    logger.Error(msg, fields...)}// Panic panic级别日志func Panic(msg string, fields ...zap.Field) {    logger.Panic(msg, fields...)}// Println 输出日志func Println(l LogLevel, format string, v ...interface{}) {    fmtMsg := fmt.Sprintf(format, v...)    lColor := levelColor(l)    lName := logLevelName(l)    msg := fmt.Sprintf(" %s", lColor(lName), fmtMsg)    log.Println(msg)}// logLevelName 获取日志级别名称func logLevelName(l LogLevel) string {    switch l {    case DebugLevel:        return "DEBUG"    case InfoLevel:        return "INFO"    case WarnLevel:        return "WARN"    case ErrorLevel:        return "ERROR"    default:        return "PANIC"    }}

在上面的代码中,我们使用 LogLevel 枚举类型来表示不同级别的日志信息,使用 levelColors 数组来存储不同级别的日志颜色,通过 levelColor 函数来根据级别获取对应的颜色函数。在输出日志时,我们先使用 Zap 来输出级别符号和日志信息,然后使用 log.Println 函数将日志信息输出到控制台。

3.2 日志输出方式

我们通过 zapcore 包中的 WriteSyncer 接口来实现不同的日志输出方式,示例代码如下:

package loggerimport (    "io/ioutil"    "log"    "os"    "time"    "go.uber.org/zap"    "go.uber.org/zap/zapcore")const (    maxLogSize  = 100 // 每个日志文件的最大大小,单位 MB    maxAge      = 30  // 日志文件的最长保留时间,单位天    timeFormat  = "2006-01-02 15:04:05.000"    rotateEvery = 24 * time.Hour)var (    fileLogger *zap.Logger)func init() {    encoderConfig := zap.NewProductionEncoderConfig()    encoderConfig.EncodeTime = zapcore.TimeEncoderOfLayout(timeFormat)    encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder    encoderConfig.EncodeCaller = zapcore.ShortCallerEncoder    logger := zap.New(zapcore.NewCore(        zapcore.NewConsoleEncoder(encoderConfig),        zapcore.Lock(os.Stdout),        zap.NewAtomicLevelAt(zapcore.InfoLevel),    ))    fileLogger = zap.New(zapcore.NewCore(        zapcore.NewConsoleEncoder(encoderConfig),        zapcore.AddSync(newRotateFileWriter("logs", "app")),        zap.NewAtomicLevelAt(zapcore.InfoLevel),    ))    logger = logger.WithOptions(zap.AddCallerSkip(1))    fileLogger = fileLogger.WithOptions(zap.AddCallerSkip(1))}// SetLogFile 设置日志文件名func SetLogFile(name string) {    fileLogger.WithOptions(zap.AddCallerSkip(1))}// newRotateFileWriter 返回一个支持按文件大小和时间分割的 io.Writerfunc newRotateFileWriter(dir, prefix string) zapcore.WriteSyncer {    return zapcore.AddSync(&zapcore.RotateFile{        Filename:   prefix + ".log",        MaxSize:    maxLogSize,        MaxAge:     maxAge,        LocalTime:  true,        Compress:   true,        Interval:   rotateEvery,        Permissions: 0644,        Lumberjack: &lumberjack.Logger{            Filename:   filepath.Join(dir, prefix+".log"),            MaxSize:    maxLogSize,            MaxAge:     maxAge,            LocalTime:  true,            Compress:   true,            Permissions: 0644,        },    })}

在上面的代码中,我们定义了一个 newRotateFileWriter 函数来返回一个支持按文件大小和时间进行分割的 io.Writer,其中使用了 github.com/natefinch/lumberjack 包来实现文件的日志轮转。我们还定义了一个 SetLogFile 函数,用于设置日志文件的名称。

3.3 日志可配置化

最后,我们需要将日志系统可配置化。我们可以通过读取配置文件来设置日志级别、输出方式等参数,示例代码如下:

package loggerimport (    "os"    "github.com/spf13/viper"    "go.uber.org/zap")// Config 日志配置type Config struct {    Level        string // 日志级别    Output       string // 日志输出方式    RotateByHour bool   // 是否按小时进行日志分割}var (    conf Config)// Init 初始化日志配置func Init() {    viper.SetConfigName("config") // 配置文件名称    viper.AddConfigPath(".")      // 配置文件路径    viper.SetConfigType("yml")    // 配置文件类型    if err := viper.ReadInConfig(); err != nil {        panic(err)    }    if err := viper.Unmarshal(&conf); err != nil {        panic(err)    }    level := zap.NewAtomicLevel()    if err := level.UnmarshalText(byte(conf.Level)); err != nil {        panic(err)    }    fileLogger = fileLogger.WithOptions(zap.WrapCore(func(core zapcore.Core) zapcore.Core {        return zapcore.NewLevelEnabler(core.Enabled(level))    }))    if conf.Output == "file" {        SetLogFile("app")    }}

在上面的代码中,我们使用 github.com/spf13/viper 包来读取配置文件,将配置项映射到 Config 结构体中,并根据配置项来设置日志级别和输出方式。

4. 结论

通过本文的介绍,我们可以知道如何使用 Golang 实现一个高效、可扩展的日志系统。在实现过程中,我们需要注意性能、安全和可维护性等方面,同时也需要考虑扩展性和可配置化。最后,希望本文能对您有所帮助。

以上就是IT培训机构千锋教育提供的相关内容,如果您有web前端培训鸿蒙开发培训python培训linux培训,java培训,UI设计培训等需求,欢迎随时联系千锋教育。

tags:
声明:本站稿件版权均属千锋教育所有,未经许可不得擅自转载。
10年以上业内强师集结,手把手带你蜕变精英
请您保持通讯畅通,专属学习老师24小时内将与您1V1沟通
免费领取
今日已有369人领取成功
刘同学 138****2860 刚刚成功领取
王同学 131****2015 刚刚成功领取
张同学 133****4652 刚刚成功领取
李同学 135****8607 刚刚成功领取
杨同学 132****5667 刚刚成功领取
岳同学 134****6652 刚刚成功领取
梁同学 157****2950 刚刚成功领取
刘同学 189****1015 刚刚成功领取
张同学 155****4678 刚刚成功领取
邹同学 139****2907 刚刚成功领取
董同学 138****2867 刚刚成功领取
周同学 136****3602 刚刚成功领取
相关推荐HOT