Init analytics modules (#350)

This commit is contained in:
Yoan Pintas 2023-06-05 15:11:34 +02:00 committed by GitHub
parent c457d74954
commit d2263372d2
125 changed files with 2018 additions and 2130 deletions

View file

@ -0,0 +1,55 @@
/*
* Copyright (c) 2023 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 io.element.android.services.analyticsproviders.posthog
import android.content.Context
import com.posthog.android.PostHog
import io.element.android.libraries.core.meta.BuildMeta
import io.element.android.libraries.di.ApplicationContext
import javax.inject.Inject
class PostHogFactory @Inject constructor(
@ApplicationContext private val context: Context,
private val buildMeta: BuildMeta,
) {
fun createPosthog(): PostHog {
return PostHog.Builder(context, PosthogConfig.postHogApiKey, PosthogConfig.postHogHost)
// Record certain application events automatically! (off/false by default)
// .captureApplicationLifecycleEvents()
// Record screen views automatically! (off/false by default)
// .recordScreenViews()
// Capture deep links as part of the screen call. (off by default)
// .captureDeepLinks()
// Maximum number of events to keep in queue before flushing (default 20)
// .flushQueueSize(20)
// Max delay before flushing the queue (30 seconds)
// .flushInterval(30, TimeUnit.SECONDS)
// Enable or disable collection of ANDROID_ID (true)
.collectDeviceId(false)
.logLevel(getLogLevel())
.build()
}
private fun getLogLevel(): PostHog.LogLevel {
return if (buildMeta.isDebuggable) {
PostHog.LogLevel.DEBUG
} else {
PostHog.LogLevel.INFO
}
}
}

View file

@ -0,0 +1,109 @@
/*
* Copyright (c) 2023 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 io.element.android.services.analyticsproviders.posthog
import com.posthog.android.Options
import com.posthog.android.PostHog
import com.posthog.android.Properties
import com.squareup.anvil.annotations.ContributesMultibinding
import im.vector.app.features.analytics.itf.VectorAnalyticsEvent
import im.vector.app.features.analytics.itf.VectorAnalyticsScreen
import im.vector.app.features.analytics.plan.UserProperties
import io.element.android.libraries.di.AppScope
import io.element.android.services.analyticsproviders.api.AnalyticsProvider
import io.element.android.services.analyticsproviders.posthog.log.analyticsTag
import timber.log.Timber
import javax.inject.Inject
private val REUSE_EXISTING_ID: String? = null
private val IGNORED_OPTIONS: Options? = null
@ContributesMultibinding(AppScope::class)
class PosthogAnalyticsProvider @Inject constructor(
private val postHogFactory: PostHogFactory,
) : AnalyticsProvider {
override val index = PosthogConfig.index
override val name = PosthogConfig.name
private var posthog: PostHog? = null
private var analyticsId: String? = null
override suspend fun init() {
posthog = createPosthog()
posthog?.optOut(false)
identifyPostHog()
}
override fun stop() {
// When opting out, ensure that the queue is flushed first, or it will be flushed later (after user has revoked consent)
posthog?.flush()
posthog?.optOut(true)
posthog?.shutdown()
posthog = null
analyticsId = null
}
override fun capture(event: VectorAnalyticsEvent) {
posthog?.capture(event.getName(), event.getProperties()?.toPostHogProperties())
}
override fun screen(screen: VectorAnalyticsScreen) {
posthog?.screen(screen.getName(), screen.getProperties()?.toPostHogProperties())
}
override fun updateUserProperties(userProperties: UserProperties) {
posthog?.identify(
REUSE_EXISTING_ID, userProperties.getProperties()?.toPostHogUserProperties(),
IGNORED_OPTIONS
)
}
override fun trackError(throwable: Throwable) {
TODO("Not yet implemented")
}
private fun createPosthog(): PostHog = postHogFactory.createPosthog()
private fun identifyPostHog() {
val id = analyticsId ?: return
if (id.isEmpty()) {
Timber.tag(analyticsTag.value).d("reset")
posthog?.reset()
} else {
Timber.tag(analyticsTag.value).d("identify")
// posthog?.identify(id, lateInitUserPropertiesFactory.createUserProperties()?.getProperties()?.toPostHogUserProperties(), IGNORED_OPTIONS)
}
}
private fun Map<String, Any?>?.toPostHogProperties(): Properties? {
if (this == null) return null
return Properties().apply {
putAll(this@toPostHogProperties)
}
}
/**
* We avoid sending nulls as part of the UserProperties as this will reset the values across all devices.
* The UserProperties event has nullable properties to allow for clients to opt in.
*/
private fun Map<String, Any?>.toPostHogUserProperties(): Properties {
return Properties().apply {
putAll(this@toPostHogUserProperties.filter { it.value != null })
}
}
}

View file

@ -0,0 +1,24 @@
/*
* Copyright (c) 2023 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 io.element.android.services.analyticsproviders.posthog
object PosthogConfig {
const val index = 0
const val name = "Posthog"
const val postHogHost = "https://posthog.element.dev"
const val postHogApiKey = "phc_VtA1L35nw3aeAtHIx1ayrGdzGkss7k1xINeXcoIQzXN"
}

View file

@ -0,0 +1,25 @@
/*
* Copyright (c) 2022 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 io.element.android.services.analyticsproviders.posthog.extensions
import im.vector.app.features.analytics.plan.Interaction
fun Interaction.Name.toAnalyticsInteraction(interactionType: Interaction.InteractionType = Interaction.InteractionType.Touch) =
Interaction(
name = this,
interactionType = interactionType
)

View file

@ -0,0 +1,21 @@
/*
* Copyright (c) 2021 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 io.element.android.services.analyticsproviders.posthog.log
import io.element.android.libraries.core.log.logger.LoggerTag
val analyticsTag = LoggerTag("Analytics")