Go zerolog와 lumberjack 같이쓰기

Go에서 로깅을 할때 기본 제공되는 log 라이브러리를 사용하는 개발자는 아마 거의 없을 것이다.

zap, zerolog, logrus 등이 많이 사용되는데 성능과 사용성을 모두 잡은 zerolog를 추천해본다.

간단한 서버 만들기

먼저 보일러플레이트를 먼저 작성해본다.

/ 로 GET 요청이 오면 “ok”를 반환하도록 echo 프레임워크를 사용해 간단한 서버를 구현했다.

package main

import (
	"net/http"

	"github.com/labstack/echo/v4"
)

func main() {
	e := echo.New()
	e.GET("/", func(c echo.Context) error {
		return c.String(http.StatusOK, "ok")
	})

	e.Logger.Fatal(e.Start(":8080"))
}

go run main.go 명령으로 서버를 띄우고 localhost:8080에 접속해 보면 “ok” 메시지를 확인할 수 있다.

zerolog, lumberjack 추가하기

이제 본격적으로 zerolog와 lumberjack을 추가해본다.

전체 코드는 아래와 같다.

package main

import (
	"net/http"

	"github.com/labstack/echo/v4"
	"github.com/labstack/echo/v4/middleware"
	"github.com/rs/zerolog"
	"gopkg.in/natefinch/lumberjack.v2"
)

func main() {
	e := echo.New()
	fileLogger := &lumberjack.Logger{
		Filename:   "request.log",
		MaxSize:    10,
		MaxBackups: 3,
		MaxAge:     1,
		Compress:   true,
	}

	logger := zerolog.New(fileLogger)
	e.Use(middleware.RequestLoggerWithConfig(middleware.RequestLoggerConfig{
		LogURI:    true,
		LogStatus: true,
		LogValuesFunc: func(c echo.Context, v middleware.RequestLoggerValues) error {
			logger.Info().Str("URI", v.URI).Int("status", v.Status).Time("time", v.StartTime.Local()).Msg("Request")

			return nil
		},
	}))

	e.GET("/", func(c echo.Context) error {
		return c.String(http.StatusOK, "ok")
	})

	logger.Fatal().Err(e.Start(":8080")).Msg("Server started")
}

간단하지만 조금 나눠서 보자.

  1. lumberjack을 활용한 log 파일 생성 및 log rotation
  2. zerolog에 lumberjack instance 할당
  3. echo 설정을 통해 http 요청이 zerolog를 통해 로깅되도록 설정

이렇게 3단계로 접근하게 된다.

lumberjack을 이용한 log 파일 생성 및 log rotation

fileLogger := &lumberjack.Logger{
		Filename:   "request.log",
		MaxSize:    10,
		MaxBackups: 3,
		MaxAge:     1,
		Compress:   true,
	}
  • Filename에는 log파일의 이름과 생성되길 바라는 path를 포함해 적는다.예) /var/log/request.log
  • MaxSize는 log가 rotation되길 바라는 최대 사이즈를 MB 단위로 명시한다.
  • MaxAge는 day 단위로 rotation을 결정한다.

참고) lumberjack 공식문서

zerolog에 lumberjack 인스턴스 할당

아래처럼 zerolog 인스턴스를 생성하면서 lumberjack을 이용해 만든 롤링 로거 인스턴스를 할당한다.

logger := zerolog.New(fileLogger)

echo 설정을 통해 http 요청이 zerolog를 통해 로깅되도록 설정

HTTP 요청을 로깅하는 부분은 같은 go 언어더라도 사용하는 프레임워크에 따라 달라지게 된다. 여기서는 echo를 중심으로 설명한다.

e.Use(middleware.RequestLoggerWithConfig(middleware.RequestLoggerConfig{
		LogURI:    true,
		LogStatus: true,
		LogValuesFunc: func(c echo.Context, v middleware.RequestLoggerValues) error {
			logger.Info()
        .Str("URI", v.URI)
        .Int("status", v.Status)
        .Time("time", v.StartTime.Local())
        .Msg("Request")

			return nil
		},
	}))

echo에서 넘겨준 RequestLoggerValues를 활용해 logging을 하며, URI, status, time, message(”Request”)를 로깅하도록 코드를 작성했다.

이외에도 필요한 내용이 있다면 위 코드처럼 체인 형태로 필요한 것들을 추가해 작성해주면 된다.

공식문서에 logger별로 middleware 설정하는 방법이 잘 안내되어 있다.

참고) echo 공식문서 - logger

검토

go run main.go 를 실행하고 localhost:8080에 GET 요청을 날려 디렉토리 내에 request.log 파일이 잘 생성되었는지, request 요청이 잘 로깅되었는지 확인한다.