✨ [PANA-8578] Assign roles to strings in session replay recordings - #4983
✨ [PANA-8578] Assign roles to strings in session replay recordings#4983sethfowler-datadog wants to merge 5 commits into
Conversation
|
/to-staging |
|
View all feedbacks in Devflow UI.
Commit c9e4928d35 will soon be integrated into staging-35.
We couldn't automatically merge the commit c9e4928d35 into staging-35! To solve the conflicts directly in Github, click here to create a fix pull request. Alternatively, you can also click here reset the integration branch or use the following Slack command: Detailsfailed to auto-fix conflicts: Failed to get merge content: Failed to merge commits because of conflicting files |
🎉 All green!🧪 All tests passed 🎯 Code Coverage (details) 🔗 Commit SHA: 937ef9e | Docs | View more details | Give us feedback! |
|
🚂 Branch Integration: starting soon, merge expected in approximately 16m (p90) Commit c9e4928d35 will soon be integrated into staging-35. |
|
🚂 Branch Integration Commit c9e4928d35 has been merged into staging-35 in merge commit 8b883b48a4. If you need to revert this integration, you can use the following command: |
Bundles Sizes Evolution
|
BeltranBulbarellaDD
left a comment
There was a problem hiding this comment.
All clear on my side!
Motivation
This PR updates the session replay recorder to assign "roles" to all strings it generates. These roles give downstream tooling the information it needs to transform session replay recordings after they're generated; most importantly, the roles are designed to give us the capability to perform additional privacy masking on the server side. The string roles ensure that this kind of transformation can be performed without the need for prohibitively expensive analysis, like DOM reconstruction, and without the need for the backend to understand the entire session replay data format.
Changes
Roles are assigned where each string is produced.
serializeNode,serializeAttributes,serializeMutationsandSerializationTransactiontag each string as they emit it, so the assignment is structural and can't drift from the code that produces the string.StringRoleconstants are added tosessionReplayConstants.ts; the schema types themselves landed earlier.Strings are grouped by role when the final record is generated.
ChangeEncodernow collects the strings a record introduces and groups them at flush time; this means that we only need to send one annotation per role, instead of annotating every string individually. Newly-introduced strings have no id until the flush happens; they're initially replaced by a placeholder, and we then replace these placeholders with string table references in a second pass. We track which changes actually include fresh strings; in the common case where no new strings are introduced, these changes can be skipped, minimizing the amount of work we need to do on the second pass.The string table is logically keyed by
(role, string). Two identical strings in different roles can be masked differently and thus can't share an entry.New
domain/record/encoding/directory holding the string table and the change encoder/decoder:itemIds.ts,changeEncoder.ts,changeDecoder.tsandstringTable.tsmoved there, joined byroles.tsandstringIds.ts. This is mostly just an organizational change to centralize the encoding logic, since we're starting to get more of it; the new files are the main things to focus on when reviewing this directory.Session replay tests now fail when the old string representations are encountered. This is enforced by
ChangeDecoder, which is used under the hood by all of the tests to present serialized change records in a human-readable way.ChangeDecoderalso gained akeepRolesoption which makes it decode string references toRoleAnnotatedStringLiterals instead of plain strings, making it possible to conveniently write tests for string role behavior.serializeDOMAttributes()returnsAttributeAssignment[]instead of aRecord<string, string>. This allows it to handle string role assignment for attributes directly and avoids some wasteful transformations that would otherwise be required. (We avoid 1/3 of the allocations we would otherwise do per element on this code path.) The change also fixes a latent bug, although it's admittedly an edge case: an attribute named__proto__was silently dropped, because assigning it on a plain object went through the inherited setter. Covered by a new test.Behavior changes worth a look
<option value="…">now serializes novalueat all, where it previously serializedvalue="***".getElementInputValue()already declined to serialize it; the censored DOM attribute was surviving underneath.value,selectedandcheckednow sort after an element's other attributes rather than keeping their DOM position. Attribute order isn't meaningful in the format, but it moves one expectation inserializeNode.snapshot.spec.ts.Checklist