일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- 잠실새내 도그존
- graphql with RN
- 화이트 해커를 위한 웹 해킹의 기술
- 지보싶 신촌점
- graphql with reactnative
- 도그존
- 예쁜술집 예술
- 홍대 예술
- 고르드
- 앙버터마카롱
- apollo react native
- 비동기배열
- promise처리
- graphql mutation error
- typescript
- graphql
- graphql 400
- 토라비
- 홍대 카페 장쌤
- 신촌 소문난집
- 화이트해커를 위한 웹 해킹의 기술
- 잠실새내
- promise메서드
- apolloclient
- 홍대 토라비
- 금별맥주
- graphql react native
- 운정 소바동
- 비동기배열처리방법
- useMutation error
- Today
- Total
yehey's 공부 노트 \n ο(=•ω<=)ρ⌒☆
[golang] logger 추가하기, custom logger 생성하기 본문
Today I Learned
: golang 에서 log 패키지를 이용해서 logger를 만들고 custom logger 도 생성하기
배경
golang으로 프로젝트 진행하면서 로깅을 추가해야했음, 기왕 추가하는거 내가 원하는 정보만 담아서 (디버깅하기 좋은 정보) 로그를 남기고 싶었음
Contents
기본 logger
type Logger struct{
mu sync.Mutex
prefix string
flag int
out io.Writer
buf []byte
}
log 패키지에서 기본으로 제공하는 Logger 타입
log.Println("logging") //2020/12/30 10:27:11 Logging 으로 출력됨
log.SetFlag(0)
log.Println("logging") // 날짜 시간 없이 logging만 출력
기본으로 logger 생성 없이 log 사용 가능
logger 포맷 변경
go log 패키지에서 제공하는 flag 옵션들을 이용해서 로그 포맷을 변경할 수 있음
const (
Ldate = 1 << iota // the date in the local time zone: 2009/01/23
Ltime // the time in the local time zone: 01:23:23
Lmicroseconds // microsecond resolution: 01:23:23.123123. assumes Ltime.
Llongfile // full file name and line number: /a/b/c/d.go:23
Lshortfile // final file name element and line number: d.go:23. overrides Llongfile
LUTC // if Ldate or Ltime is set, use UTC rather than the local time zone
Lmsgprefix // move the "prefix" from the beginning of the line to before the message
LstdFlags = Ldate | Ltime // initial values for the standard logger
)
log.SetFlags(log.Ldate|log.Ltime|log.Llongfile)
log.setPrefix("INFO: ")
log.Println("Logging")
//INFO: 2020/12/30 15:41:20 /Users/ykoh/GolandProjects/tutorials-go/go-logging/go_logging_test.go:23: Logging
표준 입출력 말고 로그 파일에 쓰기
표준 입출력에서 확인하려 하면 개발 단에서는 편하고 좋지만, 실제 운영에서는 실행 로그들을 쭉쭉 올려가며 찾아야하는 점이 번거롭고 과거 로그들은 삭제되기도 함
그래서 운영 시 로그는 파일로 작성하는 것이 표준, 보통 5~10개 정도의 파일로 운영하고 (ex. log1, log2, log3,...) 만약 주어진 파일 개수가 끝나면 과거 로그 파일부터 덮어 쓰는 방식 (파일 다 쓰는 동안 지났던 로그는 필요 없다고 판단하는 듯)
logFile,err:=os.OpenFile("logfile.txt",os.O_CREATE|os.O_WRONLY|os.O_APPEND,0666)
if err!=nil{
panic(err)
}
defer logFile.Close()
log.SetOutPut(logFile)
log.Print("test")
logfile로 출력을 변경한 결과 위와 같이 로그가 파일로 저장됨
로그 파일에도 쓰고 표준 입출력에도 찍기
사실 개발을 할 때는 표준 입출력도 찍으면서 로그가 파일에 잘 저장되고 있는지가 궁금하기 때문에..
둘 다 할 수 있는 방법을 찾아보게 됐음
func Test_Multiple_Outputs(t *testing.T) {
logFile, err := os.OpenFile("logfile.txt", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
if err != nil {
panic(err)
}
defer logFile.Close()
multiWriter := io.MultiWriter(logFile, os.Stdout)
log.SetOutput(multiWriter)
printMsgLog("test msg")
log.Println("End of Program")
}
func printMsgLog(msg string) {
log.Print(msg)
}
크게 어려운건 없었고 MultiWriter
와 SetOutput
으로 설정 할 수 있음
custom logger
func New(out io.Writer, prefix string, flag int) *Logger{
return &Logger{out:out, prefix:prefix, flag:flag}
}
log.New() 함수를 이용해서 custom logger를 생성할 수 있다.
- 로그 output 지정
- os.Stdout, os.Stderr, 파일 포인터 등을 지정해서 output으로 사용할 수 있다.
- 로그 prefix
- 상태나 카테고리를 표시할 수 있다.
- 로그 포멧을 설정할 수 있다.
- 위에서 사용했던 flag를 조합해서 원하는 로그를 만들 수 있음
type Logger struct {
Trace *log.Logger
Warn *log.Logger
Info *log.Logger
Error *log.Logger
}
var myLogger Logger
func logInit(traceHandle io.Writer, infoHandle io.Writer, warningHandle io.Writer, errorHandle io.Writer) {
myLogger.Trace = log.New(traceHandle, "[TRACE] ", log.Ldate|log.Ltime|log.Lshortfile)
myLogger.Info = log.New(infoHandle, "[INFO] ", log.Ldate|log.Ltime|log.Lshortfile)
myLogger.Warn = log.New(warningHandle, "[WARNING] ", log.Ldate|log.Ltime|log.Lshortfile)
myLogger.Error = log.New(errorHandle, "[ERROR] ", log.Ldate|log.Ltime|log.Lshortfile)
}
func Test(t *testing.T) {
logInit(ioutil.Discard, os.Stdout, os.Stdout, os.Stderr)
myLogger.Info.Println("Starting the application...")
myLogger.Trace.Println("Something noteworthy happened")
myLogger.Warn.Println("There is something you should know about")
myLogger.Error.Println("Something went wrong")
//[INFO] 2020/12/30 15:43:40 go_logging_test.go:46: Starting the application...
//[WARNING] 2020/12/30 15:43:40 go_logging_test.go:48: There is something you should know about
//[ERROR] 2020/12/30 15:43:40 go_logging_test.go:49: Something went wrong
}
Example / Practice
package tools
import (
"backup/configs"
"io"
"log"
"os"
)
type logger struct {
Error *log.Logger
Info *log.Logger
}
var MyLogger logger
func LongInit(infoHandler io.Writer, errorHandler io.Writer) {
if _, err := os.Stat(configs.Config.LogFile + "debug.log"); os.IsNotExist(err) {
os.Create(configs.Config.LogFile + "debug.log")
}
logfile, err := os.OpenFile(configs.Config.LogFile+"debug.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
if err != nil {
panic(err)
}
// defer logfile.Close()
writer := io.MultiWriter(infoHandler, logfile)
MyLogger.Info = log.New(writer, "[INFO] ", log.Ldate|log.Ltime)
MyLogger.Error = log.New(writer, "[ERROR] ", log.Ldate|log.Ltime|log.Lshortfile)
}
Warning, Trace 등은 진행하고 있는 프로젝트에서 굳이 나눌 필요가 없다고 생각해서 생성하지 않았음
INFO 의 경우 원하는 메시지만 들어가면 된다고 생각해서 날짜와 시간만 출력,
ERROR의 경우에는 디버깅 시에 어떤 에러가 어느 파일에서 일어났는지 까지 알고 싶어서 file정보를 출력하도록 추가
Learned
golang 프로젝트에 logger, 더 나아가서 custom logger 까지 적용하는 방법을 배웠다.
프로젝트 진행 및 운영에 있어서 log의 중요성을 알았고 왜 적용해야 하는지, 현재 프로젝트에는 어떻게 적용해야 하는지를 생각하고 학습하니 잘 와닿았다.
What I Will Study
운영, 개발, staging 별로 log의 level을 다르게 적용하고 파일을 분리하는 등의 시도를 하고 싶다.
참조
https://pkg.go.dev/log#pkg-examples
https://blog.advenoh.pe.kr/go/Go에서의-로그깅-Logging-in-Go/
'개발 > Golang' 카테고리의 다른 글
DB 연결 (feat. env/v11) (0) | 2024.05.31 |
---|---|
[golang] 기본 문법 및 함수 (1) | 2023.11.19 |
[golang] http response unmarshal (with type struct) (0) | 2023.10.31 |