11import http = require( "http" ) ;
22
33import Contracts = require( "../Declarations/Contracts" ) ;
4- import Client = require( "../Library/Client " ) ;
4+ import TelemetryClient = require( "../Library/TelemetryClient " ) ;
55import Sender = require( "../Library/Sender" ) ;
66import Queue = require( "../Library/Channel" ) ;
77import Util = require( "../Library/Util" ) ;
88
99class AutoCollectExceptions {
1010
1111 public static INSTANCE : AutoCollectExceptions = null ;
12+ public static get UNCAUGHT_EXCEPTION_HANDLER_NAME ( ) : string { return "uncaughtException" ; }
13+ public static get UNHANDLED_REJECTION_HANDLER_NAME ( ) : string { return "unhandledRejection" ; }
1214
1315 private _exceptionListenerHandle : ( reThrow : boolean , error : Error ) => void ;
1416 private _rejectionListenerHandle : ( reThrow : boolean , error : Error ) => void ;
15- private _client : Client ;
17+ private _client : TelemetryClient ;
1618 private _isInitialized : boolean ;
1719
18- constructor ( client : Client ) {
19- if ( ! ! AutoCollectExceptions . INSTANCE ) {
20+ constructor ( client : TelemetryClient ) {
21+ if ( ! ! AutoCollectExceptions . INSTANCE ) {
2022 throw new Error ( "Exception tracking should be configured from the applicationInsights object" ) ;
2123 }
2224
@@ -29,29 +31,28 @@ class AutoCollectExceptions {
2931 }
3032
3133 public enable ( isEnabled : boolean ) {
32- if ( isEnabled ) {
34+ if ( isEnabled ) {
3335 this . _isInitialized = true ;
3436 var self = this ;
3537 if ( ! this . _exceptionListenerHandle ) {
3638 var handle = ( reThrow : boolean , error : Error ) => {
37- var data = AutoCollectExceptions . getExceptionData ( error , false ) ;
38- var envelope = this . _client . getEnvelope ( data ) ;
39- this . _client . channel . handleCrash ( envelope ) ;
39+ this . _client . trackException ( { exception : error } ) ;
40+ this . _client . flush ( { isAppCrashing : true } ) ;
4041 if ( reThrow ) {
4142 throw error ;
4243 }
4344 } ;
4445 this . _exceptionListenerHandle = handle . bind ( this , true ) ;
4546 this . _rejectionListenerHandle = handle . bind ( this , false ) ;
4647
47- process . on ( "uncaughtException" , this . _exceptionListenerHandle ) ;
48- process . on ( "unhandledRejection" , this . _rejectionListenerHandle ) ;
48+ process . on ( AutoCollectExceptions . UNCAUGHT_EXCEPTION_HANDLER_NAME , this . _exceptionListenerHandle ) ;
49+ process . on ( AutoCollectExceptions . UNHANDLED_REJECTION_HANDLER_NAME , this . _rejectionListenerHandle ) ;
4950 }
5051
5152 } else {
5253 if ( this . _exceptionListenerHandle ) {
53- process . removeListener ( "uncaughtException" , this . _exceptionListenerHandle ) ;
54- process . removeListener ( "unhandledRejection" , this . _rejectionListenerHandle ) ;
54+ process . removeListener ( AutoCollectExceptions . UNCAUGHT_EXCEPTION_HANDLER_NAME , this . _exceptionListenerHandle ) ;
55+ process . removeListener ( AutoCollectExceptions . UNHANDLED_REJECTION_HANDLER_NAME , this . _rejectionListenerHandle ) ;
5556 this . _exceptionListenerHandle = undefined ;
5657 this . _rejectionListenerHandle = undefined ;
5758 delete this . _exceptionListenerHandle ;
@@ -60,127 +61,13 @@ class AutoCollectExceptions {
6061 }
6162 }
6263
63- /**
64- * Track an exception
65- * @param error the exception to track
66- * @param handledAt where this exception was handled (leave null for unhandled)
67- * @param properties additional properties
68- * @param measurements metrics associated with this event, displayed in Metrics Explorer on the portal. Defaults to empty.
69- */
70- public static getExceptionData ( error : Error , isHandled : boolean , properties ?:{ [ key : string ] : string ; } , measurements ?:{ [ key : string ] : number ; } ) : Contracts . Data < Contracts . ExceptionData > {
71- var exception = new Contracts . ExceptionData ( ) ;
72- exception . properties = properties ;
73- exception . severityLevel = Contracts . SeverityLevel . Error ;
74- exception . measurements = measurements ;
75- exception . exceptions = [ ] ;
76-
77- var stack = error [ "stack" ] ;
78- var exceptionDetails = new Contracts . ExceptionDetails ( ) ;
79- exceptionDetails . message = error . message ;
80- exceptionDetails . typeName = error . name ;
81- exceptionDetails . parsedStack = this . parseStack ( stack ) ;
82- exceptionDetails . hasFullStack = Util . isArray ( exceptionDetails . parsedStack ) && exceptionDetails . parsedStack . length > 0 ;
83- exception . exceptions . push ( exceptionDetails ) ;
84-
85- var data = new Contracts . Data < Contracts . ExceptionData > ( ) ;
86- data . baseType = Contracts . DataTypes . EXCEPTION ;
87- data . baseData = exception ;
88- return data ;
89- }
90-
91- private static parseStack ( stack : any ) : _StackFrame [ ] {
92- var parsedStack : _StackFrame [ ] = undefined ;
93- if ( typeof stack === "string" ) {
94- var frames = stack . split ( "\n" ) ;
95- parsedStack = [ ] ;
96- var level = 0 ;
97-
98- var totalSizeInBytes = 0 ;
99- for ( var i = 0 ; i <= frames . length ; i ++ ) {
100- var frame = frames [ i ] ;
101- if ( _StackFrame . regex . test ( frame ) ) {
102- var parsedFrame = new _StackFrame ( frames [ i ] , level ++ ) ;
103- totalSizeInBytes += parsedFrame . sizeInBytes ;
104- parsedStack . push ( parsedFrame ) ;
105- }
106- }
107-
108- // DP Constraint - exception parsed stack must be < 32KB
109- // remove frames from the middle to meet the threshold
110- var exceptionParsedStackThreshold = 32 * 1024 ;
111- if ( totalSizeInBytes > exceptionParsedStackThreshold ) {
112- var left = 0 ;
113- var right = parsedStack . length - 1 ;
114- var size = 0 ;
115- var acceptedLeft = left ;
116- var acceptedRight = right ;
117-
118- while ( left < right ) {
119- // check size
120- var lSize = parsedStack [ left ] . sizeInBytes ;
121- var rSize = parsedStack [ right ] . sizeInBytes ;
122- size += lSize + rSize ;
123-
124- if ( size > exceptionParsedStackThreshold ) {
125-
126- // remove extra frames from the middle
127- var howMany = acceptedRight - acceptedLeft + 1 ;
128- parsedStack . splice ( acceptedLeft , howMany ) ;
129- break ;
130- }
131-
132- // update pointers
133- acceptedLeft = left ;
134- acceptedRight = right ;
135-
136- left ++ ;
137- right -- ;
138- }
139- }
140- }
141-
142- return parsedStack ;
143- }
144-
14564 public dispose ( ) {
14665 AutoCollectExceptions . INSTANCE = null ;
66+ this . enable ( false ) ;
14767 this . _isInitialized = false ;
14868 }
14969}
15070
151- class _StackFrame {
15271
153- // regex to match stack frames from ie/chrome/ff
154- // methodName=$2, fileName=$4, lineNo=$5, column=$6
155- public static regex = / ^ ( [ \s ] + a t ) ? ( .* ?) ( \@ | \s \( | \s ) ( [ ^ \( \@ \n ] + ) : ( [ 0 - 9 ] + ) : ( [ 0 - 9 ] + ) ( \) ? ) $ / ;
156- public static baseSize = 58 ; //'{"method":"","level":,"assembly":"","fileName":"","line":}'.length
157- public sizeInBytes = 0 ;
158- public level : number ;
159- public method : string ;
160- public assembly : string ;
161- public fileName : string ;
162- public line : number ;
163-
164- constructor ( frame : string , level : number ) {
165- this . level = level ;
166- this . method = "<no_method>" ;
167- this . assembly = Util . trim ( frame ) ;
168- var matches = frame . match ( _StackFrame . regex ) ;
169- if ( matches && matches . length >= 5 ) {
170- this . method = Util . trim ( matches [ 2 ] ) || this . method ;
171- this . fileName = Util . trim ( matches [ 4 ] ) || "<no_filename>" ;
172- this . line = parseInt ( matches [ 5 ] ) || 0 ;
173- }
174-
175- this . sizeInBytes += this . method . length ;
176- this . sizeInBytes += this . fileName . length ;
177- this . sizeInBytes += this . assembly . length ;
178-
179- // todo: these might need to be removed depending on how the back-end settles on their size calculation
180- this . sizeInBytes += _StackFrame . baseSize ;
181- this . sizeInBytes += this . level . toString ( ) . length ;
182- this . sizeInBytes += this . line . toString ( ) . length ;
183- }
184- }
18572
18673export = AutoCollectExceptions ;
0 commit comments