Skip to content

Commit

Permalink
Merge pull request #120 from mash-up-kr/feature/exception-logging
Browse files Browse the repository at this point in the history
feat: Exception logging
  • Loading branch information
KimDoubleB authored Aug 6, 2023
2 parents 70345bd + 732793e commit e20f72e
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 23 deletions.
1 change: 1 addition & 0 deletions moit-api/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ dependencies {

implementation("org.springframework.boot:spring-boot-starter-web")
implementation("org.springframework.boot:spring-boot-starter-actuator")
implementation("org.springframework.boot:spring-boot-starter-validation")
runtimeOnly("io.micrometer:micrometer-registry-prometheus")

// security
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,42 +2,94 @@ package com.mashup.moit.common

import com.mashup.moit.common.exception.MoitException
import com.mashup.moit.common.exception.MoitExceptionType
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import org.springframework.security.core.AuthenticationException
import org.springframework.validation.BindException
import org.springframework.web.HttpRequestMethodNotSupportedException
import org.springframework.web.bind.MethodArgumentNotValidException
import org.springframework.web.bind.MissingServletRequestParameterException
import org.springframework.web.bind.annotation.ExceptionHandler
import org.springframework.web.bind.annotation.RestControllerAdvice
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException


@RestControllerAdvice
class ControllerExceptionAdvice {
private val log: Logger = LoggerFactory.getLogger(ControllerExceptionAdvice::class.java)

@ExceptionHandler(Exception::class)
fun handleException(exception: Exception): ResponseEntity<MoitApiResponse<Any>> {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(
MoitApiResponse(
success = false,
data = null,
error = MoitApiErrorResponse(
code = MoitExceptionType.SYSTEM_FAIL.name,
message = exception.message,
),
)
)
fun handleException(ex: Exception): ResponseEntity<MoitApiResponse<Any>> {
log.error("Exception handler", ex)
return errorResponse(MoitExceptionType.SYSTEM_FAIL, ex.message)
}

@ExceptionHandler(MoitException::class)
fun handleMoitException(exception: MoitException): ResponseEntity<MoitApiResponse<Any>> {
return ResponseEntity.status(exception.httpStatusCode)
.body(
MoitApiResponse(
success = false,
data = null,
error = exception.toApiErrorResponse(),
)
)
fun handleMoitException(ex: MoitException): ResponseEntity<MoitApiResponse<Any>> {
log.error("MoitException handler", ex)
return errorResponse(ex.httpStatusCode, ex.toApiErrorResponse())
}

@ExceptionHandler(MissingServletRequestParameterException::class)
protected fun handleMissingServletRequestParameterException(ex: MissingServletRequestParameterException): ResponseEntity<MoitApiResponse<Any>> {
log.error("MissingServletRequestParameterException handler", ex)
return errorResponse(MoitExceptionType.INVALID_INPUT, ex.message)
}

@ExceptionHandler(BindException::class)
protected fun handleBindException(ex: BindException): ResponseEntity<MoitApiResponse<Any>> {
log.error("BindException handler", ex)
return errorResponse(MoitExceptionType.INVALID_INPUT, ex.message)
}

@ExceptionHandler(MethodArgumentTypeMismatchException::class)
protected fun handleMethodArgumentTypeMismatchException(ex: MethodArgumentTypeMismatchException): ResponseEntity<MoitApiResponse<Any>> {
log.error("MethodArgumentTypeMismatchException handler", ex)
return errorResponse(MoitExceptionType.METHOD_ARGUMENT_TYPE_MISMATCH_VALUE, ex.message)
}

@ExceptionHandler(HttpRequestMethodNotSupportedException::class)
protected fun handleHttpRequestMethodNotSupportedException(ex: HttpRequestMethodNotSupportedException): ResponseEntity<MoitApiResponse<Any>> {
log.error("HttpRequestMethodNotSupportedException handler", ex)
return errorResponse(MoitExceptionType.HTTP_REQUEST_METHOD_NOT_SUPPORTED, ex.message)
}

@ExceptionHandler(AccessDeniedException::class)
protected fun handleAccessDeniedException(ex: AccessDeniedException): ResponseEntity<MoitApiResponse<Any>> {
log.error("AccessDeniedException handler", ex)
return errorResponse(MoitExceptionType.ACCESS_DENIED, ex.message)
}

@ExceptionHandler(AuthenticationException::class)
protected fun handleAuthenticationException(ex: AuthenticationException): ResponseEntity<MoitApiResponse<Any>> {
log.error("AuthenticationException handler", ex)
return errorResponse(MoitExceptionType.AUTHENTICATION_FAILURE, ex.message)
}

@ExceptionHandler(MethodArgumentNotValidException::class)
protected fun handleMethodArgumentNotValidException(e: MethodArgumentNotValidException): ResponseEntity<MoitApiResponse<Any>> {
log.error("MethodArgumentNotValidException handler", e)
val errorMessage = e.allErrors.joinToString(" ,")
return errorResponse(MoitExceptionType.ARGUMENT_NOT_VALID, errorMessage)
}

private fun MoitException.toApiErrorResponse() = MoitApiErrorResponse(
code = errorCode,
message = message,
)

private fun errorResponse(exceptionType: MoitExceptionType, message: String?) = errorResponse(exceptionType.httpStatusCode, MoitApiErrorResponse(exceptionType.name, message))
private fun errorResponse(status: Int, errorResponse: MoitApiErrorResponse) = errorResponse(HttpStatus.valueOf(status), errorResponse)

private fun errorResponse(status: HttpStatus, errorResponse: MoitApiErrorResponse): ResponseEntity<MoitApiResponse<Any>> = ResponseEntity.status(status)
.body(
MoitApiResponse(
success = false,
data = null,
error = errorResponse,
)
)

}
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ data class MoitJoinRequest(

@Schema(description = "moit 초대 코드")
@field:NotBlank
@Size(min = 6, max = 6)
@field:Size(min = 6, max = 6)
val invitationCode: String,
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ data class StudyDetailsResponse(
data class StudyAttendanceKeywordRequest(
@Schema(description = "Study 참석 코드")
@field:NotBlank
@Size(min = 4, max = 4)
@field:Size(min = 4, max = 4)
val attendanceKeyword: String
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@ enum class MoitExceptionType(
SYSTEM_FAIL("Internal Server Error.", "C002_SYSTEM_FAIL", 500),
INVALID_ACCESS("Invalid Access", "C003_INVALID_ACCESS", 403),
ALREADY_EXIST("Already Exist", "C004_ALREADY_EXIST", 409),
INVALID_INPUT("Invalid Input", "C004_INVALID_INPUT", 400),
METHOD_ARGUMENT_TYPE_MISMATCH_VALUE("Request method argument type mismatch", "C005_TYPE_MISMATCH_VALUE", 400),
HTTP_REQUEST_METHOD_NOT_SUPPORTED("HTTP request method not supported", "C006_HTTP_METHOD_NOT_SUPPORTED", 400),
ACCESS_DENIED("Access denied. Check authentication.", "C007_ACCESS_DENIED", 403),
AUTHENTICATION_FAILURE("Authentication failed. Check login.", "C008_AUTHENTICATION_FAILURE", 401),
ARGUMENT_NOT_VALID("Method Argument Not Valid. Check argument validation.", "C009_ARGUMENT_NOT_VALID", 400),

// ATTENDANCE
ATTENDANCE_NOT_STARTED("스터디 출석이 아직 시작되지 않았습니다.", "A001_NOT_STARTED", 400),
Expand Down

0 comments on commit e20f72e

Please sign in to comment.