Distinguish between indexable and non-indexable extra data
This commit is contained in:
parent
5c6fee08fd
commit
7fe3b18699
10 changed files with 69 additions and 11 deletions
|
|
@ -106,7 +106,7 @@ class MatrixSessionCache(
|
||||||
.onSuccess { matrixClient ->
|
.onSuccess { matrixClient ->
|
||||||
// Add the current homeserver (hashed) to the extra info
|
// Add the current homeserver (hashed) to the extra info
|
||||||
// This may not play well with multiple sessions, but it should work for now
|
// This may not play well with multiple sessions, but it should work for now
|
||||||
analyticsService.addUserData(AnalyticsUserData.HOMESERVER, matrixClient.userIdServerName().hash())
|
analyticsService.addIndexableData(AnalyticsUserData.HOMESERVER, matrixClient.userIdServerName().hash())
|
||||||
|
|
||||||
// Add the new client to the in-memory cache
|
// Add the new client to the in-memory cache
|
||||||
onNewMatrixClient(matrixClient)
|
onNewMatrixClient(matrixClient)
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ import io.element.android.libraries.matrix.api.sync.SyncService
|
||||||
import io.element.android.libraries.matrix.api.sync.SyncState
|
import io.element.android.libraries.matrix.api.sync.SyncState
|
||||||
import io.element.android.services.analytics.api.AnalyticsService
|
import io.element.android.services.analytics.api.AnalyticsService
|
||||||
import io.element.android.services.analytics.api.recordTransaction
|
import io.element.android.services.analytics.api.recordTransaction
|
||||||
|
import io.element.android.services.analyticsproviders.api.AnalyticsUserData
|
||||||
import io.element.android.services.appnavstate.api.AppForegroundStateService
|
import io.element.android.services.appnavstate.api.AppForegroundStateService
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.FlowPreview
|
import kotlinx.coroutines.FlowPreview
|
||||||
|
|
@ -77,7 +78,7 @@ class SyncOrchestrator(
|
||||||
|
|
||||||
// Wait until the sync service is not idle, either it will be running or in error/offline state
|
// Wait until the sync service is not idle, either it will be running or in error/offline state
|
||||||
val firstState = syncService.syncState.first { it != SyncState.Idle }
|
val firstState = syncService.syncState.first { it != SyncState.Idle }
|
||||||
transaction.setData("first_sync_state", firstState.name)
|
transaction.putIndexableData(AnalyticsUserData.FIRST_SYNC_STATE, firstState.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
observeStates()
|
observeStates()
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,7 @@ import io.element.android.services.analytics.api.AnalyticsLongRunningTransaction
|
||||||
import io.element.android.services.analytics.api.AnalyticsLongRunningTransaction.OpenRoom
|
import io.element.android.services.analytics.api.AnalyticsLongRunningTransaction.OpenRoom
|
||||||
import io.element.android.services.analytics.api.AnalyticsService
|
import io.element.android.services.analytics.api.AnalyticsService
|
||||||
import io.element.android.services.analytics.api.finishLongRunningTransaction
|
import io.element.android.services.analytics.api.finishLongRunningTransaction
|
||||||
|
import io.element.android.services.analyticsproviders.api.AnalyticsUserData
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
import kotlinx.collections.immutable.persistentListOf
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
|
@ -249,7 +250,7 @@ class TimelinePresenter(
|
||||||
combine(timelineController.timelineItems(), room.membersStateFlow) { items, membersState ->
|
combine(timelineController.timelineItems(), room.membersStateFlow) { items, membersState ->
|
||||||
val parent = analyticsService.getLongRunningTransaction(DisplayFirstTimelineItems)
|
val parent = analyticsService.getLongRunningTransaction(DisplayFirstTimelineItems)
|
||||||
val transaction = parent?.startChild("timelineItemsFactory.replaceWith", "Processing timeline items")
|
val transaction = parent?.startChild("timelineItemsFactory.replaceWith", "Processing timeline items")
|
||||||
transaction?.setData("items", items.count())
|
transaction?.putExtraData(AnalyticsUserData.TIMELINE_ITEM_COUNT, items.count().toString())
|
||||||
timelineItemsFactory.replaceWith(
|
timelineItemsFactory.replaceWith(
|
||||||
timelineItems = items,
|
timelineItems = items,
|
||||||
roomMembers = membersState.roomMembers().orEmpty()
|
roomMembers = membersState.roomMembers().orEmpty()
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,8 @@ import io.element.android.services.analyticsproviders.api.AnalyticsTransaction
|
||||||
|
|
||||||
object NoopAnalyticsTransaction : AnalyticsTransaction {
|
object NoopAnalyticsTransaction : AnalyticsTransaction {
|
||||||
override fun startChild(operation: String, description: String?): AnalyticsTransaction = NoopAnalyticsTransaction
|
override fun startChild(operation: String, description: String?): AnalyticsTransaction = NoopAnalyticsTransaction
|
||||||
override fun setData(key: String, value: Any) {}
|
override fun putExtraData(key: String, value: String) {}
|
||||||
|
override fun putIndexableData(key: String, value: String) {}
|
||||||
override fun isFinished(): Boolean = true
|
override fun isFinished(): Boolean = true
|
||||||
override fun traceId(): String? = null
|
override fun traceId(): String? = null
|
||||||
override fun attachError(throwable: Throwable) {}
|
override fun attachError(throwable: Throwable) {}
|
||||||
|
|
|
||||||
|
|
@ -149,9 +149,15 @@ class DefaultAnalyticsService(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun addUserData(key: String, value: String) {
|
override fun addExtraData(key: String, value: String) {
|
||||||
if (userConsent.get()) {
|
if (userConsent.get()) {
|
||||||
analyticsProviders.onEach { it.addUserData(key, value) }
|
analyticsProviders.onEach { it.addExtraData(key, value) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun addIndexableData(key: String, value: String) {
|
||||||
|
if (userConsent.get()) {
|
||||||
|
analyticsProviders.onEach { it.addIndexableData(key, value) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,14 +8,47 @@
|
||||||
package io.element.android.services.analyticsproviders.api
|
package io.element.android.services.analyticsproviders.api
|
||||||
|
|
||||||
interface AnalyticsTransaction {
|
interface AnalyticsTransaction {
|
||||||
|
/**
|
||||||
|
* Start a child span from this transaction.
|
||||||
|
*/
|
||||||
fun startChild(operation: String, description: String? = null): AnalyticsTransaction
|
fun startChild(operation: String, description: String? = null): AnalyticsTransaction
|
||||||
fun setData(key: String, value: Any)
|
|
||||||
|
/**
|
||||||
|
* Adds extra data to the transaction. This data is not indexed, it's just listed.
|
||||||
|
*/
|
||||||
|
fun putExtraData(key: String, value: String)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Similar to [putExtraData], adds extra data that *will be indexed* and can be used for filtering in the analytics portal.
|
||||||
|
*
|
||||||
|
* **Do not add numerical values using this function, use [putExtraData] instead.**
|
||||||
|
*/
|
||||||
|
fun putIndexableData(key: String, value: String)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the transaction has finished.
|
||||||
|
*/
|
||||||
fun isFinished(): Boolean
|
fun isFinished(): Boolean
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The optional trace id which can be used for distributed tracing.
|
||||||
|
*/
|
||||||
fun traceId(): String?
|
fun traceId(): String?
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attach a throwable to the transaction, so we can know it failed.
|
||||||
|
*/
|
||||||
fun attachError(throwable: Throwable)
|
fun attachError(throwable: Throwable)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finish the transaction. This will schedule an upload of the data.
|
||||||
|
*/
|
||||||
fun finish()
|
fun finish()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Records a child span from this transaction.
|
||||||
|
*/
|
||||||
inline fun <T> AnalyticsTransaction.recordChildTransaction(operation: String, description: String? = null, block: (AnalyticsTransaction) -> T): T {
|
inline fun <T> AnalyticsTransaction.recordChildTransaction(operation: String, description: String? = null, block: (AnalyticsTransaction) -> T): T {
|
||||||
val child = startChild(operation, description)
|
val child = startChild(operation, description)
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
|
|
@ -14,4 +14,7 @@ object AnalyticsUserData {
|
||||||
const val EVENT_CACHE_SIZE = "event_cache_size"
|
const val EVENT_CACHE_SIZE = "event_cache_size"
|
||||||
const val CRYPTO_STORE_SIZE = "crypto_store_size"
|
const val CRYPTO_STORE_SIZE = "crypto_store_size"
|
||||||
const val MEDIA_STORE_SIZE = "media_store_size"
|
const val MEDIA_STORE_SIZE = "media_store_size"
|
||||||
|
|
||||||
|
const val FIRST_SYNC_STATE = "first_sync_state"
|
||||||
|
const val TIMELINE_ITEM_COUNT = "timeline_item_count"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,9 +37,16 @@ interface AnalyticsTracker {
|
||||||
fun updateSuperProperties(updatedProperties: SuperProperties)
|
fun updateSuperProperties(updatedProperties: SuperProperties)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds user data that will be sent with every event.
|
* Adds extra data that will be sent with every event.
|
||||||
*/
|
*/
|
||||||
fun addUserData(key: String, value: String) {}
|
fun addExtraData(key: String, value: String) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Similar to [addExtraData], adds data that will be indexed in the analytics portal.
|
||||||
|
*
|
||||||
|
* **Do not add numerical values using this, use [addExtraData] instead.**
|
||||||
|
*/
|
||||||
|
fun addIndexableData(key: String, value: String) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun AnalyticsTracker.captureInteraction(name: Interaction.Name, type: Interaction.InteractionType? = null) {
|
fun AnalyticsTracker.captureInteraction(name: Interaction.Name, type: Interaction.InteractionType? = null) {
|
||||||
|
|
|
||||||
|
|
@ -113,10 +113,14 @@ class SentryAnalyticsProvider(
|
||||||
override fun updateSuperProperties(updatedProperties: SuperProperties) {
|
override fun updateSuperProperties(updatedProperties: SuperProperties) {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun addUserData(key: String, value: String) {
|
override fun addExtraData(key: String, value: String) {
|
||||||
Sentry.setExtra(key, value)
|
Sentry.setExtra(key, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun addIndexableData(key: String, value: String) {
|
||||||
|
Sentry.setTag(key, value)
|
||||||
|
}
|
||||||
|
|
||||||
override fun trackError(throwable: Throwable) {
|
override fun trackError(throwable: Throwable) {
|
||||||
Sentry.captureException(throwable)
|
Sentry.captureException(throwable)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,9 @@ class SentryAnalyticsTransaction private constructor(span: ISpan) : AnalyticsTra
|
||||||
override fun startChild(operation: String, description: String?): AnalyticsTransaction = SentryAnalyticsTransaction(
|
override fun startChild(operation: String, description: String?): AnalyticsTransaction = SentryAnalyticsTransaction(
|
||||||
inner.startChild(operation, description)
|
inner.startChild(operation, description)
|
||||||
)
|
)
|
||||||
override fun setData(key: String, value: Any) = inner.setData(key, value)
|
|
||||||
|
override fun putIndexableData(key: String, value: String) = inner.setTag(key, value)
|
||||||
|
override fun putExtraData(key: String, value: String) = inner.setData(key, value)
|
||||||
override fun traceId(): String? = inner.toSentryTrace().value
|
override fun traceId(): String? = inner.toSentryTrace().value
|
||||||
override fun isFinished(): Boolean = inner.isFinished
|
override fun isFinished(): Boolean = inner.isFinished
|
||||||
override fun attachError(throwable: Throwable) {
|
override fun attachError(throwable: Throwable) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue