The key point

  • First, each session has a unique session ID, which is the link that connects all the actions.
  • Secondly, user behavior is divided into two parts, one is user operations, such as mouse sliding, clicking, page scrolling, etc., and the other is page changes. Both of these are collectively called user actions and are recorded in the same queue.
  • At the beginning, the system will record the initial page as the first frame, which is the only time a complete page is recorded.
  • For user operations, key information such as event type and mouse position will be recorded and stored in the queue.
  • For page changes, we will start a mutationObserve to listen for changes to the page, and only record the changes to the queue each time.
  • Both events and page changes are equivalent frames, and each frame will have the current time and the time between the last frame and other basic information restored by the user
  • In case of an error, the SDK sends the queue to the monitoring system and empties the current queue.
  • The restoring end plays the recorded behavior queue one by one according to the time. The result is a video-like effect.

Preliminary ideas

A:

  1. The front end collects information, first recording the initial state of a page during initialization, then using MutationObserver to listen for DOM changes, then for all mouse events, scrolling events, and all page changes.
  2. Queue these messages to the server at reasonable times, such as when a page error occurs.
  3. The background analyzes the information gathered by the front end, turns it into a picture, and forms a “video,” or user behavior stack. Provide the corresponding calling API.
  4. When the front end needs to find the problem, it finds the corresponding error stack according to the user ID and other information.

Method 2:

  1. The front end converts to the corresponding image according to HTML (can be converted to Base64 format)
  2. Send the image to the background
  3. The background organizes the images into a “video.”

Existing SDK

  1. fundebug

Screen recording (screenshot)

  1. html2canvas
  2. puppeteer
  3. rrweb+rrweb-player+rrweb-snapshot

Html2canvas introduction

Html2canvas analyzes the loaded DOM elements in the page, and then canvas draws the GENERATED DOM nodes on the canvas, and finally converts them into pictures. It’s not really a screenshot, it’s just a reproduction of the image based on the page element information, so it’s not 100% the same as the page.

limitations

  • Images on a page cannot cross domains
  • Not all CSS features are supported, such as box-shadow and filter
  • Interception of plug-in content, such as Flash, is not supported
  • Iframe content is not supported

Browser support

  • Firefox 3.5 +
  • Google Chrome
  • Opera 12+
  • IE9+
  • Edge
  • Safari 6+

Puppeteer is introduced

Puppeteer is Google Chrome’s official Headless Chrome tool. Puppeteer is a Node library that provides an advanced API to control the Headless Chrome on the DevTools protocol.

limitations

  • Puppeteer needs Chromium. It is mainly used in automated testing.

function

  • Generate screenshots and PDF of the page.
  • Grab the SPA and generate the pre-rendered content (that is, “SSR”).
  • Grab the content you need from the website.
  • Automatic form submission, UI testing, keyboard input, etc
  • Create an up-to-date automated test environment. Run tests directly in the latest version of Chrome, using the latest JavaScript and browser features.
  • Capture a timeline trace of your site to help diagnose performance issues.

Conclusion HTML2Canvas is more suitable for c-side user behavior screenshot tracking, while Puppeteer is suitable for automated testing.

Rrweb introduction

Rrweb consists of three main parts:

  1. Rrweb-snapshot, including snapshot and rebuild functions. Snapshot is used to convert the DOM and its state into serializable data structures and add unique identifiers. Rebuild is to rebuild the data structure recorded by snapshot into the corresponding DOM.
  2. Rrweb, including record and replay two functions. Record is used to record all mutations in the DOM; Replay is to replay recorded changes one by one at the corresponding time.
  3. Rrweb – Player, a set of UI controls for RRWeb that provide GUI-based pause, fast forward, drag and drop to play at any point in time, and more.

Rrweb application scenarios:

  • User behavior analysis;
  • The remote debug;
  • Recording operation;
  • Real-time collaboration;

limitations

  • Less community resources
  • Some of the code was written in older patterns with unknown pits

The final conclusion

Overall, combined with the first idea, based on RRWeb to develop is the most feasible and fast.

Demo

At present, I have made a demo based on RRWeb. Here are the initial results: Demo code

Additional information

Rrweb some ideas of principle

zhuanlan.zhihu.com/p/60639266

MutationObserver introduction

The Mutation Observer API is used to monitor DOM changes. The API is notified of any changes to the DOM, such as the addition or subtraction of nodes, changes in attributes, and changes in text content.

The characteristics of

  • It waits for all script tasks to complete before running (that is, asynchronously triggered).
  • Instead of processing DOM changes individually, it wraps DOM changes into an array for processing.
  • It can either observe all types of changes to the DOM, or specify that only one type of change is observed.

example // Select the node that will be observed for mutations var targetNode = document.getElementById(‘some-id’);

// Options for the observer (which mutations to observe) var config = { attributes: true, childList: true, subtree: true }; // Callback function to execute when mutations are observed var callback = function(mutationsList, observer) { for(var mutation of mutationsList) { if (mutation.type == 'childList') { console.log('A child node has been added or removed.'); } else if (mutation.type == 'attributes') { console.log('The ' + mutation.attributeName + ' attribute was modified.'); }}}; // Create an observer instance linked to the callback function var observer = new MutationObserver(callback); // Start observing the target node for configured mutations observer.observe(targetNode, config); // Later, you can stop observing observer.disconnect();Copy the code

The observe method takes two arguments: the observe DOM element (article) and the observe DOM element (child node or attribute). The observe method must specify one or more of the observe DOM elements. Otherwise, an error occurs.

boolean childList = false; boolean attributes; boolean characterData; boolean subtree = false; // Indicates whether to apply the observer to all descendants of the node. boolean attributeOldValue; // Indicates whether the value of the attributes before the change needs to be recorded while observing the change. boolean characterDataOldValue; // Indicates whether to record the value before the change when observing the characterData change. sequence<DOMString> attributeFilter; // Array, representing specific attributes to observe (e.g. ['class',' SRC '])Copy the code

The Disconnect method is used to stop the observation. After this method is called, the DOM changes again and the observer is not triggered. The takeRecords method is used to clear the change record, that is, unprocessed changes are no longer processed. This method returns an array of change records.

MutationRecord object

Each time the DOM changes, a change Record instance is generated. This example contains all the information related to the change. The Mutation Observer handles an array of MutationRecord instances. The MutationRecord object contains DOM information and has the following properties:

Type: Indicates the observed change type (attribute, characterData, or childList). Target: the DOM node that has changed. AddedNodes: New DOM nodes. RemovedNodes: Deletes DOM nodes. PreviousSibling: previousSibling, null if none. NextSibling: nextSibling, null if none. AttributeName: An attribute that has changed. If attributeFilter is set, only the pre-specified attributes are returned. OldValue: indicates the value before the change. This property is valid only for attribute and characterData changes, and returns NULL if a childList change occurs.Copy the code