问题
I'm trying to migrate my application from the beautiful Logrus (very helpful for debug) and introducing the Uber log framework Zap.
With Logrus, i can initialize the logger only once and reuse it from other Go file, an example:
package main
import(
// Print filename on log
filename "github.com/onrik/logrus/filename"
// Very nice log library
log "github.com/sirupsen/logrus"
)
func main(){
// ==== SET LOGGING
Formatter := new(log.TextFormatter)
Formatter.TimestampFormat = "Jan _2 15:04:05.000000000"
Formatter.FullTimestamp = true
Formatter.ForceColors = true
log.AddHook(filename.NewHook()) // Print filename + line at every log
log.SetFormatter(Formatter)
}
From other Go file, i'm able to reuse that logger without any other initialization:
// VerifyCommandLineInput is delegated to manage the inputer parameter provide with the input flag from command line
func VerifyCommandLineInput() datastructures.Configuration {
log.Debug("VerifyCommandLineInput | Init a new configuration from the conf file")
c := flag.String("config", "./conf/test.json", "Specify the configuration file.")
flag.Parse()
if strings.Compare(*c, "") == 0 {
log.Fatal("VerifyCommandLineInput | Call the tool using --config conf/config.json")
}
file, err := os.Open(*c)
if err != nil {
log.Fatal("VerifyCommandLineInput | can't open config file: ", err)
}
defer file.Close()
decoder := json.NewDecoder(file)
cfg := datastructures.Configuration{}
err = decoder.Decode(&cfg)
if err != nil {
log.Fatal("VerifyCommandLineInput | can't decode config JSON: ", err)
}
log.Debug("VerifyCommandLineInput | Conf loaded -> ", cfg)
return cfg
}
My question is:
Using the Zap log framework, how can i initialize the log in the main function and use that logger from the other Go file?
Solution:
Initialize a new log and set as global as pointed by @Mikhail.
package main
import(
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)
func initZapLog() *zap.Logger {
config := zap.NewDevelopmentConfig()
config.EncoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder
config.EncoderConfig.TimeKey = "timestamp"
config.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
logger, _ := config.Build()
return logger
}
func main() {
loggerMgr := initZapLog()
zap.ReplaceGlobals(loggerMgr)
defer loggerMgr.Sync() // flushes buffer, if any
logger := loggerMgr.Sugar()
logger.Debug("START!")
db2.GetToken(`alessio`, `savi`, `pass`)
datastructure.LoadConfiguration()
}
Than you can use the logger in the other Go file:
func GetToken(url, user, pass string) string {
var User datastructure.User
var data string
var jsonData []byte
User.User = user
User.Pass = pass
jsonData, err := json.Marshal(User)
if err != nil {
zap.S().Errorw("Error during marshalling...", err)
return ""
}
data = string(jsonData)
zap.S().Info("Data encoded => ", data)
return ""
}
回答1:
You can set up your logger in the main function and call https://godoc.org/go.uber.org/zap#ReplaceGlobals to use it as a default global logger.
回答2:
Replacing the default go Global logger with zaps' implementation is possible, but discouraged.
Per their FAQ
Why include package-global loggers? Since so many other logging packages include a global logger, many applications aren't designed to accept loggers as explicit parameters. Changing function signatures is often a breaking change, so zap includes global loggers to simplify migration.
Avoid them where possible.
Depending on your needs, you can create a logger in main and pass it around or create a new logger in each package. I elected to create one in main and pass it around since I'm using an Atomic logger, which allows me to change log levels while my app is running via an API call. With a long history of using DI and consolidating code in general it does feel like code smell, but apparently it's significantly more performant for how zap works to pass it around over a singleton or global.
来源:https://stackoverflow.com/questions/57745017/zap-log-framework-go-initialize-log-once-and-reuse-from-other-go-file-solved