Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ android {
buildConfigField("String", "NAVER_CLIENT_SECRET", properties["NAVER_CLIENT_SECRET"].toString())
buildConfigField("String", "KAKAO_NATIVE_APP_KEY", properties["kakao.native.app.key"].toString())
manifestPlaceholders["KAKAO_NATIVE_APP_KEY_MANIFEST"] = properties["kakao.native.app.key.manifest"].toString()
buildConfigField("String", "DISCORD_WEBHOOK_URL", properties["DISCORD_WEBHOOK_URL"].toString())
}

signingConfigs {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.kuit.findu.data.dataremote.service

import com.kuit.findu.domain.model.DiscordLogBody
import retrofit2.http.Body
import retrofit2.http.POST
import retrofit2.http.Url

interface WebhookService {
@POST
suspend fun sendLog(
@Url webhookUrl: String,
@Body body: DiscordLogBody
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.kuit.findu.data.dataremote.util

import com.kuit.findu.data.dataremote.service.WebhookService
import com.kuit.findu.domain.model.DiscordLogBody
import com.kuit.findu.domain.repository.UserInfoRepository
import javax.inject.Inject

class DiscordLogger @Inject constructor(
private val webhookService: WebhookService,
private val userInfoRepository: UserInfoRepository,
private val webhookUrl: String,
) {

suspend fun logServerError(
code: Int,
method: String,
url: String,
) {
val deviceId = userInfoRepository.getDeviceId()
val nickname = userInfoRepository.getNickname()

val body = DiscordLogBody(
content = """
🚨 **Server Error 발생**

👤 User
- Nickname: $nickname
- DeviceId: $deviceId

🌐 Request
- Method: $method
- Url: $url
- Code: $code
""".trimIndent()
)

runCatching {
webhookService.sendLog(webhookUrl, body)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,42 +2,54 @@ package com.kuit.findu.data.dataremote.util

import com.google.firebase.crashlytics.FirebaseCrashlytics
import com.google.firebase.crashlytics.recordException
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import okhttp3.Interceptor
import okhttp3.Response
import javax.inject.Inject

class ErrorTrackingInterceptor @Inject constructor(
private val firebaseCrashlytics: FirebaseCrashlytics,
private val discordLogger: DiscordLogger,
) : Interceptor {

override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request()
val response: Response

try {
response = chain.proceed(request)
} catch (e: Exception) {
// 1. 네트워크 자체가 끊긴 경우 등 (IOException)
firebaseCrashlytics.recordException(e)
throw e
}

// 2. 서버에서 응답은 왔으나 4xx, 5xx 에러인 경우
if (!response.isSuccessful) {
val code = response.code

val url = request.url.toString()

// Crashlytics에 상세 정보 기록
val exceptionMessage = when (response.code) {
in (400..499) -> "Client $code Error"
in (500..599) -> "Server $code Error"
val exceptionMessage = when (code) {
in 400..499 -> "Client $code Error"
in 500..599 -> "Server $code Error"
else -> "Unknown $code Error"
}

firebaseCrashlytics.recordException(Exception(exceptionMessage)) {
key("api_method", request.method)
key("api_url", url)
key("api_status", code)
}

if (code in 500..599) {
CoroutineScope(Dispatchers.IO).launch {
discordLogger.logServerError(
code = code,
method = request.method,
url = url
)
}
}
}

return response
Expand Down
27 changes: 27 additions & 0 deletions app/src/main/java/com/kuit/findu/di/LogModule.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.kuit.findu.di

import com.kuit.findu.BuildConfig
import com.kuit.findu.data.dataremote.service.WebhookService
import com.kuit.findu.data.dataremote.util.DiscordLogger
import com.kuit.findu.domain.repository.UserInfoRepository
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton

@Module
@InstallIn(SingletonComponent::class)
object LogModule {
@Provides
@Singleton
fun provideDiscordLogger(
webhookService: WebhookService,
userInfoRepository: UserInfoRepository,
): DiscordLogger =
DiscordLogger(
webhookService,
userInfoRepository,
BuildConfig.DISCORD_WEBHOOK_URL,
)
}
42 changes: 42 additions & 0 deletions app/src/main/java/com/kuit/findu/di/LogNetworkModule.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.kuit.findu.di

import com.kuit.findu.data.dataremote.service.WebhookService
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import okhttp3.OkHttpClient
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import javax.inject.Named
import javax.inject.Singleton

@Module
@InstallIn(SingletonComponent::class)
object LogNetworkModule {

@Provides
@Singleton
@Named("webhook")
fun provideWebhookOkHttpClient(): OkHttpClient =
OkHttpClient.Builder().build()

@Provides
@Singleton
@Named("webhook")
fun provideWebhookRetrofit(
@Named("webhook") okHttpClient: OkHttpClient
): Retrofit =
Retrofit.Builder()
.baseUrl("https://discord.com/")
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create())
.build()

@Provides
@Singleton
fun provideWebhookService(
@Named("webhook") retrofit: Retrofit
): WebhookService =
retrofit.create(WebhookService::class.java)
}
7 changes: 6 additions & 1 deletion app/src/main/java/com/kuit/findu/di/NetworkModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import com.kuit.findu.BuildConfig.DEBUG
import com.kuit.findu.data.datalocal.datasource.TokenLocalDataSource
import com.kuit.findu.data.dataremote.util.AuthAuthenticator
import com.kuit.findu.data.dataremote.util.AuthInterceptor
import com.kuit.findu.data.dataremote.util.DiscordLogger
import com.kuit.findu.data.dataremote.util.ErrorTrackingInterceptor
import dagger.Module
import dagger.Provides
Expand Down Expand Up @@ -85,8 +86,12 @@ object NetworkModule {
@Singleton
fun provideErrorTrackingInterceptor(
firebaseCrashlytics: FirebaseCrashlytics,
discordLogger: DiscordLogger
): ErrorTrackingInterceptor {
return ErrorTrackingInterceptor(firebaseCrashlytics)
return ErrorTrackingInterceptor(
firebaseCrashlytics= firebaseCrashlytics,
discordLogger = discordLogger
)
}

@ExperimentalSerializationApi
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.kuit.findu.domain.model

data class DiscordLogBody(
val content: String
)