diff --git a/README.md b/README.md index c15ba04..a655059 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,7 @@ * [GlobalConfig](#globalconfig) * [GlobalConfig.init](#globalconfiginit) * [Updating configuration](#updating-configuration) + * [SDKLogger](#sdklogger) * [ChatSession APIs](#chatsession-apis) * [ChatSession Events](#chatsession-events) * [Classes and Structs](#classes-and-structs) @@ -121,6 +122,31 @@ val globalConfig = GlobalConfig(region = chatConfiguration.region) chatSession.configure(globalConfig) ``` +### SDKLogger +The `SDKLogger` class is responsible for logging relevant runtime information to the console which is useful for debugging purposes. The `SDKLogger` will log key events such as establishing a connection or failures such as failing to send a message. + +#### `SDKLogger.configure` +This API will allow you to override the SDK's built-in logger with your own [ChatSDKLogger](#chatsdklogger) implementation. This is especially useful in cases where you would want to store logs for debugging purposes. Attaching these logs to issues filed in this project will greatly expedite the resolution process. + +``` +fun configureLogger(logger: ChatSDKLogger) { + this.logger = logger +} +``` + +#### ChatSDKLogger +The ChatSDKLogger is an interface used for the `SDKLogger`. Users can override the `SDKLogger` with any class that implements the ChatSDKLogger interface. + +``` +interface ChatSDKLogger { + fun logVerbose(message: () -> String) + fun logInfo(message: () -> String) + fun logDebug(message: () -> String) + fun logWarn(message: () -> String) + fun logError(message: () -> String) +} +``` + -------------------- ### ChatSession APIs diff --git a/app/src/main/java/com/amazon/connect/chat/androidchatexample/MainActivity.kt b/app/src/main/java/com/amazon/connect/chat/androidchatexample/MainActivity.kt index 114f9fd..577e1b8 100644 --- a/app/src/main/java/com/amazon/connect/chat/androidchatexample/MainActivity.kt +++ b/app/src/main/java/com/amazon/connect/chat/androidchatexample/MainActivity.kt @@ -63,6 +63,7 @@ import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.ViewModelProvider import com.amazon.connect.chat.androidchatexample.ui.theme.androidconnectchatandroidTheme +import com.amazon.connect.chat.androidchatexample.utils.CustomLogger import com.amazon.connect.chat.androidchatexample.utils.FileUtils.getOriginalFileName import com.amazon.connect.chat.androidchatexample.utils.FileUtils.previewFileFromCacheOrDownload import com.amazon.connect.chat.androidchatexample.viewmodel.ChatViewModel @@ -74,6 +75,7 @@ import com.amazon.connect.chat.sdk.model.Message import com.amazon.connect.chat.sdk.model.MessageDirection import com.amazon.connect.chat.sdk.model.TranscriptItem import com.amazon.connect.chat.sdk.utils.CommonUtils.Companion.keyboardAsState +import com.amazon.connect.chat.sdk.utils.logger.SDKLogger import dagger.hilt.android.AndroidEntryPoint import java.net.URL @@ -91,6 +93,14 @@ class MainActivity : ComponentActivity() { ) chatViewModel = ViewModelProvider(this)[ChatViewModel::class.java] + val externalFileDir = applicationContext.getExternalFilesDir(null) + + if (externalFileDir !== null) { + val logger = CustomLogger() + logger.setLogOutputDir(externalFileDir) + SDKLogger.configureLogger(logger) + } + setContent { androidconnectchatandroidTheme { // A surface container using the 'background' color from the theme diff --git a/app/src/main/java/com/amazon/connect/chat/androidchatexample/utils/CommonUtils.kt b/app/src/main/java/com/amazon/connect/chat/androidchatexample/utils/CommonUtils.kt index 67fc560..7b6bd59 100644 --- a/app/src/main/java/com/amazon/connect/chat/androidchatexample/utils/CommonUtils.kt +++ b/app/src/main/java/com/amazon/connect/chat/androidchatexample/utils/CommonUtils.kt @@ -7,6 +7,7 @@ import com.amazon.connect.chat.sdk.model.MessageDirection import com.amazon.connect.chat.sdk.model.MessageStatus import com.amazon.connect.chat.sdk.model.TranscriptItem import java.text.SimpleDateFormat +import java.util.Date import java.util.Locale import java.util.TimeZone @@ -28,6 +29,20 @@ object CommonUtils { } } + fun formatDate(currentTimeMillis: Long, forLogs: Boolean = false): String { + val date = Date(currentTimeMillis) + var utcFormatter: SimpleDateFormat? = null + if (forLogs) { + utcFormatter = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US).apply { + timeZone = TimeZone.getTimeZone("UTC") + } + } else { + utcFormatter = SimpleDateFormat("yyyy-MM-dd_HH-mm", Locale.US).apply { + timeZone = TimeZone.getTimeZone("UTC") + } + } + return utcFormatter.format(date) + } fun getMessageDirection(transcriptItem: TranscriptItem) { when (transcriptItem) { diff --git a/app/src/main/java/com/amazon/connect/chat/androidchatexample/utils/CustomLogger.kt b/app/src/main/java/com/amazon/connect/chat/androidchatexample/utils/CustomLogger.kt index 02e3910..5eca7bd 100644 --- a/app/src/main/java/com/amazon/connect/chat/androidchatexample/utils/CustomLogger.kt +++ b/app/src/main/java/com/amazon/connect/chat/androidchatexample/utils/CustomLogger.kt @@ -1,30 +1,97 @@ package com.amazon.connect.chat.androidchatexample.utils import com.amazon.connect.chat.sdk.utils.logger.ChatSDKLogger +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import java.io.File +import java.io.FileNotFoundException +import java.text.SimpleDateFormat +import java.util.Date +import java.util.Locale +import java.util.TimeZone +import kotlin.io.path.Path +import kotlin.io.path.appendText +import kotlin.io.path.createFile +import kotlin.io.path.exists class CustomLogger : ChatSDKLogger { + private var outputFileDir: File? = null + private val job = SupervisorJob() + private val coroutineScope = CoroutineScope(job + Dispatchers.IO) + + private val currentTimeMillis = System.currentTimeMillis() + private val loggerCreationDateAndTime = CommonUtils.formatDate(currentTimeMillis, false) + override fun logVerbose(message: () -> String) { // Custom logging logic - println("VERBOSE: ${message()}") + val logMessage = "VERBOSE: ${message()}" + println(logMessage) + coroutineScope.launch { + writeToAppTempFile(logMessage) + } } override fun logInfo(message: () -> String) { // Custom logging logic - println("INFO: ${message()}") + val logMessage = "INFO: ${message()}" + println(logMessage) + coroutineScope.launch { + writeToAppTempFile(logMessage) + } } override fun logDebug(message: () -> String) { // Custom logging logic - println("DEBUG: ${message()}") + val logMessage = "DEBUG: ${message()}" + println(logMessage) + coroutineScope.launch { + writeToAppTempFile(logMessage) + } + } override fun logWarn(message: () -> String) { // Custom logging logic - println("WARN: ${message()}") + val logMessage = "WARN: ${message()}" + println(logMessage) + coroutineScope.launch { + writeToAppTempFile(logMessage) + } } override fun logError(message: () -> String) { // Custom logging logic - println("ERROR: ${message()}") + val logMessage = "ERROR: ${message()}" + println(logMessage) + coroutineScope.launch { + writeToAppTempFile(logMessage) + } + } + + fun setLogOutputDir(tempFile: File) { + outputFileDir = tempFile + } + + private suspend fun writeToAppTempFile(content: String): Result { + return withContext(Dispatchers.IO) { + runCatching { + val currentTimeMillis = System.currentTimeMillis() + val formattedDateTimeForLogs = CommonUtils.formatDate(currentTimeMillis, true) + if (outputFileDir == null || !outputFileDir!!.exists() || !outputFileDir!!.isDirectory()) { + return@runCatching false + } + val filePath = Path(outputFileDir!!.absolutePath, "$loggerCreationDateAndTime-amazon-connect-logs.txt") + + if (!filePath.exists()) { + filePath.createFile() + } + + filePath.appendText("[$formattedDateTimeForLogs] $content \n") + true + } + } } } diff --git a/chat-sdk/src/main/java/com/amazon/connect/chat/sdk/ChatSession.kt b/chat-sdk/src/main/java/com/amazon/connect/chat/sdk/ChatSession.kt index 781c979..c959711 100644 --- a/chat-sdk/src/main/java/com/amazon/connect/chat/sdk/ChatSession.kt +++ b/chat-sdk/src/main/java/com/amazon/connect/chat/sdk/ChatSession.kt @@ -1,19 +1,16 @@ package com.amazon.connect.chat.sdk import android.net.Uri -import android.util.Log import com.amazon.connect.chat.sdk.model.ChatDetails import com.amazon.connect.chat.sdk.model.ChatEvent import com.amazon.connect.chat.sdk.model.ContentType import com.amazon.connect.chat.sdk.model.GlobalConfig import com.amazon.connect.chat.sdk.model.Message -import com.amazon.connect.chat.sdk.model.MessageDirection import com.amazon.connect.chat.sdk.model.MessageReceiptType import com.amazon.connect.chat.sdk.model.MessageStatus import com.amazon.connect.chat.sdk.model.TranscriptItem import com.amazon.connect.chat.sdk.model.TranscriptResponse import com.amazon.connect.chat.sdk.repository.ChatService -import com.amazon.connect.chat.sdk.utils.logger.SDKLogger import com.amazonaws.services.connectparticipant.model.ScanDirection import com.amazonaws.services.connectparticipant.model.SortKey import com.amazonaws.services.connectparticipant.model.StartPosition