Skip to content

RUM-9511: RumAuto scenario for android benchmark app#2689

Merged
aleksandr-gringauz merged 8 commits into
developfrom
aleksandr-gringauz/RUM-9511/rum-auto-scenario-benchmark-move-to-app-save
Jun 2, 2025
Merged

RUM-9511: RumAuto scenario for android benchmark app#2689
aleksandr-gringauz merged 8 commits into
developfrom
aleksandr-gringauz/RUM-9511/rum-auto-scenario-benchmark-move-to-app-save

Conversation

@aleksandr-gringauz

@aleksandr-gringauz aleksandr-gringauz commented May 30, 2025

Copy link
Copy Markdown
Contributor

What does this PR do?

Implemented RUM Auto scenario for Android benchmark app, described here.

demo link

Created a synthetic test using this scenario link. I checked that it runs well for my local build.

RUM Session from the synthetic test: link

Sorry for a big pr. I split it into multiple commits, each containing a more or less independent part, so that it is easier to view. Also look at comments in the pr.

About the app.

  1. Uses OkHttp + Ktor 2.3.13 + kotlinx.serialization for requests to the api. Not Ktor3, because it lead to update of kotlin stdlib version for the benchmark app (now we have 1.9.24, it became 2.something). Most likely it is fine, but I decided to be cautious here.
  2. Some screens are implemented in jetpack compose. For image loading Coil is used with the OkHttp client that has DatadogInterceptor installed in it.
  3. Some screens are implemented using Android Views. For image loading Glide is used with the OkHttp client that has DatadogInterceptor installed in it. For more convenient RecyclerView implementation AdapterDelegates4 library is used. Also ViewBinding is used.

Motivation

What inspired you to submit this pull request?

Additional Notes

Anything else we should know when reviewing?

Review checklist (to be filled by reviewers)

  • Feature or bugfix MUST have appropriate tests (unit, integration, e2e)
  • Make sure you discussed the feature or bugfix with the maintaining team in an Issue
  • Make sure each commit and the PR mention the Issue number (cf the CONTRIBUTING doc)


Spacer(modifier = Modifier.width(8.dp))

