프로그래밍(Web)/Golang

[바미] Go - Logrus과 lumberjack을 사용하여 Log를 찍어보자!

Bami 2021. 6. 25. 11:20
728x90
반응형

로그를 남길 때 일반 "log"패키지 외에도 로그를 남길 수 있는 방법이 있어 공유하고자 올립니다.

Logrus라는 패키지 인데요. 

 

사용 방법은 다음과 같습니다. 먼저 패키지를 다운받아 줍니다.

github.com/sirupsen/logrus

그 후 코드를 작성해봅시다.

package main

import (
  log "github.com/sirupsen/logrus"
)

func main() {
 // 기본 ASCII 포맷터 대신 JSON으로 로깅합니다.
  log.SetFormatter(&log.JSONFormatter{})

  // 기본 stderr 대신 stdout으로 출력하기 위해 사용.
  log.SetOutput(os.Stdout)

  // 지정된 모듈에 대한 로깅 수준을 설정 -> DebugLevel 이상 부터 로깅.
  log.SetLevel(log.DebugLevel)
  // 로그 내용.
  log.WithFields(log.Fields{
    "info": "Success",
  }).Info("정상적으로 동작합니다.")
}

 

 log.SetFormatter()의 경우 &log.JSONFormatter{}과 &log.TextFormatter로 나뉘는데 원하시는대로 사용하시면 됩니다.

 

그 중에서 &log.TextFormatter는 아래와 같은 옵션을 추가 할 수 있습니다.

ype TextFormatter struct {
	// Set to true to bypass checking for a TTY before outputting colors.
	ForceColors bool

	// Force disabling colors.
	DisableColors bool

	// Force quoting of all values
	ForceQuote bool

	// DisableQuote disables quoting for all values.
	// DisableQuote will have a lower priority than ForceQuote.
	// If both of them are set to true, quote will be forced on all values.
	DisableQuote bool

	// Override coloring based on CLICOLOR and CLICOLOR_FORCE. - https://bixense.com/clicolors/
	EnvironmentOverrideColors bool

	// Disable timestamp logging. useful when output is redirected to logging
	// system that already adds timestamps.
	DisableTimestamp bool

	// Enable logging the full timestamp when a TTY is attached instead of just
	// the time passed since beginning of execution.
	FullTimestamp bool

	// TimestampFormat to use for display when a full timestamp is printed.
	// The format to use is the same than for time.Format or time.Parse from the standard
	// library.
	// The standard Library already provides a set of predefined format.
	TimestampFormat string

	// The fields are sorted by default for a consistent output. For applications
	// that log extremely frequently and don't use the JSON formatter this may not
	// be desired.
	DisableSorting bool

	// The keys sorting function, when uninitialized it uses sort.Strings.
	SortingFunc func([]string)

	// Disables the truncation of the level text to 4 characters.
	DisableLevelTruncation bool

	// PadLevelText Adds padding the level text so that all the levels output at the same length
	// PadLevelText is a superset of the DisableLevelTruncation option
	PadLevelText bool

	// QuoteEmptyFields will wrap empty fields in quotes if true
	QuoteEmptyFields bool

	// Whether the logger's out is to a terminal
	isTerminal bool

	// FieldMap allows users to customize the names of keys for default fields.
	// As an example:
	// formatter := &TextFormatter{
	//     FieldMap: FieldMap{
	//         FieldKeyTime:  "@timestamp",
	//         FieldKeyLevel: "@level",
	//         FieldKeyMsg:   "@message"}}
	FieldMap FieldMap

	// CallerPrettyfier can be set by the user to modify the content
	// of the function and file keys in the data when ReportCaller is
	// activated. If any of the returned value is the empty string the
	// corresponding key will be removed from fields.
	CallerPrettyfier func(*runtime.Frame) (function string, file string)

	terminalInitOnce sync.Once

	// The max length of the level text, generated dynamically on init
	levelTextMaxLength int
}

만약 &log.TextFormatter로 사용하시겠다 하신다면

package main

import (
  log "github.com/sirupsen/logrus"
)

func main() {
 	// 기본 ASCII 포맷터 대신 Text로 로깅합니다.
	log.SetFormatter(&log.TextFormatter{
		FullTimestamp: true,
		ForceQuote:    true,
	})
  // 기본 stderr 대신 stdout으로 출력하기 위해 사용.
  log.SetOutput(os.Stdout)

  // 지정된 모듈에 대한 로깅 수준을 설정 -> DebugLevel 이상 부터 로깅.
  log.SetLevel(log.DebugLevel)
  // 로그 내용.
  log.WithFields(log.Fields{
    "info": "Success",
  }).Info("정상적으로 동작합니다.")
}

이런식으로 작성할 수 있는데 "" 찍어주는 옵션과 타임스탬프 옵션만 필요해서 위와 같이 작성하였습니다.

 

그래서 위의 코드를 동작시키면 터미널창에 해당 내용이 로그에 찍힐겁니다.

이런식으로 찍히게 되는데 이런식으로 찍으셔도 되고,

package main

import (
  log "github.com/sirupsen/logrus"
)

