feat(ranking): 랭킹 조회 관측 로그를 추가한다
This commit is contained in:
@@ -4,6 +4,7 @@ import kr.co.vividnext.sodalive.v2.ranking.domain.CreatorRankingItem
|
||||
import kr.co.vividnext.sodalive.v2.ranking.port.out.CreatorRankingBlockPort
|
||||
import kr.co.vividnext.sodalive.v2.ranking.port.out.CreatorRankingSnapshotPort
|
||||
import kr.co.vividnext.sodalive.v2.ranking.port.out.CreatorRankingSnapshotRecord
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.beans.factory.annotation.Value
|
||||
import org.springframework.stereotype.Service
|
||||
import org.springframework.transaction.annotation.Transactional
|
||||
@@ -15,11 +16,18 @@ class CreatorRankingQueryService(
|
||||
@Value("\${cloud.aws.cloud-front.host}")
|
||||
private val cloudFrontHost: String
|
||||
) {
|
||||
private val log = LoggerFactory.getLogger(javaClass)
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
fun getCreatorRankings(viewerMemberId: Long?): CreatorRankingResult {
|
||||
val startedAt = System.currentTimeMillis()
|
||||
return runCatching {
|
||||
val latestItems = snapshotPort.findLatestSnapshots().toRankedItems()
|
||||
if (latestItems.isEmpty()) {
|
||||
return CreatorRankingResult(showRankChange = false, items = emptyList())
|
||||
return@runCatching QueryLogResult(
|
||||
result = CreatorRankingResult(showRankChange = false, items = emptyList()),
|
||||
blockedCreatorCount = 0
|
||||
)
|
||||
}
|
||||
|
||||
val previousItems = snapshotPort.findPreviousCompletedSnapshots().toRankedItems()
|
||||
@@ -34,9 +42,33 @@ class CreatorRankingQueryService(
|
||||
).maskIfBlocked(blockedCreatorIds)
|
||||
}
|
||||
|
||||
return CreatorRankingResult(showRankChange = showRankChange, items = items)
|
||||
QueryLogResult(
|
||||
result = CreatorRankingResult(showRankChange = showRankChange, items = items),
|
||||
blockedCreatorCount = blockedCreatorIds.size
|
||||
)
|
||||
}.onSuccess { logResult ->
|
||||
log.info(
|
||||
"event=creator_ranking_query_success showRankChange={} itemCount={} blockedCreatorCount={} elapsedMs={}",
|
||||
logResult.result.showRankChange,
|
||||
logResult.result.items.size,
|
||||
logResult.blockedCreatorCount,
|
||||
System.currentTimeMillis() - startedAt
|
||||
)
|
||||
}.onFailure { ex ->
|
||||
log.warn(
|
||||
"event=creator_ranking_query_failure elapsedMs={} error={}",
|
||||
System.currentTimeMillis() - startedAt,
|
||||
ex.message,
|
||||
ex
|
||||
)
|
||||
}.getOrThrow().result
|
||||
}
|
||||
|
||||
private data class QueryLogResult(
|
||||
val result: CreatorRankingResult,
|
||||
val blockedCreatorCount: Int
|
||||
)
|
||||
|
||||
private fun List<CreatorRankingSnapshotRecord>.toRankedItems(): List<CreatorRankingItem> {
|
||||
return groupBy { it.finalScore }
|
||||
.toSortedMap(compareByDescending { it })
|
||||
|
||||
@@ -8,11 +8,16 @@ import kr.co.vividnext.sodalive.v2.ranking.port.out.CreatorRankingSnapshotRecord
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Assertions.assertFalse
|
||||
import org.junit.jupiter.api.Assertions.assertNull
|
||||
import org.junit.jupiter.api.Assertions.assertThrows
|
||||
import org.junit.jupiter.api.Assertions.assertTrue
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.extension.ExtendWith
|
||||
import org.springframework.boot.test.system.CapturedOutput
|
||||
import org.springframework.boot.test.system.OutputCaptureExtension
|
||||
import java.time.LocalDateTime
|
||||
|
||||
@ExtendWith(OutputCaptureExtension::class)
|
||||
class CreatorRankingQueryServiceTest {
|
||||
@Test
|
||||
@DisplayName("스냅샷 후보와 조회 item 내부 모델은 순위 변화와 신규 진입 값을 담을 수 있다")
|
||||
@@ -177,6 +182,37 @@ class CreatorRankingQueryServiceTest {
|
||||
assertEquals("profile-1.png", result.items.single().profileImageUrl)
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("크리에이터 랭킹 조회 성공은 순위 변화 노출 여부와 반환 수를 로그로 남긴다")
|
||||
fun shouldLogCreatorRankingQuerySuccessWithResultCounts(output: CapturedOutput) {
|
||||
val snapshotPort = FakeCreatorRankingQuerySnapshotPort()
|
||||
snapshotPort.latestSnapshots = listOf(snapshot(creatorId = 1L, finalScore = 100.0))
|
||||
val service = service(snapshotPort = snapshotPort)
|
||||
|
||||
service.getCreatorRankings(viewerMemberId = null)
|
||||
|
||||
assertTrue(output.out.contains("event=creator_ranking_query_success"))
|
||||
assertTrue(output.out.contains("showRankChange=false"))
|
||||
assertTrue(output.out.contains("itemCount=1"))
|
||||
assertTrue(output.out.contains("blockedCreatorCount=0"))
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("크리에이터 랭킹 조회 실패는 에러를 로그로 남기고 예외를 전파한다")
|
||||
fun shouldLogCreatorRankingQueryFailureWithError(output: CapturedOutput) {
|
||||
val snapshotPort = FakeCreatorRankingQuerySnapshotPort()
|
||||
snapshotPort.latestFailure = IllegalStateException("latest snapshots failed")
|
||||
val service = service(snapshotPort = snapshotPort)
|
||||
|
||||
val exception = assertThrows(IllegalStateException::class.java) {
|
||||
service.getCreatorRankings(viewerMemberId = 99L)
|
||||
}
|
||||
|
||||
assertEquals("latest snapshots failed", exception.message)
|
||||
assertTrue(output.out.contains("event=creator_ranking_query_failure"))
|
||||
assertTrue(output.out.contains("error=latest snapshots failed"))
|
||||
}
|
||||
|
||||
private fun service(
|
||||
snapshotPort: CreatorRankingSnapshotPort = FakeCreatorRankingQuerySnapshotPort(),
|
||||
blockPort: CreatorRankingBlockPort = FakeCreatorRankingBlockPort()
|
||||
@@ -219,13 +255,17 @@ class CreatorRankingQueryServiceTest {
|
||||
private class FakeCreatorRankingQuerySnapshotPort : CreatorRankingSnapshotPort {
|
||||
var latestSnapshots: List<CreatorRankingSnapshotRecord> = emptyList()
|
||||
var previousSnapshots: List<CreatorRankingSnapshotRecord> = emptyList()
|
||||
var latestFailure: RuntimeException? = null
|
||||
|
||||
override fun findSnapshotsByAggregationPeriod(
|
||||
aggregationStartAtUtc: LocalDateTime,
|
||||
aggregationEndAtUtc: LocalDateTime
|
||||
): List<CreatorRankingSnapshotRecord> = emptyList()
|
||||
|
||||
override fun findLatestSnapshots(): List<CreatorRankingSnapshotRecord> = latestSnapshots
|
||||
override fun findLatestSnapshots(): List<CreatorRankingSnapshotRecord> {
|
||||
latestFailure?.let { throw it }
|
||||
return latestSnapshots
|
||||
}
|
||||
|
||||
override fun findPreviousCompletedSnapshots(): List<CreatorRankingSnapshotRecord> = previousSnapshots
|
||||
|
||||
|
||||
Reference in New Issue
Block a user