Does Zap logger support escape character '\n' and '\t' to print new line errorVerbose or stacktrace

huangapple go评论117阅读模式
英文:

Does Zap logger support escape character '\n' and '\t' to print new line errorVerbose or stacktrace

问题

func InitLogger() {
	loggerMgr, err := zap.NewProduction()
	if err != nil {
		log.Println("error")
	}
	defer loggerMgr.Sync()
	logger := loggerMgr.Sugar()
	logger.Error("START!")
}

结果

> {"level":"error","ts":1635248463.347698,"caller":"cgw-go-utils/main.go:36","msg":"START!","stacktrace":"main.raiseError\n\t/Users/I053322/dev/repo/cgw-go-utils/main.go:36\nmain.main\n\t/Users/I053322/dev/repo/cgw-go-utils/main.go:22\nruntime.main\n\t/usr/local/opt/go/libexec/src/runtime/proc.go:225"}

我想要带有转义的结果

{"level":"error","ts":1635248463.347698,"caller":"cgw-go-utils/main.go:36","msg":"START!","stacktrace":"main.raiseError
	/Users/I053322/dev/repo/cgw-go-utils/main.go:36
main.main
	/Users/I053322/dev/repo/cgw-go-utils/main.go:22
runtime.main
	/usr/local/opt/go/libexec/src/runtime/proc.go:225"}
英文:
func InitLogger() {
	loggerMgr, err := zap.NewProduction()
	if err != nil {
		log.Println("error")
	}
	defer loggerMgr.Sync()
	logger := loggerMgr.Sugar()
	logger.Error("START!")
}

The result

> {"level":"error","ts":1635248463.347698,"caller":"cgw-go-utils/main.go:36","msg":"START!","stacktrace":"main.raiseError\n\t/Users/I053322/dev/repo/cgw-go-utils/main.go:36\nmain.main\n\t/Users/I053322/dev/repo/cgw-go-utils/main.go:22\nruntime.main\n\t/usr/local/opt/go/libexec/src/runtime/proc.go:225"}

I want to get the result with escape of

{"level":"error","ts":1635248463.347698,"caller":"cgw-go-utils/main.go:36","msg":"START!","stacktrace":"main.raiseError
	/Users/I053322/dev/repo/cgw-go-utils/main.go:36
main.main
	/Users/I053322/dev/repo/cgw-go-utils/main.go:22
runtime.main
	/usr/local/opt/go/libexec/src/runtime/proc.go:225"}

答案1

得分: 1

不。

zap.NewProduction() 返回一个带有 JSON 编码的记录器,转义序列如 \n\t 会被 直接 编码成 JSON。如果不这样做,它将不是有效的 JSON。

如果你真的需要这样做,并且可以接受生成无效的 JSON,你可以通过装饰现有的 zap JSON 编码器来实现自己的编码器。

示例代码:

package main

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

func main() {
	core := zapcore.NewCore(
		&EscapeSeqJSONEncoder{Encoder: zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig())},
		os.Stdout,
		zapcore.InfoLevel,
	)
	logger := zap.New(core)
	logger.Info("foo", zap.String("some_field", "foo\nbar"))
}

type EscapeSeqJSONEncoder struct {
	zapcore.Encoder
}

func (enc *EscapeSeqJSONEncoder) Clone() zapcore.Encoder {
	return enc // TODO: change me
}

func (enc *EscapeSeqJSONEncoder) EncodeEntry(entry zapcore.Entry, fields []zapcore.Field) (*buffer.Buffer, error) {
	// 调用嵌入接口的 EncodeEntry 方法以获取原始输出
	b, err := enc.Encoder.EncodeEntry(entry, fields)
	if err != nil {
		return nil, err
	}
	newb := buffer.NewPool().Get()

	// 然后将输出转换为所需的格式
	newb.Write(bytes.Replace(b.Bytes(), []byte("\\n"), []byte("\n"), -1))
	return newb, nil
}

输出:

{"level":"info","ts":1635257984.618096,"msg":"foo","some_field":"foo\nbar"}

注意:函数 zapcore.NewCore 接受一个 zapcore.Encoder 参数,该参数是一个接口。这个接口实现起来非常麻烦。我们的想法是将其嵌入到自定义的结构体中,这样你就可以免费获得所有的方法。

英文:

No.

zap.NewProduction() returns a logger with JSON encoding, and escape sequences as \n and \t are encoded verbatim into JSON. If it didn't, it wouldn't be valid JSON.

If you really must, and you are okay with producing invalid JSON, you might implement your own encoder by decorating the existing zap JSON encoder.

Demonstrative code:

package main

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

func main() {
	core := zapcore.NewCore(
		&EscapeSeqJSONEncoder{ Encoder: zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig()) },
		os.Stdout,
		zapcore.InfoLevel,
	)
	logger := zap.New(core)
	logger.Info("foo", zap.String("some_field", "foo\nbar"))
}

type EscapeSeqJSONEncoder struct {
	zapcore.Encoder
}

func (enc *EscapeSeqJSONEncoder) Clone() zapcore.Encoder {
	return enc // TODO: change me
}

func (enc *EscapeSeqJSONEncoder) EncodeEntry(entry zapcore.Entry, fields []zapcore.Field) (*buffer.Buffer, error) {
    // call EncodeEntry on the embedded interface to get the 
    // original output
	b, err := enc.Encoder.EncodeEntry(entry, fields)
	if err != nil {
		return nil, err
	}
	newb := buffer.NewPool().Get()

    // then manipulate that output into what you need it to be
	newb.Write(bytes.Replace(b.Bytes(), []byte("\\n"), []byte("\n"), -1))
	return newb, nil
}

Outputs:

{"level":"info","ts":1635257984.618096,"msg":"foo","some_field":"foo
bar"}

<hr>

Notes: the function zapcore.NewCore takes a zapcore.Encoder argument, which is an interface. This interface is very troublesome to implement. The idea is to embed it in your custom struct, so that you get all the methods for free.

答案2

得分: 0

你可以将zap.Config的编码设置为'console'

zapConfig := zap.Config{
	Level:       level,
	Development: false,
	Sampling: &zap.SamplingConfig{
		Initial:    100,
		Thereafter: 100,
	},
	Encoding:         "console",
	EncoderConfig:    zapEncoderConfig,
	OutputPaths:      []string{"stderr"},
	ErrorOutputPaths: []string{"stderr"},
}

return zapConfig.Build()
英文:

You can set zap.Config encoding as 'console'

zapConfig := zap.Config{
	Level:       level,
	Development: false,
	Sampling: &amp;zap.SamplingConfig{
		Initial:    100,
		Thereafter: 100,
	},
	Encoding:         &quot;console&quot;,
	EncoderConfig:    zapEncoderConfig,
	OutputPaths:      []string{&quot;stderr&quot;},
	ErrorOutputPaths: []string{&quot;stderr&quot;},
}

return zapConfig.Build()

huangapple
  • 本文由 发表于 2021年10月26日 19:43:29
  • 转载请务必保留本文链接:https://go.coder-hub.com/69722488.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定