diff --git a/change/@azure-msal-browser-62b23ece-142f-4710-a265-ab3f56f1678f.json b/change/@azure-msal-browser-62b23ece-142f-4710-a265-ab3f56f1678f.json new file mode 100644 index 0000000000..534446aba9 --- /dev/null +++ b/change/@azure-msal-browser-62b23ece-142f-4710-a265-ab3f56f1678f.json @@ -0,0 +1,7 @@ +{ + "type": "minor", + "comment": "Instrument cache location #7868", + "packageName": "@azure/msal-browser", + "email": "kshabelko@microsoft.com", + "dependentChangeType": "patch" +} diff --git a/change/@azure-msal-common-0319a9b8-f8e6-42fe-81a2-ba39b331bfd1.json b/change/@azure-msal-common-0319a9b8-f8e6-42fe-81a2-ba39b331bfd1.json new file mode 100644 index 0000000000..0cad18ed72 --- /dev/null +++ b/change/@azure-msal-common-0319a9b8-f8e6-42fe-81a2-ba39b331bfd1.json @@ -0,0 +1,7 @@ +{ + "type": "minor", + "comment": "Instrument cache location #7868", + "packageName": "@azure/msal-common", + "email": "kshabelko@microsoft.com", + "dependentChangeType": "patch" +} diff --git a/lib/msal-browser/src/interaction_client/BaseInteractionClient.ts b/lib/msal-browser/src/interaction_client/BaseInteractionClient.ts index a401b8945c..112b8d7168 100644 --- a/lib/msal-browser/src/interaction_client/BaseInteractionClient.ts +++ b/lib/msal-browser/src/interaction_client/BaseInteractionClient.ts @@ -76,6 +76,12 @@ export abstract class BaseInteractionClient { this.correlationId ); this.performanceClient = performanceClient; + this.performanceClient.addFields( + { + cacheLocation: config.cache.cacheLocation, + }, + this.correlationId + ); } abstract acquireToken( diff --git a/lib/msal-browser/test/app/PublicClientApplication.spec.ts b/lib/msal-browser/test/app/PublicClientApplication.spec.ts index 33c2123da1..e970c34d42 100644 --- a/lib/msal-browser/test/app/PublicClientApplication.spec.ts +++ b/lib/msal-browser/test/app/PublicClientApplication.spec.ts @@ -926,6 +926,9 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { it("Calls NativeInteractionClient.handleRedirectPromise and emits telemetry event", (done) => { const config = { + cache: { + cacheLocation: BrowserCacheLocation.LocalStorage, + }, auth: { clientId: TEST_CONFIG.MSAL_CLIENT_ID, }, @@ -940,11 +943,11 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { }, }, }; - pca = new PublicClientApplication(config); + const testPca = new PublicClientApplication(config); stubExtensionProvider(config); - pca.initialize().then(() => { - const callbackId = pca.addPerformanceCallback((events) => { + testPca.initialize().then(() => { + const callbackId = testPca.addPerformanceCallback((events) => { expect(events.length).toEqual(1); const event = events[0]; expect(event.name).toBe( @@ -960,12 +963,13 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { ).toEqual(1); expect(event.success).toBeTruthy(); expect(event.accountType).toEqual("MSA"); - pca.removePerformanceCallback(callbackId); + expect(event.cacheLocation).toEqual("localStorage"); + testPca.removePerformanceCallback(callbackId); done(); }); // Implementation of PCA was moved to controller. // eslint-disable-next-line @typescript-eslint/no-explicit-any - pca = (pca as any).controller; + const testController = (testPca as any).controller; const testAccount: AccountInfo = { homeAccountId: TEST_DATA_CLIENT_INFO.TEST_HOME_ACCOUNT_ID, @@ -1012,12 +1016,12 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { windowTitleSubstring: "test window", }; // @ts-ignore - pca.browserStorage.setTemporaryCache( + testController.browserStorage.setTemporaryCache( TemporaryCacheKeys.NATIVE_REQUEST, JSON.stringify(nativeRequest), true ); - jest.spyOn(pca, "getAllAccounts").mockReturnValue([ + jest.spyOn(testController, "getAllAccounts").mockReturnValue([ testAccount, ]); jest.spyOn( @@ -1025,7 +1029,7 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { "handleRedirectPromise" ).mockResolvedValue(testTokenResponse); - pca.handleRedirectPromise(); + testController.handleRedirectPromise(); }); }); @@ -3636,6 +3640,7 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { expect(events[0].requestId).toBe(undefined); expect(events[0].visibilityChangeCount).toBe(0); expect(events[0].accountType).toBeUndefined(); + expect(events[0].cacheLocation).toEqual("sessionStorage"); pca.removePerformanceCallback(callbackId); done(); }); @@ -6023,6 +6028,7 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { expect(events[0].requestId).toBe(undefined); expect(events[0].visibilityChangeCount).toBe(0); expect(events[0].accountType).toBe("AAD"); + expect(events[0].cacheLocation).toBe("sessionStorage"); pca.removePerformanceCallback(callbackId); done(); @@ -6034,6 +6040,71 @@ describe("PublicClientApplication.ts Class Unit Tests", () => { }); }); + xit("instruments local storage cache location", (done) => { + const testPca = new PublicClientApplication({ + auth: { + clientId: TEST_CONFIG.MSAL_CLIENT_ID, + }, + telemetry: { + client: new BrowserPerformanceClient(testAppConfig), + application: { + appName: TEST_CONFIG.applicationName, + appVersion: TEST_CONFIG.applicationVersion, + }, + }, + system: { + allowPlatformBroker: false, + }, + cache: { + cacheLocation: BrowserCacheLocation.LocalStorage, + }, + }); + testPca.initialize().then(() => { + const testAccount: AccountInfo = { + homeAccountId: TEST_DATA_CLIENT_INFO.TEST_HOME_ACCOUNT_ID, + localAccountId: TEST_DATA_CLIENT_INFO.TEST_UID, + environment: "login.windows.net", + tenantId: "3338040d-6c67-4c5b-b112-36a304b66dad", + username: "AbeLi@microsoft.com", + idTokenClaims: { + tid: "3338040d-6c67-4c5b-b112-36a304b66dad", + }, + }; + const testTokenResponse: AuthenticationResult = { + authority: TEST_CONFIG.validAuthority, + uniqueId: testAccount.localAccountId, + tenantId: testAccount.tenantId, + scopes: TEST_CONFIG.DEFAULT_SCOPES, + idToken: "test-idToken", + idTokenClaims: {}, + accessToken: "test-accessToken", + fromCache: false, + correlationId: RANDOM_TEST_GUID, + expiresOn: TestTimeUtils.nowDateWithOffset(3600), + account: testAccount, + tokenType: AuthenticationScheme.BEARER, + }; + const silentCacheSpy: jest.SpyInstance = jest + .spyOn(SilentCacheClient.prototype, "acquireToken") + .mockRejectedValue(new Error("Expired")); + const silentRefreshSpy: jest.SpyInstance = jest + .spyOn(SilentRefreshClient.prototype, "acquireToken") + .mockResolvedValue(testTokenResponse); + + const callbackId = testPca.addPerformanceCallback((events) => { + expect(events[0].cacheLocation).toBe("localStorage"); + + testPca.removePerformanceCallback(callbackId); + done(); + }); + testPca.acquireTokenSilent({ + scopes: ["openid"], + account: testAccount, + correlationId: RANDOM_TEST_GUID, + }); + }); + }); + it("sets visibilityChange in perf event to true when visibility changes", (done) => { const testAccount: AccountInfo = { homeAccountId: TEST_DATA_CLIENT_INFO.TEST_HOME_ACCOUNT_ID, diff --git a/lib/msal-common/apiReview/msal-common.api.md b/lib/msal-common/apiReview/msal-common.api.md index 7fcba24503..aaeabff815 100644 --- a/lib/msal-common/apiReview/msal-common.api.md +++ b/lib/msal-common/apiReview/msal-common.api.md @@ -3463,6 +3463,7 @@ export type PerformanceEvent = { usePreGeneratedPkce?: boolean; msalInstanceCount?: number; sameClientIdInstanceCount?: number; + cacheLocation?: string; }; // Warning: (tsdoc-undefined-tag) The TSDoc tag "@export" is not defined in this configuration diff --git a/lib/msal-common/src/telemetry/performance/PerformanceEvent.ts b/lib/msal-common/src/telemetry/performance/PerformanceEvent.ts index da632d012b..63ede4de45 100644 --- a/lib/msal-common/src/telemetry/performance/PerformanceEvent.ts +++ b/lib/msal-common/src/telemetry/performance/PerformanceEvent.ts @@ -898,6 +898,8 @@ export type PerformanceEvent = { msalInstanceCount?: number; // Number of MSAL JS instances using the same client id in the frame sameClientIdInstanceCount?: number; + // Browser cache location + cacheLocation?: string; }; export type PerformanceEventContext = {