Skip to content

Commit e8154b2

Browse files
committed
chore: app start performance logs (WPB-23706)
1 parent ef8b52a commit e8154b2

7 files changed

Lines changed: 88 additions & 3 deletions

File tree

app/src/main/kotlin/com/wire/android/WireApplication.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import com.wire.android.feature.analytics.globalAnalyticsManager
3939
import com.wire.android.feature.analytics.model.AnalyticsEvent
4040
import com.wire.android.feature.analytics.model.AnalyticsSettings
4141
import com.wire.android.util.AppNameUtil
42+
import com.wire.android.util.AppPerformanceTracker
4243
import com.wire.android.util.CurrentScreenManager
4344
import com.wire.android.util.DataDogLogger
4445
import com.wire.android.util.logging.LogFileWriter
@@ -115,6 +116,7 @@ class WireApplication : BaseApp() {
115116

116117
override fun onCreate() {
117118
super.onCreate()
119+
AppPerformanceTracker.markAppStart()
118120

119121
enableStrictMode()
120122

app/src/main/kotlin/com/wire/android/ui/WireActivity.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ import com.wire.android.ui.theme.ThemeOption
115115
import com.wire.android.ui.theme.WireTheme
116116
import com.wire.android.ui.userprofile.self.dialog.LogoutOptionsDialog
117117
import com.wire.android.ui.userprofile.self.dialog.LogoutOptionsDialogState
118+
import com.wire.android.util.AppPerformanceTracker
118119
import com.wire.android.util.CurrentScreenManager
119120
import com.wire.android.util.LocalSyncStateObserver
120121
import com.wire.android.util.ShakeDetector
@@ -207,6 +208,11 @@ class WireActivity : BaseActivity() {
207208
InitialAppState.ENROLL_E2EI -> E2EIEnrollmentScreenDestination()
208209
InitialAppState.LOGGED_IN -> HomeScreenDestination()
209210
}
211+
212+
if (viewModel.initialAppState() != InitialAppState.LOGGED_IN) {
213+
AppPerformanceTracker.cancelAppStartTracking()
214+
}
215+
210216
appLogger.i("$TAG composable content")
211217
setComposableContent(startDestination)
212218

app/src/main/kotlin/com/wire/android/ui/WireActivityViewModel.kt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ import com.wire.android.ui.common.dialogs.CustomServerNoNetworkDialogState
5252
import com.wire.android.ui.joinConversation.JoinConversationViaCodeState
5353
import com.wire.android.ui.theme.Accent
5454
import com.wire.android.ui.theme.ThemeOption
55+
import com.wire.android.util.AppPerformanceTracker
5556
import com.wire.android.util.CurrentScreen
5657
import com.wire.android.util.CurrentScreenManager
5758
import com.wire.android.util.deeplink.DeepLinkProcessor
@@ -373,11 +374,15 @@ class WireActivityViewModel @Inject constructor(
373374
result.key,
374375
result.domain
375376
) { conversationId ->
377+
AppPerformanceTracker.markNotificationOpen()
376378
sendAction(OpenConversation(DeepLinkResult.OpenConversation(conversationId, result.switchedAccount)))
377379
}
378380

379381
is DeepLinkResult.MigrationLogin -> sendAction(OnMigrationLogin(result))
380-
is DeepLinkResult.OpenConversation -> sendAction(OpenConversation(result))
382+
is DeepLinkResult.OpenConversation -> {
383+
AppPerformanceTracker.markNotificationOpen()
384+
sendAction(OpenConversation(result))
385+
}
381386
is DeepLinkResult.OpenOtherUserProfile -> onOpenUserProfileDeepLink(result)
382387

383388
DeepLinkResult.SharingIntent -> sendAction(OnShowImportMediaScreen)

app/src/main/kotlin/com/wire/android/ui/home/conversations/messages/ConversationMessagesViewModel.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import androidx.lifecycle.viewModelScope
2828
import com.ramcosta.composedestinations.generated.app.navArgs
2929
import com.wire.android.R
3030
import com.wire.android.appLogger
31+
import com.wire.android.util.AppPerformanceTracker
3132
import com.wire.android.media.audiomessage.ConversationAudioMessagePlayer
3233
import com.wire.android.model.SnackBarMessage
3334
import com.wire.android.ui.common.visbility.VisibilityState
@@ -217,6 +218,7 @@ class ConversationMessagesViewModel @Inject constructor(
217218
messages = paginatedMessagesFlow,
218219
firstUnreadEventIndex = max(lastReadIndex - 1, 0)
219220
)
221+
AppPerformanceTracker.logConversationMessagesReady()
220222

221223
handleSelectedSearchedMessageHighlighting()
222224
}

app/src/main/kotlin/com/wire/android/ui/home/conversationslist/ConversationListViewModel.kt

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import androidx.paging.cachedIn
2828
import androidx.paging.insertSeparators
2929
import androidx.paging.map
3030
import com.wire.android.BuildConfig
31+
import com.wire.android.util.AppPerformanceTracker
3132
import com.wire.android.di.CurrentAccount
3233
import com.wire.android.mapper.UserTypeMapper
3334
import com.wire.android.mapper.toConversationItem
@@ -74,6 +75,7 @@ import kotlinx.coroutines.flow.flatMapLatest
7475
import kotlinx.coroutines.flow.flowOn
7576
import kotlinx.coroutines.flow.map
7677
import kotlinx.coroutines.flow.onStart
78+
import kotlinx.coroutines.flow.take
7779
import kotlinx.coroutines.launch
7880

7981
@Suppress("TooManyFunctions")
@@ -195,7 +197,13 @@ class ConversationListViewModelImpl @AssistedInject constructor(
195197

196198
init {
197199
observeSelfUserLegalHoldState()
198-
if (!usePagination) {
200+
if (usePagination) {
201+
viewModelScope.launch {
202+
conversationsPaginatedFlow.take(1).collect {
203+
AppPerformanceTracker.logConversationsReady()
204+
}
205+
}
206+
} else {
199207
observeNonPaginatedSearchConversationList()
200208
}
201209
}
@@ -247,6 +255,7 @@ class ConversationListViewModelImpl @AssistedInject constructor(
247255
}
248256
.flowOn(dispatcher.io())
249257
.collect {
258+
AppPerformanceTracker.logConversationsReady()
250259
conversationListState = ConversationListState.NotPaginated(
251260
isLoading = false,
252261
conversations = it,
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*
2+
* Wire
3+
* Copyright (C) 2026 Wire Swiss GmbH
4+
*
5+
* This program is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU General Public License as published by
7+
* the Free Software Foundation, either version 3 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU General Public License
16+
* along with this program. If not, see http://www.gnu.org/licenses/.
17+
*/
18+
19+
package com.wire.android.util
20+
21+
import android.os.SystemClock
22+
import com.wire.android.appLogger
23+
24+
/**
25+
* Captures timestamps at key app entry points and logs elapsed durations for DataDog Logs.
26+
*/
27+
object AppPerformanceTracker {
28+
29+
@Volatile private var appStartTime: Long? = null
30+
31+
@Volatile private var notificationOpenTime: Long? = null
32+
33+
fun markAppStart() {
34+
appStartTime = SystemClock.elapsedRealtime()
35+
}
36+
37+
// Called when the startup path will NOT lead to the conversations list (e.g. user not logged in).
38+
fun cancelAppStartTracking() {
39+
appStartTime = null
40+
}
41+
42+
fun logConversationsReady() {
43+
appStartTime?.let {
44+
val durationMs = SystemClock.elapsedRealtime() - it
45+
appLogger.i("Perf | event=conversations_list_ready | duration_ms=$durationMs")
46+
appStartTime = null
47+
}
48+
}
49+
50+
fun markNotificationOpen() {
51+
notificationOpenTime = SystemClock.elapsedRealtime()
52+
}
53+
54+
fun logConversationMessagesReady() {
55+
notificationOpenTime?.let {
56+
val durationMs = SystemClock.elapsedRealtime() - it
57+
appLogger.i("Perf | event=conversation_messages_ready | duration_ms=$durationMs")
58+
notificationOpenTime = null
59+
}
60+
}
61+
}

kalium

Submodule kalium updated 176 files

0 commit comments

Comments
 (0)