mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2026-05-21 04:37:28 +01:00
Monitor telemetry (#2326)
* Adding more telemetries for monitoring * Adding more telemetries for monitoring
This commit is contained in:
@@ -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(
|
scenario: ctx.scenario,
|
||||||
{ name: "MetricScenarioComplete" },
|
healthy,
|
||||||
{
|
timedOut,
|
||||||
scenario: ctx.scenario,
|
platform,
|
||||||
healthy: healthy.toString(),
|
api,
|
||||||
timedOut: timedOut.toString(),
|
durationMs: finalSnapshot.durationMs,
|
||||||
platform,
|
completedPhases: finalSnapshot.completed.join(","),
|
||||||
api,
|
failedPhases: finalSnapshot.failedPhases?.join(","),
|
||||||
durationMs: finalSnapshot.durationMs.toString(),
|
lcp: finalSnapshot.vitals?.lcp,
|
||||||
completedPhases: finalSnapshot.completed.join(","),
|
inp: finalSnapshot.vitals?.inp,
|
||||||
failedPhases: finalSnapshot.failedPhases?.join(","),
|
cls: finalSnapshot.vitals?.cls,
|
||||||
lcp: finalSnapshot.vitals?.lcp?.toString(),
|
fcp: finalSnapshot.vitals?.fcp,
|
||||||
inp: finalSnapshot.vitals?.inp?.toString(),
|
ttfb: finalSnapshot.vitals?.ttfb,
|
||||||
cls: finalSnapshot.vitals?.cls?.toString(),
|
});
|
||||||
fcp: finalSnapshot.vitals?.fcp?.toString(),
|
|
||||||
ttfb: finalSnapshot.vitals?.ttfb?.toString(),
|
|
||||||
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.
|
||||||
|
|||||||
Reference in New Issue
Block a user