Home  >  Article  >  Backend Development  >  How to use configuration files to configure Logger elegantly while supporting log rotation

How to use configuration files to configure Logger elegantly while supporting log rotation

王林
王林forward
2024-02-10 20:50:08918browse

如何使用配置文件优雅地配置 Logger,同时支持日志轮转

php editor Zimo will share with you how to use configuration files to elegantly configure Logger and implement log rotation. Logger is a commonly used logging tool that can help us record the running status of applications to facilitate troubleshooting and log tracking. When using Logger, you can flexibly define the log format, output target, log level, etc. through the configuration file. You can also configure log rotation rules to achieve automatic management and storage of logs. Through reasonable configuration, we can achieve more flexible and efficient logging and management. In this article, we will introduce in detail how to use configuration files to elegantly configure Logger and support log rotation.

Question content

Problem description

  • Function: test1() is the log rotation and cutting library recommended by the official document ngopkg.in/natefinch/lumberjack.v2.
  • Function: test2() is a logger that uses yaml to read the configuration according to the basic configuration in the official document.

After executing the main function,

Output in the console:

2023-05-15t08:49:16.555 0800 |info|Logger build successful: configuration from yaml | {"app":"jpz"}

Output in the log file foo.log:

{"level":"info","ts":1684111756.5545945,"msg":"Logger built successfully: lumberjack.logger"}

These two logs are definitely different.

My current requirements:

  1. Both support using the configuration file config_log_zap.yaml to make all configurations effective and let lumberjack complete the log rotation and splitting work.

  2. The console and log file output should be the same so I can quickly apply what I need via the config file. The console and log files are needed because I need to follow and record past output messages during development.

    Output in the console:

    2023-05-15t08:49:16.555 0800 |info|Logger build successful: configuration from yaml | {"app":"jpz"}

    Output in the log file foo.log:

    2023-05-15t08:49:16.555 0800 |info|Logger build successful: configuration from yaml | {"app":"jpz"}

  3. How to combine test1() and test2() into one function test0() to satisfy the above two requirements?

Please give me some help, I've been working on this for a long time.

main.go

package main

import (
    "gopkg.in/yaml.v3"
    "os"

    "go.uber.org/zap"
    "go.uber.org/zap/zapcore"
    "gopkg.in/natefinch/lumberjack.v2"
)

func test1() {
    // lumberjack.logger is already safe for concurrent use, so we don't need to
    // lock it.
    w := zapcore.addsync(&lumberjack.logger{
        filename:   "./foo.log",
        maxsize:    500, // megabytes
        maxbackups: 3,
        maxage:     28, // days
    })
    core := zapcore.newcore(
        zapcore.newjsonencoder(zap.newproductionencoderconfig()),
        w,
        zap.infolevel,
    )
    logger := zap.new(core)
    logger.info("logger construction succeeded:lumberjack.logger")
}

func test2() {
    var cfg zap.config
    yamlfile, _ := os.readfile("./config_log_zap.yaml")
    if err := yaml.unmarshal(yamlfile, &cfg); err != nil {
        panic(err)
    }

    logger := zap.must(cfg.build())
    defer logger.sync()

    logger.info("logger construction succeeded:config from yaml")
}

func main() {
    test1()
    test2()
}

config_log_zap.yaml

# For the full description for the configuration, see
# https://github.com/uber-go/zap/blob/382e2511e51cda8afde24f9e6e741f934308edfa/config.go#L58-L94
level: 'debug'
development: true
disableCaller: true
disableStacktrace: false
sampling:
  initial: 100
  thereafter: 100
encoding: 'console'
encoderConfig:
  messageKey: 'msg'
  levelKey: 'level'
  timeKey: 'ts'
  nameKey: 'logger'
  callerKey: 'caller'
  functionKey: 'function'
  stacktraceKey: 'stacktrace'
  skipLineEnding: false
  lineEnding: "\n"
  levelEncoder: 'capital'
  timeEncoder: 'iso8601'
  durationEncoder: 'string'
  callerEncoder: 'full'
  nameEncoder: 'full'
  consoleSeparator: ' | '
outputPaths:
  - 'stdout'
  - './foo.log'
errorOutputPaths:
  - 'stderr'
  - './error_logs'
initialFields:
  app: 'jpz'

Workaround

Use zap.registersink to register the lumberjack logger as a new sink:

package main

import (
    "net/url"
    "os"
    "strconv"
    "strings"

    "gopkg.in/yaml.v3"

    "go.uber.org/zap"
    "gopkg.in/natefinch/lumberjack.v2"
)

type lumberjacksink struct {
    lumberjack.logger
}

func (l *lumberjacksink) sync() error {
    return nil
}

func parsenumber(s string, fallback int) int {
    v, err := strconv.atoi(s)
    if err == nil {
        return v
    }
    return fallback
}

func test0() {
    if err := zap.registersink("lumberjack", func(u *url.url) (zap.sink, error) {
        // read parameters from url:
        // lumberjack://localhost/foo.log?maxsize=500&maxbackups=3&maxage=28
        filename := strings.trimleft(u.path, "/")
        if filename == "" {
            filename = "foo.log"
        }
        q := u.query()
        l := &lumberjacksink{
            logger: lumberjack.logger{
                filename:   filename,
                maxsize:    parsenumber(q.get("maxsize"), 500),
                maxbackups: parsenumber(q.get("maxbackups"), 3),
                maxage:     parsenumber(q.get("maxage"), 28),
            },
        }
        return l, nil
    }); err != nil {
        panic(err)
    }

    var cfg zap.config
    yamlfile, _ := os.readfile("./config_log_zap.yaml")
    if err := yaml.unmarshal(yamlfile, &cfg); err != nil {
        panic(err)
    }

    logger := zap.must(cfg.build())
    defer logger.sync()

    logger.info("logger construction succeeded:config from yaml")
}

func main() {
    test0()
}

And modify the configuration file to set outputpaths as follows:

outputPaths:
  - stdout
  - lumberjack://localhost/foo.log?maxSize=500&maxBackups=3&maxAge=28

The above is the detailed content of How to use configuration files to configure Logger elegantly while supporting log rotation. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:stackoverflow.com. If there is any infringement, please contact admin@php.cn delete