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