Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RUMM-3133 Don't override ViewScope attributes with UserActionScope #1250

Merged
merged 4 commits into from
Apr 18, 2023

Conversation

ganeshnj
Copy link
Contributor

@ganeshnj ganeshnj commented Apr 14, 2023

What and why?

Today, when a UserAction, Resource or LongTask event is sent with attributes attached, if the attributes have conflicting keys with View event, the View attributes are overwritten by the UserAction/Resource/LongTask attributes.

UserActionScope events must not update the ViewScope attributes, which has been the case for Android SDK.

How?

Updated logic that overwrites the ViewScope attributes with UserActionScope attributes with unit tests to ensure that the ViewScope attributes are not overwritten.

Fixed Resource events where parent attributes were reported when there is a conflict.

Review checklist

  • Feature or bugfix MUST have appropriate tests (unit, integration)
  • Make sure each commit and the PR mention the Issue number or JIRA reference
  • Add CHANGELOG entry for user facing changes

Custom CI job configuration (optional)

  • Run unit tests
  • Run integration tests
  • Run smoke tests

…tributes

### What and why?

Today, when a `UserAction`, `Resource` or `LongTask` event is sent with attributes attached, if the attributes have
conflicting keys with View event, the View attributes are overwritten by the `UserAction`/`Resource`/`LongTask`
attributes.

`UserActionScope` events must not update the `ViewScope` attributes, which has been the case for Android SDK.

### How?

Updated logic that overwrites the `ViewScope` attributes with `UserActionScope` attributes with unit tests to ensure
that the `ViewScope` attributes are not overwritten.

Fixed `Resource` events where parent attributes were reported when there is a conflict.
@datadog-datadog-prod-us1
Copy link

datadog-datadog-prod-us1 bot commented Apr 14, 2023

Datadog Report

Branch report: jangirg/rum-3133-fix-view-overwrite
Commit report: 7b9ab06

dd-sdk-ios: 1 Failed (0 Known Flaky), 0 New Flaky, 2152 Passed, 0 Skipped, 32m 2.17s Wall Time

❌ Failed Tests (1)

  • testTracingNSURLSessionScenario - TracingURLSessionScenarioTests - Details

    Expand for error
     Segmentation fault. Check error.crash_log for the full crash log.
    

Copy link
Member

@maxep maxep left a comment

Choose a reason for hiding this comment

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

Awesome @ganeshnj !
This contribution is on point and the tests properly follow our pattern 👏
I've left a couple of comments and I would be interested to know your opinion on how we select the command types that can propagate attributes.

attributes.merge(rumCommandAttributes: command.attributes)
attributes.mergeWithoutOverwriting(rumCommandAttributes: command.attributes)
Copy link
Member

Choose a reason for hiding this comment

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

I think we should keep overwriting the attributes here: it is consuming a RUMStopResourceCommand in a RUMResourceScope.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The issue I found here was as below (from test case)

monitor.addAttribute(forKey: "abc", value: "123")

// when
monitor.startView(key: "View", name: nil, attributes: [:])
monitor.addUserAction(type: .custom, name: "action1", attributes: ["abc": "456"])

monitor.startResourceLoading(resourceKey: "/resource1", url: URL(string: "https://foo.com/1")!, attributes: ["abc": "456"])
monitor.stopResourceLoading(resourceKey: "/resource1", response: .mockAny(), size: nil, attributes: ["def": "789"])

here want to keep the abc attribute value reported in the resource event as 456 (along with def: 789). Currently, we overwrite it to 123 which is incorrect from my understanding. Anything that is child scope must take a precedence over the parent scope.

Do you have an example where this logic will go wrong? I can investigate further.

Comment on lines 425 to 431
// RUMM-3133 Don't override View attributes with UserAction, Resource or LongTask attributes
switch command {
case is RUMUserActionCommand, is RUMResourceCommand, is RUMAddLongTaskCommand:
break
default:
attributes.merge(rumCommandAttributes: command.attributes)
}
Copy link
Member

Choose a reason for hiding this comment

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

I think we should do the opposite and check for view-related command types instead.
Maybe it could use a

internal protocol RUMViewCommand: RUMCommand { }

for selecting which command types can propagate attributes to the view-scope. It would be less error prone when we add command types. WDYT?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

For sure having one base protocol for all the commands that we don't want to propagate would be ideal. I like the idea but I'm not sure what other commands we can expect here. This is the same rational behind using break with current default behavior.

Any hints on commands that we don't want propagation for?

@ganeshnj ganeshnj marked this pull request as ready for review April 17, 2023 13:22
@ganeshnj ganeshnj requested a review from a team as a code owner April 17, 2023 13:22
Copy link
Member

@maxep maxep left a comment

