Monitor telemetry (#2326)

* Adding more telemetries for monitoring

* Adding more telemetries for monitoring
This commit is contained in:
sunghyunkang1111
2026-01-12 11:15:26 -06:00
committed by GitHub
parent e6461cf079
commit 896b3e974e
2 changed files with 65 additions and 24 deletions
+59 -19
View File
@@ -1,6 +1,7 @@
import { Metric, onCLS, onFCP, onINP, onLCP, onTTFB } from "web-vitals"; import { Metric, onCLS, onFCP, onINP, onLCP, onTTFB } from "web-vitals";
import { configContext } from "../ConfigContext"; import { configContext } from "../ConfigContext";
import { trackEvent } from "../Shared/appInsights"; import { Action } from "../Shared/Telemetry/TelemetryConstants";
import { traceFailure, traceMark, traceStart, traceSuccess } from "../Shared/Telemetry/TelemetryProcessor";
import { userContext } from "../UserContext"; import { userContext } from "../UserContext";
import MetricScenario, { reportHealthy, reportUnhealthy } from "./MetricEvents"; import MetricScenario, { reportHealthy, reportUnhealthy } from "./MetricEvents";
import { scenarioConfigs } from "./MetricScenarioConfigs"; import { scenarioConfigs } from "./MetricScenarioConfigs";
@@ -83,6 +84,13 @@ class ScenarioMonitor {
ctx.phases.set(phase, { startMarkName: phaseStartMarkName }); ctx.phases.set(phase, { startMarkName: phaseStartMarkName });
}); });
traceMark(Action.MetricsScenario, {
event: "scenario_start",
scenario,
requiredPhases: config.requiredPhases.join(","),
timeoutMs: config.timeoutMs,
});
ctx.timeoutId = window.setTimeout(() => this.emit(ctx, false, true), config.timeoutMs); ctx.timeoutId = window.setTimeout(() => this.emit(ctx, false, true), config.timeoutMs);
this.contexts.set(scenario, ctx); this.contexts.set(scenario, ctx);
} }
@@ -96,6 +104,12 @@ class ScenarioMonitor {
const startMarkName = `scenario_${scenario}_${phase}_start`; const startMarkName = `scenario_${scenario}_${phase}_start`;
performance.mark(startMarkName); performance.mark(startMarkName);
ctx.phases.set(phase, { startMarkName }); ctx.phases.set(phase, { startMarkName });
traceStart(Action.MetricsScenario, {
event: "phase_start",
scenario,
phase,
});
} }
completePhase(scenario: MetricScenario, phase: MetricPhase) { completePhase(scenario: MetricScenario, phase: MetricPhase) {
@@ -110,6 +124,22 @@ class ScenarioMonitor {
phaseCtx.endMarkName = endMarkName; phaseCtx.endMarkName = endMarkName;
ctx.completed.add(phase); ctx.completed.add(phase);
const navigationStart = performance.timeOrigin;
const startEntry = performance.getEntriesByName(phaseCtx.startMarkName)[0];
const endEntry = performance.getEntriesByName(endMarkName)[0];
const endTimeISO = endEntry ? new Date(navigationStart + endEntry.startTime).toISOString() : undefined;
const durationMs = startEntry && endEntry ? endEntry.startTime - startEntry.startTime : undefined;
traceSuccess(Action.MetricsScenario, {
event: "phase_complete",
scenario,
phase,
endTimeISO,
durationMs,
completedCount: ctx.completed.size,
requiredCount: ctx.config.requiredPhases.length,
});
this.tryEmitIfReady(ctx); this.tryEmitIfReady(ctx);
} }
@@ -133,6 +163,14 @@ class ScenarioMonitor {
// Build a snapshot with failure info // Build a snapshot with failure info
const failureSnapshot = this.buildSnapshot(ctx, { final: false, timedOut: false }); const failureSnapshot = this.buildSnapshot(ctx, { final: false, timedOut: false });
traceFailure(Action.MetricsScenario, {
event: "phase_fail",
scenario,
phase,
failedPhases: Array.from(ctx.failed).join(","),
completedPhases: Array.from(ctx.completed).join(","),
});
// Emit unhealthy immediately // Emit unhealthy immediately
this.emit(ctx, false, false, failureSnapshot); this.emit(ctx, false, false, failureSnapshot);
} }
@@ -191,27 +229,22 @@ class ScenarioMonitor {
// Build snapshot if not provided // Build snapshot if not provided
const finalSnapshot = snapshot || this.buildSnapshot(ctx, { final: false, timedOut }); const finalSnapshot = snapshot || this.buildSnapshot(ctx, { final: false, timedOut });
// Emit enriched telemetry with performance data traceMark(Action.MetricsScenario, {
// TODO: Call portal backend metrics endpoint event: "scenario_end",
trackEvent(
{ name: "MetricScenarioComplete" },
{
scenario: ctx.scenario, scenario: ctx.scenario,
healthy: healthy.toString(), healthy,
timedOut: timedOut.toString(), timedOut,
platform, platform,
api, api,
durationMs: finalSnapshot.durationMs.toString(), durationMs: finalSnapshot.durationMs,
completedPhases: finalSnapshot.completed.join(","), completedPhases: finalSnapshot.completed.join(","),
failedPhases: finalSnapshot.failedPhases?.join(","), failedPhases: finalSnapshot.failedPhases?.join(","),
lcp: finalSnapshot.vitals?.lcp?.toString(), lcp: finalSnapshot.vitals?.lcp,
inp: finalSnapshot.vitals?.inp?.toString(), inp: finalSnapshot.vitals?.inp,
cls: finalSnapshot.vitals?.cls?.toString(), cls: finalSnapshot.vitals?.cls,
fcp: finalSnapshot.vitals?.fcp?.toString(), fcp: finalSnapshot.vitals?.fcp,
ttfb: finalSnapshot.vitals?.ttfb?.toString(), ttfb: finalSnapshot.vitals?.ttfb,
phaseTimings: JSON.stringify(finalSnapshot.phaseTimings), });
},
);
// Call portal backend health metrics endpoint // Call portal backend health metrics endpoint
if (healthy && !timedOut) { if (healthy && !timedOut) {
@@ -227,9 +260,16 @@ class ScenarioMonitor {
private cleanupPerformanceEntries(ctx: InternalScenarioContext) { private cleanupPerformanceEntries(ctx: InternalScenarioContext) {
performance.clearMarks(ctx.startMarkName); performance.clearMarks(ctx.startMarkName);
ctx.config.requiredPhases.forEach((phase) => { ctx.config.requiredPhases.forEach((phase) => {
performance.clearMarks(`scenario_${ctx.scenario}_${phase}`); const phaseCtx = ctx.phases.get(phase);
if (phaseCtx?.startMarkName) {
performance.clearMarks(phaseCtx.startMarkName);
}
if (phaseCtx?.endMarkName) {
performance.clearMarks(phaseCtx.endMarkName);
}
performance.clearMarks(`scenario_${ctx.scenario}_${phase}_failed`);
performance.clearMeasures(`scenario_${ctx.scenario}_${phase}_duration`);
}); });
performance.clearMeasures(`scenario_${ctx.scenario}_total`);
} }
private buildSnapshot( private buildSnapshot(
@@ -2,6 +2,7 @@
// Some of the enums names are used in Fabric. Please do not rename them. // Some of the enums names are used in Fabric. Please do not rename them.
export enum Action { export enum Action {
CollapseTreeNode, CollapseTreeNode,
MetricsScenario,
CreateCollection, // Used in Fabric. Please do not rename. CreateCollection, // Used in Fabric. Please do not rename.
CreateGlobalSecondaryIndex, CreateGlobalSecondaryIndex,
CreateDocument, // Used in Fabric. Please do not rename. CreateDocument, // Used in Fabric. Please do not rename.