-
Notifications
You must be signed in to change notification settings - Fork 142
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
✨ [RUM-7019] Add setAccount API and account in RUM events #3242
base: main
Are you sure you want to change the base?
Conversation
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## main #3242 +/- ##
==========================================
+ Coverage 93.68% 93.71% +0.02%
==========================================
Files 288 290 +2
Lines 7617 7651 +34
Branches 1739 1745 +6
==========================================
+ Hits 7136 7170 +34
Misses 481 481 ☔ View full report in Codecov by Sentry. |
fd6582e
to
afda0b9
Compare
afda0b9
to
4c268b7
Compare
Bundles Sizes Evolution
🚀 CPU Performance
🧠 Memory Performance
|
/to-staging |
Devflow running:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some minor nits, but everything looks great!
import type { Context } from '../../tools/serialisation/context' | ||
import { sanitizeContext } from '../context/contextUtils' | ||
|
||
export function sanitizeAccount(newAccount: Context) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The return value of this function is not just a Context
, but an Account
, right? It might make sense to update the function signature to capture that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sanitizeAccount
and sanitizeUser
are manipulating Context
and are used by Context Manager functions that expect a Context
:
accountContextManager.setContext(sanitizeAccount(newUser))
If I update the signature I will have to cast the result. But maybe I could rename to sanitizeAccountContext
?
getAccount: monitor(() => accountContextManager.getContext()), | ||
|
||
setAccountProperty: monitor((key, property) => { | ||
const sanitizedProperty = sanitizeAccount({ [key]: property })[key] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's unfortunate that this logic has to be repeated twice. It'd be nice if the context manager itself could be configured with a sanitizer, and it'd just handle the work internally. Not a blocker for this PR, but might be nice to consider as a followup.
if (!isEmptyObject(commonContext.account)) { | ||
if (commonContext.account.id) { | ||
;(serverRumEvent.account as Mutable<RumEvent['account']>) = commonContext.account as Account & | ||
Context & { id: string } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm guessing the as Account
type assertion is losing the type narrowing you just did with the if (commonContext.account.id)
check, and that's why you need & { id: string }
. Out of curiosity, does the assignment type check if you just get rid of the whole type assertion?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The type of commonContext.account
is Account
so even with the narrowing it is still "just" an Account
and we must enforce { id: string }
.
But because there's overlap between Account
and Context
, I could do:
if (commonContext.account.id) {
;(serverRumEvent.account as Mutable<RumEvent['account']>) = commonContext.account as { id: string }
} else {
@@ -0,0 +1,5 @@ | |||
export interface Account { | |||
id?: string | undefined |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
❓ question: Shouldn't the id be required?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In theory yes 😅 But the issue is that Context Manager is manipulating Context
so we loose the original type when passing the User
or Account
object. Until now it was fine because both Context
and User
have no required properties.
I could require the id
property but we would have to cast the context, and maybe getting an account without an id
.
export function buildCommonContext(
globalContextManager: ContextManager,
userContextManager: ContextManager,
acccountContextManager: ContextManager
): CommonContext {
return {
view: {
referrer: document.referrer,
url: window.location.href,
},
context: globalContextManager.getContext(),
user: userContextManager.getContext(),
account: acccountContextManager.getContext() as Account,
}
}
That's why I preferred not requiring the Id and checking it in the assembly. Hope it makes sense.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Following @BenoitZugmeyer comment, we now use Context
type in the CommonContext
for account property. So now the Account
type have a required id property.
;(serverRumEvent.account as Mutable<RumEvent['account']>) = commonContext.account as Account & | ||
Context & { id: string } | ||
} else { | ||
display.warn("The account object is missing the 'id' property, it will not be sent to the intake.") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💬 suggestion: We likely don’t want to print a warning every time an event is assembled. Wouldn’t this check be more appropriate in sanitizeContext
or checkContext
?
* @param property Value of the property | ||
* | ||
*/ | ||
setAccountProperty: (key: any, property: any) => void |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
❓ question: key: string
be more accurate? I know we also have any
for user API but might worth reconsider.
/** | ||
* Set account information to all events, stored in `@account` | ||
*/ | ||
setAccount: (newAccount: Account & { id: string }) => void |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💬 suggestion: maybe using a proper type here would be nicer for the user
setAccount: (newAccount: Account & { id: string }) => void | |
setAccount: (newAccount: Account) => void |
I understand that you don't want account.id
to be required in the type we use internally, since we cannot enforce it. I think it's fine to use Context
instead of Account
internally (see this patch).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💯 and we enforce the type just after in the assembly anyway. We should though how the context management could handle sanitization like @sethfowler-datadog proposed, but also typing.
Datadog ReportBranch report: ❌ 16 Failed (0 Known Flaky), 17373 Passed, 345 Skipped, 1m 53.93s Total Time ❌ Failed Tests (16)
New Flaky Tests (1)
|
Motivation
Adding a standard way to set an account.
Changes
id
insetAccount
.id
property is missing.Testing
I have gone over the contributing documentation.