feat: API 요청 / 응답 결과 기록 필터 추가

This commit is contained in:
이상진 2025-07-27 22:35:07 +09:00
parent 792a2281e6
commit d34a6ad27e

View File

@ -0,0 +1,65 @@
package roomescape.common.log
import com.fasterxml.jackson.databind.ObjectMapper
import io.github.oshai.kotlinlogging.KotlinLogging
import jakarta.servlet.FilterChain
import jakarta.servlet.http.HttpServletRequest
import jakarta.servlet.http.HttpServletResponse
import org.springframework.core.Ordered
import org.springframework.core.annotation.Order
import org.springframework.stereotype.Component
import org.springframework.web.filter.OncePerRequestFilter
import org.springframework.web.util.ContentCachingRequestWrapper
import org.springframework.web.util.ContentCachingResponseWrapper
private val log = KotlinLogging.logger {}
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
class LoggingFilter(
private val objectMapper: ObjectMapper
) : OncePerRequestFilter() {
override fun doFilterInternal(
request: HttpServletRequest,
response: HttpServletResponse,
filterChain: FilterChain
) {
val cachedRequest = ContentCachingRequestWrapper(request)
val cachedResponse = ContentCachingResponseWrapper(response)
val startTime = System.currentTimeMillis()
filterChain.doFilter(cachedRequest, cachedResponse)
val duration = System.currentTimeMillis() - startTime
logAPISummary(cachedRequest, cachedResponse, duration)
cachedResponse.copyBodyToResponse()
}
private fun logAPISummary(
request: ContentCachingRequestWrapper,
response: ContentCachingResponseWrapper,
duration: Long
) {
val payload = linkedMapOf<String, Any>(
"type" to "API_LOG",
"method" to request.method,
"url" to request.requestURL.toString(),
)
request.queryString?.let { payload["query_params"] = it }
payload["remote_ip"] = request.remoteAddr
payload["status_code"] = response.status
payload["duration_ms"] = duration
if (log.isDebugEnabled()) {
request.contentAsByteArray.takeIf { it.isNotEmpty() }
?.let { payload["request_body"] = objectMapper.readValue(it, Map::class.java) }
response.contentAsByteArray.takeIf { it.isNotEmpty() }
?.let { payload["response_body"] = objectMapper.readValue(it, Map::class.java) }
}
log.info { objectMapper.writeValueAsString(payload) }
}
}