개요
- 런타임중 panic이 발생했을 경우, stacktrace가 출력되고 프로그램이 종료됨
- panic은 다른 언어의 Exception과 유사
- recover 및 추가 작업을 통해 프로그램 종료 없이 stacktrace 출력 구현
- recover는 다른 언어의 try...catch와 유사
- 또한 error가 발생한 경우에도 stacktrace를 출력 가능하도록 구현
코드1 (error 생성할때 stacktrace 추가)
errors.go
package errors
import (
"errors"
"fmt"
"runtime"
)
func New(message string) error {
stackTraceBuf := make([]byte, 1<<10)
runtime.Stack(stackTraceBuf, true)
return errors.New(fmt.Sprintf("%s\n, %s", message, stackTraceBuf))
}
repository.go
package repository
import (
"apiserver/server/model"
"apiserver/server/errors"
)
type AccountRepository struct {
}
func (r *AccountRepository) Select(nickname string) (*model.Account, error) {
return nil, errors.New("Not implement")
}
출력1
[Error] Not implement
, goroutine 20 [running]:
apiserver/server/errors.New({0x7b1871, 0xd})
D:/Dev/project/golang_APIServer/app/server/errors/errors.go:11 +0x4d
apiserver/server/repository.(*AccountRepository).Select(...)
D:/Dev/project/golang_APIServer/app/server/repository/account.go:14
apiserver/server/service.(*AccountService).GetAccount(...)
D:/Dev/project/golang_APIServer/app/server/service/account.go:13
apiserver/server/controller.(*AccountController).login(0xc0000ce0e0, 0xc0000fa9a0)
D:/Dev/project/golang_APIServer/app/server/controller/account.go:31 +0x73
github.com/gofiber/fiber/v2.(*App).next(0xc0000d0f00, 0xc00025c000)
C:/Users/natae/go/pkg/mod/github.com/gofiber/fiber/v2@v2.37.1/router.go:132 +0x1be
github.com/gofiber/fiber/v2.(*Ctx).Next(0xc00025e020)
C:/Users/natae/go/pkg/mod/github.com/gofiber/fiber/v2@v2.37.1/ctx.go:892 +0x53
apiserver/server.ResponsePrintMiddleware(0xc00025c000)
D:/Dev/project/golang_APIServer/app/server/middleware.go:35 +0x25
github.com/gofiber/fiber/v2.(*Ctx).Next(0x7b0b6b)
C:/User...
코드2 (panic 발생시 프로그램 종료없이 stacktrace 출력)
recover.go
func PrintPanicStack() {
defer func() {
if r := recover(); r != nil {
stackTraceBuf := make([]byte, 1<<10)
runtime.Stack(stackTraceBuf, true)
fmt.PrintF("PrintPanicStack: %v\n %s", r, stackTraceBuf)
}
}()
}
repository.go
package repository
import (
"apiserver/server/model"
)
type AccountRepository struct {
}
func (r *AccountRepository) Select(nickname string) (*model.Account, error) {
panic("Sorry")
}
출력2
[Error] PrintPanicStack: Sorry
goroutine 7 [running]:
apiserver/server.RecoverAndStackTraceMiddleware.func1()
D:/Dev/project/golang_APIServer/app/server/middleware.go:15 +0x7e
panic({0xdb77e0, 0xe87ac0})
C:/Program Files/Go/src/runtime/panic.go:1038 +0x215
apiserver/server/repository.(*AccountRepository).Select(...)
D:/Dev/project/golang_APIServer/app/server/repository/account.go:12
apiserver/server/service.(*AccountService).GetAccount(...)
D:/Dev/project/golang_APIServer/app/server/service/account.go:13
apiserver/server/controller.(*AccountController).login(0xc0000060f0, 0xc00013a840)
D:/Dev/project/golang_APIServer/app/server/controller/account.go:31 +0xfc
github.com/gofiber/fiber/v2.(*App).next(0xc000118f00, 0xc00029c000)
C:/Users/natae/go/pkg/mod/github.com/gofiber/fiber/v2@v2.37.1/router.go:132 +0x1be
github.com/gofiber/fiber/v2.(*Ctx).Next(0xc00029e020)
C:/Users/natae/go/pkg/mod/github.com/gofiber/fiber/v2@v2.37.1/ctx.go:892 +0x53
apiserver/server.ResponsePrintMiddleware(0xc00029c000)
D:/Dev/project/golang_APIServer/app...
결론
- 자세한 코드는 github 참고
- error에 stacktrace 추가하는 부분은 빈번하게 error가 발생할 경우, 부하를 발생시킬 수 있어서, 필요한 부분만 사용하는 게 좋을 것 같음