1
- import { Performance , performance } from "node:perf_hooks" ;
2
- import { basename } from "node:path" ;
3
- import { cpus } from "node:os" ;
1
+ import { Performance , performance , PerformanceObserver } from "node:perf_hooks" ;
2
+ import { basename } from "node:path" ;
3
+ import { cpus } from "node:os" ;
4
4
5
5
// Global array to store complete events.
6
6
const traceEvents = [ ] ;
7
7
8
8
// Metadata events.
9
-
10
9
const processMetadata = {
11
- name : 'process_name' , // Used to label the main process
10
+ name : 'process_name' ,
12
11
ph : 'M' ,
13
12
pid : 0 ,
14
13
tid : process . pid ,
@@ -17,17 +16,17 @@ const processMetadata = {
17
16
} ;
18
17
19
18
const threadMetadata = {
20
- name : 'thread_name' , // Used to label the child processes
19
+ name : 'thread_name' ,
21
20
ph : 'M' ,
22
21
pid : 0 ,
23
22
tid : process . pid ,
24
23
ts : 0 ,
25
- args : { name : `Child Process: ${ basename ( process . argv . at ( 0 ) ) } ${ basename ( process . argv . at ( 1 ) ) } ${ process . argv . slice ( 2 ) . join ( ' ' ) } ` } ,
24
+ args : {
25
+ name : `Child Process: ${ basename ( process . argv . at ( 0 ) ) } ${ basename ( process . argv . at ( 1 ) ) } ${ process . argv . slice ( 2 ) . join ( ' ' ) } `
26
+ } ,
26
27
} ;
27
28
28
-
29
29
const originalMark = Performance . prototype . mark ;
30
- const originalMeasure = Performance . prototype . measure ;
31
30
32
31
let correlationIdCounter = 0 ;
33
32
function generateCorrelationId ( ) {
@@ -57,7 +56,7 @@ function parseStack(stack) {
57
56
if ( match ) {
58
57
frames . push ( {
59
58
functionName : null ,
60
- file : match [ 1 ] ,
59
+ file : match [ 1 ] . replace ( process . cwd ( ) , '' ) ,
61
60
line : Number ( match [ 2 ] ) ,
62
61
column : Number ( match [ 3 ] ) ,
63
62
} ) ;
@@ -69,47 +68,49 @@ function parseStack(stack) {
69
68
return frames ;
70
69
}
71
70
72
- Performance . prototype . mark = function ( name , options ) {
71
+ // Patch mark to include call stack
72
+ Performance . prototype . mark = function ( name , options ) {
73
73
const err = new Error ( ) ;
74
74
const callStack = parseStack ( err . stack ) ;
75
75
const opt = Object . assign ( { } , options , {
76
76
detail : Object . assign ( { } , ( options && options . detail ) || { } , { callStack } ) ,
77
77
} ) ;
78
78
return originalMark . call ( this , name , opt ) ;
79
79
} ;
80
- Performance . prototype . measure = function ( name , start , end , options ) {
81
- const startEntry = performance . getEntriesByName ( start , 'mark' ) [ 0 ] ;
82
- const endEntry = performance . getEntriesByName ( end , 'mark' ) [ 0 ] ;
83
- let event = null ;
84
80
85
- if ( startEntry && endEntry ) {
86
- const ts = startEntry . startTime * 1000 ; // Convert ms to µs
87
- const dur = ( endEntry . startTime - startEntry . startTime ) * 1000 ;
81
+ // Use PerformanceObserver to enrich and capture measure events
82
+ const observer = new PerformanceObserver ( ( list ) => {
83
+ for ( const entry of list . getEntries ( ) ) {
84
+ const startEntry = performance . getEntriesByName ( entry . startTime ? entry . name . split ( ' -> ' ) [ 0 ] : '' , 'mark' ) [ 0 ] ;
85
+ const endEntry = performance . getEntriesByName ( entry . name , 'mark' ) [ 0 ] ; // fallback if needed
88
86
89
87
const correlationId = generateCorrelationId ( ) ;
90
- const callFrame = ( startEntry . detail ?. callStack || [ ] ) [ 0 ] || { } ;
88
+ const callFrame = ( startEntry ? .detail ?. callStack || [ ] ) [ 0 ] || { } ;
91
89
const file = ( callFrame . file || 'unknown' ) . replace ( process . cwd ( ) , '.' ) ;
92
90
const functionName = callFrame . functionName != null ? callFrame . functionName : 'anonymous' ;
93
91
const line = callFrame . line || null ;
94
92
95
- event = {
96
- name : name . replace ( process . cwd ( ) , '' ) , // sometimes the name includes a path
93
+ const ts = entry . startTime * 1000 ;
94
+ const dur = entry . duration * 1000 ;
95
+
96
+ const event = {
97
+ name : entry . name . replace ( process . cwd ( ) , '' ) ,
97
98
cat : 'measure' ,
98
99
ph : 'X' ,
99
100
ts,
100
101
dur,
101
102
pid : 0 ,
102
103
tid : process . pid ,
103
104
args : {
104
- startDetail : startEntry . detail || { } ,
105
- endDetail : endEntry . detail || { } ,
105
+ startDetail : startEntry ? .detail || { } ,
106
+ endDetail : endEntry ? .detail || { } ,
106
107
uiLabel : functionName ,
107
108
correlationId,
108
109
timestamp : new Date ( ) . toISOString ( ) ,
109
110
durationMs : dur / 1000 ,
110
111
file,
111
112
functionName,
112
- line
113
+ line,
113
114
}
114
115
} ;
115
116
@@ -122,15 +123,12 @@ Performance.prototype.measure = function(name, start, end, options) {
122
123
123
124
traceEvents . push ( event ) ;
124
125
console . log ( `traceEvent:JSON:${ JSON . stringify ( event ) } ` ) ;
125
- } else {
126
- console . warn ( 'Missing start or end mark for measure' , name ) ;
127
126
}
128
-
129
- return originalMeasure . call ( this , name , start , end , options ) ;
130
- } ;
127
+ } ) ;
128
+ observer . observe ( { entryTypes : [ 'measure' ] , buffered : true } ) ;
131
129
132
130
// Return the complete Chrome Trace profile object.
133
- performance . profile = function ( ) {
131
+ performance . profile = function ( ) {
134
132
return {
135
133
metadata : {
136
134
source : "Nx Advanced Profiling" ,
@@ -160,4 +158,3 @@ performance.profile = function() {
160
158
traceEvents
161
159
} ;
162
160
} ;
163
-
0 commit comments