๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด/Go

[Go] ์‹ค๋ฌด ํ™˜๊ฒฝ์—์„œ ๋กœ๊ทธ ์ œ๋Œ€๋กœ ๋‚จ๊ธฐ๊ธฐ(Logging)

by ์„œ์•„๋ž‘๐Ÿ˜ƒ 2025. 11. 10.

 

๋“ค์–ด๊ฐ€๋ฉฐ

24์‹œ๊ฐ„ ์„œ๋ฒ„๋ฅผ ์šด์˜ํ•˜๋Š” ์‹ค๋ฌดํ™˜๊ฒฝ์—์„œ๋Š” ์–ธ์ œ ์–ด๋–ค ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ• ์ง€ ๋ชจ๋ฆ…๋‹ˆ๋‹ค. ์ด๋ฏธ ์ด์Šˆ๊ฐ€ ๋ฐœ์ƒํ•œ ์ƒํƒœ์—์„œ ๊ธฐ์ˆ ์ž๋“ค์ด ์ œ์ผ ๋จผ์ € ํ™•์ธํ•˜๋Š” ๊ฒƒ๋“ค์€ "๋กœ๊ทธ"์ž…๋‹ˆ๋‹ค. ๋ชจ๋“  ์‹œ์Šคํ…œ์—๋Š” ์ด๋ฒคํŠธ ๋ฐœ์ƒ์‹œ ๋กœ๊ทธ๋ฅผ ์ฐ๊ฒŒ ๋˜๊ธฐ ๋•Œ๋ฌธ์—, ์–ธ์–ด์™€ ํ”„๋ ˆ์ž„์›Œํฌ ๋“ฑ ํ™˜๊ฒฝ์ด ๋ฐ”๋€Œ๋”๋ผ๋„ ๋ณด๊ธฐ ํŽธํ•˜๊ฒŒ ๋กœ๊ทธ ํ™˜๊ฒฝ ์„ค์ •๋ถ€ํ„ฐ ํ•˜๋Š” ๊ฒƒ์ด ์ผ๋ฐ˜์ ์ž…๋‹ˆ๋‹ค.

 

lorus

go์—์„œ๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ logํŒจํ‚ค์ง€๊ฐ€ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ํ† ์ดํ”„๋กœ์ ํŠธ์—์„œ๋Š” logํŒจํ‚ค์ง€๋งŒ ์‚ฌ์šฉํ•ด๋„ ๋ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์šฐ๋ฆฌ๋Š” ์‹ค๋ฌดํ™˜๊ฒฝ์—์„œ ์‚ฌ์šฉํ•ด์•ผํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์กฐ๊ธˆ๋” ๋งŽ์€ ๊ธฐ๋Šฅ์„ ์ง€์›ํ•˜๋Š” ์„œ๋“œํŒŒํ‹ฐ ํŒจํ‚ค์ง€๋ฅผ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. logrus๋Š”  go์˜ log ํŒจํ‚ค์ง€์™€ ํ˜ธํ™˜๋˜๋ฉด์„œ ์ƒ์œ„ ์ง‘ํ•ฉ์ฒด๋ผ๊ณ  ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.(๊ณต์‹ ๋งํฌ)

go get -u github.com/sirupsen/logrus

์•„๋ž˜์™€ ๊ฐ™์ด ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

package main

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

var log = logrus.New()

func main() {
	// ๋กœ๊ทธ ์ถœ๋ ฅ ํฌ๋งท ์„ค์ •
	log.SetFormatter(&logrus.TextFormatter{
		FullTimestamp: true,
	})

	// ๋กœ๊ทธ ์ถœ๋ ฅ ์œ„์น˜
	log.SetOutput(os.Stdout)

	// ๋กœ๊ทธ ๋ ˆ๋ฒจ ์„ค์ •
	log.SetLevel(logrus.DebugLevel)

	log.Debug("๋””๋ฒ„๊ทธ ๋กœ๊ทธ์ž…๋‹ˆ๋‹ค.")
	log.Info("์ •๋ณด ๋กœ๊ทธ์ž…๋‹ˆ๋‹ค.")
	log.Warn("๊ฒฝ๊ณ  ๋กœ๊ทธ์ž…๋‹ˆ๋‹ค.")
	log.Error("์—๋Ÿฌ ๋กœ๊ทธ์ž…๋‹ˆ๋‹ค.")
}

 

lumberjack

lumberjack์€ ๋กœ๊ทธ ํŒŒ์ผ ์ €์žฅ ๊ธฐ๊ฐ„, ์šฉ๋Ÿ‰, ๋กœ๊ทธ ๋กœํ…Œ์ด์…˜, ํŒŒ์ผ ์ €์žฅ ๋“ฑ์˜ ํŽธ์˜ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. (๊ณต์‹ ๋งํฌ)

go get github.com/natefinch/lumberjack
package main

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

func main() {
	log := logrus.New()

	// ํŒŒ์ผ ํšŒ์ „ ์„ค์ •
	log.SetOutput(&lumberjack.Logger{
		Filename:   "logs/app.log",
		MaxSize:    10, // MB
		MaxBackups: 5,
		MaxAge:     7,  // days
		Compress:   true,
	})

	log.SetFormatter(&logrus.JSONFormatter{}) // JSON ํฌ๋งท
	log.SetLevel(logrus.InfoLevel)

	log.Info("์„œ๋ฒ„ ์‹œ์ž‘")
	log.Warn("๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰ ๋†’์Œ")
	log.Error("DB ์—ฐ๊ฒฐ ์‹คํŒจ")
}

 

 

