Adjust metrics to the new specifications (#5937)

* Add `AnalyticsTransactions` with a set of `TransactionDefinition` items matching those in the user story

* Use that for `AnalyticsLongRunningTransactions`, make sure we send the right fields (name, operation, description)

* Add `AnalyticsSendMessageWatcher` to track how long it takes for an event to be sent and for us to get a call back for that from sync

* Add `Noop` implementation for enterprise
This commit is contained in:
Jorge Martin Espinosa
2026-01-05 16:23:26 +01:00
committed by GitHub
parent bc62d4c8ba
commit 71031008dd
33 changed files with 443 additions and 48 deletions

View File

@@ -320,7 +320,7 @@ class RootFlowNode(
is ResolvedIntent.Navigation -> {
val openingRoomFromNotification = intent.getBooleanExtra(ROOM_OPENED_FROM_NOTIFICATION, false)
if (openingRoomFromNotification && resolvedIntent.deeplinkData is DeeplinkData.Room) {
analyticsService.startLongRunningTransaction(AnalyticsLongRunningTransaction.NotificationTapOpensTimeline)
analyticsService.startLongRunningTransaction(AnalyticsLongRunningTransaction.NotificationToMessage)
}
navigateTo(resolvedIntent.deeplinkData)
}

View File

@@ -10,8 +10,10 @@ package io.element.android.appnav.di
import io.element.android.features.messages.api.pinned.PinnedEventsTimelineProvider
import io.element.android.libraries.matrix.api.timeline.TimelineProvider
import io.element.android.services.analytics.api.watchers.AnalyticsSendMessageWatcher
interface TimelineBindings {
val timelineProvider: TimelineProvider
val pinnedEventsTimelineProvider: PinnedEventsTimelineProvider
val analyticsSendMessageWatcher: AnalyticsSendMessageWatcher
}

View File

@@ -49,7 +49,7 @@ import io.element.android.libraries.matrix.api.room.RoomMembershipObserver
import io.element.android.libraries.matrix.api.room.alias.ResolvedRoomAlias
import io.element.android.libraries.matrix.ui.room.LoadingRoomState
import io.element.android.services.analytics.api.AnalyticsLongRunningTransaction.LoadJoinedRoomFlow
import io.element.android.services.analytics.api.AnalyticsLongRunningTransaction.NotificationTapOpensTimeline
import io.element.android.services.analytics.api.AnalyticsLongRunningTransaction.NotificationToMessage
import io.element.android.services.analytics.api.AnalyticsLongRunningTransaction.OpenRoom
import io.element.android.services.analytics.api.AnalyticsService
import kotlinx.coroutines.flow.SharingStarted
@@ -128,7 +128,7 @@ class RoomFlowNode(
override fun onBuilt() {
super.onBuilt()
val parentTransaction = analyticsService.getLongRunningTransaction(NotificationTapOpensTimeline)
val parentTransaction = analyticsService.getLongRunningTransaction(NotificationToMessage)
val openRoomTransaction = analyticsService.startLongRunningTransaction(OpenRoom, parentTransaction)
analyticsService.startLongRunningTransaction(LoadJoinedRoomFlow, openRoomTransaction)
resolveRoomId()

View File

@@ -98,6 +98,8 @@ class JoinedRoomLoadedFlowNode(
private val callback: Callback = callback()
override val graph = roomGraphFactory.create(inputs.room)
private val sendMessageWatcher = (graph as? TimelineBindings)?.analyticsSendMessageWatcher
// This is an ugly hack to check activity recreation
private var currentActivity: Activity? = null
@@ -109,6 +111,7 @@ class JoinedRoomLoadedFlowNode(
Timber.v("OnCreate => ${inputs.room.roomId}")
appNavigationStateService.onNavigateToRoom(id, inputs.room.roomId)
activeRoomsHolder.addRoom(inputs.room)
sendMessageWatcher?.start()
fetchRoomMembers()
trackVisitedRoom()
},
@@ -120,6 +123,7 @@ class JoinedRoomLoadedFlowNode(
},
onDestroy = {
Timber.v("OnDestroy")
sendMessageWatcher?.stop()
// If we're just going through an activity recreation there's no need to destroy the Room object
// Destroying it would actually cause an issue where its methods can no longer be called
if (currentActivity?.isChangingConfigurations != true) {

View File

@@ -19,22 +19,29 @@ import com.bumble.appyx.testing.junit4.util.MainDispatcherRule
import com.bumble.appyx.testing.unit.common.helper.parentNodeTestHelper
import com.google.common.truth.Truth.assertThat
import io.element.android.appnav.di.RoomGraphFactory
import io.element.android.appnav.di.TimelineBindings
import io.element.android.appnav.room.RoomNavigationTarget
import io.element.android.appnav.room.joined.FakeJoinedRoomLoadedFlowNodeCallback
import io.element.android.appnav.room.joined.JoinedRoomLoadedFlowNode
import io.element.android.features.forward.api.ForwardEntryPoint
import io.element.android.features.forward.test.FakeForwardEntryPoint
import io.element.android.features.messages.api.MessagesEntryPoint
import io.element.android.features.messages.api.pinned.PinnedEventsTimelineProvider
import io.element.android.features.messages.test.pinned.FakePinnedEventsTimelineProvider
import io.element.android.features.roomdetails.api.RoomDetailsEntryPoint
import io.element.android.features.space.api.SpaceEntryPoint
import io.element.android.libraries.architecture.childNode
import io.element.android.libraries.matrix.api.room.JoinedRoom
import io.element.android.libraries.matrix.api.timeline.TimelineProvider
import io.element.android.libraries.matrix.test.A_SESSION_ID
import io.element.android.libraries.matrix.test.FakeMatrixClient
import io.element.android.libraries.matrix.test.room.FakeBaseRoom
import io.element.android.libraries.matrix.test.room.FakeJoinedRoom
import io.element.android.libraries.matrix.test.room.aRoomInfo
import io.element.android.libraries.matrix.test.timeline.FakeTimelineProvider
import io.element.android.services.analytics.api.watchers.AnalyticsSendMessageWatcher
import io.element.android.services.analytics.test.FakeAnalyticsService
import io.element.android.services.analytics.test.watchers.FakeAnalyticsSendMessageWatcher
import io.element.android.services.appnavstate.api.ActiveRoomsHolder
import io.element.android.services.appnavstate.impl.DefaultActiveRoomsHolder
import io.element.android.services.appnavstate.test.FakeAppNavigationStateService
@@ -72,9 +79,20 @@ class JoinedRoomLoadedFlowNodeTest {
}
}
private class FakeRoomGraphFactory : RoomGraphFactory {
private class FakeRoomGraphFactory(
private val timelineProvider: FakeTimelineProvider = FakeTimelineProvider(),
private val pinnedEventsTimelineProvider: FakePinnedEventsTimelineProvider = FakePinnedEventsTimelineProvider(),
private val analyticsSendMessageWatcher: FakeAnalyticsSendMessageWatcher = FakeAnalyticsSendMessageWatcher(),
) : RoomGraphFactory {
override fun create(room: JoinedRoom): Any {
return Unit
return object : TimelineBindings {
override val timelineProvider: TimelineProvider
get() = this@FakeRoomGraphFactory.timelineProvider
override val pinnedEventsTimelineProvider: PinnedEventsTimelineProvider
get() = this@FakeRoomGraphFactory.pinnedEventsTimelineProvider
override val analyticsSendMessageWatcher: AnalyticsSendMessageWatcher
get() = this@FakeRoomGraphFactory.analyticsSendMessageWatcher
}
}
}