RUM-9508: LogsCustom scenario for android benchmark app#2625
Conversation
| } | ||
|
|
||
| @Composable | ||
| private fun <T> DropDownMenuView( |
There was a problem hiding this comment.
There was a problem hiding this comment.
this is strange, here Composable is in ignoreAnnotated, looks like it didn't work....
| import androidx.compose.ui.unit.dp | ||
|
|
||
| @Composable | ||
| internal fun LogsScreen( |
There was a problem hiding this comment.
| } | ||
|
|
||
| @Composable | ||
| private fun <T> ExpandedItemView( |
There was a problem hiding this comment.
|
|
||
| @Preview(showBackground = true) | ||
| @Composable | ||
| fun LogsScreenPreview() { |
There was a problem hiding this comment.
| } | ||
|
|
||
| @Composable | ||
| private fun IntervalItemView( |
There was a problem hiding this comment.
bca5d7e to
1971d70
Compare
|
|
||
| @Preview(showBackground = true) | ||
| @Composable | ||
| internal fun LogsScreenPreview() { |
There was a problem hiding this comment.
⚪ Code Quality Violation
| internal fun LogsScreenPreview() { | |
| internal fun LogsScreenPreview { |
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.
| } | ||
|
|
||
| @Composable | ||
| private fun ValueChooserItemView( |
There was a problem hiding this comment.
| androidXWorkManager = "2.8.1" # Next version will bring coroutines | ||
| googleAccompanist = "0.20.2" | ||
| googleMaterial = "1.3.0" | ||
| dagger = "2.56.2" |
There was a problem hiding this comment.
Integrated dagger in the benchmark app. If anyone has any objections - tell me.
There was a problem hiding this comment.
If it doesn't bring a dramatic compilation time penalty, I'm personally okay with that.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Two questions from me about this:
- 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?
- If it's for dependency injection, why not
Hiltinstead ofDagger2?
There was a problem hiding this comment.
- 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.
- Why I didn't use hilt https://github.com/DataDog/dd-sdk-android/pull/2625/files#r2071751641
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## develop #2625 +/- ##
========================================
Coverage 70.02% 70.02%
========================================
Files 820 820
Lines 30568 30568
Branches 5132 5132
========================================
Hits 21405 21405
+ Misses 7733 7720 -13
- Partials 1430 1443 +13 🚀 New features to boost your workflow:
|
| * Class to control the benchmark test in sample application. It takes the [Config] which is parsed | ||
| * from Synthetics variables in order to decide which scenario it should run for the benchmark test. | ||
| */ | ||
| internal class DatadogBenchmark(config: Config) { |
There was a problem hiding this comment.
Refactored this file.
- Created
DatadogFeaturesInitializerthat is responsible of initializing different features of Datadog based on run and scenario. - Moved
DatadogBenchmark.Configout ofDatadogBenchmarkand renamed itBenchmarkConfig. DatadogBaseMeteris created inside a dagger module calledDatadogActivityModule.- deleted
DatadogBenchmarkclass.
| } | ||
|
|
||
| // the same as the default one | ||
| private const val CAPACITY_BACK_PRESSURE_STRATEGY = 1024 |
There was a problem hiding this comment.
This value was 32 before. I think that for benchmarking we should use the default one that is most likely used by the clients.
| ~ Copyright 2016-Present Datadog, Inc. | ||
| --> | ||
|
|
||
| <navigation xmlns:android="http://schemas.android.com/apk/res/android" |
There was a problem hiding this comment.
Removed this, instead now use kotlin to configure navigation graph. See FragmentsNavigationManagerImpl.
- I prefer kotlin over xml for navigation
- Wanted to compute startDestination based on
BenchmarkConfig. - Create different navigationGraphs for different scenarios. Though it is not exactly necessary and I'm not sure I'll leave it this way.
- Maybe I'll use typesafe navigation in future prs.
2,3,4 can most likely be done in xml, but imho doing it in kotlin is much easier.
| Assertions.assertThat(config.scenario).isEqualTo(null) | ||
| Assertions.assertThat(config.run).isEqualTo(null) | ||
| } | ||
|
|
||
| @Test | ||
| fun `M enable session replay W config run is instrumented`() { |
There was a problem hiding this comment.
this moved to DatadogFeaturesInitializerTest and I added some new tests there
| Logs.enable(logsConfig, sdkCore) | ||
| } | ||
|
|
||
| private fun needToEnableRum(): Boolean { |
There was a problem hiding this comment.
Previously Benchmark App initialized Rum feature in Application.onCreate. Now it is done in Activity.onCreate. I did it because Logs feature doesn't actually need Rum to work and on iOS they don't initialize it in LogsCustom scenario (link).
And you only know what scenario it is in Activity.onCreate.
There was a problem hiding this comment.
The general recommendation we give is to initialize all the components at the Application.onCreate to have all the observability as early as possible.
If we choose to initialize things in the Activity.onCreate we may have it called several times in the application lifecycle (e.g. due to configuration change), meaning that we will have multiple calls to Rum.create.
This won't have any impact, because once RUM feature is initialized, the subsequent initialization calls won't do anything, but still, do we want to keep it as an example of the SDK usage? What is the benefit of this change?
There was a problem hiding this comment.
What is the benefit of this change?
Right now we pass what scenario we want to run as intent extras. See this and this.
And the features we want to initialize depend on the scenario.
Thus we have to initialize the features in Activity.onCreate.
Prior to this pr sessionreplay was initialized in Activity.onCreate as well (link).
My pr added the Logs feature and I moved the initialization of Rum feature to Activity.onCreate (because Logs don't need it).
we may have it called several times in the application lifecycle (e.g. due to configuration change)
This is a good point. This can be mitigated by moving DatadogFeaturesInitializer to the application scope and creating some sort of isInitialized flag in it that allows initialization only once.
do we want to keep it as an example of the SDK usage?
I can write a comment in code explaining that you should consider initializing everything in Application.onCreate.
There was a problem hiding this comment.
- added the comment for
DatadogFeaturesInitializer - added
isInitializedflag inDatadogFeaturesInitializer
| */ | ||
|
|
||
| package com.datadog.benchmark.sample.fragment | ||
| package com.datadog.benchmark.sample.ui.sessionreplay |
There was a problem hiding this comment.
Moved all screen related files to the folder ui/scenario_name.
1971d70 to
e29760d
Compare
e29760d to
26b95d4
Compare
| Logs.enable(logsConfig, sdkCore) | ||
| } | ||
|
|
||
| private fun needToEnableRum(): Boolean { |
There was a problem hiding this comment.
The general recommendation we give is to initialize all the components at the Application.onCreate to have all the observability as early as possible.
If we choose to initialize things in the Activity.onCreate we may have it called several times in the application lifecycle (e.g. due to configuration change), meaning that we will have multiple calls to Rum.create.
This won't have any impact, because once RUM feature is initialized, the subsequent initialization calls won't do anything, but still, do we want to keep it as an example of the SDK usage? What is the benefit of this change?
| androidXWorkManager = "2.8.1" # Next version will bring coroutines | ||
| googleAccompanist = "0.20.2" | ||
| googleMaterial = "1.3.0" | ||
| dagger = "2.56.2" |
There was a problem hiding this comment.
If it doesn't bring a dramatic compilation time penalty, I'm personally okay with that.
| config = BenchmarkConfig.resolveSyntheticsBundle(intent.extras) | ||
|
|
||
| benchmarkActivityComponent = DaggerBenchmarkActivityComponent.factory().create( | ||
| deps = (application as BenchmarkApplication).benchmarkAppComponent, |
There was a problem hiding this comment.
suggestion: maybe benchmarkAppComponent can be an internal extension property for the Application class? if used from multiple places
| private fun createStartDestination(scenario: SyntheticsScenario?): String { | ||
| return when (scenario) { | ||
| SyntheticsScenario.SessionReplay -> SESSION_REPLAY_METERIAL_FRAGMENT_KEY | ||
| SyntheticsScenario.SessionReplayCompose -> TODO() |
There was a problem hiding this comment.
maybe create JIRA tickets in put a reference for all these TODO items?
| "os" to "iOS 17.2", | ||
| "battery" to "80%" | ||
| ), | ||
| "network" to mapOf( |
There was a problem hiding this comment.
nb: this will clash with the default network property set by SDK (unfortunately, LogEvent has custom attribute in the shared root namespace) and so will be ignored.
There was a problem hiding this comment.
thanks for spotting this
changed all the attribute keys to have benchmark_ prefix.
| private fun MockedStatic<Rum>.verifyRumEnabled() { | ||
| verify { | ||
| Rum.enable( | ||
| rumConfiguration = any(), | ||
| sdkCore = any() | ||
| ) | ||
| } | ||
| } |
There was a problem hiding this comment.
The alternative to these checks is Logs.isEnabled, etc. and this will also allow to avoid using mockStatic, but then it won't be really a unit-test then.
There was a problem hiding this comment.
thanks for the info
for now didn't change anything here
| .trackLongTasks(THRESHOLD_LONG_TASK_INTERVAL) | ||
| .trackNonFatalAnrs(true) | ||
| .setViewEventMapper { event -> | ||
| event.context?.additionalProperties?.put(ATTR_IS_MAPPED, true) |
There was a problem hiding this comment.
what's this attribute used for ?
| "benchmark_log_type" to "user_event", | ||
| "benchmark_session" to mapOf( | ||
| "id" to UUID.randomUUID().toString(), | ||
| "startTime" to "2024-02-27T12:00:00Z", |
There was a problem hiding this comment.
why is the date hardcoded ? same question regarding the user:id below.
There was a problem hiding this comment.
it is a copy paste from ios link
I suppose it doesn't matter what we put here. These are just test payloads that have different sizes.
What does this PR do?
Implemented LogsCustom scenario for Android Benchmarking app that is described here. demo: link
created a synthetics test described here. Link. I checked that is works for my local build.
Also see comments in the pr.
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)