Skip to content

Commit 1bdfb9e

Browse files
improve: integrate Event Logger module and send events (RMCCX-9004)
1 parent bde7cfb commit 1bdfb9e

32 files changed

+649
-129
lines changed

inappmessaging/USERGUIDE.md

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,39 @@ If you want to enable SDK debug logging (tags begins with "IAM_"), add this meta
7474
android:value="true"/>
7575
```
7676

77-
### <a name="configure"></a>5. Call configure()
77+
### <a name="error-logging"></a>5. Configure Event Logger (Optional)
78+
Event Logger is a troubleshooting utility which helps to track or send important SDK events to a remote API server.
79+
80+
To enable this feature, set the Event Logger API URL and Key. To obtain these credentials, please reach out to the In-App Messaging Team.
81+
82+
* Option 1 (Build-time): Add this metadata in `AndroidManifest.xml`:
83+
```xml
84+
<meta-data
85+
android:name="com.rakuten.tech.mobile.inappmessaging.eventloggerapiurl"
86+
android:value="${event-logger-api-url}" />
87+
88+
<meta-data
89+
android:name="com.rakuten.tech.mobile.inappmessaging.eventloggerapikey"
90+
android:value="${event-logger-api-key}"/>
91+
```
92+
* Option 2 (Runtime): Call `setEventLoggerConfig` API in your Application's `onCreate`:
93+
```kotlin
94+
class MainApplication : Application() {
95+
96+
override fun onCreate() {
97+
InAppMessaging.setEventLoggerConfig(apiUrl = "<event-logger-api-key>", apiKey = "<event-logger-api-key>")
98+
}
99+
}
100+
```
101+
102+
To disable this feature, do not provide the Event Logger API URL and Key; or to explicitly disable it, add this metadata in `AndroidManifest.xml`:
103+
```xml
104+
<meta-data
105+
android:name="com.rakuten.tech.mobile.inappmessaging.enableeventlogger"
106+
android:value="false" />
107+
```
108+
109+
### <a name="configure"></a>6. Call configure()
78110
This method initializes the SDK and should be called in your Application's `onCreate`.
79111

80112
An optional lambda function callback can be set to receive exceptions that caused failed configuration or non-fatal failures in the SDK.
@@ -510,6 +542,7 @@ All the events "launch the app event, login event, purchase successful event, cu
510542
#### 7.8.0 (In-Progress)
511543
* Improvements:
512544
- RMCCX-9127: Update userguide to add SDK logic for [Deeplink handling](#deeplink-handling).
545+
- RMCCX-9004: Integrate `Event Logger` module and send events. For more details, see [Configure Event Logger](#error-logging) section.
513546

514547
#### 7.7.0 (2024-10-22)
515548
* Improvements:

inappmessaging/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ dependencies {
6363
implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.0.0'
6464
implementation 'com.google.code.gson:gson:2.9.1'
6565
implementation "com.squareup.picasso:picasso:2.71828"
66-
implementation "io.github.rakutentech.sdkutils:sdk-utils:2.1.1"
66+
implementation "io.github.rakutentech.sdkutils:sdk-utils:2.2.0"
6767
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
6868
implementation 'androidx.appcompat:appcompat:1.1.0'
6969

inappmessaging/src/main/java/com/rakuten/tech/mobile/inappmessaging/runtime/EventTrackerHelper.kt

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
package com.rakuten.tech.mobile.inappmessaging.runtime
22

33
import android.text.TextUtils
4+
import com.rakuten.tech.mobile.inappmessaging.runtime.eventlogger.Event
45
import com.rakuten.tech.mobile.inappmessaging.runtime.utils.ClassUtil
5-
import com.rakuten.tech.mobile.inappmessaging.runtime.utils.InAppLogger
66

77
internal object EventTrackerHelper {
88

@@ -33,8 +33,7 @@ internal object EventTrackerHelper {
3333
com.rakuten.tech.mobile.analytics.RatTracker.event(eventName, serializableData).track()
3434
return true
3535
} catch (e: Exception) {
36-
InAppLogger(TAG).warn("sendEvent - analytics.track() failed")
37-
InAppLogger(TAG).debug("exception: $e")
36+
InAppErrorLogger.logError(TAG, InAppError(ex = e, ev = Event.ImpressionRatTrackerFailed))
3837
}
3938
}
4039
}

inappmessaging/src/main/java/com/rakuten/tech/mobile/inappmessaging/runtime/InApp.kt

Lines changed: 44 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import com.rakuten.tech.mobile.inappmessaging.runtime.data.repositories.AccountR
1212
import com.rakuten.tech.mobile.inappmessaging.runtime.data.repositories.CampaignRepository
1313
import com.rakuten.tech.mobile.inappmessaging.runtime.data.repositories.ConfigResponseRepository
1414
import com.rakuten.tech.mobile.inappmessaging.runtime.data.repositories.HostAppInfoRepository
15+
import com.rakuten.tech.mobile.inappmessaging.runtime.eventlogger.SdkApi
16+
import com.rakuten.tech.mobile.inappmessaging.runtime.eventlogger.Event as ELEvent
1517
import com.rakuten.tech.mobile.inappmessaging.runtime.exception.InAppMessagingException
1618
import com.rakuten.tech.mobile.inappmessaging.runtime.manager.DisplayManager
1719
import com.rakuten.tech.mobile.inappmessaging.runtime.manager.EventsManager
@@ -71,9 +73,14 @@ internal class InApp(
7173
displayManager.displayMessage()
7274
}
7375
} catch (ex: Exception) {
74-
InAppLogger(TAG).error("registerActivity - error: ${ex.message}")
75-
errorCallback?.let {
76-
it(InAppMessagingException("In-App Messaging register activity failed", ex))
76+
"In-App Messaging register activity failed".let {
77+
InAppErrorLogger.logError(
78+
TAG,
79+
InAppError(
80+
it, InAppMessagingException(it, ex),
81+
ELEvent.OperationFailed(SdkApi.REGISTER_ACTIVITY.name),
82+
),
83+
)
7784
}
7885
}
7986
}
@@ -87,9 +94,14 @@ internal class InApp(
8794
}
8895
hostAppInfoRepo.registerActivity(null)
8996
} catch (ex: Exception) {
90-
InAppLogger(TAG).warn("unregisterActivity - error: ${ex.message}")
91-
errorCallback?.let {
92-
it(InAppMessagingException("In-App Messaging unregister activity failed", ex))
97+
"In-App Messaging unregister activity failed".let {
98+
InAppErrorLogger.logError(
99+
TAG,
100+
InAppError(
101+
it, InAppMessagingException(it, ex),
102+
ELEvent.OperationFailed(SdkApi.UNREGISTER_ACTIVITY.name),
103+
),
104+
)
93105
}
94106
}
95107
}
@@ -129,9 +141,14 @@ internal class InApp(
129141
eventsManager.onEventReceived(event)
130142
}
131143
} catch (ex: Exception) {
132-
InAppLogger(TAG).error("logEvent - error: ${ex.message}")
133-
errorCallback?.let {
134-
it(InAppMessagingException("In-App Messaging log event failed", ex))
144+
"In-App Messaging log event failed".let {
145+
InAppErrorLogger.logError(
146+
TAG,
147+
InAppError(
148+
it, InAppMessagingException(it, ex),
149+
ELEvent.OperationFailed(SdkApi.LOG_EVENT.name),
150+
),
151+
)
135152
}
136153
}
137154
}
@@ -169,6 +186,7 @@ internal class InApp(
169186
@SuppressWarnings(
170187
"TooGenericExceptionCaught",
171188
"CanBeNonNullable",
189+
"LongMethod",
172190
)
173191
private fun closeCampaign(clearQueuedCampaigns: Boolean? = null, viewId: String? = null) {
174192
if (configRepo.isConfigEnabled()) {
@@ -182,9 +200,14 @@ internal class InApp(
182200
removeMessage(viewId)
183201
}
184202
} catch (ex: Exception) {
185-
InAppLogger(TAG).warn("closeCampaign - error: ${ex.message}")
186-
errorCallback?.let {
187-
it(InAppMessagingException("In-App Messaging close message failed", ex))
203+
"In-App Messaging close message failed".let {
204+
InAppErrorLogger.logError(
205+
TAG,
206+
InAppError(
207+
it, InAppMessagingException(it, ex),
208+
ELEvent.OperationFailed(SdkApi.CLOSE_MESSAGE.name),
209+
),
210+
)
188211
}
189212
}
190213
}
@@ -251,6 +274,15 @@ internal class InApp(
251274
* Flag to enable/disable debug logging.
252275
**/
253276
fun isDebugging(): Boolean = metadata.getBoolean("com.rakuten.tech.mobile.inappmessaging.debugging")
277+
278+
fun enableEventLogger(): Boolean =
279+
metadata.getBoolean("com.rakuten.tech.mobile.inappmessaging.enableeventlogger", true)
280+
281+
fun eventLoggerApiUrl(): String? =
282+
metadata.getString("com.rakuten.tech.mobile.inappmessaging.eventloggerapiurl")
283+
284+
fun eventLoggerApiKey(): String? =
285+
metadata.getString("com.rakuten.tech.mobile.inappmessaging.eventloggerapikey")
254286
}
255287

256288
companion object {
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package com.rakuten.tech.mobile.inappmessaging.runtime
2+
3+
import android.util.Log
4+
import com.rakuten.tech.mobile.inappmessaging.runtime.eventlogger.Event
5+
import com.rakuten.tech.mobile.inappmessaging.runtime.eventlogger.InAppEventLogger
6+
import com.rakuten.tech.mobile.inappmessaging.runtime.utils.InAppLogger
7+
8+
/**
9+
* @property message Descriptive error message.
10+
* @property ex Non-fatal exception (caught exception).
11+
* @property ev Event for the Event Logger platform.
12+
* @property meta Any metadata for this error.
13+
*/
14+
internal data class InAppError(
15+
var message: String? = null,
16+
val ex: Exception? = null,
17+
val ev: Event? = null,
18+
val meta: Map<String, String>? = null,
19+
)
20+
21+
/**
22+
* Utility class to log or report errors to different destinations.
23+
* - Logcat
24+
* - Callback for host app
25+
* - Remote logger (Event Logger platform)
26+
*/
27+
internal object InAppErrorLogger {
28+
29+
fun logError(tag: String, error: InAppError) {
30+
val errorMessage = error.message ?: "Unexpected error"
31+
val exceptionCause = (error.ex?.cause ?: error.ex?.message)?.let { ", Cause: $it" }.orEmpty()
32+
val fullMessage = "$errorMessage$exceptionCause"
33+
34+
if (InAppLogger.isDebug) {
35+
// To avoid initializing InAppLogger everytime based on tag, we will use the default logging utility
36+
Log.e(tag, "$fullMessage ${error.meta.orEmpty()}", error.ex)
37+
}
38+
39+
error.ex?.let { ex ->
40+
InAppMessaging.errorCallback?.invoke(ex)
41+
}
42+
43+
error.ev?.let { inAppEvent ->
44+
inAppEvent.message = fullMessage
45+
inAppEvent.info["tag"] = tag
46+
if (error.meta != null) {
47+
inAppEvent.info.putAll(error.meta)
48+
}
49+
50+
InAppEventLogger.logEvent(inAppEvent)
51+
}
52+
}
53+
}

inappmessaging/src/main/java/com/rakuten/tech/mobile/inappmessaging/runtime/InAppMessaging.kt

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ import androidx.annotation.NonNull
66
import androidx.annotation.RestrictTo
77
import com.rakuten.tech.mobile.inappmessaging.runtime.data.models.appevents.Event
88
import com.rakuten.tech.mobile.inappmessaging.runtime.data.repositories.AccountRepository
9+
import com.rakuten.tech.mobile.inappmessaging.runtime.eventlogger.EventLoggerConfig
10+
import com.rakuten.tech.mobile.inappmessaging.runtime.eventlogger.InAppEventLogger
11+
import com.rakuten.tech.mobile.inappmessaging.runtime.eventlogger.Event as ELEvent
12+
import com.rakuten.tech.mobile.inappmessaging.runtime.eventlogger.SdkApi
913
import com.rakuten.tech.mobile.inappmessaging.runtime.exception.InAppMessagingException
1014
import com.rakuten.tech.mobile.inappmessaging.runtime.utils.InAppLogger
1115
import com.rakuten.tech.mobile.inappmessaging.runtime.utils.Initializer
@@ -102,6 +106,8 @@ abstract class InAppMessaging internal constructor() {
102106
*/
103107
var errorCallback: ((ex: Exception) -> Unit)? = null
104108

109+
private var eventLoggerConfig: EventLoggerConfig? = null
110+
105111
private var instance: InAppMessaging = NotConfiguredInAppMessaging()
106112

107113
/**
@@ -134,6 +140,8 @@ abstract class InAppMessaging internal constructor() {
134140
enableTooltipFeature: Boolean? = false,
135141
): Boolean {
136142
return try {
143+
InAppEventLogger.configure(context, eventLoggerConfig)
144+
137145
if (!shouldProcess(subscriptionKey)) {
138146
InAppLogger(TAG).info("configure called but using RMC, skipping")
139147
return false
@@ -154,14 +162,33 @@ abstract class InAppMessaging internal constructor() {
154162
} catch (ex: Exception) {
155163
// reset instance when configuration failed
156164
setNotConfiguredInstance()
157-
errorCallback?.let {
158-
it(InAppMessagingException("In-App Messaging configuration failed", ex))
165+
"In-App Messaging configuration failed".let {
166+
InAppErrorLogger.logError(
167+
TAG,
168+
InAppError(
169+
it, InAppMessagingException(it, ex),
170+
ELEvent.OperationFailed(SdkApi.CONFIG.name),
171+
),
172+
)
159173
}
160-
InAppLogger(TAG).error("configure - error: ${ex.message}")
161174
false
162175
}
163176
}
164177

178+
/**
179+
* Configures the Event Logger platform for sending SDK critical or warning events.
180+
*
181+
* @param apiUrl An optional EventLogger API URL. Default is the value set in the app's AndroidManifest.
182+
* @param apiKey An optional EventLogger API Key. Default is the value set in the app's AndroidManifest.
183+
* @param enableEventLogger An optional flag to en/dis-able capturing events. Enabled by default.
184+
*
185+
* This method is intended for internal use only, and clients should not call this method directly.
186+
*/
187+
@JvmOverloads
188+
fun setEventLoggerConfig(apiUrl: String, apiKey: String, enableEventLogger: Boolean = true) {
189+
this.eventLoggerConfig = EventLoggerConfig(apiUrl, apiKey, enableEventLogger)
190+
}
191+
165192
@SuppressWarnings("LongParameterList")
166193
@Throws(InAppMessagingException::class)
167194
internal fun initialize(

inappmessaging/src/main/java/com/rakuten/tech/mobile/inappmessaging/runtime/coroutine/MessageActionsCoroutine.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import android.content.ActivityNotFoundException
66
import android.content.Intent
77
import android.net.Uri
88
import androidx.annotation.VisibleForTesting
9+
import com.rakuten.tech.mobile.inappmessaging.runtime.InAppError
10+
import com.rakuten.tech.mobile.inappmessaging.runtime.InAppErrorLogger
911
import com.rakuten.tech.mobile.inappmessaging.runtime.InAppMessaging
1012
import com.rakuten.tech.mobile.inappmessaging.runtime.R
1113
import com.rakuten.tech.mobile.inappmessaging.runtime.data.ui.UiMessage
@@ -29,8 +31,8 @@ import com.rakuten.tech.mobile.inappmessaging.runtime.manager.MessageReadinessMa
2931
import com.rakuten.tech.mobile.inappmessaging.runtime.manager.PushPrimerTrackerManager
3032
import com.rakuten.tech.mobile.inappmessaging.runtime.utils.BuildVersionChecker
3133
import com.rakuten.tech.mobile.inappmessaging.runtime.utils.CheckPermissionResult
32-
import com.rakuten.tech.mobile.inappmessaging.runtime.utils.InAppLogger
3334
import com.rakuten.tech.mobile.inappmessaging.runtime.utils.PermissionUtil
35+
import com.rakuten.tech.mobile.inappmessaging.runtime.eventlogger.Event as ELEvent
3436
import java.util.Date
3537
import kotlin.collections.ArrayList
3638

@@ -166,7 +168,7 @@ internal class MessageActionsCoroutine(
166168
try {
167169
activityContext.startActivity(intent)
168170
} catch (e: ActivityNotFoundException) {
169-
InAppLogger(TAG).info("handleDeeplinkRedirection - error: ${e.message}")
171+
InAppErrorLogger.logError(TAG, InAppError(ex = e, ev = ELEvent.CampaignRedirectActionFailed(uri)))
170172
}
171173
}
172174
}

inappmessaging/src/main/java/com/rakuten/tech/mobile/inappmessaging/runtime/data/repositories/CampaignRepository.kt

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
package com.rakuten.tech.mobile.inappmessaging.runtime.data.repositories
22

33
import com.google.gson.Gson
4+
import com.rakuten.tech.mobile.inappmessaging.runtime.InAppError
5+
import com.rakuten.tech.mobile.inappmessaging.runtime.InAppErrorLogger
46
import com.rakuten.tech.mobile.inappmessaging.runtime.InAppMessaging
57
import com.rakuten.tech.mobile.inappmessaging.runtime.data.enums.InAppMessageType
68
import com.rakuten.tech.mobile.inappmessaging.runtime.data.responses.ping.Message
9+
import com.rakuten.tech.mobile.inappmessaging.runtime.eventlogger.Event
710
import com.rakuten.tech.mobile.inappmessaging.runtime.utils.InAppLogger
811
import com.rakuten.tech.mobile.sdkutils.PreferencesUtil
912
import org.json.JSONObject
@@ -130,23 +133,37 @@ internal abstract class CampaignRepository {
130133
)
131134
}
132135

133-
@SuppressWarnings("TooGenericExceptionCaught")
136+
@SuppressWarnings(
137+
"TooGenericExceptionCaught",
138+
"LongMethod",
139+
)
134140
private fun loadCachedData() {
135-
if (InAppMessaging.instance().isLocalCachingEnabled()) {
136-
InAppLogger(TAG).debug("start")
137-
messages.clear()
141+
if (!InAppMessaging.instance().isLocalCachingEnabled()) {
142+
return
143+
}
144+
145+
InAppLogger(TAG).debug("start")
146+
messages.clear()
147+
val cachedData = retrieveData()
148+
if (cachedData.isNotEmpty()) {
138149
try {
139-
val jsonObject = JSONObject(retrieveData())
150+
val jsonObject = JSONObject(cachedData)
140151
for (key in jsonObject.keys()) {
141152
messages[key] = Gson().fromJson(
142153
jsonObject.getJSONObject(key).toString(), Message::class.java,
143154
)
144155
}
145156
} catch (ex: Exception) {
146-
InAppLogger(TAG).debug(ex.cause, "invalid JSON format for $IAM_USER_CACHE data")
157+
InAppErrorLogger.logError(
158+
TAG,
159+
InAppError(
160+
"invalid JSON format for $IAM_USER_CACHE data",
161+
ex, ev = Event.UserDataCacheDecodingFailed,
162+
),
163+
)
147164
}
148-
InAppLogger(TAG).debug("end")
149165
}
166+
InAppLogger(TAG).debug("end")
150167
}
151168

152169
private fun retrieveData(): String {

0 commit comments

Comments
 (0)