Skip to content

Commit

Permalink
- Dynamically load BrowserPerformanceMeasurement and capture perf mea…
Browse files Browse the repository at this point in the history
…surements if session storage flag is enabled.

- Update browser perf doc.
  • Loading branch information
konstantin-msft committed Dec 11, 2023
1 parent 80f4592 commit 4d2c212
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 11 deletions.
16 changes: 16 additions & 0 deletions lib/msal-browser/docs/performance.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,3 +109,19 @@ const callbackId: string = msalInstance.addPerformanceCallback((events: Performa

const removed: boolean = msalInstance.removePerformanceCallback(callbackId);
```

### Measuring browser performance

Browser performance measurements are disabled by default due to significant performance overhead they impose.
Applications that want to enable performance measurements reported to the browser's performance timeline should:

1. Open browser developer tools
- Edge, Chrome and Firefox browsers: press F12
- Safari: go into Safari's preferences (`Safari Menu` > `Preferences`), select the `Advanced Tab` and enable `Show features for web developers`. Once that menu is enabled, you will find the developer console by clicking on `Develop` > `Show Javascript Console`
2. Navigate to `Session Storage`:
- [Edge](https://learn.microsoft.com/en-us/microsoft-edge/devtools-guide-chromium/storage/sessionstorage)
- [Chrome](https://developer.chrome.com/docs/devtools/storage/sessionstorage)
- [Firefox](https://firefox-source-docs.mozilla.org/devtools-user/storage_inspector/local_storage_session_storage)
- Safari: navigate to `Storage` tab and expand `Session Storage`
3. Select target domain
4. Add `msal.browser.performance.enabled` key to `Session Stirage`, set it's value to `1`, refresh the page and check the browser's performance timeline.
79 changes: 76 additions & 3 deletions lib/msal-browser/src/telemetry/BrowserPerformanceClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,35 @@ import {
PerformanceEvent,
PerformanceEvents,
PreQueueEvent,
SubMeasurement,
} from "@azure/msal-common";
import { Configuration } from "../config/Configuration";
import { name, version } from "../packageMetadata";
import {
BROWSER_PERF_ENABLED_KEY,
BrowserCacheLocation,
} from "../utils/BrowserConstants";

export class BrowserPerformanceClient
extends PerformanceClient
implements IPerformanceClient
{
private static PERF_MEASUREMENT_MODULE = (() => {
let sessionStorage: Storage | undefined;
try {
sessionStorage = window[BrowserCacheLocation.SessionStorage];
const perfEnabled = sessionStorage?.getItem(
BROWSER_PERF_ENABLED_KEY
);
if (Number(perfEnabled) === 1) {
return import("./BrowserPerformanceMeasurement");
}
// Mute errors if it's a non-browser environment or cookies are blocked.
} catch (e) {}

return undefined;
})();

constructor(configuration: Configuration, intFields?: Set<string>) {
super(
configuration.auth.clientId,
Expand Down Expand Up @@ -47,6 +68,34 @@ export class BrowserPerformanceClient
return document.visibilityState?.toString() || null;
}

private deleteIncompleteSubMeasurements(
inProgressEvent: InProgressPerformanceEvent
): void {
void BrowserPerformanceClient.PERF_MEASUREMENT_MODULE?.then(
(module) => {
const rootEvent = this.eventsByCorrelationId.get(
inProgressEvent.event.correlationId
);
const isRootEvent =
rootEvent &&
rootEvent.eventId === inProgressEvent.event.eventId;
const incompleteMeasurements: SubMeasurement[] = [];
if (isRootEvent && rootEvent?.incompleteSubMeasurements) {
rootEvent.incompleteSubMeasurements.forEach(
(subMeasurement: SubMeasurement) => {
incompleteMeasurements.push({ ...subMeasurement });
}
);
}
// Clean up remaining marks for incomplete sub-measurements
module.BrowserPerformanceMeasurement.flushMeasurements(
inProgressEvent.event.correlationId,
incompleteMeasurements
);
}
);
}

supportsBrowserPerformanceNow(): boolean {
return (
typeof window !== "undefined" &&
Expand Down Expand Up @@ -78,17 +127,41 @@ export class BrowserPerformanceClient
? window.performance.now()
: undefined;

const browserMeasurement =
BrowserPerformanceClient.PERF_MEASUREMENT_MODULE?.then((module) => {
return new module.BrowserPerformanceMeasurement(
measureName,
inProgressEvent.event.correlationId
);
});
void browserMeasurement?.then((measurement) =>
measurement.startMeasurement()
);

return {
...inProgressEvent,
end: (
event?: Partial<PerformanceEvent>
): PerformanceEvent | null => {
return inProgressEvent.end({
const res = inProgressEvent.end({
...event,
startPageVisibility,
endPageVisibility: this.getPageVisibility(),
durationMs: this.getPerformanceDurationMs(startTime),
durationMs: this.getPerfDurationMs(startTime),
});
void browserMeasurement?.then((measurement) =>
measurement.endMeasurement()
);
this.deleteIncompleteSubMeasurements(inProgressEvent);

return res;
},
discard: () => {
inProgressEvent.discard();
void browserMeasurement?.then((measurement) =>
measurement.flushMeasurement()
);
this.deleteIncompleteSubMeasurements(inProgressEvent);
},
};
}
Expand Down Expand Up @@ -192,7 +265,7 @@ export class BrowserPerformanceClient
* @param startTime {DOMHighResTimeStamp | undefined}
* @returns {number | undefined}
*/
private getPerformanceDurationMs(
private getPerfDurationMs(
startTime: DOMHighResTimeStamp | undefined
): number | undefined {
if (!startTime || !this.supportsBrowserPerformanceNow()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,6 @@

import { IPerformanceMeasurement, SubMeasurement } from "@azure/msal-common";

/**
* @deprecated This class will be removed in a future major version
*/
export class BrowserPerformanceMeasurement implements IPerformanceMeasurement {
private readonly measureName: string;
private readonly correlationId: string;
Expand Down
2 changes: 2 additions & 0 deletions lib/msal-browser/src/utils/BrowserConstants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -239,3 +239,5 @@ export const CacheLookupPolicy = {
} as const;
export type CacheLookupPolicy =
(typeof CacheLookupPolicy)[keyof typeof CacheLookupPolicy];

export const BROWSER_PERF_ENABLED_KEY = "msal.browser.performance.enabled";
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,11 @@ describe("BrowserPerformanceClient.ts", () => {

const result = measurement.end();

console.log(JSON.stringify(result, null, 2));

expect(result?.durationMs).toBe(50);
expect(
// @ts-ignore
BrowserPerformanceClient.PERF_MEASUREMENT_MODULE
).toBeUndefined();
});

it("captures page visibilityState", () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@
* Licensed under the MIT License.
*/

/**
* @deprecated This class will be removed in a future major version
*/
export interface IPerformanceMeasurement {
startMeasurement(): void;
endMeasurement(): void;
Expand Down

0 comments on commit 4d2c212

Please sign in to comment.