zap은 Time, Time % to zap을 보았을 때 가장 빠르게 작동한다. 다만,Objects Allcated를 보았을 때는 object당 할당되는 것이 구조화되게끔 작성해야한다는 것을 알 수 있다.
https://github.com/uber-go/zap
SugaredLogger
구조화된 로깅 패키지보다 4-10배 정도 빠르기를 가지며 구조화된 logging, printf style logging지원, key-value 쌍을 허용한다.
sugar := zap.NewExample().Sugar()
defer sugar.Sync()
sugar.Infow("failed to fetch URL",
"url", "http://example.com",
"attempt", 3,
"backoff", time.Second,
)
sugar.Infof("failed to fetch URL: %s", "http://example.com") // printf형식도 지원
https://github.com/uber-go/zap/blob/master/sugar.go 에서 supar logger 확인이 가능하다.
// Infow logs a message with some additional context. The variadic key-value
// pairs are treated as they are in With.
func (s *SugaredLogger) Infow(msg string, keysAndValues ...interface{}) {
s.log(InfoLevel, msg, nil, keysAndValues)
}
sugar.Infow를 확인해보면 위와 같다. infow는 method and receiver 구성이 되어있고 sugar를 pointer를 통해 참조하여 그 값을 사용할 수 있다.
msg를 첫번재 arg로 이후에는 keyAndValues...interface()를 두번째 ars로 가진다. 따라서 sugar.Infow에 key-value 구성이 3가지 존재하는 것을 확인할 수 있다. 또한 코드에서 Infof를 통해 printf형식도 지원하는 것을 알 수 있다.
결과는 아래와 같다.
{"level":"info","msg":"failed to fetch URL","url":"http://example.com" ,"attempt":3,"backoff":"1s"}
{"level":"info","msg":"failed to fetch URL: http://example.com"}
Logger
할당량이 적지만 훨씬 빠르고 강력한 형식의 구조화된 로딩만 지원한다.
logger := zap.NewExample()
defer logger.Sync()
logger.Info("failed to fetch URL",
zap.String("url", "http://example.com"),
zap.Int("attempt", 3),
zap.Duration("backoff", time.Second),
)
sugar는 key-value였고 infow였던 것에 비해서 keyAndValues와 다르게 더욱 구조화되어있다는 것을 확인할 수 있다.
결과는 아래와 같다 :
{"level":"info","msg":"failed to fetch URL","url":"http://example.com" ,"attempt":3,"backoff":"1s"}
flag란 깃발. 즉, 무엇에 대해서 서로의 약속을 정하거나 기억해야할 때 사용한다.
https://pkg.go.dev/github.com/spf13/pflag#section-readme
pointer를 활용해 flag를 설정
package안에 활용할 수 있는 func이 많지만 그 하나를 살펴보자.
StringVarP 는 receiver와 함께 사용되고 있다.
// StringVarP is like StringVar, but accepts a shorthand letter that can be used after a single dash.
func StringVarP(p *string, name, shorthand string, value string, usage string) {
CommandLine.VarP(newStringValue(value, p), name, shorthand, usage)
}
FlagSet struct를 pointer를 통해서 접근하여 그 값을 건드린다. args에는 가장 처음으로 문자열 그 다음으로는 설정할 이름을 적는다. 이후 shorthand string값으로 약식 문자를 적는다. flag의 value가 될 value를 마지막으로 string usage를 넘겨준다.
viper는 구성 형식에 대해서 걱정하지 않기 위해 사용한다. config file을 빌드하고 비정렬화를 진행한다.
pointer와 receiver를 활용한 viper활용
func SetConfigFile(in string) { v.SetConfigFile(in) }
func (v *Viper) SetConfigFile(in string) {
if in != "" {
v.configFile = in
}
}
이때, SetconfigFile을 v object에 접근하여 configFile값을 argument인 string type in 변수로 configFile이 넣어진다.
type Option struct{}를 만들어 구성요소에 logger, flag, viper, loglevel 등을 넣을 수 있다.
그렇다면 Option struct를 활용하여 객체로 만들고 sugar logger와 pflag, 그리고 viper를 활용할 수 있다.
생성한 객체에 대한 setting이 다 되었다면 sugar를 통해서 logging을 진행한다.
logging을 진행할때, sugar를 사용하면 되지만 컨테이너 환경에서 관리할 때 환경 설정을 바꾸거나 더 편리한 세팅을 위하여 pflag, viper를 함께 struct로 관리하여 객체지향적으로 관리하기에 참고하면 좋겠다!