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" ;
44
55// Global array to store complete events.
66const traceEvents = [ ] ;
77
88// Metadata events.
9-
109const processMetadata = {
11- name : 'process_name' , // Used to label the main process
10+ name : 'process_name' ,
1211 ph : 'M' ,
1312 pid : 0 ,
1413 tid : process . pid ,
@@ -17,17 +16,17 @@ const processMetadata = {
1716} ;
1817
1918const threadMetadata = {
20- name : 'thread_name' , // Used to label the child processes
19+ name : 'thread_name' ,
2120 ph : 'M' ,
2221 pid : 0 ,
2322 tid : process . pid ,
2423 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+ } ,
2627} ;
2728
28-
2929const originalMark = Performance . prototype . mark ;
30- const originalMeasure = Performance . prototype . measure ;
3130
3231let correlationIdCounter = 0 ;
3332function generateCorrelationId ( ) {
@@ -57,7 +56,7 @@ function parseStack(stack) {
5756 if ( match ) {
5857 frames . push ( {
5958 functionName : null ,
60- file : match [ 1 ] ,
59+ file : match [ 1 ] . replace ( process . cwd ( ) , '' ) ,
6160 line : Number ( match [ 2 ] ) ,
6261 column : Number ( match [ 3 ] ) ,
6362 } ) ;
@@ -69,47 +68,49 @@ function parseStack(stack) {
6968 return frames ;
7069}
7170
72- Performance . prototype . mark = function ( name , options ) {
71+ // Patch mark to include call stack
72+ Performance . prototype . mark = function ( name , options ) {
7373 const err = new Error ( ) ;
7474 const callStack = parseStack ( err . stack ) ;
7575 const opt = Object . assign ( { } , options , {
7676 detail : Object . assign ( { } , ( options && options . detail ) || { } , { callStack } ) ,
7777 } ) ;
7878 return originalMark . call ( this , name , opt ) ;
7979} ;
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 ;
8480
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
8886
8987 const correlationId = generateCorrelationId ( ) ;
90- const callFrame = ( startEntry . detail ?. callStack || [ ] ) [ 0 ] || { } ;
88+ const callFrame = ( startEntry ? .detail ?. callStack || [ ] ) [ 0 ] || { } ;
9189 const file = ( callFrame . file || 'unknown' ) . replace ( process . cwd ( ) , '.' ) ;
9290 const functionName = callFrame . functionName != null ? callFrame . functionName : 'anonymous' ;
9391 const line = callFrame . line || null ;
9492
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 ( ) , '' ) ,
9798 cat : 'measure' ,
9899 ph : 'X' ,
99100 ts,
100101 dur,
101102 pid : 0 ,
102103 tid : process . pid ,
103104 args : {
104- startDetail : startEntry . detail || { } ,
105- endDetail : endEntry . detail || { } ,
105+ startDetail : startEntry ? .detail || { } ,
106+ endDetail : endEntry ? .detail || { } ,
106107 uiLabel : functionName ,
107108 correlationId,
108109 timestamp : new Date ( ) . toISOString ( ) ,
109110 durationMs : dur / 1000 ,
110111 file,
111112 functionName,
112- line
113+ line,
113114 }
114115 } ;
115116
@@ -122,15 +123,12 @@ Performance.prototype.measure = function(name, start, end, options) {
122123
123124 traceEvents . push ( event ) ;
124125 console . log ( `traceEvent:JSON:${ JSON . stringify ( event ) } ` ) ;
125- } else {
126- console . warn ( 'Missing start or end mark for measure' , name ) ;
127126 }
128-
129- return originalMeasure . call ( this , name , start , end , options ) ;
130- } ;
127+ } ) ;
128+ observer . observe ( { entryTypes : [ 'measure' ] , buffered : true } ) ;
131129
132130// Return the complete Chrome Trace profile object.
133- performance . profile = function ( ) {
131+ performance . profile = function ( ) {
134132 return {
135133 metadata : {
136134 source : "Nx Advanced Profiling" ,
@@ -160,4 +158,3 @@ performance.profile = function() {
160158 traceEvents
161159 } ;
162160} ;
163-
0 commit comments