From 26a0cdc2200ed7b1c016c8e964570a7b070a634f Mon Sep 17 00:00:00 2001 From: Mehrdad Reshadi Date: Sun, 27 Jul 2025 01:21:46 -0700 Subject: [PATCH] Add a plugin to track network performance info We have a configurable logic to decide which network events should be tracked and how. So, we may want to only track the performance information of those network requests. This plugin links network response events to their corresponding timing information for better logging. --- package.json | 2 + .../.gitignore | 7 ++++ .../.npmignore | 6 +++ .../babel.config.js | 2 + .../jest.config.js | 6 +++ .../package.json | 41 ++++++++++++++++++ .../src/index.ts | 42 +++++++++++++++++++ .../test/index.test.ts | 10 +++++ .../tsconfig.json | 11 +++++ .../src/ALNetworkPublisher.ts | 4 +- packages/hyperion-react-testapp/package.json | 7 +++- .../src/AutoLoggingWrapper.ts | 4 +- 12 files changed, 137 insertions(+), 5 deletions(-) create mode 100644 packages/hyperion-autologging-plugin-network-performance-timing/.gitignore create mode 100644 packages/hyperion-autologging-plugin-network-performance-timing/.npmignore create mode 100644 packages/hyperion-autologging-plugin-network-performance-timing/babel.config.js create mode 100644 packages/hyperion-autologging-plugin-network-performance-timing/jest.config.js create mode 100644 packages/hyperion-autologging-plugin-network-performance-timing/package.json create mode 100644 packages/hyperion-autologging-plugin-network-performance-timing/src/index.ts create mode 100644 packages/hyperion-autologging-plugin-network-performance-timing/test/index.test.ts create mode 100644 packages/hyperion-autologging-plugin-network-performance-timing/tsconfig.json diff --git a/package.json b/package.json index 3646f604..70740b99 100644 --- a/package.json +++ b/package.json @@ -61,6 +61,7 @@ "./packages/hyperion-react", "./packages/hyperion-autologging", "./packages/hyperion-autologging-plugin-eventhash", + "./packages/hyperion-autologging-plugin-network-performance-timing", "./packages/hyperion-autologging-visualizer", "./packages/hyperion-util", "./packages/hyperion-react-testapp", @@ -70,6 +71,7 @@ "hyperion-async-counter": "*", "hyperion-autologging": "*", "hyperion-autologging-plugin-eventhash": "*", + "hyperion-autologging-plugin-network-performance-timing": "*", "hyperion-autologging-visualizer": "*", "hyperion-channel": "*", "hyperion-core": "*", diff --git a/packages/hyperion-autologging-plugin-network-performance-timing/.gitignore b/packages/hyperion-autologging-plugin-network-performance-timing/.gitignore new file mode 100644 index 00000000..11995f85 --- /dev/null +++ b/packages/hyperion-autologging-plugin-network-performance-timing/.gitignore @@ -0,0 +1,7 @@ +*.log +.DS_Store +node_modules +dist +coverage +package-lock.json +test/**/*.js diff --git a/packages/hyperion-autologging-plugin-network-performance-timing/.npmignore b/packages/hyperion-autologging-plugin-network-performance-timing/.npmignore new file mode 100644 index 00000000..17c50f99 --- /dev/null +++ b/packages/hyperion-autologging-plugin-network-performance-timing/.npmignore @@ -0,0 +1,6 @@ +*.log +.DS_Store +coverage +test/**/*.js +jest.config.js +babel.config.js diff --git a/packages/hyperion-autologging-plugin-network-performance-timing/babel.config.js b/packages/hyperion-autologging-plugin-network-performance-timing/babel.config.js new file mode 100644 index 00000000..a933e2ea --- /dev/null +++ b/packages/hyperion-autologging-plugin-network-performance-timing/babel.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('hyperion-devtools/babel.config'); +module.exports = baseConfig; \ No newline at end of file diff --git a/packages/hyperion-autologging-plugin-network-performance-timing/jest.config.js b/packages/hyperion-autologging-plugin-network-performance-timing/jest.config.js new file mode 100644 index 00000000..e5536729 --- /dev/null +++ b/packages/hyperion-autologging-plugin-network-performance-timing/jest.config.js @@ -0,0 +1,6 @@ +const baseConfig = require('hyperion-devtools/jest.config'); +/* + * For a detailed explanation regarding each configuration property and type check, visit: + * https://jestjs.io/docs/configuration + */ +module.exports = baseConfig; diff --git a/packages/hyperion-autologging-plugin-network-performance-timing/package.json b/packages/hyperion-autologging-plugin-network-performance-timing/package.json new file mode 100644 index 00000000..865f51a2 --- /dev/null +++ b/packages/hyperion-autologging-plugin-network-performance-timing/package.json @@ -0,0 +1,41 @@ +{ + "name": "hyperion-autologging-plugin-network-performance-timing", + "description": "plugin for autologging to add performance timing data to network responses", + "version": "0.3.4", + "license": "MIT", + "scripts": { + "build": "tsc", + "build-react": "react-scripts build", + "watch": "npm run build -- --watch", + "start": "npm run watch", + "test": "npm run build & jest" + }, + "workspaces": [ + "../hyperion-devtools", + "../hyperion-globals", + "../hyperion-channel" + ], + "dependencies": { + "hyperion-channel": "*", + "hyperion-globals": "*", + "xxhashjs": "^0.2.2" + }, + "devDependencies": { + "hyperion-devtools": "*", + "@types/jest": "^29.5.14", + "@types/xxhashjs": "^0.2.4" + }, + "eslintConfig": {}, + "browserslist": { + "production": [ + ">0.2%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + } +} diff --git a/packages/hyperion-autologging-plugin-network-performance-timing/src/index.ts b/packages/hyperion-autologging-plugin-network-performance-timing/src/index.ts new file mode 100644 index 00000000..10d6decd --- /dev/null +++ b/packages/hyperion-autologging-plugin-network-performance-timing/src/index.ts @@ -0,0 +1,42 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. All Rights Reserved. + */ + +'use strict'; +import * as ALEventExtension from "hyperion-autologging/src/ALEventExtension"; +import { ALNetworkResponseEvent } from "hyperion-autologging/src/ALNetworkPublisher"; +import type { ALChannelEvent } from "hyperion-autologging/src/AutoLogging"; +import { Channel } from "hyperion-channel"; +import { assert } from "hyperion-globals"; +import { TimedTrigger } from "hyperion-timed-trigger/src/TimedTrigger"; + +export function init(channel: Channel): void { + + const urls = new Map(); + const observer = new PerformanceObserver((list) => { + for (const entry of list.getEntries()) { + assert(entry.entryType === 'resource', "Unexpected entry type!"); + const url = entry.name; + const response = urls.get(url); + if (response) { + ALEventExtension.setEventExtension(response, 'perf', entry); + urls.delete(url); + } + } + }); + observer.observe({ entryTypes: ['resource'] }); + + const cleaner = new TimedTrigger(() => { + urls.clear(); + }, 1000 * 60); // Clear every minutes + + channel.addListener('al_network_response', eventData => { + urls.set(eventData.requestEvent.url, eventData); + if (cleaner.isDone()) { + cleaner.restart(); + } else { + cleaner.delay(); + } + }); + +} \ No newline at end of file diff --git a/packages/hyperion-autologging-plugin-network-performance-timing/test/index.test.ts b/packages/hyperion-autologging-plugin-network-performance-timing/test/index.test.ts new file mode 100644 index 00000000..e7e80d39 --- /dev/null +++ b/packages/hyperion-autologging-plugin-network-performance-timing/test/index.test.ts @@ -0,0 +1,10 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. All Rights Reserved. + * + * @jest-environment jsdom + */ +'use strict'; + +test("empty test", () => { + expect(0); +}); \ No newline at end of file diff --git a/packages/hyperion-autologging-plugin-network-performance-timing/tsconfig.json b/packages/hyperion-autologging-plugin-network-performance-timing/tsconfig.json new file mode 100644 index 00000000..b92b796f --- /dev/null +++ b/packages/hyperion-autologging-plugin-network-performance-timing/tsconfig.json @@ -0,0 +1,11 @@ +{ + // see https://www.typescriptlang.org/tsconfig to better understand tsconfigs + "extends": "hyperion-devtools", + "compilerOptions": { + // "jsx": "react-jsx", + "jsx": "preserve", + }, + "include": [ + "src", + ], +} \ No newline at end of file diff --git a/packages/hyperion-autologging/src/ALNetworkPublisher.ts b/packages/hyperion-autologging/src/ALNetworkPublisher.ts index 9778c933..56d27101 100644 --- a/packages/hyperion-autologging/src/ALNetworkPublisher.ts +++ b/packages/hyperion-autologging/src/ALNetworkPublisher.ts @@ -11,9 +11,9 @@ import { assert } from "hyperion-globals"; import * as Types from "hyperion-util/src/Types"; import performanceAbsoluteNow from "hyperion-util/src/performanceAbsoluteNow"; import * as ALEventIndex from "./ALEventIndex"; -import { ALLoggableEvent, ALOptionalFlowletEvent, ALSharedInitOptions } from "./ALType"; +import { ALExtensibleEvent, ALLoggableEvent, ALOptionalFlowletEvent, ALSharedInitOptions } from "./ALType"; -type ALNetworkEvent = ALLoggableEvent & ALOptionalFlowletEvent & Readonly<{ +type ALNetworkEvent = ALLoggableEvent & ALOptionalFlowletEvent & ALExtensibleEvent & Readonly<{ initiatorType: "fetch" | "xmlhttprequest"; // https://developer.mozilla.org/en-US/docs/Web/API/PerformanceResourceTiming/initiatorType }>; diff --git a/packages/hyperion-react-testapp/package.json b/packages/hyperion-react-testapp/package.json index d82799a7..9a757b61 100644 --- a/packages/hyperion-react-testapp/package.json +++ b/packages/hyperion-react-testapp/package.json @@ -9,7 +9,8 @@ "../hyperion-react", "../hyperion-autologging", "../hyperion-autologging-visualizer", - "../hyperion-autologging-plugin-eventhash" + "../hyperion-autologging-plugin-eventhash", + "../hyperion-autologging-plugin-network-performance-timing" ], "dependencies": { "@testing-library/jest-dom": "^6.6.3", @@ -22,6 +23,8 @@ "@vitejs/plugin-react": "^4.3.4", "hyperion-autologging": "*", "hyperion-autologging-visualizer": "*", + "hyperion-autologging-plugin-eventhash": "*", + "hyperion-autologging-plugin-network-performance-timing": "*", "hyperion-globals": "*", "hyperion-hook": "*", "hyperion-react": "*", @@ -60,4 +63,4 @@ "last 1 safari version" ] } -} +} \ No newline at end of file diff --git a/packages/hyperion-react-testapp/src/AutoLoggingWrapper.ts b/packages/hyperion-react-testapp/src/AutoLoggingWrapper.ts index b4a9d543..e0ba8b6c 100644 --- a/packages/hyperion-react-testapp/src/AutoLoggingWrapper.ts +++ b/packages/hyperion-react-testapp/src/AutoLoggingWrapper.ts @@ -19,6 +19,7 @@ import * as Flags from "hyperion-globals/src/Flags"; import "hyperion-autologging/src/reference"; import * as PluginEventHash from "hyperion-autologging-plugin-eventhash/src/index"; import { getSessionFlowID } from "hyperion-autologging/src/ALSessionFlowID"; +import * as PluginNetworkPerformanceTiming from "hyperion-autologging-plugin-network-performance-timing/src/index"; export let interceptionStatus = "disabled"; @@ -69,7 +70,8 @@ export function init() { flowletManager, channel, plugins: [ - PluginEventHash.init + PluginEventHash.init, + PluginNetworkPerformanceTiming.init, ], componentNameValidator: testCompValidator, flowletPublisher: {