I tried using a log library called zap with reference to this article. Make a note of what you were addicted to about the Caller information that was logged at that time.
conf.Build (zap.AddCallerSkip (x)). *main/main.go: 30 is output.package main
import (
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	"time"
)
func main() {
	conf := zap.Config{
		Level:            zap.NewAtomicLevelAt(zap.DebugLevel),
		Development:      true,
		Encoding:         "console",
		OutputPaths:      []string{"stdout"},
		ErrorOutputPaths: []string{"stdout"},
		EncoderConfig: zapcore.EncoderConfig{
			LevelKey:     "level",
			TimeKey:      "time",
			MessageKey:   "msg",
			CallerKey:    "caller",
			EncodeTime:   zapcore.ISO8601TimeEncoder,
			EncodeLevel:  zapcore.LowercaseLevelEncoder,
			EncodeCaller: zapcore.ShortCallerEncoder,
		},
	}
	l, err := conf.Build()
	if err != nil {
		panic(err)
	}
	l.Info("Zap Start.", zap.Time("time", time.Now()))
}
// Output:
// 2021-01-04T23:46:14.963+0900    info    main/main.go:30 Zap Start.      {"time": "2021-01-04T23:46:14.963+0900"}
//The folder structure looks like this.
// main
// ├── go.mod
// ├── go.sum
// └── main.go
I wanted to reuse the zap instance once created to make it with a web application, so I made my own logger package.
No problem with this! I thought, log became logger/logger.go: 41.
Sure, it's logger/logger.go that calls the zap method, but I want to know the Caller that is one level higher.
As far as I read the source, it seems that it is not possible to specify the Caller one level higher in zap's Config.
Is there no choice but to output separately with the runtime package? .. ..
2021/1/6 postscript *
I found that it can be changed by specifying * conf.Build (zap.AddCallerSkip (x)). *
//The folder structure looks like this(It deviates from the Go standard, but this time it is simplified for explanation.)。
// main
// ├── go.mod
// ├── go.sum
// ├── main.go
// └── logger
//     └── logger.go
logger.go
package logger
import (
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
)
var (
	l *zap.Logger
)
func SetUp() error {
	conf := zap.Config{
		Level:            zap.NewAtomicLevelAt(zap.DebugLevel),
		Development:      true,
		Encoding:         "console",
		OutputPaths:      []string{"stdout"},
		ErrorOutputPaths: []string{"stdout"},
		EncoderConfig: zapcore.EncoderConfig{
			LevelKey:     "level",
			TimeKey:      "time",
			MessageKey:   "msg",
			CallerKey:    "caller",
			EncodeTime:   zapcore.ISO8601TimeEncoder,
			EncodeLevel:  zapcore.LowercaseLevelEncoder,
			EncodeCaller: zapcore.ShortCallerEncoder,
		},
	}
	var err error
	l, err = conf.Build()
	if err != nil {
		return err
	}
	return nil
}
func Info(msg string, fields ...zap.Field){
	l.Info(msg,fields...)
}
main.go
package main
import (
	"go.uber.org/zap"
	"main/logger"
	"time"
)
func main() {
	err := logger.SetUp()
	if err != nil {
		panic(err)
	}
	logger.Info("Zap Start.", zap.Time("time", time.Now()))
}
// Output:
// 2021-01-05T00:12:44.683+0900    info    logger/logger.go:41     Zap Start.      {"time": "2021-01-05T00:12:44.683+0900"}
//↑ Here logger/logger.not go, main/main.I want to go.
logger.go
package logger
import (
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
)
var (
	l    *zap.Logger
	Info func(msg string, fields ...zap.Field) //Here is change 1
)
func SetUp() error {
	conf := zap.Config{
		Level:            zap.NewAtomicLevelAt(zap.DebugLevel),
		Development:      true,
		Encoding:         "console",
		OutputPaths:      []string{"stdout"},
		ErrorOutputPaths: []string{"stdout"},
		EncoderConfig: zapcore.EncoderConfig{
			LevelKey:     "level",
			TimeKey:      "time",
			MessageKey:   "msg",
			CallerKey:    "caller",
			EncodeTime:   zapcore.ISO8601TimeEncoder,
			EncodeLevel:  zapcore.LowercaseLevelEncoder,
			EncodeCaller: zapcore.ShortCallerEncoder,
		},
	}
	var err error
	l, err = conf.Build()
	if err != nil {
		return err
	}
	Info = l.Info //Here is change 2
	return nil
}
Since main.go is the same as before, it is omitted. I got main/main.go safely. ↓ Output result
2021-01-05T00:19:47.157+0900    info    main/main.go:14 Zap Start.      {"time": "2021-01-05T00:19:47.157+0900"}
Based on the following policy, we finally made the following form.
zap.SugaredLogger (it is troublesome to write zap.field).zap.Logger only when you output many times and you really care about the speed.zap.Logger is Info and Warn only for the following reasons.I'm going to proceed with this logger.go
package logger
import (
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
)
var (
	l *zap.Logger
	s *zap.SugaredLogger
	Debug     func(args ...interface{})
	Info      func(args ...interface{})
	Warn      func(args ...interface{})
	Error     func(args ...interface{})
	Debugf    func(tmpl string, args ...interface{})
	Infof     func(tmpl string, args ...interface{})
	Warnf     func(tmpl string, args ...interface{})
	Errorf    func(tmpl string, args ...interface{})
	InfoQuick func(msg string, fields ...zap.Field)
	WarnQuick func(msg string, fields ...zap.Field)
)
func SetUp() error {
	//TODO:Allows you to set using environment variables
	conf := zap.Config{
		Level:            zap.NewAtomicLevelAt(zap.DebugLevel),
		Development:      true,
		Encoding:         "console",
		OutputPaths:      []string{"stdout"},
		ErrorOutputPaths: []string{"stdout"},
		EncoderConfig: zapcore.EncoderConfig{
			LevelKey:     "level",
			TimeKey:      "time",
			MessageKey:   "msg",
			CallerKey:    "caller",
			EncodeTime:   zapcore.ISO8601TimeEncoder,
			EncodeLevel:  zapcore.LowercaseLevelEncoder,
			EncodeCaller: zapcore.ShortCallerEncoder,
		},
	}
	var err error
	l, err = conf.Build()
	if err != nil {
		return err
	}
	s = l.Sugar()
	//Make the function DI in order to display the Log Caller correctly.
	//For example, another function func Debug(...){ s.Debug(...) }If defined as
	//All callers of the output log are logger/logger.It becomes go.
	Debug = s.Debug
	Info = s.Info
	Warn = s.Warn
	Error = s.Error
	Debugf = s.Debugf
	Infof = s.Infof
	Warnf = s.Warnf
	Errorf = s.Errorf
	InfoQuick = l.Info
	WarnQuick = l.Warn
	return nil
}
Recommended Posts