@@ -43,6 +43,8 @@ export default class LiveInstrumentRemote {
4343 }
4444
4545 this . sourceMapper = new SourceMapper ( this . scriptLoaded . bind ( this ) ) ;
46+
47+ ContextReceiver . initialize ( ) ;
4648 }
4749
4850 async start ( ) : Promise < void > {
@@ -93,84 +95,87 @@ export default class LiveInstrumentRemote {
9395 } ) ) ;
9496 }
9597
96- let instrumentIds = this . breakpointIdToInstrumentIds . get ( message . params . hitBreakpoints [ 0 ] ) ; // TODO: Handle multiple hit breakpoints
97- if ( ! instrumentIds ) {
98- this . removeBreakpoint ( message . params . hitBreakpoints [ 0 ] ) ;
99- return ;
100- }
98+ message . params . hitBreakpoints . forEach ( breakpointId => { // There should only be a single breakpoint, but handle multiple just in case
99+ let instrumentIds = this . breakpointIdToInstrumentIds . get ( breakpointId ) ;
100+ if ( ! instrumentIds ) {
101+ this . removeBreakpoint ( message . params . hitBreakpoints [ 0 ] ) ;
102+ return ;
103+ }
101104
102- let instruments = instrumentIds . map ( id => this . instruments . get ( id ) ) ;
103- let conditionsSatisfied = Promise . all ( instruments . map ( instrument => {
104- if ( instrument . condition === undefined || instrument . condition === null )
105- return true ;
106-
107- return new Promise < boolean > ( ( resolve , reject ) => {
108- this . session . post ( "Debugger.evaluateOnCallFrame" , {
109- callFrameId : frame . callFrameId ,
110- expression : instrument . condition ,
111- silent : false ,
112- throwOnSideEffect : true
113- } , ( err , res ) => {
114- if ( err ) {
115- console . log ( `Error evaluating condition (${ instrument . condition } ): ${ err } ` ) ;
116- resolve ( false ) ;
117- } else {
118- if ( res . result . type === 'object' && res . result . subtype === 'error' ) {
119- if ( res . result . className === 'EvalError' ) {
120- console . log ( `Could not evaluate condition (${ instrument . condition } ) due to possible side effects` ) ;
105+ let instruments = instrumentIds . map ( id => this . instruments . get ( id ) ) ;
106+ let dataGathered = Promise . all ( instruments . map ( instrument => {
107+ return new Promise < any > ( ( resolve , reject ) => {
108+ this . session . post ( "Debugger.evaluateOnCallFrame" , {
109+ callFrameId : frame . callFrameId ,
110+ expression : instrument . createExpression ( ) ,
111+ silent : false , // In case of an exception, don't affect the program flow
112+ throwOnSideEffect : true , // Disallow side effects
113+ returnByValue : true // Return the entire JSON object rather than just the remote id
114+ } , ( err , res ) => {
115+ if ( err ) {
116+ this . handleConditionalFailed ( instrument ,
117+ `Error evaluating condition (${ instrument . condition } ): ${ err } ` ) ;
118+ resolve ( { success : false } ) ;
119+ } else {
120+ if ( res . result . type === 'object' && res . result . subtype === 'error' ) {
121+ if ( res . result . className === 'EvalError' ) {
122+ this . handleConditionalFailed ( instrument ,
123+ `Could not evaluate condition (${ instrument . condition } ) due to possible side effects` ) ;
124+ } else {
125+ this . handleConditionalFailed ( instrument ,
126+ `Error evaluating condition (${ instrument . condition } ): ${ res . result . description } ` ) ;
127+ }
128+ resolve ( { success : false } ) ;
129+ } else if ( res . result . type !== 'object' ) {
130+ this . handleConditionalFailed ( instrument ,
131+ `Invalid condition for instrument id: ${ instrument . id } : ${ instrument . condition } ==> ${ res . result } ` ) ;
132+ resolve ( { success : false } ) ;
121133 } else {
122- console . log ( `Error evaluating condition ( ${ instrument . condition } ): ${ res . result . description } ` ) ;
134+ resolve ( res . result . value ) ;
123135 }
124- resolve ( false ) ;
125- } else if ( res . result . type !== 'boolean' ) {
126- console . log ( "Invalid condition for instrument id: " + instrument . id + ": " + instrument . condition , res . result ) ;
127- resolve ( false ) ;
128- } else {
129- resolve ( res . result . value ) ;
130136 }
131- }
137+ } ) ;
132138 } ) ;
133- } ) ;
134- } ) ) ;
135-
136- Promise . all ( promises ) . then ( ( ) => conditionsSatisfied )
137- . then ( conditions => {
138- for ( let i = 0 ; i < instruments . length ; i ++ ) {
139- if ( conditions [ i ] ) {
140- let instrument = instruments [ i ] ;
141- if ( ! instrument ) {
142- continue ;
143- }
139+ } ) ) ;
140+
141+ Promise . all ( promises ) . then ( ( ) => dataGathered )
142+ . then ( data => {
143+ for ( let i = 0 ; i < instruments . length ; i ++ ) {
144+ if ( data [ i ] . success ) {
145+ let instrument = instruments [ i ] ;
146+ if ( ! instrument ) {
147+ continue ;
148+ }
144149
145- if ( instrument . type == LiveInstrumentType . BREAKPOINT ) {
146- ContextReceiver . applyBreakpoint (
147- instrument . id ,
148- instrument . location . source ,
149- instrument . location . line ,
150- message . params . callFrames ,
151- variables
152- ) ;
153- } else if ( instrument . type == LiveInstrumentType . LOG ) {
154- let logInstrument = < LiveLog > instrument ;
155- ContextReceiver . applyLog (
156- instrument . id ,
157- logInstrument . logFormat ,
158- logInstrument . logArguments ,
159- variables
160- ) ;
161- } else if ( instrument . type == LiveInstrumentType . METER ) {
162- let meterInstrument = < LiveMeter > instrument ;
163- ContextReceiver . applyMeter (
164- instrument . id ,
165- variables
166- ) ;
167- }
168- if ( instrument . isFinished ( ) ) {
169- this . removeBreakpoint ( instrument . id ) ;
150+ if ( instrument . type == LiveInstrumentType . BREAKPOINT ) {
151+ ContextReceiver . applyBreakpoint (
152+ instrument . id ,
153+ instrument . location . source ,
154+ instrument . location . line ,
155+ message . params . callFrames ,
156+ variables
157+ ) ;
158+ } else if ( instrument . type == LiveInstrumentType . LOG ) {
159+ let logInstrument = < LiveLog > instrument ;
160+ ContextReceiver . applyLog (
161+ instrument . id ,
162+ logInstrument . logFormat ,
163+ data [ i ] . logArguments
164+ ) ;
165+ } else if ( instrument . type == LiveInstrumentType . METER ) {
166+ let meterInstrument = < LiveMeter > instrument ;
167+ ContextReceiver . applyMeter (
168+ instrument . id ,
169+ variables
170+ ) ;
171+ }
172+ if ( instrument . isFinished ( ) ) {
173+ this . removeBreakpoint ( instrument . id ) ;
174+ }
170175 }
171176 }
172- }
173- } ) ;
177+ } ) ;
178+ } ) ;
174179 } ) ;
175180 }
176181
@@ -332,6 +337,15 @@ export default class LiveInstrumentRemote {
332337 }
333338 }
334339
340+ handleConditionalFailed ( instrument : LiveInstrument , error : string ) {
341+ this . removeInstrument ( instrument . id ) ;
342+ this . eventBus . publish ( "spp.processor.status.live-instrument-removed" , {
343+ occurredAt : Date . now ( ) ,
344+ instrument : JSON . stringify ( instrument . toJson ( ) ) ,
345+ cause : `EventBusException:LiveInstrumentException[CONDITIONAL_FAILED]: ${ error } `
346+ } ) ;
347+ }
348+
335349 // TODO: Call this regularly to clean up old instruments
336350 // TODO: Ensure the cache doesn't get too large
337351 private cleanCache ( ) {
0 commit comments