RUM-5843 Introduce the RumMonitor#addViewLoadingTime API#2243
Conversation
8857cb3 to
51443c5
Compare
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## develop #2243 +/- ##
===========================================
+ Coverage 70.05% 70.09% +0.04%
===========================================
Files 730 730
Lines 27189 27185 -4
Branches 4590 4594 +4
===========================================
+ Hits 19045 19053 +8
+ Misses 6842 6838 -4
+ Partials 1302 1294 -8
|
|
|
||
| /** | ||
| * Adds view loading time to current RUM view based on the time elapsed since the view was started. | ||
| * This method should be called only once per view. |
There was a problem hiding this comment.
Why do we enforce it requirement on the client side? Cannot we just check in the implementation that if it was called already for the view, then ignore subsequent calls?
There was a problem hiding this comment.
we follow same approach as on iOS and for now on their end they allow it to be called multiple times. @ganeshnj maybe you want to add some thoughts here ?
There was a problem hiding this comment.
Important
I agree with @0xnm , we can't ask the customer to know whether or not the method has already been called. They could have several code paths that would lead to calling this method, and it would be a hassle to ask them to track whether or not that method have been called for a given View.
We need to make our SDK resilient enough to handle "misuse".
|
|
||
| // Then | ||
| argumentCaptor<ViewEvent> { | ||
| verify(mockWriter, times(viewLoadingTimeEvents.size)) |
There was a problem hiding this comment.
why should we allow multiple calls?
There was a problem hiding this comment.
Note
Not sure what the RFC stated, but imo the first loading time is the one that should be kept, otherwise, if the same screen is updated/refreshed, we would report a longer loading time than what the end user experienced.
| datadogBenchmark.stop() | ||
| } | ||
|
|
||
| @OptIn(ExperimentalRumApi::class) |
There was a problem hiding this comment.
It seems it is not needed here? I don't see any addViewLoadingTime call here
There was a problem hiding this comment.
yup a left - over from previous tries :(
| @OptIn(ExperimentalRumApi::class) | ||
| override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) { | ||
| if (event == Lifecycle.Event.ON_RESUME) { | ||
| GlobalRumMonitor.get().addViewLoadingTime() |
There was a problem hiding this comment.
won't we have multiple calls for the same view here when application goes info background and then back into foreground?
There was a problem hiding this comment.
when the app goes into background there will be a new view...we stop the view on the onPause the way I remember.
There was a problem hiding this comment.
no, here view tracking relies on navigation - I don't think navigation events are fired when app changes the state (but I may be wrong). While addViewLoadingTime call here relies not on the navigation, but on the lifecycle events.
There was a problem hiding this comment.
let me double check this, you might be right, I was assuming we rely on the view lifecycle here
| @OptIn(ExperimentalRumApi::class) | ||
| override fun onResume() { | ||
| super.onResume() | ||
| GlobalRumMonitor.get().addViewLoadingTime() |
There was a problem hiding this comment.
same: I guess we can have multiple calls for the same view?
| @OptIn(ExperimentalRumApi::class) | ||
| override fun onViewCreated(view: View, savedInstanceState: Bundle?) { | ||
| super.onViewCreated(view, savedInstanceState) | ||
| GlobalRumMonitor.get().addViewLoadingTime() |
There was a problem hiding this comment.
onResume will be called right after onViewCreated effectively discarding this call
| object : ImageLoadedCallback { | ||
| override fun onImageLoaded(resource: Drawable) { | ||
| imageViewRemote.setImageDrawable(resource) | ||
| if (imageLoadedCounter.decrementAndGet() == 0) { |
There was a problem hiding this comment.
should we extract this into a common private method? same snippet is used 4 times.
| ) | ||
|
|
||
| @Volatile | ||
| private var pageWasLoaded: Boolean = false |
There was a problem hiding this comment.
| private var pageWasLoaded: Boolean = false | |
| private var pageIsLoaded: Boolean = false |
There was a problem hiding this comment.
I know that the WebView callbacks are being executed on a different thread this is the reason why I want to keep it as @volatile
There was a problem hiding this comment.
my suggestion is not about volatile, but about naming
| private lateinit var webView: WebView | ||
|
|
||
| @Volatile | ||
| private var pageWasLoaded: Boolean = false |
There was a problem hiding this comment.
| private var pageWasLoaded: Boolean = false | |
| private var pageIsLoaded: Boolean = false |
| ) | ||
|
|
||
| @Volatile | ||
| private var pageWasLoaded: Boolean = false |
There was a problem hiding this comment.
| private var pageWasLoaded: Boolean = false | |
| private var pageIsLoaded: Boolean = false |
51443c5 to
fe279fd
Compare
| * If the view is not started, this method does nothing. | ||
| * If the view is not active(stopped), this method does nothing. |
There was a problem hiding this comment.
Note
Since the loading time is applied to the current RUM view (maybe should be the current active RUM View), those two lines are misleading IMO. It feels like we make the assumption that a view is necessarily an Activity/Fragment with a lifecycle (start, resume, …), which is not always the case.
| * If the view is not started, this method does nothing. | |
| * If the view is not active(stopped), this method does nothing. | |
| * If no view is started or active, this method does nothing. |
There was a problem hiding this comment.
I am following the same docs as in iOS
|
|
||
| /** | ||
| * Adds view loading time to current RUM view based on the time elapsed since the view was started. | ||
| * This method should be called only once per view. |
There was a problem hiding this comment.
Important
I agree with @0xnm , we can't ask the customer to know whether or not the method has already been called. They could have several code paths that would lead to calling this method, and it would be a hassle to ask them to track whether or not that method have been called for a given View.
We need to make our SDK resilient enough to handle "misuse".
|
|
||
| // Then | ||
| argumentCaptor<ViewEvent> { | ||
| verify(mockWriter, times(viewLoadingTimeEvents.size)) |
There was a problem hiding this comment.
Note
Not sure what the RFC stated, but imo the first loading time is the one that should be kept, otherwise, if the same screen is updated/refreshed, we would report a longer loading time than what the end user experienced.
|
|
||
| @OptIn(ExperimentalRumApi::class) | ||
| override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) { | ||
| if (event == Lifecycle.Event.ON_RESUME && !viewIsLoaded) { |
There was a problem hiding this comment.
Note
Is this sample the kind of use case we want to showcase ? Tracking the onResume time is not relevant most of the time. We should probably instead only do what you added in the DataListViewModel where we actually load something from the network, which would be a better example of how to use this new API.
There was a problem hiding this comment.
For some reason I cannot reply to your comment one by one @xgouchet. Regarding the addViewLoadingTime being called multiple times the whole approach was discussed and agreed in the RFC.
There was a problem hiding this comment.
Regarding your last comment, that is a nice to have in the Sample app, my intention was to add the viewLoadingTime for most of the views there. In that case I will remove the call for this view and maybe add a task to enrich the sample app. This is not the scope for this PR. @0xnm what's your opinion on that ?
There was a problem hiding this comment.
It depends on the nature of the screen, some screens may not load anything from the network/disk. But maybe to highlight that this method shouldn't be blindly used in the onResume we may want indeed to have it called only in the data stream.
There was a problem hiding this comment.
On the same time we could agree that there will be use cases on the customer's end where simple static views like these ones would have to be measured. In that case we will remove these use - cases from the sample app and only maintain the ones that imply an async data ?
2b818a3 to
13199cd
Compare
13199cd to
61ca355
Compare
| startCustomRumViewButton.setOnClickListener { | ||
| GlobalRumMonitor.get().startView(this, "Custom RUM View") | ||
| } | ||
| // add webview on load listener |
There was a problem hiding this comment.
Note
Is this comment needed here ? Feels like its a TODO that didn't get removed
61ca355 to
02d3565
Compare
What does this PR do?
A brief description of the change being made with this pull request.
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)