Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,15 @@ androidXConstraintLayout = "2.0.4"
androidXCore = "1.3.1"
androidXFragment = "1.2.4"
androidXLeanback = "1.0.0"
androidXLifecycleRuntimeCompose = "2.8.7"
androidXMetrics = "1.0.0-beta02"
androidXMultidex = "2.0.1"
androidXNavigation = "2.7.7"
androidXRecyclerView = "1.3.2"
androidXWorkManager = "2.8.1" # Next version will bring coroutines
googleAccompanist = "0.20.2"
googleMaterial = "1.3.0"
dagger = "2.56.2"

@aleksandr-gringauz aleksandr-gringauz May 1, 2025

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Integrated dagger in the benchmark app. If anyone has any objections - tell me.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it doesn't bring a dramatic compilation time penalty, I'm personally okay with that.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Benchmark app is a small app that compiles very fast. Dagger might add something, but it is not noticeable (I didn't measure, just describe the feeling) and will not be in any foreseeable future.

The Dagger annotation processor is run only when compiling the application module, it is not run when compiling dd-sdk-core for example.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two questions from me about this:

  1. it seems that you refactor a lot of code to adapt to Dagger2, is there anything that you can not handle without Dagger2 for your task? or it's just you prefer using it for dependency injection?
  2. If it's for dependency injection, why not Hilt instead of Dagger2?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Yes, I could do it without dagger or any di framework. But imho it is a great tool and it is the first thing I set up if I do any kind of android app event if it is a sample. It saves a lot of time.
  2. Why I didn't use hilt https://github.com/DataDog/dd-sdk-android/pull/2625/files#r2071751641


# DD-TRACE-OT
openTracing = "0.32.0"
Expand Down Expand Up @@ -144,6 +146,9 @@ androidXNavigationFragment = { module = "androidx.navigation:navigation-fragment
androidXNavigationRuntime = { module = "androidx.navigation:navigation-runtime", version.ref = "androidXNavigation" }
androidXRecyclerView = { module = "androidx.recyclerview:recyclerview", version.ref = "androidXRecyclerView" }
androidXWorkManager = { module = "androidx.work:work-runtime", version.ref = "androidXWorkManager" }
androidXLifecycleCompose = { module = "androidx.lifecycle:lifecycle-runtime-compose", version.ref = "androidXLifecycleRuntimeCompose" }
daggerLib = { module = "com.google.dagger:dagger", version.ref = "dagger" }
daggerCompiler = { module = "com.google.dagger:dagger-compiler", version.ref = "dagger" }
googleAccompanistAppCompatTheme = { module = "com.google.accompanist:accompanist-appcompat-theme", version.ref = "googleAccompanist" }
googleAccompanistPager = { module = "com.google.accompanist:accompanist-pager", version.ref = "googleAccompanist" }
googleAccompanistPagerIndicators = { module = "com.google.accompanist:accompanist-pager-indicators", version.ref = "googleAccompanist" }
Expand Down
5 changes: 5 additions & 0 deletions sample/benchmark/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -87,12 +87,17 @@ dependencies {
implementation(libs.bundles.androidXNavigation)
implementation(libs.androidXAppCompat)
implementation(libs.androidXConstraintLayout)
implementation(libs.androidXLifecycleCompose)
implementation(libs.googleMaterial)
implementation(libs.glideCore)
implementation(libs.material3Android)
implementation(libs.timber)
implementation(platform(libs.androidXComposeBom))
implementation(libs.bundles.androidXCompose)
implementation(libs.coilCompose)
implementation(libs.daggerLib)
kapt(libs.daggerCompiler)
implementation(libs.coroutinesCore)
implementation(project(":features:dd-sdk-android-logs"))
implementation(project(":features:dd-sdk-android-rum"))
implementation(project(":features:dd-sdk-android-trace"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,102 +6,28 @@

package com.datadog.benchmark.sample

import android.annotation.SuppressLint
import android.app.Application
import android.util.Log
import com.datadog.android.Datadog
import com.datadog.android.compose.enableComposeActionTracking
import com.datadog.android.core.configuration.BackPressureMitigation
import com.datadog.android.core.configuration.BackPressureStrategy
import com.datadog.android.core.configuration.BatchSize
import com.datadog.android.core.configuration.Configuration
import com.datadog.android.core.configuration.UploadFrequency
import com.datadog.android.privacy.TrackingConsent
import com.datadog.android.rum.Rum
import com.datadog.android.rum.RumConfiguration
import com.datadog.android.rum.tracking.NavigationViewTrackingStrategy
import com.datadog.sample.benchmark.BuildConfig
import com.datadog.sample.benchmark.R
import androidx.annotation.Keep
import com.datadog.android.api.SdkCore
import com.datadog.benchmark.sample.di.app.BenchmarkAppComponent
import com.datadog.benchmark.sample.di.app.DaggerBenchmarkAppComponent
import javax.inject.Inject

internal class BenchmarkApplication : Application() {

override fun onCreate() {
super.onCreate()
initDatadogSdk()
}

private fun initDatadogSdk() {
Datadog.initialize(
this,
createDatadogConfiguration(),
TrackingConsent.GRANTED
)
val rumConfig = createRumConfiguration()
Rum.enable(rumConfig)
}

private fun createRumConfiguration(): RumConfiguration {
return RumConfiguration.Builder(BuildConfig.BENCHMARK_RUM_APPLICATION_ID)
.useViewTrackingStrategy(
NavigationViewTrackingStrategy(
R.id.nav_host_fragment,
true,
BenchmarkNavigationPredicate()
)
)
.setTelemetrySampleRate(SAMPLE_RATE_TELEMETRY)
.trackUserInteractions()
.trackLongTasks(THRESHOLD_LONG_TASK_INTERVAL)
.trackNonFatalAnrs(true)
.setViewEventMapper { event ->
event.context?.additionalProperties?.put(ATTR_IS_MAPPED, true)
event
}
.setActionEventMapper { event ->
event.context?.additionalProperties?.put(ATTR_IS_MAPPED, true)
event
}
.setResourceEventMapper { event ->
event.context?.additionalProperties?.put(ATTR_IS_MAPPED, true)
event
}
.setErrorEventMapper { event ->
event.context?.additionalProperties?.put(ATTR_IS_MAPPED, true)
event
}
.setLongTaskEventMapper { event ->
event.context?.additionalProperties?.put(ATTR_IS_MAPPED, true)
event
}
.enableComposeActionTracking()
.build()
}

@SuppressLint("LogNotTimber")
private fun createDatadogConfiguration(): Configuration {
val configBuilder = Configuration.Builder(
clientToken = BuildConfig.BENCHMARK_CLIENT_TOKEN,
env = BuildConfig.BUILD_TYPE
)
.setBatchSize(BatchSize.SMALL)
.setUploadFrequency(UploadFrequency.FREQUENT)
internal lateinit var benchmarkAppComponent: BenchmarkAppComponent

configBuilder.setBackpressureStrategy(
BackPressureStrategy(
CAPACITY_BACK_PRESSURE_STRATEGY,
{ Log.w("BackPressure", "THRESHOLD REACHED!") },
{ Log.e("BackPressure", "ITEM DROPPED $it!") },
BackPressureMitigation.IGNORE_NEWEST
)
)
@Inject
@Keep
internal lateinit var sdkCore: SdkCore

return configBuilder.build()
}
override fun onCreate() {
super.onCreate()

companion object {
private const val ATTR_IS_MAPPED = "is_mapped"
private const val SAMPLE_RATE_TELEMETRY = 100f
private const val THRESHOLD_LONG_TASK_INTERVAL = 250L
private const val CAPACITY_BACK_PRESSURE_STRATEGY = 32
benchmarkAppComponent = DaggerBenchmarkAppComponent.factory().create(this)
benchmarkAppComponent.inject(this)
}
}

internal val Application.benchmarkAppComponent: BenchmarkAppComponent
get() = (this as BenchmarkApplication).benchmarkAppComponent
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
/*
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
* This product includes software developed at Datadog (https://www.datadoghq.com/).
* Copyright 2016-Present Datadog, Inc.
*/

package com.datadog.benchmark.sample

import com.datadog.android.api.SdkCore
import com.datadog.android.compose.enableComposeActionTracking
import com.datadog.android.log.Logs
import com.datadog.android.log.LogsConfiguration
import com.datadog.android.rum.Rum
import com.datadog.android.rum.RumConfiguration
import com.datadog.android.rum.tracking.NavigationViewTrackingStrategy
import com.datadog.android.sessionreplay.SessionReplay
import com.datadog.android.sessionreplay.SessionReplayConfiguration
import com.datadog.android.sessionreplay.SessionReplayPrivacy
import com.datadog.android.sessionreplay.compose.ComposeExtensionSupport
import com.datadog.android.sessionreplay.material.MaterialExtensionSupport
import com.datadog.benchmark.sample.config.BenchmarkConfig
import com.datadog.benchmark.sample.config.SyntheticsRun
import com.datadog.benchmark.sample.config.SyntheticsScenario
import com.datadog.benchmark.sample.navigation.BenchmarkNavigationPredicate
import com.datadog.sample.benchmark.BuildConfig
import com.datadog.sample.benchmark.R
import javax.inject.Inject
import javax.inject.Singleton

/**
* The general recommendation is to initialize all the components at the Application.onCreate
* to have all the observability as early as possible. However in the Benchmark app we know what features
* we need only in [MainActivity.onCreate], it depends on the [SyntheticsScenario] which is derived from intent extras.
*/
@Singleton
@Suppress("TooManyFunctions")
internal class DatadogFeaturesInitializer @Inject constructor(
private val sdkCore: SdkCore
) {
private var isInitialized = false
fun initialize(config: BenchmarkConfig) {
if (isInitialized) {
return
}
isInitialized = true

if (needToEnableRum(config)) {
enableRum()
}

if (needToEnableLogs(config)) {
enableLogs()
}

if (needToEnableSessionReplay(config)) {
enableSessionReplay()
}
}

private fun needToEnableSessionReplay(config: BenchmarkConfig): Boolean {
return isInstrumentedRun(config) && isSessionReplayScenario(config)
}

@Suppress("DEPRECATION")
private fun enableSessionReplay() {
val sessionReplayConfig = SessionReplayConfiguration
.Builder(SAMPLE_IN_ALL_SESSIONS)
.setPrivacy(SessionReplayPrivacy.ALLOW)
.addExtensionSupport(MaterialExtensionSupport())
.addExtensionSupport(ComposeExtensionSupport())
.build()

SessionReplay.enable(sessionReplayConfig, sdkCore)
}

private fun needToEnableLogs(config: BenchmarkConfig): Boolean {
return isInstrumentedRun(config) && isLogsScenario(config)
}

private fun enableLogs() {
val logsConfig = LogsConfiguration.Builder().build()
Logs.enable(logsConfig, sdkCore)
}

private fun needToEnableRum(config: BenchmarkConfig): Boolean {
return when (isInstrumentedRun(config)) {
true -> isSessionReplayScenario(config) || isRumScenario(config)
false -> isSessionReplayScenario(config)
}
}

private fun createRumConfiguration(): RumConfiguration {
return RumConfiguration.Builder(BuildConfig.BENCHMARK_RUM_APPLICATION_ID)
.useViewTrackingStrategy(
NavigationViewTrackingStrategy(
R.id.nav_host_fragment,
true,
BenchmarkNavigationPredicate()
)
)
.setTelemetrySampleRate(SAMPLE_RATE_TELEMETRY)
.trackUserInteractions()
.trackLongTasks(THRESHOLD_LONG_TASK_INTERVAL)
.trackNonFatalAnrs(true)
.setViewEventMapper { event ->
event.context?.additionalProperties?.put(ATTR_IS_MAPPED, true)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what's this attribute used for ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know. I didn't change anything here, it's the same as it was before link

It is the same in the sample app link and it is pretty old code.

event
}
.setActionEventMapper { event ->
event.context?.additionalProperties?.put(ATTR_IS_MAPPED, true)
event
}
.setResourceEventMapper { event ->
event.context?.additionalProperties?.put(ATTR_IS_MAPPED, true)
event
}
.setErrorEventMapper { event ->
event.context?.additionalProperties?.put(ATTR_IS_MAPPED, true)
event
}
.setLongTaskEventMapper { event ->
event.context?.additionalProperties?.put(ATTR_IS_MAPPED, true)
event
}
.enableComposeActionTracking()
.build()
}

private fun enableRum() {
val rumConfig = createRumConfiguration()
Rum.enable(rumConfig, sdkCore = sdkCore)
}

private fun isSessionReplayScenario(config: BenchmarkConfig) = when (config.scenario) {
SyntheticsScenario.SessionReplayCompose,
SyntheticsScenario.Upload,
SyntheticsScenario.SessionReplay -> true
SyntheticsScenario.Rum,
SyntheticsScenario.Trace,
SyntheticsScenario.LogsCustom,
SyntheticsScenario.LogsHeavyTraffic,
null -> false
}

private fun isRumScenario(config: BenchmarkConfig) = when (config.scenario) {
SyntheticsScenario.Rum -> true
SyntheticsScenario.SessionReplay,
SyntheticsScenario.SessionReplayCompose,
SyntheticsScenario.Trace,
SyntheticsScenario.LogsCustom,
SyntheticsScenario.LogsHeavyTraffic,
SyntheticsScenario.Upload,
null -> false
}

private fun isLogsScenario(config: BenchmarkConfig) = when (config.scenario) {
SyntheticsScenario.LogsCustom,
SyntheticsScenario.LogsHeavyTraffic -> true
SyntheticsScenario.SessionReplay,
SyntheticsScenario.SessionReplayCompose,
SyntheticsScenario.Rum,
SyntheticsScenario.Trace,
SyntheticsScenario.Upload,
null -> false
}

private fun isInstrumentedRun(config: BenchmarkConfig) = config.run == SyntheticsRun.Instrumented

companion object {
private const val SAMPLE_IN_ALL_SESSIONS = 100f
private const val ATTR_IS_MAPPED = "is_mapped"
private const val SAMPLE_RATE_TELEMETRY = 100f
private const val THRESHOLD_LONG_TASK_INTERVAL = 250L
}
}
Loading