Golang中Zerolog将错误写入stderr其他内容写入stdout的实现方法

Golang中Zerolog将错误写入stderr其他内容写入stdout的实现方法 你好,

说实话,我有点困惑。我的一个Git仓库收到了一个问题反馈,他们问我是否可以将项目的错误信息输出到stderr,而其他所有内容输出到stdout。我正在使用zerolog和lumberjack来在命令行和文件之间分割输出。有人能帮助我或为我指明正确的方向吗?

package logger

import (
	"io"
	"os"
	"path"

	"gickup/types"

	"github.com/rs/zerolog"
	"github.com/rs/zerolog/log"
	"gopkg.in/natefinch/lumberjack.v2"
)

func NewRollingFile(config types.FileLogging) io.Writer {
	if config.Dir != "" {
		if err := os.MkdirAll(config.Dir, 0744); err != nil {
			log.Error().Err(err).Str("path", config.Dir).Msg("can't create log directory")
			return nil
		}

更多关于Golang中Zerolog将错误写入stderr其他内容写入stdout的实现方法的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于Golang中Zerolog将错误写入stderr其他内容写入stdout的实现方法的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


使用Zerolog实现错误日志到stderr、其他日志到stdout,可以通过MultiLevelWriter配合LevelWriter实现。以下是具体实现方法:

package logger

import (
    "io"
    "os"
    "path"

    "github.com/rs/zerolog"
    "github.com/rs/zerolog/log"
    "gopkg.in/natefinch/lumberjack.v2"
)

// 创建分级输出writer
func createLevelWriters(config types.FileLogging) zerolog.LevelWriter {
    // 创建文件writer
    fileWriter := &lumberjack.Logger{
        Filename:   path.Join(config.Dir, "app.log"),
        MaxSize:    config.MaxSize,
        MaxBackups: config.MaxBackups,
        MaxAge:     config.MaxAge,
        Compress:   config.Compress,
    }

    // 创建MultiLevelWriter,将不同级别日志路由到不同输出
    multiWriter := zerolog.MultiLevelWriter(
        // 错误及以上级别写入stderr
        zerolog.LevelWriterAdapter{
            Writer: zerolog.SyncWriter(os.Stderr),
            Level:  zerolog.ErrorLevel,
        },
        // 所有级别都写入文件
        zerolog.LevelWriterAdapter{
            Writer: fileWriter,
            Level:  zerolog.TraceLevel,
        },
        // 除错误外的其他级别写入stdout
        zerolog.LevelWriterAdapter{
            Writer: zerolog.SyncWriter(os.Stdout),
            Level:  zerolog.NoLevel, // 匹配所有级别
            ExcludeLevels: []zerolog.Level{
                zerolog.ErrorLevel,
                zerolog.FatalLevel,
                zerolog.PanicLevel,
            },
        },
    )

    return multiWriter
}

func NewRollingFile(config types.FileLogging) io.Writer {
    if config.Dir != "" {
        if err := os.MkdirAll(config.Dir, 0744); err != nil {
            log.Error().Err(err).Str("path", config.Dir).Msg("can't create log directory")
            return nil
        }
    }

    return createLevelWriters(config)
}

// 初始化logger使用示例
func setupLogger(config types.FileLogging) {
    writer := NewRollingFile(config)
    if writer == nil {
        return
    }

    logger := zerolog.New(writer).With().Timestamp().Logger()
    zerolog.DefaultContextLogger = &logger

    // 测试日志输出
    logger.Info().Msg("普通信息到stdout和文件")
    logger.Warn().Msg("警告信息到stdout和文件")
    logger.Error().Msg("错误信息到stderr和文件")
    logger.Debug().Msg("调试信息到stdout和文件")
}

如果需要更细粒度的控制,可以使用自定义Writer实现:

type splitWriter struct {
    stdout io.Writer
    stderr io.Writer
    file   io.Writer
}

func (w *splitWriter) WriteLevel(level zerolog.Level, p []byte) (n int, err error) {
    // 错误级别写入stderr
    if level >= zerolog.ErrorLevel {
        n, err = w.stderr.Write(p)
        if err != nil {
            return n, err
        }
    } else {
        // 其他级别写入stdout
        n, err = w.stdout.Write(p)
        if err != nil {
            return n, err
        }
    }
    
    // 所有级别都写入文件
    _, err = w.file.Write(p)
    return n, err
}

func (w *splitWriter) Write(p []byte) (n int, err error) {
    // 默认写入stdout(用于无级别日志)
    return w.stdout.Write(p)
}

func createSplitWriter(config types.FileLogging) zerolog.LevelWriter {
    fileWriter := &lumberjack.Logger{
        Filename:   path.Join(config.Dir, "app.log"),
        MaxSize:    config.MaxSize,
        MaxBackups: config.MaxBackups,
        MaxAge:     config.MaxAge,
        Compress:   config.Compress,
    }

    return &splitWriter{
        stdout: zerolog.SyncWriter(os.Stdout),
        stderr: zerolog.SyncWriter(os.Stderr),
        file:   fileWriter,
    }
}

这样配置后,错误级别(Error、Fatal、Panic)的日志会输出到stderr,其他级别的日志输出到stdout,所有日志都会写入文件。

回到顶部