Skip to content

Commit

Permalink
Reduce frequency of upload calls (microsoft#153)
Browse files Browse the repository at this point in the history
* Reduce frequency of upload calls

* Compatibility with vue-fragment and PR feedback

* Bumping version to 0.6.17

* Upgrading packages and better mutation suspension logic

* Better handle async task execution across pages

* Updating trim-newlines version

* Bug fix: horizontal scrolling on elements
  • Loading branch information
sarveshnagpal committed Jul 21, 2021
1 parent 5957c43 commit 42c72e6
Show file tree
Hide file tree
Showing 25 changed files with 691 additions and 2,024 deletions.
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ On Windows, grab an installer from here: https://git-scm.com/download/win and go

On Mac and Linux, it's pre-installed.

### Node.js (12+)
### Node.js (14+)

On Windows, grab an installer from nodejs.org and go with the default options:
```
Expand Down
2 changes: 1 addition & 1 deletion lerna.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"packages": [
"packages/*"
],
"version": "0.6.16",
"version": "0.6.17",
"npmClient": "yarn",
"useWorkspaces": true
}
8 changes: 6 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "clarity",
"private": true,
"version": "0.6.16",
"version": "0.6.17",
"repository": "https://github.com/microsoft/clarity.git",
"author": "Sarvesh Nagpal <sarveshn@microsoft.com>",
"license": "MIT",
Expand All @@ -20,6 +20,10 @@
"test": "yarn workspace clarity-js test"
},
"devDependencies": {
"lerna": "^4.0.0"
"lerna": "^4.0.0",
"trim-newlines": "^4.0.2"
},
"resolutions": {
"trim-newlines": "^4.0.2"
}
}
26 changes: 13 additions & 13 deletions packages/clarity-decode/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "clarity-decode",
"version": "0.6.16",
"version": "0.6.17",
"description": "An analytics library that uses web page interactions to generate aggregated insights",
"author": "Microsoft Corp.",
"license": "MIT",
Expand All @@ -26,20 +26,20 @@
"url": "https://github.com/Microsoft/clarity/issues"
},
"dependencies": {
"clarity-js": "^0.6.16"
"clarity-js": "^0.6.17"
},
"devDependencies": {
"@rollup/plugin-commonjs": "^11.1.0",
"@rollup/plugin-node-resolve": "^7.1.3",
"del-cli": "3.0.0",
"husky": "4.2.3",
"lint-staged": "10.1.2",
"rollup": "^2.7.3",
"rollup-plugin-terser": "^5.3.0",
"rollup-plugin-typescript2": "^0.27.0",
"ts-node": "8.8.2",
"tslint": "6.1.1",
"typescript": "^3.8.3"
"@rollup/plugin-commonjs": "^19.0.1",
"@rollup/plugin-node-resolve": "^13.0.2",
"del-cli": "^4.0.1",
"husky": "^7.0.1",
"lint-staged": "^11.0.1",
"rollup": "^2.53.2",
"rollup-plugin-terser": "^7.0.2",
"rollup-plugin-typescript2": "^0.30.0",
"ts-node": "^10.1.0",
"tslint": "^6.1.3",
"typescript": "^4.3.5"
},
"scripts": {
"build": "yarn build:clean && yarn build:main",
Expand Down
30 changes: 15 additions & 15 deletions packages/clarity-devtools/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "clarity-devtools",
"version": "0.6.16",
"version": "0.6.17",
"private": true,
"description": "Adds Clarity debugging support to browser devtools",
"author": "Microsoft Corp.",
Expand All @@ -24,24 +24,24 @@
"url": "https://github.com/Microsoft/clarity/issues"
},
"dependencies": {
"clarity-decode": "^0.6.16",
"clarity-js": "^0.6.16",
"clarity-visualize": "^0.6.16"
"clarity-decode": "^0.6.17",
"clarity-js": "^0.6.17",
"clarity-visualize": "^0.6.17"
},
"devDependencies": {
"@rollup/plugin-node-resolve": "^7.1.3",
"@types/chrome": "0.0.35",
"del-cli": "^1.1.0",
"lint-staged": "^7.3.0",
"@rollup/plugin-node-resolve": "^13.0.2",
"@types/chrome": "0.0.147",
"del-cli": "^4.0.1",
"lint-staged": "^11.0.1",
"pubsub-js": "^1.7.0",
"rollup": "^2.7.3",
"rollup": "^2.53.2",
"rollup-plugin-copy": "^3.3.0",
"rollup-plugin-terser": "^5.3.0",
"rollup-plugin-typescript2": "^0.27.0",
"source-map-loader": "^0.2.4",
"ts-node": "^8.0.1",
"tslint": "^5.11.0",
"typescript": "^3.2.4"
"rollup-plugin-terser": "^7.0.2",
"rollup-plugin-typescript2": "^0.30.0",
"source-map-loader": "^3.0.0",
"ts-node": "^10.1.0",
"tslint": "^6.1.3",
"typescript": "^4.3.5"
},
"scripts": {
"build": "yarn build:clean && yarn build:main",
Expand Down
4 changes: 2 additions & 2 deletions packages/clarity-devtools/static/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
"manifest_version": 2,
"name": "Clarity Developer Tools",
"description": "Get insights about how customers use your website.",
"version": "0.6.16",
"version_name": "0.6.16",
"version": "0.6.17",
"version_name": "0.6.17",
"minimum_chrome_version": "50",
"devtools_page": "devtools.html",
"icons": {
Expand Down
31 changes: 16 additions & 15 deletions packages/clarity-js/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "clarity-js",
"version": "0.6.16",
"version": "0.6.17",
"description": "An analytics library that uses web page interactions to generate aggregated insights",
"author": "Microsoft Corp.",
"license": "MIT",
Expand All @@ -26,23 +26,24 @@
"url": "https://github.com/microsoft/clarity/issues"
},
"devDependencies": {
"@rollup/plugin-commonjs": "^11.1.0",
"@rollup/plugin-node-resolve": "^7.1.3",
"@types/chai": "^4.2.14",
"@types/mocha": "^8.0.4",
"@types/resize-observer-browser": "^0.1.3",
"@rollup/plugin-commonjs": "^19.0.1",
"@rollup/plugin-node-resolve": "^13.0.2",
"@types/chai": "^4.2.21",
"@types/mocha": "^8.2.3",
"@types/resize-observer-browser": "^0.1.6",
"chai": "^4.2.0",
"del-cli": "3.0.0",
"husky": "4.2.3",
"lint-staged": "10.1.2",
"mocha": "^8.2.1",
"del-cli": "^4.0.1",
"husky": "^7.0.1",
"lint-staged": "^11.0.1",
"mocha": "^9.0.2",
"playwright": "^1.6.2",
"rollup": "^2.7.3",
"rollup-plugin-terser": "^5.3.0",
"rollup-plugin-typescript2": "^0.27.0",
"rollup": "^2.53.2",
"rollup-plugin-terser": "^7.0.2",
"rollup-plugin-typescript2": "^0.30.0",
"ts-mocha": "^8.0.0",
"tslint": "6.1.1",
"typescript": "^3.8.3"
"tslib": "^2.3.0",
"tslint": "^6.1.3",
"typescript": "^4.3.5"
},
"scripts": {
"build": "yarn build:clean && yarn build:main",
Expand Down
4 changes: 2 additions & 2 deletions packages/clarity-js/src/core/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import { Config, Time } from "@clarity-types/core";

let config: Config = {
projectId: null,
delay: 3 * Time.Second,
delay: 1 * Time.Second,
cssRules: false,
lean: true,
lean: false,
track: true,
content: true,
mask: [],
Expand Down
71 changes: 46 additions & 25 deletions packages/clarity-js/src/core/task.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { AsyncTask, Priority, RequestIdleCallbackDeadline, RequestIdleCallbackOptions } from "@clarity-types/core";
import { AsyncTask, Priority, RequestIdleCallbackDeadline, RequestIdleCallbackOptions, Task, Timer } from "@clarity-types/core";
import { Setting, TaskFunction, TaskResolve, Tasks } from "@clarity-types/core";
import { Code, Metric, Severity } from "@clarity-types/data";
import * as metadata from "@src/data/metadata";
import * as metric from "@src/data/metric";
import * as log from "@src/diagnostic/log";

Expand Down Expand Up @@ -45,7 +46,10 @@ export async function schedule(task: TaskFunction, priority: Priority = Priority

let promise = new Promise<void>((resolve: TaskResolve): void => {
let insert = priority === Priority.High ? "unshift" : "push";
queuedTasks[insert]({ task, resolve });
// Queue this task for asynchronous execution later
// We also store a unique page identifier (id) along with the task to ensure
// ensure that we do not accidentally execute this task in context of a different page
queuedTasks[insert]({ task, resolve, id: metadata.id() });
});

// If there is no active task running, and Clarity is not in pause state,
Expand All @@ -60,61 +64,78 @@ function run(): void {
if (entry) {
activeTask = entry;
entry.task().then((): void => {
// Bail out if the context in which this task was operating is different from the current page
// An example scenario where task could span across pages is Single Page Applications (SPA)
// A task that started on page #1, but completes on page #2
if (entry.id !== metadata.id()) { return; }
entry.resolve();
activeTask = null; // Reset active task back to null now that the promise is resolved
run();
}).catch((error: Error): void => {
// If one of the scheduled tasks failed, log, recover and continue processing rest of the tasks
if (entry.id !== metadata.id()) { return; }
log.log(Code.RunTask, error, Severity.Warning);
activeTask = null;
run();
});
}
}

export function shouldYield(method: Metric): boolean {
if (method in tracker) {
let elapsed = performance.now() - tracker[method].start;
return (elapsed > tracker[method].yield);
export function state(timer: Timer): Task {
let id = key(timer);
if (id in tracker) {
let elapsed = performance.now() - tracker[id].start;
return (elapsed > tracker[id].yield) ? Task.Wait : Task.Run;
}
return true;
// If this task is no longer being tracked, send stop message to the caller
return Task.Stop;
}

export function start(method: Metric): void {
tracker[method] = { start: performance.now(), calls: 0, yield: Setting.LongTask };
export function start(timer: Timer): void {
tracker[key(timer)] = { start: performance.now(), calls: 0, yield: Setting.LongTask };
}

function restart(method: Metric): void {
if (tracker && tracker[method]) {
let c = tracker[method].calls;
let y = tracker[method].yield;
start(method);
tracker[method].calls = c + 1;
tracker[method].yield = y;
function restart(timer: Timer): void {
let id = key(timer);
if (tracker && tracker[id]) {
let c = tracker[id].calls;
let y = tracker[id].yield;
start(timer);
tracker[id].calls = c + 1;
tracker[id].yield = y;
}
}

export function stop(method: Metric): void {
export function stop(timer: Timer): void {
let end = performance.now();
let duration = end - tracker[method].start;
metric.sum(method, duration);
let id = key(timer);
let duration = end - tracker[id].start;
metric.sum(timer.cost, duration);
metric.count(Metric.InvokeCount);

// For the first execution, which is synchronous, time is automatically counted towards TotalDuration.
// However, for subsequent asynchronous runs, we need to manually update TotalDuration metric.
if (tracker[method].calls > 0) { metric.sum(Metric.TotalCost, duration); }
if (tracker[id].calls > 0) { metric.sum(Metric.TotalCost, duration); }
}

export async function suspend(method: Metric): Promise<void> {
export async function suspend(timer: Timer): Promise<Task> {
// Suspend and yield the thread only if the task is still being tracked
// It's possible that Clarity is wrapping up instrumentation on a page and we are still in the middle of an async task.
// In that case, we do not wish to continue yielding thread.
// Instead, we will turn async task into a sync task and maximize our chances of getting some data back.
if (method in tracker) {
stop(method);
tracker[method].yield = (await wait()).timeRemaining();
restart(method);
let id = key(timer);
if (id in tracker) {
stop(timer);
tracker[id].yield = (await wait()).timeRemaining();
restart(timer);
}
// After we are done with suspending task, ensure that we are still operating in the right context
// If the task is still being tracked, continue running the task, otherwise ask caller to stop execution
return id in tracker ? Task.Run : Task.Stop;
}

function key(timer: Timer): string {
return `${timer.id}.${timer.cost}`;
}

async function wait(): Promise<RequestIdleCallbackDeadline> {
Expand Down
2 changes: 1 addition & 1 deletion packages/clarity-js/src/core/version.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
let version = "0.6.16";
let version = "0.6.17";
export default version;
8 changes: 6 additions & 2 deletions packages/clarity-js/src/data/metadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export function start(): void {
}

// Override configuration based on what's in the session storage
config.lean = config.track && s.upgrade === BooleanFlag.True ? false : config.lean;
config.lean = config.track && s.upgrade !== null ? s.upgrade === BooleanFlag.False : config.lean;
config.upload = config.track && typeof config.upload === Constant.String && s.upload ? s.upload : config.upload;


Expand Down Expand Up @@ -77,6 +77,10 @@ export function metadata(cb: MetadataCallback): void {
callback = cb;
}

export function id(): string {
return data ? [data.userId, data.sessionId, data.pageNum].join(Constant.Dot) : Constant.Empty;
}

export function consent(): void {
if (core.active()) {
config.track = true;
Expand Down Expand Up @@ -124,7 +128,7 @@ function shortid(): string {
}

function session(): Session {
let output: Session = { session: shortid(), ts: Math.round(Date.now()), count: 1, upgrade: BooleanFlag.False, upload: Constant.Empty };
let output: Session = { session: shortid(), ts: Math.round(Date.now()), count: 1, upgrade: null, upload: Constant.Empty };
let value = getCookie(Constant.SessionKey);
if (value) {
let parts = value.split(Constant.Pipe);
Expand Down
Loading

0 comments on commit 42c72e6

Please sign in to comment.