์ตœ์ข… ์„ธํŒ…

logger ํŒจํ‚ค์ง€ ๋‚ด logger.go ๋ชจ๋“ˆ ํŒŒ์ผ์„ ์ƒ์„ฑํ•˜๊ณ  ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.

// Package logger
package logger

import (
	"io"
	"os"

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

var Log = InitLogger("dev")

func InitLogger(env string) *logrus.Logger {
	log := logrus.New()
	log.SetOutput(io.MultiWriter(
		os.Stdout,
		&lumberjack.Logger{
			Filename:   "logs/myapp.log",
			MaxSize:    10, // MB
			MaxBackups: 5,
			MaxAge:     7, // days
			Compress:   true,
		}))

	log.SetFormatter(&logrus.TextFormatter{
		FullTimestamp:   true,
		TimestampFormat: "2006-01-02 15:04:05",
		ForceColors:     true,
	})
	log.SetReportCaller(true)
	log.SetLevel(logrus.InfoLevel)

	return log
}

func Info(args ...interface{})          { Log.Info(args...) }
func Warn(args ...interface{})          { Log.Warn(args...) }
func Error(args ...interface{})         { Log.Error(args...) }
func Debug(args ...interface{})         { Log.Debug(args...) }
func Infof(f string, a ...interface{})  { Log.Infof(f, a...) }
func Warnf(f string, a ...interface{})  { Log.Warnf(f, a...) }
func Errorf(f string, a ...interface{}) { Log.Errorf(f, a...) }
func Debugf(f string, a ...interface{}) { Log.Debugf(f, a...) }

logrus์˜ SetFormatter์˜ ์ธ์ž๋ฅผ &logrus.JSONFormatter{} ํ˜•ํƒœ๋กœ ์„ค์ •ํ•˜๋Š” ๊ฒฝ์šฐ๋„ ๋งŽ์Šต๋‹ˆ๋‹ค. ์ €๋Š” ์ปค์Šคํ…€ ํ…์ŠคํŠธ ํฌ๋งท์œผ๋กœ ์ง„ํ–‰ํ–ˆ์Šต๋‹ˆ๋‹ค. TimestampFormat์— ๋“ค์–ด๊ฐ€๋Š” ๊ฐ’์€ Go์˜ ๊ณ ์ •๋œ time layout ํŒจํ„ด์ด๊ธฐ ๋•Œ๋ฌธ์— ์ž„์˜๋กœ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค(์‹ ๊ธฐ).

 

๊ทธ๋ฆฌ๊ณ  ๋กœ๊ฑฐ ๋ชจ๋“ˆ ํ•˜๋‹จ์˜ wrapping ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•˜์—ฌ ์™ธ๋ถ€ ํŒจํ‚ค์ง€์—์„œ logger.Info(...)์™€ ๊ฐ™์ด ์‚ฌ์šฉํ•ด๋„ ๋˜์ง€๋งŒ, ๋กœ๊ทธ๋ฅผ ํ˜ธ์ถœํ•œ ํŒŒ์ผ ์ •๋ณด๋ฅผ ๋‚จ๊ธฐ๋Š” SetReportCaller์—์„œ ๋ชจ๋‘ logger.wrappingํ•จ์ˆ˜๋งŒ ๊ฐ€๋ฆฌํ‚ค๊ณ  ์žˆ์–ด์„œ ์ €๋Š” logger.Log.Info(...)์™€ ๊ฐ™์ด ํ˜ธ์ถœํ•  ๊ณ„ํš์ž…๋‹ˆ๋‹ค.

 

๋˜, SetOutput์˜ ์„ค์ •์—์„œ io.MultiWriter์— Stdout๊ณผ lumberjack๋ฅผ ๊ฐ™์ด ๋„ฃ์–ด์„œ ๋กœ๊ทธํŒŒ์ผ write๊ณผ ์ฝ˜์†”์ถœ๋ ฅ๊นŒ์ง€ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ–ˆ์Šต๋‹ˆ๋‹ค.

 

main์—์„œ loging ํ…Œ์ŠคํŠธ๋ฅผ ํ•ด๋ด…๋‹ˆ๋‹ค.

package main

import (
	"fmt"
	"runtime"

	"myapp/logger"
)

func main() {
	logger.Log.Infof("=== Go Trading Bot ===")
	logger.Log.Infof("Go Version: %s\n", runtime.Version())
	logger.Log.Infof("OS/Arch: %s/%s\n", runtime.GOOS, runtime.GOARCH)
	logger.Log.Infof("Environment configured successfully!")
}
INFO[2025-11-10 14:44:24]/home/user/myapp/main.go:11 main.main() === Go Trading Bot ===                       
INFO[2025-11-10 14:44:24]/home/user/myapp/main.go:12 main.main() Go Version: go1.24.10                        
INFO[2025-11-10 14:44:24]/home/user/myapp/main.go:13 main.main() OS/Arch: linux/amd64                         
INFO[2025-11-10 14:44:24]/home/user/myapp/main.go:14 main.main() Environment configured successfully!

 

log/myapp์—๋„ ๋กœ๊ทธํŒŒ์ผ์— ๋‚ด์šฉ์ด ์“ฐ์—ฌ์ง€๋ฉด์„œ ์ฝ˜์†”์—๋„ ์ถœ๋ ฅ๋ฉ๋‹ˆ๋‹ค.

๋Œ“๊ธ€