generated from pricelees/issue-pr-template
refactor: 기존 로깅 필터, AOP, 예외 핸들러에 새로 정의된 WebLogMessageConverter 반영
This commit is contained in:
parent
eeb87e1bc3
commit
1cbece032f
@ -14,6 +14,10 @@ enum class HttpStatus(
|
|||||||
INTERNAL_SERVER_ERROR(500)
|
INTERNAL_SERVER_ERROR(500)
|
||||||
;
|
;
|
||||||
|
|
||||||
|
fun isClientError(): Boolean {
|
||||||
|
return code in 400..<500
|
||||||
|
}
|
||||||
|
|
||||||
fun value(): Int {
|
fun value(): Int {
|
||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,9 +1,7 @@
|
|||||||
package com.sangdol.common.log.web
|
package com.sangdol.common.web.asepct
|
||||||
|
|
||||||
import com.sangdol.common.log.config.LogType
|
import com.sangdol.common.log.constant.LogType
|
||||||
import com.sangdol.common.log.message.ApiLogMessageConverter
|
import com.sangdol.common.web.support.log.WebLogMessageConverter
|
||||||
import com.sangdol.common.log.message.ConvertResponseMessageRequest
|
|
||||||
import com.sangdol.common.log.message.getEndpoint
|
|
||||||
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 jakarta.servlet.http.HttpServletRequest
|
import jakarta.servlet.http.HttpServletRequest
|
||||||
@ -13,7 +11,6 @@ import org.aspectj.lang.annotation.Around
|
|||||||
import org.aspectj.lang.annotation.Aspect
|
import org.aspectj.lang.annotation.Aspect
|
||||||
import org.aspectj.lang.annotation.Pointcut
|
import org.aspectj.lang.annotation.Pointcut
|
||||||
import org.aspectj.lang.reflect.MethodSignature
|
import org.aspectj.lang.reflect.MethodSignature
|
||||||
import org.slf4j.MDC
|
|
||||||
import org.springframework.http.ResponseEntity
|
import org.springframework.http.ResponseEntity
|
||||||
import org.springframework.web.bind.annotation.PathVariable
|
import org.springframework.web.bind.annotation.PathVariable
|
||||||
import org.springframework.web.bind.annotation.RequestBody
|
import org.springframework.web.bind.annotation.RequestBody
|
||||||
@ -25,7 +22,7 @@ private val log: KLogger = KotlinLogging.logger {}
|
|||||||
|
|
||||||
@Aspect
|
@Aspect
|
||||||
class ControllerLoggingAspect(
|
class ControllerLoggingAspect(
|
||||||
private val messageConverter: ApiLogMessageConverter,
|
private val messageConverter: WebLogMessageConverter,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
@Pointcut("execution(* com.sangdol..web..*Controller*.*(..))")
|
@Pointcut("execution(* com.sangdol..web..*Controller*.*(..))")
|
||||||
@ -34,10 +31,8 @@ class ControllerLoggingAspect(
|
|||||||
|
|
||||||
@Around("allController()")
|
@Around("allController()")
|
||||||
fun logAPICalls(joinPoint: ProceedingJoinPoint): Any? {
|
fun logAPICalls(joinPoint: ProceedingJoinPoint): Any? {
|
||||||
val startTime: Long = MDC.get("startTime").toLongOrNull() ?: System.currentTimeMillis()
|
|
||||||
val controllerPayload: Map<String, Any> = parsePayload(joinPoint)
|
|
||||||
|
|
||||||
val servletRequest: HttpServletRequest = servletRequest()
|
val servletRequest: HttpServletRequest = servletRequest()
|
||||||
|
val controllerPayload: Map<String, Any> = parseControllerPayload(joinPoint)
|
||||||
|
|
||||||
log.info {
|
log.info {
|
||||||
messageConverter.convertToControllerInvokedMessage(servletRequest, controllerPayload)
|
messageConverter.convertToControllerInvokedMessage(servletRequest, controllerPayload)
|
||||||
@ -45,29 +40,22 @@ class ControllerLoggingAspect(
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
return joinPoint.proceed()
|
return joinPoint.proceed()
|
||||||
.also { logSuccess(servletRequest.getEndpoint(), startTime, it) }
|
.also { logSuccess(servletRequest, it as ResponseEntity<*>) }
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
throw e
|
throw e
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun logSuccess(endpoint: String, startTime: Long, result: Any) {
|
private fun logSuccess(servletRequest: HttpServletRequest, result: ResponseEntity<*>) {
|
||||||
val responseEntity = result as ResponseEntity<*>
|
val body: Any? = if (log.isDebugEnabled()) result.body else null
|
||||||
var convertResponseMessageRequest = ConvertResponseMessageRequest(
|
|
||||||
type = LogType.CONTROLLER_SUCCESS,
|
val logMessage = messageConverter.convertToResponseMessage(
|
||||||
endpoint = endpoint,
|
type = LogType.SUCCEED,
|
||||||
httpStatus = responseEntity.statusCode.value(),
|
servletRequest = servletRequest,
|
||||||
startTime = startTime,
|
httpStatusCode = result.statusCode.value(),
|
||||||
|
responseBody = body,
|
||||||
)
|
)
|
||||||
|
|
||||||
if (log.isDebugEnabled()) {
|
|
||||||
convertResponseMessageRequest = convertResponseMessageRequest.copy(
|
|
||||||
body = responseEntity.body
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
val logMessage = messageConverter.convertToResponseMessage(convertResponseMessageRequest)
|
|
||||||
|
|
||||||
log.info { logMessage }
|
log.info { logMessage }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,14 +63,16 @@ class ControllerLoggingAspect(
|
|||||||
return (RequestContextHolder.currentRequestAttributes() as ServletRequestAttributes).request
|
return (RequestContextHolder.currentRequestAttributes() as ServletRequestAttributes).request
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun parsePayload(joinPoint: JoinPoint): Map<String, Any> {
|
private fun parseControllerPayload(joinPoint: JoinPoint): Map<String, Any> {
|
||||||
val signature = joinPoint.signature as MethodSignature
|
val signature = joinPoint.signature as MethodSignature
|
||||||
val args = joinPoint.args
|
val args = joinPoint.args
|
||||||
val payload = mutableMapOf<String, Any>()
|
val payload = mutableMapOf<String, Any>(
|
||||||
payload["controller_method"] = joinPoint.signature.toShortString()
|
"controller_method" to joinPoint.signature.toShortString()
|
||||||
|
)
|
||||||
|
|
||||||
val requestParams: MutableMap<String, Any> = mutableMapOf()
|
val requestParams: MutableMap<String, Any> = mutableMapOf()
|
||||||
val pathVariables: MutableMap<String, Any> = mutableMapOf()
|
val pathVariables: MutableMap<String, Any> = mutableMapOf()
|
||||||
|
|
||||||
signature.method.parameters.forEachIndexed { index, parameter ->
|
signature.method.parameters.forEachIndexed { index, parameter ->
|
||||||
val arg = args[index]
|
val arg = args[index]
|
||||||
|
|
||||||
@ -97,9 +87,10 @@ class ControllerLoggingAspect(
|
|||||||
parameter.getAnnotation(RequestParam::class.java)?.let {
|
parameter.getAnnotation(RequestParam::class.java)?.let {
|
||||||
requestParams[parameter.name] = arg
|
requestParams[parameter.name] = arg
|
||||||
}
|
}
|
||||||
|
}.also {
|
||||||
|
if (pathVariables.isNotEmpty()) payload["path_variable"] = pathVariables
|
||||||
|
if (requestParams.isNotEmpty()) payload["request_param"] = requestParams
|
||||||
}
|
}
|
||||||
if (pathVariables.isNotEmpty()) payload["path_variable"] = pathVariables
|
|
||||||
if (requestParams.isNotEmpty()) payload["request_param"] = requestParams
|
|
||||||
|
|
||||||
return payload
|
return payload
|
||||||
}
|
}
|
||||||
@ -1,19 +1,15 @@
|
|||||||
package com.sangdol.roomescape.common.exception
|
package com.sangdol.common.web.exception
|
||||||
|
|
||||||
|
import com.sangdol.common.log.constant.LogType
|
||||||
import com.sangdol.common.types.exception.CommonErrorCode
|
import com.sangdol.common.types.exception.CommonErrorCode
|
||||||
import com.sangdol.common.types.exception.ErrorCode
|
import com.sangdol.common.types.exception.ErrorCode
|
||||||
import com.sangdol.common.types.exception.RoomescapeException
|
import com.sangdol.common.types.exception.RoomescapeException
|
||||||
import com.sangdol.common.types.web.CommonErrorResponse
|
import com.sangdol.common.types.web.CommonErrorResponse
|
||||||
import com.sangdol.common.types.web.HttpStatus
|
import com.sangdol.common.types.web.HttpStatus
|
||||||
import com.sangdol.roomescape.auth.exception.AuthException
|
import com.sangdol.common.web.support.log.WebLogMessageConverter
|
||||||
import com.sangdol.roomescape.common.log.ApiLogMessageConverter
|
|
||||||
import com.sangdol.roomescape.common.log.ConvertResponseMessageRequest
|
|
||||||
import com.sangdol.roomescape.common.log.LogType
|
|
||||||
import com.sangdol.roomescape.common.log.getEndpoint
|
|
||||||
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 jakarta.servlet.http.HttpServletRequest
|
import jakarta.servlet.http.HttpServletRequest
|
||||||
import org.slf4j.MDC
|
|
||||||
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
|
||||||
@ -23,8 +19,8 @@ import org.springframework.web.bind.annotation.RestControllerAdvice
|
|||||||
private val log: KLogger = KotlinLogging.logger {}
|
private val log: KLogger = KotlinLogging.logger {}
|
||||||
|
|
||||||
@RestControllerAdvice
|
@RestControllerAdvice
|
||||||
class ExceptionControllerAdvice(
|
class GlobalExceptionHandler(
|
||||||
private val messageConverter: ApiLogMessageConverter
|
private val messageConverter: WebLogMessageConverter
|
||||||
) {
|
) {
|
||||||
@ExceptionHandler(value = [RoomescapeException::class])
|
@ExceptionHandler(value = [RoomescapeException::class])
|
||||||
fun handleRoomException(
|
fun handleRoomException(
|
||||||
@ -35,14 +31,7 @@ class ExceptionControllerAdvice(
|
|||||||
val httpStatus: HttpStatus = errorCode.httpStatus
|
val httpStatus: HttpStatus = errorCode.httpStatus
|
||||||
val errorResponse = CommonErrorResponse(errorCode)
|
val errorResponse = CommonErrorResponse(errorCode)
|
||||||
|
|
||||||
val type = if (e is AuthException) LogType.AUTHENTICATION_FAILURE else LogType.APPLICATION_FAILURE
|
logException(servletRequest, httpStatus, errorResponse, e)
|
||||||
logException(
|
|
||||||
type = type,
|
|
||||||
servletRequest = servletRequest,
|
|
||||||
httpStatus = httpStatus.value(),
|
|
||||||
errorResponse = errorResponse,
|
|
||||||
exception = e
|
|
||||||
)
|
|
||||||
|
|
||||||
return ResponseEntity
|
return ResponseEntity
|
||||||
.status(httpStatus.value())
|
.status(httpStatus.value())
|
||||||
@ -54,26 +43,21 @@ class ExceptionControllerAdvice(
|
|||||||
servletRequest: HttpServletRequest,
|
servletRequest: HttpServletRequest,
|
||||||
e: Exception
|
e: Exception
|
||||||
): ResponseEntity<CommonErrorResponse> {
|
): ResponseEntity<CommonErrorResponse> {
|
||||||
val message: String = if (e is MethodArgumentNotValidException) {
|
if (e is MethodArgumentNotValidException) {
|
||||||
e.bindingResult.allErrors
|
e.bindingResult.allErrors
|
||||||
.mapNotNull { it.defaultMessage }
|
.mapNotNull { it.defaultMessage }
|
||||||
.joinToString(", ")
|
.joinToString(", ")
|
||||||
} else {
|
} else {
|
||||||
e.message!!
|
e.message!!
|
||||||
|
}.also {
|
||||||
|
log.warn { "[ExceptionControllerAdvice] Invalid Request Value Exception occurred: $it" }
|
||||||
}
|
}
|
||||||
log.debug { "[ExceptionControllerAdvice] Invalid Request Value Exception occurred: $message" }
|
|
||||||
|
|
||||||
val errorCode: ErrorCode = CommonErrorCode.INVALID_INPUT_VALUE
|
val errorCode: ErrorCode = CommonErrorCode.INVALID_INPUT_VALUE
|
||||||
val httpStatus: HttpStatus = errorCode.httpStatus
|
val httpStatus: HttpStatus = errorCode.httpStatus
|
||||||
val errorResponse = CommonErrorResponse(errorCode)
|
val errorResponse = CommonErrorResponse(errorCode)
|
||||||
|
|
||||||
logException(
|
logException(servletRequest, httpStatus, errorResponse, e)
|
||||||
type = LogType.APPLICATION_FAILURE,
|
|
||||||
servletRequest = servletRequest,
|
|
||||||
httpStatus = httpStatus.value(),
|
|
||||||
errorResponse = errorResponse,
|
|
||||||
exception = e
|
|
||||||
)
|
|
||||||
|
|
||||||
return ResponseEntity
|
return ResponseEntity
|
||||||
.status(httpStatus.value())
|
.status(httpStatus.value())
|
||||||
@ -91,13 +75,7 @@ class ExceptionControllerAdvice(
|
|||||||
val httpStatus: HttpStatus = errorCode.httpStatus
|
val httpStatus: HttpStatus = errorCode.httpStatus
|
||||||
val errorResponse = CommonErrorResponse(errorCode)
|
val errorResponse = CommonErrorResponse(errorCode)
|
||||||
|
|
||||||
logException(
|
logException(servletRequest, httpStatus, errorResponse, e)
|
||||||
type = LogType.UNHANDLED_EXCEPTION,
|
|
||||||
servletRequest = servletRequest,
|
|
||||||
httpStatus = httpStatus.value(),
|
|
||||||
errorResponse = errorResponse,
|
|
||||||
exception = e
|
|
||||||
)
|
|
||||||
|
|
||||||
return ResponseEntity
|
return ResponseEntity
|
||||||
.status(httpStatus.value())
|
.status(httpStatus.value())
|
||||||
@ -105,25 +83,21 @@ class ExceptionControllerAdvice(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun logException(
|
private fun logException(
|
||||||
type: LogType,
|
|
||||||
servletRequest: HttpServletRequest,
|
servletRequest: HttpServletRequest,
|
||||||
httpStatus: Int,
|
httpStatus: HttpStatus,
|
||||||
errorResponse: CommonErrorResponse,
|
errorResponse: CommonErrorResponse,
|
||||||
exception: Exception
|
exception: Exception
|
||||||
) {
|
) {
|
||||||
val commonRequest = ConvertResponseMessageRequest(
|
val type = if (httpStatus.isClientError()) LogType.APPLICATION_FAILURE else LogType.UNHANDLED_EXCEPTION
|
||||||
type = type,
|
val actualException: Exception? = if (errorResponse.message == exception.message) null else exception
|
||||||
endpoint = servletRequest.getEndpoint(),
|
|
||||||
httpStatus = httpStatus,
|
|
||||||
startTime = MDC.get("startTime")?.toLongOrNull(),
|
|
||||||
body = errorResponse,
|
|
||||||
)
|
|
||||||
|
|
||||||
val logMessage = if (errorResponse.message == exception.message) {
|
val logMessage = messageConverter.convertToResponseMessage(
|
||||||
messageConverter.convertToResponseMessage(commonRequest)
|
type = type,
|
||||||
} else {
|
servletRequest = servletRequest,
|
||||||
messageConverter.convertToResponseMessage(commonRequest.copy(exception = exception))
|
httpStatusCode = httpStatus.value(),
|
||||||
}
|
responseBody = errorResponse,
|
||||||
|
exception = actualException
|
||||||
|
)
|
||||||
|
|
||||||
log.warn { logMessage }
|
log.warn { logMessage }
|
||||||
}
|
}
|
||||||
@ -1,13 +1,13 @@
|
|||||||
package com.sangdol.common.log.web
|
package com.sangdol.common.web.servlet
|
||||||
|
|
||||||
import com.sangdol.common.log.message.ApiLogMessageConverter
|
|
||||||
import com.sangdol.common.utils.MdcPrincipalIdUtil
|
import com.sangdol.common.utils.MdcPrincipalIdUtil
|
||||||
|
import com.sangdol.common.utils.MdcStartTimeUtil
|
||||||
|
import com.sangdol.common.web.support.log.WebLogMessageConverter
|
||||||
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 jakarta.servlet.FilterChain
|
import jakarta.servlet.FilterChain
|
||||||
import jakarta.servlet.http.HttpServletRequest
|
import jakarta.servlet.http.HttpServletRequest
|
||||||
import jakarta.servlet.http.HttpServletResponse
|
import jakarta.servlet.http.HttpServletResponse
|
||||||
import org.slf4j.MDC
|
|
||||||
import org.springframework.web.filter.OncePerRequestFilter
|
import org.springframework.web.filter.OncePerRequestFilter
|
||||||
import org.springframework.web.util.ContentCachingRequestWrapper
|
import org.springframework.web.util.ContentCachingRequestWrapper
|
||||||
import org.springframework.web.util.ContentCachingResponseWrapper
|
import org.springframework.web.util.ContentCachingResponseWrapper
|
||||||
@ -15,7 +15,7 @@ import org.springframework.web.util.ContentCachingResponseWrapper
|
|||||||
private val log: KLogger = KotlinLogging.logger {}
|
private val log: KLogger = KotlinLogging.logger {}
|
||||||
|
|
||||||
class HttpRequestLoggingFilter(
|
class HttpRequestLoggingFilter(
|
||||||
private val messageConverter: ApiLogMessageConverter
|
private val messageConverter: WebLogMessageConverter
|
||||||
) : OncePerRequestFilter() {
|
) : OncePerRequestFilter() {
|
||||||
override fun doFilterInternal(
|
override fun doFilterInternal(
|
||||||
request: HttpServletRequest,
|
request: HttpServletRequest,
|
||||||
@ -27,14 +27,13 @@ class HttpRequestLoggingFilter(
|
|||||||
val cachedRequest = ContentCachingRequestWrapper(request)
|
val cachedRequest = ContentCachingRequestWrapper(request)
|
||||||
val cachedResponse = ContentCachingResponseWrapper(response)
|
val cachedResponse = ContentCachingResponseWrapper(response)
|
||||||
|
|
||||||
val startTime = System.currentTimeMillis()
|
MdcStartTimeUtil.setCurrentTime()
|
||||||
MDC.put("startTime", startTime.toString())
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
filterChain.doFilter(cachedRequest, cachedResponse)
|
filterChain.doFilter(cachedRequest, cachedResponse)
|
||||||
cachedResponse.copyBodyToResponse()
|
cachedResponse.copyBodyToResponse()
|
||||||
} finally {
|
} finally {
|
||||||
MDC.remove("startTime")
|
MdcStartTimeUtil.clear()
|
||||||
MdcPrincipalIdUtil.clear()
|
MdcPrincipalIdUtil.clear()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user