func main() {
 	// 기본 ASCII 포맷터 대신 Text로 로깅합니다.
	log.SetFormatter(&log.TextFormatter{
		FullTimestamp: true,
		ForceQuote:    true,
	})
  // 기본 stderr 대신 stdout으로 출력하기 위해 사용.
  log.SetOutput(os.Stdout)

  // 지정된 모듈에 대한 로깅 수준을 설정 -> DebugLevel 이상 부터 로깅.
  log.SetLevel(log.DebugLevel)
  // 로그 내용.
  log.Info("정상적으로 동작합니다.")
 }

이렇게 log.Info()를 사용하셔서 찍어주셔도 무방합니다. 결과는 동일합니다.

 

728x90

이렇게만 한다면 터미널에만 log 데이터가 찍히게 되는데 원하시는 것은 Log파일에 저 Log를 찍는 것을 원하실 겁니다.

이 때 사용하기 좋은 패키지가 lumberjack 이라는 패키지입니다.

 

먼저

go get gopkg.in/natefinch/lumberjack.v2

으로 패키지를 설치하여 주시고,  import 해봅시다!

 

package main

import (
  "gopkg.in/natefinch/lumberjack.v2"
  log "github.com/sirupsen/logrus"
)

func main() {
 	// 기본 ASCII 포맷터 대신 Text로 로깅합니다.
	log.SetFormatter(&log.TextFormatter{
		FullTimestamp: true,
		ForceQuote:    true,
	})
  // 기본 stderr 대신 stdout으로 출력하기 위해 사용.
  log.SetOutput(os.Stdout)

  // 지정된 모듈에 대한 로깅 수준을 설정 -> DebugLevel 이상 부터 로깅.
  log.SetLevel(log.DebugLevel)
  // 로그 내용.
  log.Info("정상적으로 동작합니다.")
 }

lumberjack의 사용 방법은 다음과 같은데요.

log.SetOutput(&lumberjack.Logger{
    Filename:   "log파일이 생성될 경로",
    MaxSize:    500,
    MaxBackups: 3, 
    MaxAge:     28,
    Compress:   true,
})

각 항목들의 설명은 다음과 같습니다.

  • Filename - log파일이 생성될 경로
  • MaxSize - log파일의 최대 사이즈. (MB 단위)
  • MaxBackups - 보존 할 최대 이전 로그 파일 수.
  • MaxAge - 타임 스탬프를 기준으로 오래된 로그 파일을 보관할 수있는 최대 일수.
  • Compress - 압축 여부를 결정. 기본값은 압축을 수행하지 않음.

이런식으로 구성되며 추가해보죠.

 

package main

import (
  "gopkg.in/natefinch/lumberjack.v2"
  log "github.com/sirupsen/logrus"
)

func main() {
  lum := &lumberjack.Logger{
        Filename:   "exam/exam.log",
        MaxSize:    500,
        MaxBackups: 3, 
        MaxAge:     28,
        Compress:   true,
  }
  // log파일에 출력되도록 수정.
  log.SetOutput(lum)
    
  // 기본 ASCII 포맷터 대신 Text로 로깅합니다.
  log.SetFormatter(&log.TextFormatter{
    FullTimestamp: true,
    ForceQuote:    true,
  })

  // 지정된 모듈에 대한 로깅 수준을 설정 -> DebugLevel 이상 부터 로깅.
  log.SetLevel(log.DebugLevel)
  
  // 로그 내용.
  log.Info("정상적으로 동작합니다.")
 }

이렇게 해준 뒤 실행을 하면 지정하신 경로에 폴더가 생성되고, log파일이 생성되어 파일안에 log가 작성되는 것을 확인 할 수 있습니다.

 

여기서 log.SetReportCaller(true) 옵션을 추가해주면 해당 이벤트 발생 하는 함수, 파일명이 찍히게 되어 오류가 났을 때 좀 더 원활하게 찾으실 수 있습니다.

package main

import (
  "gopkg.in/natefinch/lumberjack.v2"
  log "github.com/sirupsen/logrus"
)

func main() {
  lum := &lumberjack.Logger{
        Filename:   "exam/exam.log",
        MaxSize:    500,
        MaxBackups: 3, 
        MaxAge:     28,
        Compress:   true,
  }
  // log파일에 출력되도록 수정.
  log.SetOutput(lum)
    
  // 기본 ASCII 포맷터 대신 Text로 로깅합니다.
  log.SetFormatter(&log.TextFormatter{
    FullTimestamp: true,
    ForceQuote:    true,
  })

  // 지정된 모듈에 대한 로깅 수준을 설정 -> DebugLevel 이상 부터 로깅.
  log.SetLevel(log.DebugLevel)
  
  // 해당 이벤트 발생 하는 함수, 파일명이 찍힘.
  log.SetReportCaller(true)
  
  // 로그 내용.
  log.Info("정상적으로 동작합니다.")
 }

이렇게 추가해주시고 실행시켜주시면 다음과 같은 log가 출력 되실 겁니다.

time="2021-06-25T10:53:17+09:00" level="info" msg="정상적으로 동작합니다." func="go/main" file="C:/Users/DEV/Documents/go/main.go:30" 

 

긴 글 읽어주셔서 감사합니다. 도움 되셨길 바랍니다. 

혹시나 설명이 잘 못 되어 있는 부분이 있다면 언제든지 지적해주시면 빠른 시일내에 수정하도록 하겠습니다.

 

참조 문서 : https://pkg.go.dev/gopkg.in/natefinch/lumberjack.v2@v2.0.0
              https://pkg.go.dev/github.com/sirupsen/logrus#readme-logging-method-name

728x90
반응형