Frontend performance metrics (#2439)

* Added enriched metrics

* Add more traces for observability
This commit is contained in:
sunghyunkang1111
2026-04-01 09:42:32 -05:00
committed by GitHub
parent eac5842176
commit 2ba58cd1a5
14 changed files with 363 additions and 103 deletions
+10 -2
View File
@@ -10,7 +10,7 @@ import { DatabaseAccount } from "../Contracts/DataModels";
import * as ViewModels from "../Contracts/ViewModels";
import { isExpectedError } from "../Metrics/ErrorClassification";
import { scenarioMonitor } from "../Metrics/ScenarioMonitor";
import { trace, traceFailure } from "../Shared/Telemetry/TelemetryProcessor";
import { trace, traceFailure, traceStart, traceSuccess } from "../Shared/Telemetry/TelemetryProcessor";
import { UserContext, userContext } from "../UserContext";
export function getAuthorizationHeader(): ViewModels.AuthorizationTokenHeaderMetadata {
@@ -74,7 +74,11 @@ export async function acquireMsalTokenForAccount(
silent: boolean = false,
user_hint?: string,
) {
const msalStartKey = traceStart(Action.AcquireMsalToken, {
acquireTokenType: silent ? "silent" : "interactive",
});
if (userContext.databaseAccount.properties?.documentEndpoint === undefined) {
traceFailure(Action.AcquireMsalToken, { error: "No document endpoint" }, msalStartKey);
throw new Error("Database account has no document endpoint defined");
}
let hrefEndpoint = "";
@@ -107,6 +111,7 @@ export async function acquireMsalTokenForAccount(
// See https://learn.microsoft.com/en-us/entra/identity-platform/msal-js-sso#sso-between-different-apps
try {
const loginResponse = await msalInstance.ssoSilent(loginRequest);
traceSuccess(Action.AcquireMsalToken, { method: "ssoSilent" }, msalStartKey);
return loginResponse.accessToken;
} catch (silentError) {
trace(Action.SignInAad, ActionModifiers.Mark, {
@@ -122,6 +127,7 @@ export async function acquireMsalTokenForAccount(
// See https://learn.microsoft.com/en-us/entra/identity-platform/msal-js-prompt-behavior#interactive-requests-with-promptnone
// The hint will be used to pre-fill the username field in the popup if silent is false.
const loginResponse = await msalInstance.loginPopup({ prompt: silent ? "none" : "login", ...loginRequest });
traceSuccess(Action.AcquireMsalToken, { method: "loginPopup" }, msalStartKey);
return loginResponse.accessToken;
} catch (error) {
traceFailure(Action.SignInAad, {
@@ -129,6 +135,7 @@ export async function acquireMsalTokenForAccount(
acquireTokenType: silent ? "silent" : "interactive",
errorMessage: JSON.stringify(error),
});
traceFailure(Action.AcquireMsalToken, { error: JSON.stringify(error) }, msalStartKey);
// Mark expected failure for health metrics so timeout emits healthy
if (isExpectedError(error)) {
scenarioMonitor.markExpectedFailure();
@@ -161,7 +168,8 @@ export async function acquireTokenWithMsal(
try {
// attempt silent acquisition first
return (await msalInstance.acquireTokenSilent(tokenRequest)).accessToken;
const token = (await msalInstance.acquireTokenSilent(tokenRequest)).accessToken;
return token;
} catch (silentError) {
if (silentError instanceof msal.InteractionRequiredAuthError && silent === false) {
try {
+10 -1
View File
@@ -1,6 +1,8 @@
import { configContext } from "ConfigContext";
import { FeatureRegistration } from "Contracts/DataModels";
import { AuthorizationTokenHeaderMetadata } from "Contracts/ViewModels";
import { Action } from "Shared/Telemetry/TelemetryConstants";
import { traceFailure, traceStart, traceSuccess } from "Shared/Telemetry/TelemetryProcessor";
import { getAuthorizationHeader } from "Utils/AuthorizationUtils";
export const featureRegistered = async (subscriptionId: string, feature: string) => {
@@ -9,20 +11,27 @@ export const featureRegistered = async (subscriptionId: string, feature: string)
const authorizationHeader: AuthorizationTokenHeaderMetadata = getAuthorizationHeader();
const headers = { [authorizationHeader.header]: authorizationHeader.token };
const startKey = traceStart(Action.CheckFeatureRegistration, {
feature,
});
let response;
try {
response = await _fetchWithTimeout(url, headers);
} catch (error) {
traceFailure(Action.CheckFeatureRegistration, { feature, error: String(error) }, startKey);
return false;
}
if (!response?.ok) {
traceFailure(Action.CheckFeatureRegistration, { feature, status: response?.status }, startKey);
return false;
}
const featureRegistration = (await response?.json()) as FeatureRegistration;
return featureRegistration?.properties?.state === "Registered";
const registered = featureRegistration?.properties?.state === "Registered";
traceSuccess(Action.CheckFeatureRegistration, { feature, registered }, startKey);
return registered;
};
async function _fetchWithTimeout(