Choose a reason for hiding this comment

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

Perfect! CI status didn't get through but it's actually green:
image

Thanks again, @ganeshnj !

@ganeshnj ganeshnj changed the title RUMM-3133 Don't override ViewScope attributes with UserActionScope at… RUMM-3133 Don't override ViewScope attributes with UserActionScope Apr 18, 2023
Copy link
Member

@ncreated ncreated left a comment

Choose a reason for hiding this comment

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

Nice 🏅🎯! It's good to go IMO, but I left some extra context on how we recently started facilitating tests around collecting events .

Comment on lines +1506 to +1528
let rumEventMatchers = try core.waitAndReturnRUMEventMatchers()

let viewEvents = rumEventMatchers.filterRUMEvents(ofType: RUMViewEvent.self) { event in
return event.view.name != RUMOffViewEventsHandlingRule.Constants.applicationLaunchViewName
}
XCTAssertEqual(viewEvents.count, 4)
XCTAssertEqual(try viewEvents[0].attribute(forKeyPath: "context.abc"), "123")
XCTAssertEqual(try viewEvents[1].attribute(forKeyPath: "context.abc"), "123")
XCTAssertEqual(try viewEvents[2].attribute(forKeyPath: "context.abc"), "123")
XCTAssertEqual(try viewEvents[3].attribute(forKeyPath: "context.abc"), "123")

let actionEvents = rumEventMatchers.filterRUMEvents(ofType: RUMActionEvent.self) { event in
return event.view.name != RUMOffViewEventsHandlingRule.Constants.applicationLaunchViewName
}
XCTAssertEqual(actionEvents.count, 1)
XCTAssertEqual(try actionEvents[0].attribute(forKeyPath: "context.abc"), "456")

let resourceEvents = rumEventMatchers.filterRUMEvents(ofType: RUMResourceEvent.self) { event in
return event.view.name != RUMOffViewEventsHandlingRule.Constants.applicationLaunchViewName
}
XCTAssertEqual(resourceEvents.count, 1)
XCTAssertEqual(try resourceEvents[0].attribute(forKeyPath: "context.abc"), "789")
XCTAssertEqual(try resourceEvents[0].attribute(forKeyPath: "context.def"), "789")
Copy link
Member

Choose a reason for hiding this comment

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

non-blocking/ This is really good 👌, but we use legacy RUMEventMatchers concept here - perhaps it was inspired by surrounding tests 🙂 that weren't yet migrated. Not a change request, but I wanted to share a bit on how we could facilitate such tests today.

Recently we introduced two concepts that could make this code simpler and make assertions better: the DatadogCoreProxy and handy DDAssert* variants. If leveraging both, we could get rid of matchers and assert on models directly (including full assertion on dictionaries vs only partial ones with matchers). There would be no throwing and the entire test will run slightly faster.

Here's how it could look in the our new model. I'd love to see it even simplified with some contributions to DatadogCoreProxy and DDAssert* (e.g. type declarations seem redundant and force unwrapping isn't nice):

let viewEvents: [RUMViewEvent] = core.waitAndReturnEvents(of: RUMFeature.self, ofType: RUMViewEvent.self)
DDAssertDictionariesEqual(viewEvents[0].context!.contextInfo, ["abc": "123"])
DDAssertDictionariesEqual(viewEvents[1].context!.contextInfo, ["abc": "123"])
DDAssertDictionariesEqual(viewEvents[2].context!.contextInfo, ["abc": "123"])
DDAssertDictionariesEqual(viewEvents[3].context!.contextInfo, ["abc": "123"])

let actionEvents: [RUMActionEvent] = core.waitAndReturnEvents(of: RUMFeature.self, ofType: RUMActionEvent.self)
    .filter { $0.view.name != RUMOffViewEventsHandlingRule.Constants.applicationLaunchViewName }
DDAssertDictionariesEqual(actionEvents[0].context!.contextInfo, ["abc": "456"])

let resourceEvents: [RUMResourceEvent] = core.waitAndReturnEvents(of: RUMFeature.self, ofType: RUMResourceEvent.self)
    .filter { $0.view.name != RUMOffViewEventsHandlingRule.Constants.applicationLaunchViewName }
DDAssertDictionariesEqual(resourceEvents[0].context!.contextInfo, ["abc": "789", "def": "789"])

@ganeshnj ganeshnj merged commit 2d4b014 into develop Apr 18, 2023
@ganeshnj ganeshnj deleted the jangirg/rum-3133-fix-view-overwrite branch April 18, 2023 14:12
@ncreated ncreated mentioned this pull request Apr 26, 2023
6 tasks
@maxep maxep mentioned this pull request May 17, 2023
6 tasks
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