@@ -6,6 +6,8 @@ import com.fasterxml.jackson.databind.exc.MismatchedInputException
66import nexters.tuk.contract.ApiResponse
77import nexters.tuk.contract.BaseException
88import nexters.tuk.contract.ErrorType
9+ import nexters.tuk.infrastructure.slack.SlackAlertSender
10+ import nexters.tuk.infrastructure.slack.SlackErrorAlert
911import org.slf4j.LoggerFactory
1012import org.springframework.http.ResponseEntity
1113import org.springframework.http.converter.HttpMessageNotReadableException
@@ -14,33 +16,40 @@ import org.springframework.web.bind.annotation.RestControllerAdvice
1416import org.springframework.web.server.MissingRequestValueException
1517import org.springframework.web.server.ServerWebInputException
1618import org.springframework.web.servlet.resource.NoResourceFoundException
19+ import jakarta.servlet.http.HttpServletRequest
20+ import java.time.ZonedDateTime
1721
1822@RestControllerAdvice
19- class ApiControllerAdvice {
23+ class ApiControllerAdvice (
24+ private val slackAlertSender : SlackAlertSender
25+ ) {
2026 private val log = LoggerFactory .getLogger(ApiControllerAdvice ::class .java)
2127
2228 @ExceptionHandler
23- fun handle (e : BaseException ): ResponseEntity <ApiResponse <* >> {
29+ fun handle (e : BaseException , request : HttpServletRequest ): ResponseEntity <ApiResponse <* >> {
2430 log.warn(" BaseException : {}" , e.message, e)
31+ sendSlackAlert(request, e.errorType, e.message)
2532 return failureResponse(errorType = e.errorType, errorMessage = e.message)
2633 }
2734
2835 @ExceptionHandler
29- fun handle (e : IllegalArgumentException ): ResponseEntity <ApiResponse <* >> {
36+ fun handle (e : IllegalArgumentException , request : HttpServletRequest ): ResponseEntity <ApiResponse <* >> {
3037 log.warn(" BaseException : {}" , e.message, e)
38+ sendSlackAlert(request, ErrorType .BAD_REQUEST , e.message)
3139 return failureResponse(errorType = ErrorType .BAD_REQUEST , errorMessage = e.message)
3240 }
3341
3442 @ExceptionHandler
35- fun handle (e : MissingRequestValueException ): ResponseEntity <ApiResponse <* >> {
43+ fun handle (e : MissingRequestValueException , request : HttpServletRequest ): ResponseEntity <ApiResponse <* >> {
3644 val name = e.methodParameter?.parameter?.name
3745 val type = e.methodParameter?.parameter?.type?.simpleName
3846 val message = " 필수 요청 파라미터 '$name ' (타입: $type )가 누락되었습니다."
47+ sendSlackAlert(request, ErrorType .BAD_REQUEST , message)
3948 return failureResponse(errorType = ErrorType .BAD_REQUEST , errorMessage = message)
4049 }
4150
4251 @ExceptionHandler
43- fun handle (e : HttpMessageNotReadableException ): ResponseEntity <ApiResponse <* >> {
52+ fun handle (e : HttpMessageNotReadableException , request : HttpServletRequest ): ResponseEntity <ApiResponse <* >> {
4453 val errorMessage = when (val rootCause = e.rootCause) {
4554 is InvalidFormatException -> {
4655 val fieldName = rootCause.path.joinToString(" ." ) { it.fieldName ? : " ?" }
@@ -74,11 +83,12 @@ class ApiControllerAdvice {
7483 else -> " 요청 본문을 처리하는 중 오류가 발생했습니다. JSON 메세지 규격을 확인해주세요."
7584 }
7685
86+ sendSlackAlert(request, ErrorType .BAD_REQUEST , errorMessage)
7787 return failureResponse(errorType = ErrorType .BAD_REQUEST , errorMessage = errorMessage)
7888 }
7989
8090 @ExceptionHandler
81- fun handleBadRequest (e : ServerWebInputException ): ResponseEntity <ApiResponse <* >> {
91+ fun handleBadRequest (e : ServerWebInputException , request : HttpServletRequest ): ResponseEntity <ApiResponse <* >> {
8292 val errorMessage = when (val rootCause = e.rootCause) {
8393 is InvalidFormatException -> {
8494 val fieldName = rootCause.path.joinToString(" ." ) { it.fieldName ? : " ?" }
@@ -114,19 +124,27 @@ class ApiControllerAdvice {
114124 else -> " 요청 본문을 처리하는 중 오류가 발생했습니다. JSON 메세지 규격을 확인해주세요."
115125 }
116126
127+ sendSlackAlert(request, ErrorType .BAD_REQUEST , errorMessage)
117128 return failureResponse(errorType = ErrorType .BAD_REQUEST , errorMessage = errorMessage)
118129 }
119130
120131 @ExceptionHandler
121- fun handleNotFound (e : NoResourceFoundException ): ResponseEntity <ApiResponse <* >> {
132+ fun handleNotFound (e : NoResourceFoundException , request : HttpServletRequest ): ResponseEntity <ApiResponse <* >> {
133+ val message = " 리소스를 찾을 수 없습니다: ${request.requestURI} "
134+ sendSlackAlert(request, ErrorType .NOT_FOUND , message)
122135 return failureResponse(errorType = ErrorType .NOT_FOUND )
123136 }
124137
125138 @ExceptionHandler
126- fun handle (e : Throwable ): ResponseEntity <ApiResponse <* >> {
139+ fun handle (e : Throwable , request : HttpServletRequest ): ResponseEntity <ApiResponse <* >> {
127140 log.error(" Exception : {}" , e.message, e)
128- val errorType = ErrorType .INTERNAL_ERROR
129- return failureResponse(errorType = errorType)
141+ val message = e.message ? : " 알 수 없는 서버 오류가 발생했습니다"
142+ sendSlackAlert(request, ErrorType .INTERNAL_ERROR , message)
143+ return failureResponse(errorType = ErrorType .INTERNAL_ERROR )
144+ }
145+
146+ private fun sendSlackAlert (request : HttpServletRequest , errorType : ErrorType , errorMessage : String? = null) {
147+ slackAlertSender.sendAlert(SlackErrorAlert (errorType.status.value(), request.method, request.requestURI, ZonedDateTime .now(), errorMessage ? : errorType.message))
130148 }
131149
132150 private fun failureResponse (errorType : ErrorType , errorMessage : String? = null): ResponseEntity <ApiResponse <* >> =
0 commit comments