@@ -71,29 +71,55 @@ export class Logger {
7171 }
7272 }
7373
74+ /**
75+ * Recursively end all unended events in the event tree.
76+ * This ensures all events have end marks before measuring.
77+ */
78+ private endAllEvents ( events : Array < LoggerEvent > ) : void {
79+ for ( const event of events ) {
80+ if ( ! event . end ) {
81+ event . end = performance . mark ( idEnd ( event . id ) ) ;
82+ }
83+ if ( event . events . length > 0 ) {
84+ this . endAllEvents ( event . events ) ;
85+ }
86+ }
87+ }
88+
7489 report ( print : boolean = true ) : PerformanceMeasure | undefined {
7590 const firstEvent = this . events [ 0 ] ;
7691 if ( ! firstEvent ) return ;
92+
93+ // Ensure all events are ended before reporting
94+ this . endAllEvents ( this . events ) ;
95+
7796 const lastEvent = this . events [ this . events . length - 1 ] ! ;
7897 const name = 'root' ;
7998 const id = nameToId ( name ) ;
80- const measure = performance . measure (
81- idLength ( id ) ,
82- idStart ( firstEvent . id ) ,
83- idEnd ( lastEvent . id ) ,
84- ) ;
85- if ( print ) {
86- this . reportEvent ( {
87- end : lastEvent . end ,
88- events : this . events ,
89- id,
90- indent : 0 ,
91- measure,
92- name,
93- start : firstEvent ! . start ,
94- } ) ;
99+
100+ try {
101+ const measure = performance . measure (
102+ idLength ( id ) ,
103+ idStart ( firstEvent . id ) ,
104+ idEnd ( lastEvent . id ) ,
105+ ) ;
106+ if ( print ) {
107+ this . reportEvent ( {
108+ end : lastEvent . end ,
109+ events : this . events ,
110+ id,
111+ indent : 0 ,
112+ measure,
113+ name,
114+ start : firstEvent ! . start ,
115+ } ) ;
116+ }
117+ return measure ;
118+ } catch {
119+ // If measuring fails (e.g., marks don't exist), silently skip reporting
120+ // to avoid crashing the application
121+ return ;
95122 }
96- return measure ;
97123 }
98124
99125 private reportEvent ( {
@@ -107,41 +133,46 @@ export class Logger {
107133 const lastIndex = parent . events . length - 1 ;
108134
109135 parent . events . forEach ( ( event , index ) => {
110- const measure = performance . measure (
111- idLength ( event . id ) ,
112- idStart ( event . id ) ,
113- idEnd ( event . id ) ,
114- ) ;
115- const duration = Math . ceil ( measure . duration * 100 ) / 100 ;
116- const percentage =
117- Math . ceil ( ( measure . duration / parent . measure . duration ) * 100 * 100 ) /
118- 100 ;
119- const severity = indent ? getSeverity ( duration , percentage ) : undefined ;
120-
121- let durationLabel = `${ duration . toFixed ( 2 ) . padStart ( 8 ) } ms` ;
122- if ( severity ?. type === 'duration' ) {
123- durationLabel = severity . color ( durationLabel ) ;
124- }
125-
126- const branch = index === lastIndex ? '└─ ' : '├─ ' ;
127- const prefix = ! indent ? '' : '│ ' . repeat ( indent - 1 ) + branch ;
128- const maxLength = 38 - prefix . length ;
129-
130- const percentageBranch = ! indent ? '' : '↳ ' ;
131- const percentagePrefix = indent
132- ? ' ' . repeat ( indent - 1 ) + percentageBranch
133- : '' ;
134- let percentageLabel = `${ percentagePrefix } ${ percentage . toFixed ( 2 ) } %` ;
135- if ( severity ?. type === 'percentage' ) {
136- percentageLabel = severity . color ( percentageLabel ) ;
136+ try {
137+ const measure = performance . measure (
138+ idLength ( event . id ) ,
139+ idStart ( event . id ) ,
140+ idEnd ( event . id ) ,
141+ ) ;
142+ const duration = Math . ceil ( measure . duration * 100 ) / 100 ;
143+ const percentage =
144+ Math . ceil ( ( measure . duration / parent . measure . duration ) * 100 * 100 ) /
145+ 100 ;
146+ const severity = indent ? getSeverity ( duration , percentage ) : undefined ;
147+
148+ let durationLabel = `${ duration . toFixed ( 2 ) . padStart ( 8 ) } ms` ;
149+ if ( severity ?. type === 'duration' ) {
150+ durationLabel = severity . color ( durationLabel ) ;
151+ }
152+
153+ const branch = index === lastIndex ? '└─ ' : '├─ ' ;
154+ const prefix = ! indent ? '' : '│ ' . repeat ( indent - 1 ) + branch ;
155+ const maxLength = 38 - prefix . length ;
156+
157+ const percentageBranch = ! indent ? '' : '↳ ' ;
158+ const percentagePrefix = indent
159+ ? ' ' . repeat ( indent - 1 ) + percentageBranch
160+ : '' ;
161+ let percentageLabel = `${ percentagePrefix } ${ percentage . toFixed ( 2 ) } %` ;
162+ if ( severity ?. type === 'percentage' ) {
163+ percentageLabel = severity . color ( percentageLabel ) ;
164+ }
165+ const jobPrefix = colors . gray ( '[root] ' ) ;
166+ console . log (
167+ `${ jobPrefix } ${ colors . gray ( prefix ) } ${ color (
168+ `${ event . name . padEnd ( maxLength ) } ${ durationLabel } (${ percentageLabel } )` ,
169+ ) } `,
170+ ) ;
171+ this . reportEvent ( { ...event , indent : indent + 1 , measure } ) ;
172+ } catch {
173+ // If measuring fails (e.g., marks don't exist), silently skip this event
174+ // to avoid crashing the application
137175 }
138- const jobPrefix = colors . gray ( '[root] ' ) ;
139- console . log (
140- `${ jobPrefix } ${ colors . gray ( prefix ) } ${ color (
141- `${ event . name . padEnd ( maxLength ) } ${ durationLabel } (${ percentageLabel } )` ,
142- ) } `,
143- ) ;
144- this . reportEvent ( { ...event , indent : indent + 1 , measure } ) ;
145176 } ) ;
146177 }
147178
0 commit comments