diff --git a/src/main/kotlin/roomescape/common/log/ApiLogMessageConverter.kt b/src/main/kotlin/roomescape/common/log/ApiLogMessageConverter.kt new file mode 100644 index 00000000..e1b0264f --- /dev/null +++ b/src/main/kotlin/roomescape/common/log/ApiLogMessageConverter.kt @@ -0,0 +1,81 @@ +package roomescape.common.log + +import com.fasterxml.jackson.databind.ObjectMapper +import jakarta.servlet.http.HttpServletRequest +import org.slf4j.MDC + +enum class LogType { + INCOMING_HTTP_REQUEST, + CONTROLLER_INVOKED, + CONTROLLER_SUCCESS, + AUTHENTICATION_FAILURE, + APPLICATION_FAILURE, + UNHANDLED_EXCEPTION +} + +class ApiLogMessageConverter( + private val objectMapper: ObjectMapper +) { + fun convertToHttpRequestMessage( + request: HttpServletRequest + ): String { + val payload: MutableMap = commonRequestPayload(LogType.INCOMING_HTTP_REQUEST, request) + + request.queryString?.let { payload["query_params"] = it } + payload["client_ip"] = request.remoteAddr + payload["user_agent"] = request.getHeader("User-Agent") + + return objectMapper.writeValueAsString(payload) + } + + fun convertToControllerInvokedMessage( + request: HttpServletRequest, + controllerPayload: Map, + ): String { + val payload: MutableMap = commonRequestPayload(LogType.CONTROLLER_INVOKED, request) + val memberId: Long? = MDC.get("member_id")?.toLong() + if (memberId != null) payload["member_id"] = memberId else payload["member_id"] = "NONE" + + payload.putAll(controllerPayload) + + return objectMapper.writeValueAsString(payload) + } + + fun convertToResponseMessage(request: ConvertResponseMessageRequest): String { + val payload: MutableMap = mutableMapOf() + payload["type"] = request.type + payload["status_code"] = request.httpStatus + + MDC.get("member_id")?.toLongOrNull() + ?.let { payload["member_id"] = it } + ?: run { payload["member_id"] = "NONE" } + + request.startTime?.let { payload["start_time"] = it } + request.body?.let { payload["response_body"] = it } + request.exception?.let { + payload["exception"] = mapOf( + "class" to it.javaClass.simpleName, + "message" to it.message + ) + } + + return objectMapper.writeValueAsString(payload) + } + + private fun commonRequestPayload( + logType: LogType, + request: HttpServletRequest + ): MutableMap = mutableMapOf( + "type" to logType, + "method" to request.method, + "uri" to request.requestURI + ) +} + +data class ConvertResponseMessageRequest( + val type: LogType, + val httpStatus: Int = 200, + val startTime: Long? = null, + val body: Any? = null, + val exception: Exception? = null +)