Skip to content

Commit aeaa7be

Browse files
authored
feat: add rpc timing event track (#3743)
* feat: add rpc timing event track * feat: can configure measure report * chore: revert typings * feat: adjust config
1 parent 76ff557 commit aeaa7be

File tree

8 files changed

+108
-9
lines changed

8 files changed

+108
-9
lines changed

packages/connection/src/common/rpc-service/center.ts

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
1-
import { Deferred, DisposableStore, IDisposable, randomString } from '@opensumi/ide-core-common';
1+
import {
2+
Deferred,
3+
DisposableStore,
4+
IDisposable,
5+
IReporterService,
6+
IReporterTimer,
7+
REPORT_NAME,
8+
randomString,
9+
} from '@opensumi/ide-core-common';
210
import { addElement } from '@opensumi/ide-utils/lib/arrays';
311

412
import { METHOD_NOT_REGISTERED } from '../constants';
@@ -12,6 +20,8 @@ import { ProtocolRegistry, ServiceRegistry } from './registry';
1220

1321
import type { MessageConnection } from '@opensumi/vscode-jsonrpc';
1422

23+
const kDefaultMinimumReportThresholdTime = 200;
24+
1525
export class RPCServiceCenter implements IDisposable {
1626
private _disposables = new DisposableStore();
1727

@@ -30,6 +40,16 @@ export class RPCServiceCenter implements IDisposable {
3040
this.logger = logger || console;
3141
}
3242

43+
private _reporterService: IReporterService | undefined;
44+
private _reportThreshold: number = kDefaultMinimumReportThresholdTime;
45+
setReporter(
46+
reporterService: IReporterService,
47+
minimumReportThresholdTime: number = kDefaultMinimumReportThresholdTime,
48+
) {
49+
this._reporterService = reporterService;
50+
this._reportThreshold = minimumReportThresholdTime;
51+
}
52+
3353
registerService(serviceName: string, type: ServiceType): void {
3454
if (type === ServiceType.Service) {
3555
if (this.bench) {
@@ -98,8 +118,13 @@ export class RPCServiceCenter implements IDisposable {
98118

99119
async broadcast(serviceName: string, _name: string, ...args: any[]): Promise<any> {
100120
await this.ready();
101-
102121
const name = getMethodName(serviceName, _name);
122+
123+
let timer: IReporterTimer | undefined;
124+
if (this._reporterService) {
125+
timer = this._reporterService.time(REPORT_NAME.RPC_TIMMING_MEASURE);
126+
}
127+
103128
const broadcastResult = await Promise.all(this.proxies.map((proxy) => proxy.invoke(name, ...args)));
104129

105130
const doubtfulResult = [] as any[];
@@ -117,9 +142,33 @@ export class RPCServiceCenter implements IDisposable {
117142
}
118143

119144
if (result.length === 0) {
145+
if (timer) {
146+
timer.timeEnd(
147+
name,
148+
{
149+
success: false,
150+
},
151+
{
152+
minimumReportThresholdTime: this._reportThreshold,
153+
},
154+
);
155+
}
156+
120157
throw new Error(`broadcast rpc \`${name}\` error: no remote service can handle this call`);
121158
}
122159

160+
if (timer) {
161+
timer.timeEnd(
162+
name,
163+
{
164+
success: true,
165+
},
166+
{
167+
minimumReportThresholdTime: this._reportThreshold,
168+
},
169+
);
170+
}
171+
123172
// FIXME: this is an unreasonable design, if remote service only returned doubtful result, we will return an empty array.
124173
// but actually we should throw an error to tell user that no remote service can handle this call.
125174
// or just return `undefined`.

packages/core-browser/src/bootstrap/connection.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
import { BackService } from '@opensumi/ide-core-common/lib/module';
1515

1616
import { ClientAppStateService } from '../application';
17+
import { AppConfig } from '../react-providers/config-provider';
1718

1819
import { ModuleConstructor } from './app.interface';
1920

@@ -25,6 +26,7 @@ export async function createConnectionService(
2526
channelHandler: WSChannelHandler,
2627
options: ISumiConnectionOptions = {},
2728
) {
29+
const appConfig = injector.get(AppConfig) as AppConfig;
2830
const reporterService: IReporterService = injector.get(IReporterService);
2931
channelHandler.setReporter(reporterService);
3032

@@ -69,6 +71,11 @@ export async function createConnectionService(
6971

7072
const clientCenter = new RPCServiceCenter();
7173
clientCenter.setSumiConnection(channel.createSumiConnection(options));
74+
75+
if (appConfig?.measure?.connection) {
76+
clientCenter.setReporter(reporterService, appConfig.measure.connection.minimumReportThresholdTime);
77+
}
78+
7279
initConnectionService(injector, modules, clientCenter);
7380

7481
return channel;

packages/core-browser/src/react-providers/config-provider.tsx

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ export const AppConfig = Symbol('AppConfig');
1818
export interface AppConfig {
1919
/**
2020
* APP的名称
21-
* 默认值为 `ClientApp.DEFAULT_APPLICATION_NAME` 即 `OPENSUMI`
21+
* 默认值为 `ClientApp.DEFAULT_APPLICATION_NAME` 即 `OpenSumi`
2222
*/
2323
appName?: string;
2424
/**
@@ -284,6 +284,10 @@ export interface AppConfig {
284284
* 支持的通信协议类型
285285
*/
286286
connectionProtocols?: string[];
287+
/**
288+
* 埋点上报的配置
289+
*/
290+
measure?: IMeasureConfig;
287291
/**
288292
* 是否启用 Diff 协议文件自动恢复
289293
*/
@@ -294,6 +298,20 @@ export interface ICollaborationClientOpts {
294298
port?: number;
295299
}
296300

301+
export interface IMeasureConfig {
302+
/**
303+
* 是否开启连接性能监控
304+
*/
305+
connection?: IConnectionMeasureConfig;
306+
}
307+
308+
export interface IConnectionMeasureConfig {
309+
/**
310+
* 最低上报阈值时间,单位 ms
311+
*/
312+
minimumReportThresholdTime?: number;
313+
}
314+
297315
export const ConfigContext = React.createContext<AppConfig>({
298316
workspaceDir: '',
299317
injector: null as any,

packages/core-common/src/reporter.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
IReporter,
77
IReporterService,
88
IReporterTimer,
9+
IReporterTimerEndOptions,
910
PerformanceData,
1011
PointData,
1112
REPORT_NAME,
@@ -18,8 +19,18 @@ class ReporterTimer implements IReporterTimer {
1819
this.now = Date.now();
1920
}
2021

21-
timeEnd(msg?: string, extra?: any) {
22-
const duration = Date.now() - this.now;
22+
getElapsedTime() {
23+
return Date.now() - this.now;
24+
}
25+
26+
timeEnd(msg?: string, extra?: any, options?: IReporterTimerEndOptions) {
27+
const duration = this.getElapsedTime();
28+
29+
if (options?.minimumReportThresholdTime && duration < options.minimumReportThresholdTime) {
30+
// 不满足最小时间要求,不上报
31+
return duration;
32+
}
33+
2334
this.reporter.performance(this.name, {
2435
duration,
2536
metadata: this.metadata,

packages/core-common/src/types/reporter.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ export enum REPORT_NAME {
3838
TERMINAL_MEASURE = 'terminalMeasure',
3939
SEARCH_MEASURE = 'searchMeasure',
4040
QUICK_OPEN_MEASURE = 'quickOpenMeasure',
41+
RPC_TIMMING_MEASURE = 'rpcTimingMeasure',
4142
}
4243

4344
export enum REPORT_HOST {
@@ -71,8 +72,16 @@ export interface PerformanceData extends PointData {
7172

7273
export const IReporterService = Symbol('IReporterService');
7374

75+
export interface IReporterTimerEndOptions {
76+
/**
77+
* 上报的最小时间阈值,单位毫秒
78+
* 经过的时间要大于这个值才会上报
79+
*/
80+
minimumReportThresholdTime?: number;
81+
}
82+
7483
export interface IReporterTimer {
75-
timeEnd(msg?: string, extra?: any): number;
84+
timeEnd(msg?: string, extra?: any, options?: IReporterTimerEndOptions): number;
7685
}
7786

7887
export interface IReporterService {

packages/startup/entry/web/app.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ renderApp(
2020
modules: [DESIGN_MENUBAR_CONTAINER_VIEW_ID],
2121
},
2222
},
23+
measure: {
24+
connection: {
25+
minimumReportThresholdTime: 400,
26+
},
27+
},
2328
},
2429
}),
2530
);

packages/startup/entry/web/render-app.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ export async function renderApp(opts: IClientAppOpts) {
6868
// eslint-disable-next-line no-console
6969
console.timeEnd('Render');
7070
};
71-
registerLocalStorageProvider(GeneralSettingsId.Theme, opts.workspaceDir || '', 'prefix1');
71+
registerLocalStorageProvider(GeneralSettingsId.Theme, opts.workspaceDir || '', 'sumi-dev');
7272

7373
const app = new ClientApp(opts);
7474

packages/utils/src/functional.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,14 +49,14 @@ export function diffSets<T>(before: Set<T>, after: Set<T>): { removed: T[]; adde
4949
}
5050

5151
export function findFirstTruthy<T>(...sources: Array<T | (() => T)>): T | undefined {
52-
for (let i = 0; i < sources.length - 1; i++) {
52+
for (let i = 0; i <= sources.length - 1; i++) {
5353
const result = check(sources[i]);
5454
if (result) {
5555
return result;
5656
}
5757
}
5858

59-
return check(sources[sources.length - 1]);
59+
return undefined;
6060

6161
function check(value: T | (() => T)): T | undefined {
6262
if (typeof value === 'function') {

0 commit comments

Comments
 (0)