When using the zap library in your own Logger with Golang, how to put the hierarchy above Logger in Caller

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.

review

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

trouble

//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.

solution

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"}

Final Logger shape

Based on the following policy, we finally made the following form.

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

When using the zap library in your own Logger with Golang, how to put the hierarchy above Logger in Caller
Try HeloWorld in your own language (with How to & code)
How to use the C library in Python
How to pass the path to the library built with pyenv and virtualenv in PyCharm
How to define your own target in Sage
How to deal with SessionNotCreatedException when using Selenium
How to display in the entire window when setting the background image with tkinter
Steps to install your own library with pip
What I did when I was angry to put it in with the enable-shared option
Call your own C library with Go using cgo
Complement the library you put in anaconda with jedi-vim
How to access with cache when reading_json in pandas
Try to put LED in your own PC (slightly)
How to exit when using Python in Terminal (Mac)
[Linux] How to put your IP in a variable
How to deal with the terminal getting into the pipenv environment without permission when using pipenv with vscode
[Ansible] How to call variables when creating your own module
How to debug the Python standard library in Visual Studio
How to not load images when using PhantomJS with Selenium
How to use pyenv and pyenv-virtualenv in your own way
How to manipulate the DOM in an iframe with Selenium
How to resolve CSRF Protection when using AngularJS with Django
How to generate a query using the IN operator in Django
Things to keep in mind when using Python with AtCoder
Notes on how to use marshmallow in the schema library
Things to keep in mind when using cgi with python.
How to write when you want to put a number after the group number to be replaced with a regular expression in re.sub of Python
How to not escape Japanese when dealing with json in python
How to display formulas in latex when using sympy (> = 1.4) in Google Colaboratory
Make the theme of Pythonista 3 like Monokai (how to make your own theme)
How to use python put in pyenv on macOS with PyCall
How to make your own domain site with heroku (free plan)
[Beginner memo] How to specify the library reading path in Python
How to create your own Transform
[Python] How to import the library
How to deal with OAuth2 error when using Google APIs from Python
Put your own image data in Deep Learning and play with it
How to fix the initial population with a genetic algorithm using DEAP
[python] How to add RDF triples to your own Fuseki server using rdflib
How to access data with object ['key'] for your own Python class
How to deal with the problem that Japanese characters are garbled when outputting logs using JSON log formatter
How to correctly upgrade the software when building Linux (CentOS) with Vagrant ~ Using the example of upgrading from Python 2.7 to Python 3.6 ~
How to run your own app in real (SHARP 304SH) without going through Google Play using Android Studio