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

Merged
pricelees merged 14 commits from feature/#26 into main 2025-07-29 06:49:56 +00:00
2 changed files with 35 additions and 74 deletions
Showing only changes of commit 0cab9c133a - Show all commits

View File

@ -0,0 +1,35 @@
package roomescape.common.log
import com.fasterxml.jackson.databind.ObjectMapper
import org.springframework.boot.web.servlet.FilterRegistrationBean
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.context.annotation.DependsOn
import org.springframework.core.Ordered
import org.springframework.web.filter.OncePerRequestFilter
@Configuration
class LogConfiguration {
@Bean
@DependsOn(value = ["apiLogMessageConverter"])
fun filterRegistrationBean(
apiLogMessageConverter: ApiLogMessageConverter
): FilterRegistrationBean<OncePerRequestFilter> {
val filter = HttpRequestLoggingFilter(apiLogMessageConverter)
return FilterRegistrationBean<OncePerRequestFilter>(filter)
.apply { this.order = Ordered.HIGHEST_PRECEDENCE + 2 }
}
@Bean
@DependsOn(value = ["apiLogMessageConverter"])
fun apiLoggingAspect(apiLogMessageConverter: ApiLogMessageConverter): ControllerLoggingAspect {
return ControllerLoggingAspect(apiLogMessageConverter)
}
@Bean
fun apiLogMessageConverter(objectMapper: ObjectMapper): ApiLogMessageConverter {
return ApiLogMessageConverter(objectMapper)
}
}

View File

@ -1,74 +0,0 @@
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
import java.nio.charset.StandardCharsets
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"] = parseContent(it) }
response.contentAsByteArray.takeIf { it.isNotEmpty() }
?.let { payload["response_body"] = parseContent(it) }
}
log.info { objectMapper.writeValueAsString(payload) }
}
private fun parseContent(content: ByteArray): Any {
return try {
objectMapper.readValue(content, Map::class.java)
} catch (_: Exception) {
String(content, StandardCharsets.UTF_8)
}
}
}