Repository navigation
Conversation
|
✅ All CI checks and tests passed. Datadog automation helped this PR pass. 🎉 All green!🧪 All tests passed 🔄 Datadog retried 1 test - 1 passed on retry 🎯 Code Coverage (details) 🔗 Commit SHA: c29b60b | Docs | View more details | Give us feedback! |
7166051 to
83930b2
Compare
|
@codex review |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
🛡️ Codex Security Review · Automatically triggeredSecurity review completed. No security issues were found in this pull request. Reviewed commit: Only the user who started this review can view the report in Codex. ℹ️ About Codex security reviews in GitHubThis is an experimental Codex feature. Security reviews are triggered when:
Once complete, Codex will leave suggestions, or a comment if no findings are found. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 83930b2f31
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
83930b2 to
c29b60b
Compare
There was a problem hiding this comment.
Resources that finish before the first RUM session skip completion bookkeeping, leaving pending counters positive and preventing stopped view/session scopes from completing. Both successful-resource and resource-error paths need the dropped-event notification.
🤖 Bits Code Review · Commit c29b60b
| val rumContext = getRumContext() | ||
| val sessionId = rumContext.sessionId | ||
| if (sessionId == null) { | ||
| sent = true |
There was a problem hiding this comment.
Balance pending counters when dropping sessionless resources
When a startup resource completes before the first RUM session, this return removes its scope without calling eventDropped(), leaving pendingResourceCount positive. A subsequent stopSession() cannot complete the stopped view/session scopes, retaining them until renewal. The equivalent guard in sendError() leaves pendingErrorCount positive after resource-to-error conversion. Previously, the no-op write invoked the dropped-event callback and balanced these counters. Both sessionless paths must preserve that notification and cleanup.
React: 👍 useful · 👎 wrong · 😕 unclear · 👀 right, but not acting on it
What each reaction means
- 👍 Useful: correct, and you're fixing it or will.
- 👎 Wrong: the finding is incorrect, for example the bug can't happen or the code was misread.
- 😕 Unclear: you can't tell what it means or why it matters.
- 👀 Right, not acting: correct, but intended, out of scope for this PR, a known risk, or too minor.
🤖 Bits Code Review · Open Bits AI session
| @Suppress("UnsafeThirdPartyFunctionCall") // currentContext is non-null | ||
| val contextSnapshot = HashMap(currentContext) |
There was a problem hiding this comment.
is it just for an additional guard? onContextUpdate argument for the context is of Map type, so it is not mutable unless receiver tries to cast to the mutable map explicitly (unlikely, I think).
as a price to pay - extra object allocation and iteration to copy.
| } | ||
|
|
||
| @ParameterizedTest | ||
| @CsvSource("false,false", "true,false", "true,true") |
There was a problem hiding this comment.
I'm not sure we need parametrized tests with boolean inputs. Maybe just a single test with forged values?
If we need to extend the coverage, we can use RepeatedTest
| val applicationId: String = NULL_UUID, | ||
| val sessionId: String = NULL_UUID, | ||
| val applicationId: String, | ||
| val sessionId: String? = null, | ||
| val isSessionActive: Boolean = false, | ||
| val viewId: String? = null, | ||
| val viewName: String? = null, | ||
| val viewUrl: String? = null, | ||
| val actionId: String? = null, | ||
| val sessionState: RumSessionScope.State = RumSessionScope.State.NOT_TRACKED, | ||
| val sessionStartReason: RumSessionScope.StartReason = RumSessionScope.StartReason.USER_APP_LAUNCH, | ||
| val sessionState: RumSessionScope.State? = null, | ||
| val sessionStartReason: RumSessionScope.StartReason? = null, |
There was a problem hiding this comment.
what is the benefit of dropping NULL_UUID and RumSessionScope.State.NOT_TRACKED here?
maybe we can extract RumContext into dd-sdk-android-internal, so that all modules can access it directly and use properties/methods specific to this class instead of relying on the generic types (e.g. strings, nulls)?
| val sessionId = rumContext.sessionId | ||
| if (sessionId == null) { | ||
| sent = true | ||
| return | ||
| } |
There was a problem hiding this comment.
it seems this change is not related and should be (if valid) in a standalone PR?
| val rulePsr = resourceAttributes.remove(RumAttributes.RULE_PSR) as? Number | ||
|
|
||
| val rumContext = getRumContext() | ||
| val sessionId = rumContext.sessionId |
| it["application_id"]?.let { value -> combinedAttributes[LogAttributes.RUM_APPLICATION_ID] = value } | ||
| it["session_id"]?.let { value -> combinedAttributes[LogAttributes.RUM_SESSION_ID] = value } | ||
| it["view_id"]?.let { value -> combinedAttributes[LogAttributes.RUM_VIEW_ID] = value } | ||
| it["action_id"]?.let { value -> combinedAttributes[LogAttributes.RUM_ACTION_ID] = value } |
There was a problem hiding this comment.
Maybe also worth to extract to the constants?
| if (it.syntheticsTestId != null) { | ||
| logSynthetics("_dd.application.id", it.applicationId) | ||
| logSynthetics("_dd.session.id", it.sessionId) | ||
| it.sessionId?.let { id -> logSynthetics("_dd.session.id", id) } |
There was a problem hiding this comment.
Don't we have something broken after this change? looks like synthetics attributes should always be bound to the session?
| @Suppress("ReturnCount") | ||
| fun fromFeatureContext(featureContext: Map<String, Any?>): RumContext? { | ||
| val applicationId = featureContext[APPLICATION_ID] as? String ?: return null | ||
| val sessionId = (featureContext[SESSION_ID] as? String)?.takeUnless { it.isBlank() || it == NULL_UUID } |
There was a problem hiding this comment.
nit: putting every ?: on a new line makes it bit more readable:
val sessionId = (featureContext[SESSION_ID] as? String)
?.takeUnless { it.isBlank() || it == NULL_UUID }
?: return RumContext(applicationId = applicationId)| it.clear() | ||
| rumContext?.toMap()?.let(it::putAll) | ||
| } | ||
| publishRumContext(rumContext.toMap()) |
There was a problem hiding this comment.
this might be too much for GC.
handleEvent executed for the every event, and this change gonna create new Map object every time.
Previous version was submitting runnable to the executor and only creates map there. Not sure if it's really affects the performance, but worth to check
What does this PR do?
Keep application identity available independently of the RUM session lifecycle. While RUM is enabled, the monitor always produces a
RumContextwith a requiredapplicationId;sessionIdand session metadata are nullable. Having no session means an application-only context, not a missing RUM context.application_idwhen no session exists, clearing stale session, view and action correlation. Failed event processing also falls back to application-only context.Motivation
RUM-17009: Android PR #3304 cleared the entire RUM context to prevent zero-UUID correlation in logs and traces. That also removed application attribution when sessions ended. This PR preserves that correlation safeguard while retaining application identity.
The telemetry approach follows iOS PR #3095: application identity comes from configuration, independently of session state. Android additionally refactors its internal context to represent an optional session; the iOS PR leaves its shared context model unchanged.
Additional Notes
No public API changes.
NULL_UUIDremains for compatibility and required schema fallbacks, but no longer represents an absent session in the internal RUM context.Local validation: the context refactor passed 13,260 unit tests (one assumption-based skip), all 74 instrumented integration tests, formatting, Detekt and generated-file checks. The subsequent WebView correlation fix passed all 194 WebView tests, formatting and Detekt; its regression test was verified to fail before the fix.
Review checklist (to be filled by reviewers)