Column() {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Quality Violation

Suggested change
Column() {
Column {
An empty parentheses block before a lambda is redundant. (...read more)

If a function has a lambda parameter and you're passing a lambda expression, parentheses are unnecessary. Including unnecessary syntax makes the code less readable.

View in Datadog  Leave us feedback  Documentation

@aleksandr-gringauz
aleksandr-gringauz force-pushed the aleksandr-gringauz/RUM-9511/rum-auto-scenario-benchmark-move-to-app-save branch 3 times, most recently from 9c246f2 to 5a7f10a Compare June 2, 2025 07:18
@codecov-commenter

codecov-commenter commented Jun 2, 2025

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 70.00%. Comparing base (faae92a) to head (415d233).
⚠️ Report is 2055 commits behind head on develop.

Additional details and impacted files
@@             Coverage Diff             @@
##           develop    #2689      +/-   ##
===========================================
+ Coverage    69.91%   70.00%   +0.09%     
===========================================
  Files          822      822              
  Lines        30693    30693              
  Branches      5169     5169              
===========================================
+ Hits         21456    21484      +28     
+ Misses        7794     7761      -33     
- Partials      1443     1448       +5     

see 41 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@aleksandr-gringauz
aleksandr-gringauz force-pushed the aleksandr-gringauz/RUM-9511/rum-auto-scenario-benchmark-move-to-app-save branch 2 times, most recently from b853349 to ce4e10c Compare June 2, 2025 09:47
import javax.inject.Inject

@SuppressLint("CustomSplashScreen")
internal class LaunchActivity : AppCompatActivity() {

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.

Important place.

Now the first activity that is launched is this LaunchActivity and then we launch a different activity with actual UI of the benchmarking scenario.

I had to do this, because automatic tracking of gestures in RUM is initialized here before Activity.onCreate is called. We have to know that need to enable RUM feature before Activity.onCreate.

The solution is to introduce this LaunchActivity which determines which scenario we run, initializes all necessary Datadog features and then launch the activity with the scenario itself.

Thanks @ambushwork for suggesting this idea.

val context: Context
val benchmarkConfig: BenchmarkConfig

val sdkCore: SdkCore

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.

All Datadog stuff moved to application component, because we initialize Datadog in LaunchActivity.onCreate and it only has access to BenchmarkAppComponent.

BenchmarkActivityComponent corresponds to the activity with scenario UI.

}
}

private fun NavGraphBuilder.navGraphRumAutoScenario() {

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.

Only this navGraphRumAutoScenario is new here, other code just moved and didn't change.

}

private fun initializeCoil() {
Coil.setImageLoader(ImageLoader(applicationContext).newBuilder().okHttpClient(okHttpClient.get()).build())

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.

Initializing Coil with OkHttp client that already exists in dagger graph and is used everywhere (in Glide and for rickandmorty api requests).

import com.datadog.sample.benchmark.R
import javax.inject.Inject

internal class SessionReplayNavigationManagerImpl @Inject constructor() :

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.

This is FragmentsNavigationManagerImpl that I renamed to SessionReplayNavigationManagerImpl.

To me it looks better that each scenario has its own "NavigationManager", I created RumAutoScenarioNavigator for rumAuto. This one is for session replay.

) {
val lazyListState: LazyListState = rememberLazyListState()

LastItemTracker(

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.

Tracking then last item appears, so that we can load more items.

}
}

@AssistedFactory

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.

}
.launchIn(lifecycleScope)

trackRecyclerViewVisibleItems(

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.

tracking visible items, so that we can load more items when end is reached

Comment thread gradle/libs.versions.toml
ktorServerNetty = { module = "io.ktor:ktor-server-netty", version.ref = "ktorServer" }
ktorServerSSE = { module = "io.ktor:ktor-server-sse", version.ref = "ktorServer" }

# ktor client

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.

this should have been in another commit, sorry

sdkInstanceName = DATADOG_SDK_INSTANCE_NAME
) {
@Inject
lateinit var okHttpClient: OkHttpClient

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.

reusing okhttpclient that is already in dagger graph

@aleksandr-gringauz
aleksandr-gringauz marked this pull request as ready for review June 2, 2025 10:10
@aleksandr-gringauz
aleksandr-gringauz requested review from a team as code owners June 2, 2025 10:10
0xnm
0xnm previously approved these changes Jun 2, 2025

@0xnm 0xnm left a comment

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.

nice job!

Comment thread gradle/libs.versions.toml Outdated
Comment on lines 95 to 96
ktorClient = "2.3.13"
ktor = "1.6.8"

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.

should we simply do ktor = 2.3.13, without introducing ktorClient option?

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.

done

setContentView(binding.root)

binding.rumAutoBottomNavbar.setContent {
val currentTab: RumAutoScenarioTab? by rumAutoScenarioNavigator.currentTab.collectAsStateWithLifecycle(null)

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.

is explicit type needed here?

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.

removed the explicit type, not needed

fun provideBenchmarkConfig(
holder: BenchmarkConfigHolder
): BenchmarkConfig {
return holder.config!!

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.

is there a way to avoid !! call?

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.

changed to config field to be lateinit

ExtendWith(ForgeExtension::class)
)
@MockitoSettings(strictness = Strictness.LENIENT)
class KtorHttpClientUtilsTest {

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.

minor: let's add given / when / then blocks to the tests for the readability

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.

done

Comment on lines +33 to +37
@Extensions(
ExtendWith(MockitoExtension::class),
ExtendWith(ForgeExtension::class)
)
@MockitoSettings(strictness = Strictness.LENIENT)

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.

this is unnecessary it seems

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.

removed these annotations, not needed

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.

do we need this file?

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 added the transitive dependencies plugin here just for my own convenience to look at the dependencies I am using. Not very important.

0xnm
0xnm previously approved these changes Jun 2, 2025
@aleksandr-gringauz
aleksandr-gringauz force-pushed the aleksandr-gringauz/RUM-9511/rum-auto-scenario-benchmark-move-to-app-save branch from 36234a6 to 3655f68 Compare June 2, 2025 12:17
Comment thread gradle/libs.versions.toml
# Local Server
ktorCore = { module = "io.ktor:ktor", version.ref = "ktor" }
ktorGson = { module = "io.ktor:ktor-gson", version.ref = "ktor" }
ktorGson = { module = "io.ktor:ktor-serialization-gson", version.ref = "ktor" }

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.

the name of the artifact changed when I changed to ktor=2.3.13, that is why sample:vendor-lib didn't compile

@aleksandr-gringauz
aleksandr-gringauz requested a review from 0xnm June 2, 2025 14:16
@aleksandr-gringauz
aleksandr-gringauz merged commit 581d7ca into develop Jun 2, 2025
@aleksandr-gringauz
aleksandr-gringauz deleted the aleksandr-gringauz/RUM-9511/rum-auto-scenario-benchmark-move-to-app-save branch June 2, 2025 14:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants