Update to analytics events 0.23.0 and refactor

This commit is contained in:
Valere 2024-05-29 17:39:16 +02:00
parent 09c68f3421
commit a363e392b4
6 changed files with 75 additions and 34 deletions

View file

@ -53,6 +53,7 @@ import im.vector.app.core.pushers.FcmHelper
import im.vector.app.core.resources.BuildMeta
import im.vector.app.features.analytics.DecryptionFailureTracker
import im.vector.app.features.analytics.VectorAnalytics
import im.vector.app.features.analytics.plan.SuperProperties
import im.vector.app.features.call.webrtc.WebRtcCallManager
import im.vector.app.features.configuration.VectorConfiguration
import im.vector.app.features.invite.InvitesAcceptor
@ -130,6 +131,12 @@ class VectorApplication :
appContext = this
flipperProxy.init(matrix)
vectorAnalytics.init()
vectorAnalytics.updateSuperProperties(
SuperProperties(
appPlatform = SuperProperties.AppPlatform.EA,
cryptoSDK = SuperProperties.CryptoSDK.Rust,
)
)
invitesAcceptor.initialize()
autoRageShaker.initialize()
decryptionFailureTracker.start()

View file

@ -160,7 +160,7 @@ dependencies {
api 'com.facebook.stetho:stetho:1.6.0'
// Analytics
api 'com.github.matrix-org:matrix-analytics-events:0.22.0'
api 'com.github.matrix-org:matrix-analytics-events:0.23.0'
api libs.google.phonenumber

View file

@ -22,8 +22,6 @@ import im.vector.app.core.dispatchers.CoroutineDispatchers
import im.vector.app.core.pushers.UnregisterUnifiedPushUseCase
import im.vector.app.core.services.GuardServiceStarter
import im.vector.app.core.session.ConfigureAndStartSessionUseCase
import im.vector.app.features.analytics.VectorAnalytics
import im.vector.app.features.analytics.plan.SuperProperties
import im.vector.app.features.call.webrtc.WebRtcCallManager
import im.vector.app.features.crypto.keysrequest.KeyRequestHandler
import im.vector.app.features.crypto.verification.IncomingVerificationRequestHandler
@ -58,7 +56,6 @@ class ActiveSessionHolder @Inject constructor(
private val unregisterUnifiedPushUseCase: UnregisterUnifiedPushUseCase,
private val applicationCoroutineScope: CoroutineScope,
private val coroutineDispatchers: CoroutineDispatchers,
private val vectorAnalytics: VectorAnalytics,
) {
private var activeSessionReference: AtomicReference<Session?> = AtomicReference()
@ -75,13 +72,6 @@ class ActiveSessionHolder @Inject constructor(
session.callSignalingService().addCallListener(callManager)
imageManager.onSessionStarted(session)
guardServiceStarter.start()
vectorAnalytics.updateSuperProperties(
SuperProperties(
platformCodeName = SuperProperties.PlatformCodeName.EA,
cryptoSDK = SuperProperties.CryptoSDK.Rust,
cryptoSDKVersion = session.cryptoService().getCryptoVersion(applicationContext, false)
)
)
}
suspend fun clearActiveSession() {

View file

@ -0,0 +1,43 @@
/*
* Copyright (c) 2024 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.app.features.analytics.impl
import im.vector.app.ActiveSessionDataSource
import im.vector.app.features.analytics.plan.SuperProperties
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
import javax.inject.Inject
/**
* Gathers the super properties that are static to this platform or
* that can be automatically resolved from the current session.
*/
class AutoSuperPropertiesFlowProvider @Inject constructor(
activeSessionDataSource: ActiveSessionDataSource,
) {
val superPropertiesFlow: Flow<SuperProperties> = activeSessionDataSource.stream()
.map { session ->
SuperProperties(
appPlatform = SuperProperties.AppPlatform.EA,
cryptoSDK = SuperProperties.CryptoSDK.Rust,
cryptoSDKVersion = session.getOrNull()?.cryptoService()?.getCryptoVersion(false)
)
}
.distinctUntilChanged()
}

View file

@ -42,6 +42,7 @@ class DefaultVectorAnalytics @Inject constructor(
private val analyticsConfig: AnalyticsConfig,
private val analyticsStore: AnalyticsStore,
private val lateInitUserPropertiesFactory: LateInitUserPropertiesFactory,
private val autoSuperPropertiesFlowProvider: AutoSuperPropertiesFlowProvider,
@NamedGlobalScope private val globalScope: CoroutineScope
) : VectorAnalytics {
@ -69,6 +70,7 @@ class DefaultVectorAnalytics @Inject constructor(
override fun init() {
observeUserConsent()
observeAnalyticsId()
observeAutoSuperProperties()
}
override fun getUserConsent(): Flow<Boolean> {
@ -116,6 +118,12 @@ class DefaultVectorAnalytics @Inject constructor(
.launchIn(globalScope)
}
private fun observeAutoSuperProperties() {
autoSuperPropertiesFlowProvider.superPropertiesFlow.onEach {
updateSuperProperties(it)
}.launchIn(globalScope)
}
private suspend fun identifyPostHog() {
val id = analyticsId ?: return
if (!userConsent.orFalse()) return
@ -171,20 +179,14 @@ class DefaultVectorAnalytics @Inject constructor(
override fun capture(event: VectorAnalyticsEvent) {
Timber.tag(analyticsTag.value).d("capture($event)")
posthog
?.takeIf { userConsent == true }
?.capture(
event.getName(),
analyticsId,
event.getProperties()?.toPostHogProperties().orEmpty().withSuperProperties()
posthog?.takeIf { userConsent == true }?.capture(
event.getName(), analyticsId, event.getProperties()?.toPostHogProperties().orEmpty().withSuperProperties()
)
}
override fun screen(screen: VectorAnalyticsScreen) {
Timber.tag(analyticsTag.value).d("screen($screen)")
posthog
?.takeIf { userConsent == true }
?.screen(screen.getName(), screen.getProperties()?.toPostHogProperties().orEmpty().withSuperProperties())
posthog?.takeIf { userConsent == true }?.screen(screen.getName(), screen.getProperties()?.toPostHogProperties().orEmpty().withSuperProperties())
}
override fun updateUserProperties(userProperties: UserProperties) {
@ -198,9 +200,7 @@ class DefaultVectorAnalytics @Inject constructor(
private fun doUpdateUserProperties(userProperties: UserProperties) {
// we need a distinct id to set user properties
val distinctId = analyticsId ?: return
posthog
?.takeIf { userConsent == true }
?.identify(distinctId, userProperties.getProperties())
posthog?.takeIf { userConsent == true }?.identify(distinctId, userProperties.getProperties())
}
private fun Map<String, Any?>?.toPostHogProperties(): Map<String, Any>? {
@ -233,7 +233,7 @@ class DefaultVectorAnalytics @Inject constructor(
* Adds super properties to the actual property set.
* If a property of the same name is already on the reported event it will not be overwritten.
*/
private fun Map<String, Any>.withSuperProperties(): Map<String, Any> {
private fun Map<String, Any>.withSuperProperties(): Map<String, Any>? {
val withSuperProperties = this.toMutableMap()
val superProperties = this@DefaultVectorAnalytics.superProperties?.getProperties()
superProperties?.forEach {
@ -241,7 +241,7 @@ class DefaultVectorAnalytics @Inject constructor(
withSuperProperties[it.key] = it.value
}
}
return withSuperProperties
return withSuperProperties.takeIf { it.isEmpty().not() }
}
override fun trackError(throwable: Throwable) {
@ -251,13 +251,7 @@ class DefaultVectorAnalytics @Inject constructor(
}
override fun updateSuperProperties(updatedProperties: SuperProperties) {
if (this.superProperties == null) {
this.superProperties = updatedProperties
return
}
this.superProperties = SuperProperties(
platformCodeName = updatedProperties.platformCodeName ?: this.superProperties?.platformCodeName,
cryptoSDK = updatedProperties.cryptoSDK ?: this.superProperties?.cryptoSDK,
appPlatform = updatedProperties.appPlatform ?: this.superProperties?.appPlatform,
cryptoSDKVersion = updatedProperties.cryptoSDKVersion ?: superProperties?.cryptoSDKVersion

View file

@ -26,9 +26,12 @@ import im.vector.app.test.fixtures.AnalyticsConfigFixture.anAnalyticsConfig
import im.vector.app.test.fixtures.aUserProperties
import im.vector.app.test.fixtures.aVectorAnalyticsEvent
import im.vector.app.test.fixtures.aVectorAnalyticsScreen
import io.mockk.every
import io.mockk.mockk
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
@ -45,6 +48,9 @@ class DefaultVectorAnalyticsTest {
private val fakeAnalyticsStore = FakeAnalyticsStore()
private val fakeLateInitUserPropertiesFactory = FakeLateInitUserPropertiesFactory()
private val fakeSentryAnalytics = FakeSentryAnalytics()
private val mockAutoSuperPropertiesFlowProvider = mockk<AutoSuperPropertiesFlowProvider>().also {
every { it.superPropertiesFlow } returns flowOf(SuperProperties())
}
private val defaultVectorAnalytics = DefaultVectorAnalytics(
postHogFactory = FakePostHogFactory(fakePostHog.instance).instance,
@ -52,7 +58,8 @@ class DefaultVectorAnalyticsTest {
analyticsStore = fakeAnalyticsStore.instance,
globalScope = CoroutineScope(Dispatchers.Unconfined),
analyticsConfig = anAnalyticsConfig(isEnabled = true),
lateInitUserPropertiesFactory = fakeLateInitUserPropertiesFactory.instance
lateInitUserPropertiesFactory = fakeLateInitUserPropertiesFactory.instance,
autoSuperPropertiesFlowProvider = mockAutoSuperPropertiesFlowProvider,
)
@Before
@ -180,7 +187,7 @@ class DefaultVectorAnalyticsTest {
fakeAnalyticsStore.givenUserContent(consent = true)
val updatedProperties = SuperProperties(
platformCodeName = SuperProperties.PlatformCodeName.EA,
appPlatform = SuperProperties.AppPlatform.EA,
cryptoSDKVersion = "0.0",
cryptoSDK = SuperProperties.CryptoSDK.Rust
)
@ -214,7 +221,7 @@ class DefaultVectorAnalyticsTest {
fakeAnalyticsStore.givenUserContent(consent = true)
val superProperties = SuperProperties(
platformCodeName = SuperProperties.PlatformCodeName.EA,
appPlatform = SuperProperties.AppPlatform.EA,
cryptoSDKVersion = "0.0",
cryptoSDK = SuperProperties.CryptoSDK.Rust
)