-
Notifications
You must be signed in to change notification settings - Fork 2.3k
Expand file tree
/
Copy pathparse.ts
More file actions
130 lines (111 loc) · 3.48 KB
/
parse.ts
File metadata and controls
130 lines (111 loc) · 3.48 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
/**
* @license
* Copyright 2025 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import {logger} from '../logger.js';
import {
AgentFocus,
TraceEngine,
PerformanceTraceFormatter,
PerformanceInsightFormatter,
} from '../third_party/index.js';
const engine = TraceEngine.TraceModel.Model.createWithAllHandlers();
export interface TraceResult {
parsedTrace: TraceEngine.TraceModel.ParsedTrace;
insights: TraceEngine.Insights.Types.TraceInsightSets | null;
}
export function traceResultIsSuccess(
x: TraceResult | TraceParseError,
): x is TraceResult {
return 'parsedTrace' in x;
}
export interface TraceParseError {
error: string;
}
export async function parseRawTraceBuffer(
buffer: Uint8Array<ArrayBufferLike> | undefined,
): Promise<TraceResult | TraceParseError> {
engine.resetProcessor();
if (!buffer) {
return {
error: 'No buffer was provided.',
};
}
const asString = new TextDecoder().decode(buffer);
if (!asString) {
return {
error: 'Decoding the trace buffer returned an empty string.',
};
}
try {
const data = JSON.parse(asString) as
| {
traceEvents: TraceEngine.Types.Events.Event[];
}
| TraceEngine.Types.Events.Event[];
const events = Array.isArray(data) ? data : data.traceEvents;
await engine.parse(events);
const parsedTrace = engine.parsedTrace();
if (!parsedTrace) {
return {
error: 'No parsed trace was returned from the trace engine.',
};
}
const insights = parsedTrace?.insights ?? null;
return {
parsedTrace,
insights,
};
} catch (e) {
const errorText = e instanceof Error ? e.message : JSON.stringify(e);
logger(`Unexpected error parsing trace: ${errorText}`);
return {
error: errorText,
};
}
}
const extraFormatDescriptions = `Information on performance traces may contain main thread activity represented as call frames and network requests.
${PerformanceTraceFormatter.callFrameDataFormatDescription}
${PerformanceTraceFormatter.networkDataFormatDescription}`;
export function getTraceSummary(result: TraceResult): string {
const focus = AgentFocus.fromParsedTrace(result.parsedTrace);
const formatter = new PerformanceTraceFormatter(focus);
const summaryText = formatter.formatTraceSummary();
return `## Summary of Performance trace findings:
${summaryText}
## Details on call tree & network request formats:
${extraFormatDescriptions}`;
}
export type InsightName = keyof TraceEngine.Insights.Types.InsightModels;
export type InsightOutput = {output: string} | {error: string};
export function getInsightOutput(
result: TraceResult,
insightSetId: string,
insightName: InsightName,
): InsightOutput {
if (!result.insights) {
return {
error: 'No Performance insights are available for this trace.',
};
}
const insightSet = result.insights.get(insightSetId);
if (!insightSet) {
return {
error:
'No Performance Insights for the given insight set id. Only use ids given in the "Available insight sets" list.',
};
}
const matchingInsight =
insightName in insightSet.model ? insightSet.model[insightName] : null;
if (!matchingInsight) {
return {
error: `No Insight with the name ${insightName} found. Double check the name you provided is accurate and try again.`,
};
}
const formatter = new PerformanceInsightFormatter(
AgentFocus.fromParsedTrace(result.parsedTrace),
matchingInsight,
);
return {output: formatter.formatInsight()};
}