generated from pricelees/issue-pr-template
refactor: 기존 log 관련 클래스 모듈 분리 및 일부 클래스는 재사용성 고려 리팩터링
This commit is contained in:
parent
51a0dab2b4
commit
33406fbc93
@ -0,0 +1,55 @@
|
||||
package com.sangdol.common.log
|
||||
|
||||
import ch.qos.logback.classic.spi.ILoggingEvent
|
||||
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
|
||||
import com.sangdol.common.log.message.AbstractLogMaskingConverter
|
||||
import io.kotest.assertions.assertSoftly
|
||||
import io.kotest.core.spec.style.FunSpec
|
||||
import io.kotest.matchers.equals.shouldBeEqual
|
||||
import io.kotest.matchers.shouldBe
|
||||
import io.kotest.matchers.string.shouldContain
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
|
||||
class TestLogMaskingConverter : AbstractLogMaskingConverter(
|
||||
sensitiveKeys = setOf("account", "address"),
|
||||
objectMapper = jacksonObjectMapper()
|
||||
)
|
||||
|
||||
class AbstractLogMaskingConverterTest : FunSpec({
|
||||
|
||||
val converter = TestLogMaskingConverter()
|
||||
val event: ILoggingEvent = mockk()
|
||||
val account = "sangdol@example.com"
|
||||
val address = "서울특별시 강북구 수유1동 123-456"
|
||||
|
||||
context("sensitiveKeys=${converter.sensitiveKeys}에 있는 항목은 가린다.") {
|
||||
context("평문 로그를 처리할 때, 여러 key / value가 있는 경우 서로 간의 구분자는 trim 처리한다.") {
|
||||
listOf(":", "=", " : ", " = ").forEach { keyValueDelimiter ->
|
||||
listOf(",", ", ").forEach { valueDelimiter ->
|
||||
test("key1${keyValueDelimiter}value1${valueDelimiter}key2${keyValueDelimiter}value2 형식을 처리한다.") {
|
||||
every {
|
||||
event.formattedMessage
|
||||
} returns "account$keyValueDelimiter$account${valueDelimiter}address$keyValueDelimiter$address"
|
||||
|
||||
assertSoftly(converter.convert(event)) {
|
||||
this shouldBe "account${keyValueDelimiter}${account.first()}${converter.mask}${account.last()}${valueDelimiter}address${keyValueDelimiter}${address.first()}${converter.mask}${address.last()}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
context("JSON 로그") {
|
||||
test("정상 처리") {
|
||||
val json = "{\"request_body\":{\"account\":\"%s\",\"address\":\"%s\"}}"
|
||||
|
||||
every {
|
||||
event.formattedMessage
|
||||
} returns json.format(account, address)
|
||||
|
||||
converter.convert(event) shouldBeEqual json.format("${account.first()}${converter.mask}${account.last()}", "${address.first()}${converter.mask}${address.last()}")
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
@ -1,8 +1,9 @@
|
||||
package com.sangdol.roomescape.common.log
|
||||
package com.sangdol.common.log
|
||||
|
||||
import com.sangdol.common.config.JacksonConfig
|
||||
import com.sangdol.roomescape.auth.exception.AuthErrorCode
|
||||
import com.sangdol.roomescape.auth.exception.AuthException
|
||||
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
|
||||
import com.sangdol.common.log.config.LogType
|
||||
import com.sangdol.common.log.message.ApiLogMessageConverter
|
||||
import com.sangdol.common.log.message.ConvertResponseMessageRequest
|
||||
import io.kotest.core.spec.style.StringSpec
|
||||
import io.kotest.matchers.shouldBe
|
||||
import io.mockk.every
|
||||
@ -11,7 +12,7 @@ import jakarta.servlet.http.HttpServletRequest
|
||||
import org.slf4j.MDC
|
||||
|
||||
class ApiLogMessageConverterTest : StringSpec({
|
||||
val converter = ApiLogMessageConverter(JacksonConfig().objectMapper())
|
||||
val converter = ApiLogMessageConverter(jacksonObjectMapper())
|
||||
val request: HttpServletRequest = mockk()
|
||||
|
||||
beforeTest {
|
||||
@ -58,11 +59,11 @@ class ApiLogMessageConverterTest : StringSpec({
|
||||
type = LogType.CONTROLLER_SUCCESS,
|
||||
endpoint = endpoint,
|
||||
httpStatus = 200,
|
||||
exception = AuthException(AuthErrorCode.MEMBER_NOT_FOUND, "테스트 메시지!")
|
||||
exception = RuntimeException("테스트 메시지!")
|
||||
)
|
||||
|
||||
converter.convertToResponseMessage(request) shouldBe """
|
||||
{"type":"CONTROLLER_SUCCESS","endpoint":"$endpoint","status_code":200,"principal_id":1,"exception":{"class":"AuthException","message":"테스트 메시지!"}}
|
||||
{"type":"CONTROLLER_SUCCESS","endpoint":"$endpoint","status_code":200,"principal_id":1,"exception":{"class":"RuntimeException","message":"테스트 메시지!"}}
|
||||
""".trimIndent()
|
||||
}
|
||||
})
|
||||
@ -0,0 +1,28 @@
|
||||
package com.sangdol.common.log
|
||||
|
||||
import com.sangdol.common.log.sql.SlowQueryPredicate
|
||||
import com.sangdol.common.log.sql.SqlLogFormatter
|
||||
import io.kotest.assertions.assertSoftly
|
||||
import io.kotest.core.spec.style.StringSpec
|
||||
import io.kotest.matchers.shouldBe
|
||||
|
||||
class MDCAwareSlowQueryListenerWithoutParamsTest : StringSpec({
|
||||
"SQL 메시지에서 Params 항목은 가린다." {
|
||||
val message = """Query:["select * from members m where m.email=?"], Params:[(a@a.a)]"""
|
||||
val expected = """Query:["select * from members m where m.email=?"]"""
|
||||
val result = SqlLogFormatter().maskParams(message)
|
||||
|
||||
result shouldBe expected
|
||||
}
|
||||
|
||||
"입력된 thresholdMs 보다 소요시간이 긴 쿼리를 기록한다." {
|
||||
val slowQueryThreshold = 10L
|
||||
val slowQueryPredicate = SlowQueryPredicate(thresholdMs = slowQueryThreshold)
|
||||
|
||||
assertSoftly(slowQueryPredicate) {
|
||||
this.test(slowQueryThreshold) shouldBe true
|
||||
this.test(slowQueryThreshold + 1) shouldBe true
|
||||
this.test(slowQueryThreshold - 1) shouldBe false
|
||||
}
|
||||
}
|
||||
})
|
||||
@ -1,77 +0,0 @@
|
||||
package com.sangdol.roomescape.common.log
|
||||
|
||||
import ch.qos.logback.classic.spi.ILoggingEvent
|
||||
import io.kotest.assertions.assertSoftly
|
||||
import io.kotest.core.spec.style.FunSpec
|
||||
import io.kotest.matchers.equals.shouldBeEqual
|
||||
import io.kotest.matchers.string.shouldContain
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
|
||||
class RoomescapeLogMaskingConverterTest : FunSpec({
|
||||
|
||||
val converter = RoomescapeLogMaskingConverter()
|
||||
val event: ILoggingEvent = mockk()
|
||||
|
||||
context("평문 로그에서는 key=value 형식을 처리한다.") {
|
||||
|
||||
test("2글자 초과이면 맨 앞, 맨 뒤를 제외한 나머지를 가린다.") {
|
||||
val email = "a@a.a"
|
||||
val password = "password12"
|
||||
val accessToken = "accessToken12"
|
||||
|
||||
every {
|
||||
event.formattedMessage
|
||||
} returns "email=${email}, password=${password}, accessToken = $accessToken"
|
||||
|
||||
assertSoftly(converter.convert(event)) {
|
||||
this shouldContain "email=${email}"
|
||||
this shouldContain "password=${password.first()}****${password.last()}"
|
||||
this shouldContain "accessToken = ${accessToken.first()}****${accessToken.last()}"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
test("2글자 이하이면 전부 가린다.") {
|
||||
val email = "a@a.a"
|
||||
val password = "pa"
|
||||
val accessToken = "a"
|
||||
|
||||
every {
|
||||
event.formattedMessage
|
||||
} returns "email=${email}, password=${password}, accessToken = ${accessToken}"
|
||||
|
||||
assertSoftly(converter.convert(event)) {
|
||||
this shouldContain "email=${email}"
|
||||
this shouldContain "password=****"
|
||||
this shouldContain "accessToken = ****"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
context("JSON 형식 로그를 처리한다.") {
|
||||
val json = "{\"request_body\":{\"email\":\"a@a.a\",\"password\":\"password12\"}}"
|
||||
|
||||
test("2글자 초과이면 맨 앞, 맨 뒤를 제외한 나머지를 가린다.") {
|
||||
val password = "password12"
|
||||
val json = "{\"request_body\":{\"email\":\"a@a.a\",\"password\":\"${password}\"}}"
|
||||
|
||||
every {
|
||||
event.formattedMessage
|
||||
} returns json
|
||||
|
||||
converter.convert(event) shouldBeEqual "{\"request_body\":{\"email\":\"a@a.a\",\"password\":\"${password.first()}****${password.last()}\"}}"
|
||||
}
|
||||
|
||||
test("2글자 이하이면 전부 가린다.") {
|
||||
val password = "pa"
|
||||
val json = "{\"request_body\":{\"email\":\"a@a.a\",\"password\":\"${password}\"}}"
|
||||
|
||||
every {
|
||||
event.formattedMessage
|
||||
} returns json
|
||||
|
||||
converter.convert(event) shouldBeEqual "{\"request_body\":{\"email\":\"a@a.a\",\"password\":\"****\"}}"
|
||||
}
|
||||
}
|
||||
})
|
||||
Loading…
x
Reference in New Issue
Block a user