diff --git a/app/client/src/UITelemetry/PageLoadInstrumentation.ts b/app/client/src/UITelemetry/PageLoadInstrumentation.ts index b297163d1465..ccb173d0b4af 100644 --- a/app/client/src/UITelemetry/PageLoadInstrumentation.ts +++ b/app/client/src/UITelemetry/PageLoadInstrumentation.ts @@ -9,6 +9,16 @@ import type { } from "web-vitals"; import isString from "lodash/isString"; +type TNavigator = Navigator & { + deviceMemory: number; + connection: { + effectiveType: string; + downlink: number; + rtt: number; + saveData: boolean; + }; +}; + export class PageLoadInstrumentation extends InstrumentationBase { // PerformanceObserver to observe resource timings resourceTimingObserver: PerformanceObserver | null = null; @@ -16,10 +26,6 @@ export class PageLoadInstrumentation extends InstrumentationBase { rootSpan: Span; // List of resource URLs to ignore ignoreResourceUrls: string[] = []; - // Timestamp when the page was last hidden - pageLastHiddenAt: number = 0; - // Duration the page was hidden for - pageHiddenFor: number = 0; // Flag to check if navigation entry was pushed wasNavigationEntryPushed: boolean = false; // Set to keep track of resource entries @@ -44,7 +50,11 @@ export class PageLoadInstrumentation extends InstrumentationBase { } enable(): void { - this.addVisibilityChangeListener(); + // Register connection change listener + this.addConnectionAttributes(); + + // Add device attributes to the root span + this.addDeviceAttributes(); // Listen for LCP and FCP events // reportAllChanges: true will report all LCP and FCP events @@ -61,19 +71,28 @@ export class PageLoadInstrumentation extends InstrumentationBase { } } - private addVisibilityChangeListener() { - // Listen for page visibility changes to track time spent on hidden page - document.addEventListener("visibilitychange", () => { - if (document.visibilityState === "hidden") { - this.pageLastHiddenAt = performance.now(); - } else { - const endTime = performance.now(); - - this.pageHiddenFor = endTime - this.pageLastHiddenAt; - } + private addDeviceAttributes() { + this.rootSpan.setAttributes({ + deviceMemory: (navigator as TNavigator).deviceMemory, + hardwareConcurrency: navigator.hardwareConcurrency, }); } + private addConnectionAttributes() { + if ((navigator as TNavigator).connection) { + const { downlink, effectiveType, rtt, saveData } = ( + navigator as TNavigator + ).connection; + + this.rootSpan.setAttributes({ + effectiveConnectionType: effectiveType, + connectionDownlink: downlink, + connectionRtt: rtt, + connectionSaveData: saveData, + }); + } + } + // Handler for LCP report private onLCPReport(metric: LCPMetricWithAttribution) { const { @@ -156,7 +175,6 @@ export class PageLoadInstrumentation extends InstrumentationBase { element: this.getElementName(element), entryType, loadTime, - pageHiddenFor: this.pageHiddenFor, }, 0, ); diff --git a/app/client/src/UITelemetry/generateTraces.ts b/app/client/src/UITelemetry/generateTraces.ts index d3860933f177..12476bcbcfa1 100644 --- a/app/client/src/UITelemetry/generateTraces.ts +++ b/app/client/src/UITelemetry/generateTraces.ts @@ -7,7 +7,13 @@ import type { import { SpanKind } from "@opentelemetry/api"; import { context } from "@opentelemetry/api"; import { trace } from "@opentelemetry/api"; -import { deviceType, browserName, browserVersion } from "react-device-detect"; +import { + deviceType, + browserName, + browserVersion, + osName, + osVersion, +} from "react-device-detect"; import { APP_MODE } from "entities/App"; import { matchBuilderPath, matchViewerPath } from "constants/routes"; import nanoid from "nanoid"; @@ -33,7 +39,7 @@ const getAppMode = memoizeOne((pathname: string) => { return appMode; }); -const getCommonTelemetryAttributes = () => { +export const getCommonTelemetryAttributes = () => { const pathname = window.location.pathname; const appMode = getAppMode(pathname); @@ -44,6 +50,8 @@ const getCommonTelemetryAttributes = () => { browserVersion, otlpSessionId: OTLP_SESSION_ID, hostname: window.location.hostname, + osName, + osVersion, }; }; diff --git a/app/client/src/index.tsx b/app/client/src/index.tsx index 2a950f2c8d5d..c5c6db423d36 100755 --- a/app/client/src/index.tsx +++ b/app/client/src/index.tsx @@ -29,6 +29,7 @@ import { getAppsmithConfigs } from "ee/configs"; import { PageViewTiming } from "@newrelic/browser-agent/features/page_view_timing"; import { PageViewEvent } from "@newrelic/browser-agent/features/page_view_event"; import { Agent } from "@newrelic/browser-agent/loaders/agent"; +import { getCommonTelemetryAttributes } from "UITelemetry/generateTraces"; const { newRelic } = getAppsmithConfigs(); const { enableNewRelic } = newRelic; @@ -56,7 +57,7 @@ const newRelicBrowserAgentConfig = { // The agent loader code executes immediately on instantiation. if (enableNewRelic) { - new Agent( + const newRelicBrowserAgent = new Agent( { ...newRelicBrowserAgentConfig, features: [PageViewTiming, PageViewEvent], @@ -65,6 +66,11 @@ if (enableNewRelic) { // Passing a null value throws an error as well. So we pass undefined. undefined, ); + + const { appMode, otlpSessionId } = getCommonTelemetryAttributes(); + + newRelicBrowserAgent.setCustomAttribute("otlpSessionId", otlpSessionId); + newRelicBrowserAgent.setCustomAttribute("appMode", appMode); } const shouldAutoFreeze = process.env.NODE_ENV === "development";