generated from pricelees/issue-pr-template
feat: 전역으로 쓰이는 Masking Converter 구현 및 logback default 설정 추가
This commit is contained in:
parent
38d82e06b2
commit
fb9a647f32
@ -0,0 +1,77 @@
|
||||
package roomescape.common.log
|
||||
|
||||
import ch.qos.logback.classic.pattern.MessageConverter
|
||||
import ch.qos.logback.classic.spi.ILoggingEvent
|
||||
import com.fasterxml.jackson.databind.JsonNode
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import com.fasterxml.jackson.databind.node.ArrayNode
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode
|
||||
import com.fasterxml.jackson.databind.node.TextNode
|
||||
import io.github.oshai.kotlinlogging.KLogger
|
||||
import io.github.oshai.kotlinlogging.KotlinLogging
|
||||
import roomescape.common.config.JacksonConfig
|
||||
|
||||
private val SENSITIVE_KEYS = setOf("password", "accessToken")
|
||||
private val log: KLogger = KotlinLogging.logger {}
|
||||
|
||||
class RoomescapeLogMaskingConverter(
|
||||
private val objectMapper: ObjectMapper = JacksonConfig().objectMapper()
|
||||
) : MessageConverter() {
|
||||
|
||||
override fun convert(event: ILoggingEvent): String {
|
||||
val message: String = event.formattedMessage
|
||||
log.warn { "[RoomescapeLogMaskingConverter.convert] formattedMessage: $message" }
|
||||
|
||||
return if (isJsonString(message)) {
|
||||
maskedJsonString(message)
|
||||
} else {
|
||||
maskedPlainMessage(message)
|
||||
}
|
||||
}
|
||||
|
||||
private fun isJsonString(message: String): Boolean {
|
||||
val trimmed = message.trim()
|
||||
|
||||
return trimmed.startsWith("{") && trimmed.endsWith("}")
|
||||
}
|
||||
|
||||
private fun maskedJsonString(body: String): String = objectMapper.readValue(body, JsonNode::class.java)
|
||||
.apply { maskRecursive(this) }
|
||||
.toString()
|
||||
|
||||
private fun maskedPlainMessage(message: String): String {
|
||||
val keys: String = SENSITIVE_KEYS.joinToString("|")
|
||||
val regex = Regex("(?i)($keys)(\\s*=\\s*)(\\S+)")
|
||||
|
||||
return regex.replace(message) { matchResult ->
|
||||
val key = matchResult.groupValues[1]
|
||||
val delimiter = matchResult.groupValues[2]
|
||||
|
||||
"${key}${delimiter}****"
|
||||
}
|
||||
}
|
||||
|
||||
private fun maskRecursive(node: JsonNode?) {
|
||||
node?.forEachEntry { key, childNode ->
|
||||
when {
|
||||
childNode.isValueNode -> {
|
||||
if (key in SENSITIVE_KEYS) (node as ObjectNode).put(key, "****")
|
||||
}
|
||||
|
||||
childNode.isObject -> maskRecursive(childNode)
|
||||
childNode.isArray -> {
|
||||
val arrayNode = childNode as ArrayNode
|
||||
val originSize = arrayNode.size()
|
||||
if (originSize > 1) {
|
||||
val first = arrayNode.first()
|
||||
arrayNode.removeAll()
|
||||
arrayNode.add(first)
|
||||
arrayNode.add(TextNode("(...logged only first of $originSize elements)"))
|
||||
}
|
||||
|
||||
arrayNode.forEach { maskRecursive(it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,7 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<included>
|
||||
<conversionRule conversionWord="maskedMessage"
|
||||
class="roomescape.common.log.RoomescapeLogMaskingConverter" />
|
||||
|
||||
<property name="CONSOLE_LOG_PATTERN"
|
||||
value="%d{yyyy-MM-dd HH:mm:ss.SSS} %highlight(%-5level) %green(${PID:- }) --- [%15.15thread] %cyan(%-40logger{36}) : %msg%n%throwable"/>
|
||||
value="%d{yyyy-MM-dd HH:mm:ss.SSS} %highlight(%-5level) %green(${PID:- }) --- [%15.15thread] %cyan(%-40logger{36}) : %maskedMessage%n%throwable"/>
|
||||
|
||||
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
|
||||
@ -3,4 +3,8 @@
|
||||
<springProfile name="local">
|
||||
<include resource="logback-local.xml"/>
|
||||
</springProfile>
|
||||
|
||||
<springProfile name="default">
|
||||
<include resource="logback-local.xml"/>
|
||||
</springProfile>
|
||||
</configuration>
|
||||
Loading…
x
Reference in New Issue
Block a user