From 9a5cb5c21024060f3a7d3e25b163a299dcfddf25 Mon Sep 17 00:00:00 2001 From: alexchen Date: Wed, 12 Oct 2022 00:21:07 +0800 Subject: [PATCH] =?UTF-8?q?feat():=20=20=E6=94=B6=E9=9B=86=E9=9D=9EpageLoa?= =?UTF-8?q?d=E7=9A=84api?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refs NEXT_BUILDER-2059 --- packages/brick-icons/src/BrickIcon.tsx | 2 +- packages/brick-kit/src/core/Router.spec.ts | 2 +- packages/brick-kit/src/core/Router.ts | 4 +- .../easyops-analytics/src/ApiAnalysis.spec.ts | 98 ++++++++++++++++++- packages/easyops-analytics/src/ApiAnalysis.ts | 28 ++++-- .../src/Illustrations.spec.tsx | 4 +- 6 files changed, 123 insertions(+), 15 deletions(-) diff --git a/packages/brick-icons/src/BrickIcon.tsx b/packages/brick-icons/src/BrickIcon.tsx index 1e542782c4..57ed884c4c 100644 --- a/packages/brick-icons/src/BrickIcon.tsx +++ b/packages/brick-icons/src/BrickIcon.tsx @@ -27,7 +27,7 @@ export const BrickIcon = ({ // eslint-disable-next-line no-console console.error("Load icons failed:", error); } - // Avoid prototype collisions, such as `icon: "toString"`. + // Avoid prototype collisions, such as `icon: "toString"`.. if (hasOwnProperty(categoryIcons, icon)) { component = categoryIcons[icon]; } diff --git a/packages/brick-kit/src/core/Router.spec.ts b/packages/brick-kit/src/core/Router.spec.ts index 232a6b0dad..393e2644ed 100644 --- a/packages/brick-kit/src/core/Router.spec.ts +++ b/packages/brick-kit/src/core/Router.spec.ts @@ -37,7 +37,7 @@ jest.mock("@next-core/easyops-analytics", () => ({ apiAnalyzer: { create: () => jest.mock, getInstance: () => ({ - pageTracker: jest.fn, + tracePage: jest.fn, }), }, userAnalytics: { diff --git a/packages/brick-kit/src/core/Router.ts b/packages/brick-kit/src/core/Router.ts index 23a693f78e..e1bd714b3f 100644 --- a/packages/brick-kit/src/core/Router.ts +++ b/packages/brick-kit/src/core/Router.ts @@ -238,7 +238,7 @@ export class Router { const renderStartTime = performance.now(); // Create the page tracker before page load. // And the API Analyzer maybe disabled. - const pageTracker = apiAnalyzer.getInstance()?.pageTracker(); + const tracePageEnd = apiAnalyzer.getInstance()?.tracePage(); const locationContext = (this.locationContext = new LocationContext( this.kernel, @@ -555,7 +555,7 @@ export class Router { this.mediaEventTargetHandler as EventListener ); - pageTracker?.({ + tracePageEnd?.({ path: locationContext.getCurrentMatch().path, username: getAuth().username, pageTitle: document.title, diff --git a/packages/easyops-analytics/src/ApiAnalysis.spec.ts b/packages/easyops-analytics/src/ApiAnalysis.spec.ts index 958dc8229e..fa6e79a698 100644 --- a/packages/easyops-analytics/src/ApiAnalysis.spec.ts +++ b/packages/easyops-analytics/src/ApiAnalysis.spec.ts @@ -31,7 +31,7 @@ describe("ApiAnalysis", () => { Date.now = jest.fn(() => 1603109440807); Math.random = jest.fn(() => 0.2); process.env.NODE_ENV = "production"; - pageTracker = analyzer.pageTracker(); + pageTracker = analyzer.tracePage(); }); afterEach(() => { @@ -75,8 +75,44 @@ describe("ApiAnalysis", () => { }, }, }; + + const response2 = { + config: { + url: "api/auth/login2", + method: "GET", + meta: { + st: 1603109440805, + time: 1603109440807, + type: "api", + page: "http://localhost:8081/developers/brick-book?category=", + org: 8888, + username: "mock-user", + uid: "abc", + }, + }, + status: 200, + statusText: "OK", + headers: new Headers({ + "x-b3-traceid": "fake-trace-id2", + "content-length": "28", + }), + data: { + code: 0, + error: "", + message: "", + data: { + loggedIn: true, + username: "easyops", + org: 8888, + location: "", + userInstanceId: "5c6bbc5010976", + loginFrom: "easyops", + }, + }, + }; analyzer.analyses(response as any); pageTracker(params); + analyzer.analyses(response2); const data = { model: "easyops.FRONTEND_STAT", columns: [ @@ -146,6 +182,26 @@ describe("ApiAnalysis", () => { username: "mock-user", route: "/developers/:id", }, + { + api: "api/auth/login2", + code: 0, + duration: 2, + et: 1603109440807, + lt: 0, + msg: "", + page: "http://localhost/", + pageId: "88-" + uuid, + size: 28, + st: 1603109440805, + _ver: 1603109440805, + status: 200, + time: 1603109440807, + traceId: "fake-trace-id2", + type: "apiRequest", + uid: "abc", + username: "mock-user", + route: "/developers/:id", + }, ]); }); @@ -238,6 +294,26 @@ describe("ApiAnalysis", () => { username: "mock-user", route: "/developers/:id", }, + { + api: "api/auth/login2", + code: 0, + duration: 2, + et: 1603109440807, + lt: 0, + msg: "", + page: "http://localhost/", + pageId: "88-" + uuid, + size: 28, + st: 1603109440805, + _ver: 1603109440805, + status: 200, + time: 1603109440807, + traceId: "fake-trace-id2", + type: "apiRequest", + uid: "abc", + username: "mock-user", + route: "/developers/:id", + }, ]); }); @@ -326,6 +402,26 @@ describe("ApiAnalysis", () => { username: "mock-user", route: "/developers/:id", }, + { + api: "api/auth/login2", + code: 0, + duration: 2, + et: 1603109440807, + lt: 0, + msg: "", + page: "http://localhost/", + pageId: "88-" + uuid, + size: 28, + st: 1603109440805, + _ver: 1603109440805, + status: 200, + time: 1603109440807, + traceId: "fake-trace-id2", + type: "apiRequest", + uid: "abc", + username: "mock-user", + route: "/developers/:id", + }, ]); }); }); diff --git a/packages/easyops-analytics/src/ApiAnalysis.ts b/packages/easyops-analytics/src/ApiAnalysis.ts index e8ae5d272e..858f918a6c 100644 --- a/packages/easyops-analytics/src/ApiAnalysis.ts +++ b/packages/easyops-analytics/src/ApiAnalysis.ts @@ -30,7 +30,7 @@ export interface ApiMetric { username?: string; // Date time?: number; - type?: "api"; + type?: "api" | "apiRequest"; st: number; et: number; duration: number; @@ -65,6 +65,7 @@ export type PageMetric = Pick< pageTitle: string; }; export type MixMetric = ApiMetric | PageMetric; +type PageBasicInfo = Pick; interface ApiAnalysisServiceProps { api: string; @@ -74,7 +75,8 @@ class ApiAnalysisService { public logs: MixMetric[] = []; public queue: ApiMetric[] = []; private initialized = false; - + private pageBasicInfo: PageBasicInfo = null; + private tracePageState: "start" | "end" = "start"; constructor(props: ApiAnalysisServiceProps) { this.api = props.api; this.initialized = true; @@ -128,7 +130,9 @@ class ApiAnalysisService { log = this.gatherResponse(response as HttpResponse); } - this.queue.push(log); + this.tracePageState === "start" + ? this.queue.push(log) + : this.traceApi(log); // this.logs.push(log); } catch (e) /* istanbul ignore next */ { // eslint-disable-next-line no-console @@ -149,8 +153,10 @@ class ApiAnalysisService { } return uuid; } - - pageTracker(): ({ + traceApi(api: ApiMetric): void { + this.logs.push({ ...api, type: "apiRequest", ...this.pageBasicInfo }); + } + tracePage(): ({ path, pageTitle, username, @@ -161,11 +167,13 @@ class ApiAnalysisService { }) => void { const startTime = Date.now(); this.queue = []; + this.pageBasicInfo = null; + this.tracePageState = "start"; return ({ path, pageTitle, username }) => { const endTime = Date.now(); // page load time const lt = endTime - startTime; - const extra = { + this.pageBasicInfo = { lt, route: path, pageId: this.genUUID(), @@ -188,11 +196,15 @@ class ApiAnalysisService { .reduce((a, b) => a + b, 0), pageTitle, username, - ...extra, + ...this.pageBasicInfo, }; this.logs.push(pageMetric); - const queuedApiList = this.queue.map((api) => ({ ...api, ...extra })); + const queuedApiList = this.queue.map((api) => ({ + ...api, + ...this.pageBasicInfo, + })); this.logs.push(...queuedApiList); + this.tracePageState = "end"; }; } diff --git a/packages/easyops-illustrations/src/Illustrations.spec.tsx b/packages/easyops-illustrations/src/Illustrations.spec.tsx index 09caf4f70e..e5bf375599 100644 --- a/packages/easyops-illustrations/src/Illustrations.spec.tsx +++ b/packages/easyops-illustrations/src/Illustrations.spec.tsx @@ -91,11 +91,11 @@ describe("Illustration", () => { }); it("translateIllustrationConfig should work when category is feedback", () => { - const illustrationConfig: any = translateIllustrationConfig(true, { + const illustrationConfig = translateIllustrationConfig(true, { name: "info", category: "feedback", theme: "light", - }); + }) as any; expect(illustrationConfig.name).toEqual("info"); expect(illustrationConfig.category).toEqual("feedback"); });