[#26] 모니터링 환경 구성 #27

Merged
pricelees merged 14 commits from feature/#26 into main 2025-07-29 06:49:56 +00:00
Showing only changes of commit 5e0a52cb47 - Show all commits

View File

@ -2,55 +2,110 @@ package roomescape.common.exception
import io.github.oshai.kotlinlogging.KLogger import io.github.oshai.kotlinlogging.KLogger
import io.github.oshai.kotlinlogging.KotlinLogging import io.github.oshai.kotlinlogging.KotlinLogging
import org.slf4j.MDC
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity import org.springframework.http.ResponseEntity
import org.springframework.http.converter.HttpMessageNotReadableException import org.springframework.http.converter.HttpMessageNotReadableException
import org.springframework.web.bind.MethodArgumentNotValidException import org.springframework.web.bind.MethodArgumentNotValidException
import org.springframework.web.bind.annotation.ExceptionHandler import org.springframework.web.bind.annotation.ExceptionHandler
import org.springframework.web.bind.annotation.RestControllerAdvice import org.springframework.web.bind.annotation.RestControllerAdvice
import roomescape.auth.exception.AuthException
import roomescape.common.dto.response.CommonErrorResponse import roomescape.common.dto.response.CommonErrorResponse
import roomescape.common.log.ApiLogMessageConverter
import roomescape.common.log.ConvertResponseMessageRequest
import roomescape.common.log.LogType
private val log: KLogger = KotlinLogging.logger {}
@RestControllerAdvice @RestControllerAdvice
class ExceptionControllerAdvice( class ExceptionControllerAdvice(
private val log: KLogger = KotlinLogging.logger {} private val messageConverter: ApiLogMessageConverter
) { ) {
@ExceptionHandler(value = [RoomescapeException::class]) @ExceptionHandler(value = [RoomescapeException::class])
fun handleRoomException(e: RoomescapeException): ResponseEntity<CommonErrorResponse> { fun handleRoomException(e: RoomescapeException): ResponseEntity<CommonErrorResponse> {
val errorCode: ErrorCode = e.errorCode val errorCode: ErrorCode = e.errorCode
val httpStatus: HttpStatus = errorCode.httpStatus
val errorResponse = CommonErrorResponse(errorCode)
val type = if (e is AuthException) LogType.AUTHENTICATION_FAILURE else LogType.APPLICATION_FAILURE
logException(
type = type,
httpStatus = httpStatus.value(),
errorResponse = errorResponse,
exception = e
)
return ResponseEntity return ResponseEntity
.status(errorCode.httpStatus) .status(httpStatus)
.body(CommonErrorResponse(errorCode, e.message)) .body(errorResponse)
} }
@ExceptionHandler(value = [HttpMessageNotReadableException::class]) @ExceptionHandler(value = [MethodArgumentNotValidException::class, HttpMessageNotReadableException::class])
fun handleHttpMessageNotReadableException(e: HttpMessageNotReadableException): ResponseEntity<CommonErrorResponse> { fun handleInvalidRequestValueException(e: Exception): ResponseEntity<CommonErrorResponse> {
log.debug { "message: ${e.message}" } val message: String = if (e is MethodArgumentNotValidException) {
e.bindingResult.allErrors
.mapNotNull { it.defaultMessage }
.joinToString(", ")
} else {
e.message!!
}
log.debug { "[ExceptionControllerAdvice] Invalid Request Value Exception occurred: $message" }
val errorCode: ErrorCode = CommonErrorCode.INVALID_INPUT_VALUE val errorCode: ErrorCode = CommonErrorCode.INVALID_INPUT_VALUE
return ResponseEntity val httpStatus: HttpStatus = errorCode.httpStatus
.status(errorCode.httpStatus) val errorResponse = CommonErrorResponse(errorCode)
.body(CommonErrorResponse(errorCode))
}
@ExceptionHandler(value = [MethodArgumentNotValidException::class]) logException(
fun handleMethodArgumentNotValidException(e: MethodArgumentNotValidException): ResponseEntity<CommonErrorResponse> { type = LogType.APPLICATION_FAILURE,
val message: String = e.bindingResult.allErrors httpStatus = httpStatus.value(),
.mapNotNull { it.defaultMessage } errorResponse = errorResponse,
.joinToString(", ") exception = e
log.debug { "message: $message" } )
val errorCode: ErrorCode = CommonErrorCode.INVALID_INPUT_VALUE
return ResponseEntity return ResponseEntity
.status(errorCode.httpStatus) .status(httpStatus)
.body(CommonErrorResponse(errorCode)) .body(errorResponse)
} }
@ExceptionHandler(value = [Exception::class]) @ExceptionHandler(value = [Exception::class])
fun handleException(e: Exception): ResponseEntity<CommonErrorResponse> { fun handleException(e: Exception): ResponseEntity<CommonErrorResponse> {
log.error(e) { "message: ${e.message}" } log.error(e) { "[ExceptionControllerAdvice] Unexpected exception occurred: ${e.message}" }
val errorCode: ErrorCode = CommonErrorCode.UNEXPECTED_SERVER_ERROR val errorCode: ErrorCode = CommonErrorCode.UNEXPECTED_SERVER_ERROR
val httpStatus: HttpStatus = errorCode.httpStatus
val errorResponse = CommonErrorResponse(errorCode)
logException(
type = LogType.UNHANDLED_EXCEPTION,
httpStatus = httpStatus.value(),
errorResponse = errorResponse,
exception = e
)
return ResponseEntity return ResponseEntity
.status(errorCode.httpStatus) .status(httpStatus)
.body(CommonErrorResponse(errorCode)) .body(errorResponse)
}
private fun logException(
type: LogType,
httpStatus: Int,
errorResponse: CommonErrorResponse,
exception: Exception
) {
val commonRequest = ConvertResponseMessageRequest(
type = type,
httpStatus = httpStatus,
startTime = MDC.get("startTime")?.toLongOrNull(),
body = errorResponse,
)
val logMessage = if (errorResponse.message == exception.message) {
messageConverter.convertToResponseMessage(commonRequest)
} else {
messageConverter.convertToResponseMessage(commonRequest.copy(exception = exception))
}
log.warn { logMessage }
} }
} }