44// TODO: Process Errors
55// TODO: Handle Server Settings
66// TODO: Lock configuration.
7- // TODO: Look into using templated strings `${1 + 1}`
7+ // TODO: Look into using templated strings `${1 + 1}`.
8+ // TODO: Add plugin for populating module info.
9+ // TODO: Add plugin for populating defaults.
810
911module Exceptionless {
1012 export class ExceptionlessClient {
@@ -24,10 +26,15 @@ module Exceptionless {
2426 this . createException ( exception ) . submit ( ) ;
2527 }
2628
27- public submitUnhandledException ( exception :Error ) : void {
29+ public createUnhandledException ( exception :Error ) : EventBuilder {
2830 var builder = this . createException ( exception ) ;
2931 builder . pluginContextData . markAsUnhandledError ( ) ;
30- builder . submit ( ) ;
32+
33+ return builder ;
34+ }
35+
36+ public submitUnhandledException ( exception :Error ) : void {
37+ this . createUnhandledException ( exception ) . submit ( ) ;
3138 }
3239
3340 public createFeatureUsage ( feature :string ) : EventBuilder {
@@ -138,6 +145,37 @@ module Exceptionless {
138145 public getLastReferenceId ( ) : string {
139146 return this . config . lastReferenceIdManager . getLast ( ) ;
140147 }
148+
149+ public register ( ) : void {
150+ var oldOnErrorHandler :any = window . onerror ;
151+ ( < any > window ) . onerror = ( message :string , filename :string , lineno :number , colno :number , error :Error ) => {
152+ if ( error !== null ) {
153+ this . submitUnhandledException ( error ) ;
154+ } else {
155+ // Only message, filename and lineno work here.
156+ var e :IError = { message : message , stack_trace : [ { file_name : filename , line_number : lineno , column : colno } ] } ;
157+ this . createUnhandledException ( new Error ( message ) ) . setMessage ( message ) . setProperty ( '@error' , e ) . submit ( ) ;
158+ }
159+
160+ if ( oldOnErrorHandler ) {
161+ try {
162+ return oldOnErrorHandler ( message , filename , lineno , colno , error ) ;
163+ } catch ( e ) {
164+ this . config . log . error ( 'An error occurred while calling previous error handler: ' + e . message ) ;
165+ }
166+ }
167+
168+ return false ;
169+ }
170+ }
171+
172+ private static _instance :ExceptionlessClient = null ;
173+ public static get default ( ) {
174+ if ( ExceptionlessClient . _instance === null ) {
175+ ExceptionlessClient . _instance = new ExceptionlessClient ( null ) ;
176+ }
177+ return ExceptionlessClient . _instance ;
178+ }
141179 }
142180
143181 export class Configuration {
@@ -285,13 +323,15 @@ module Exceptionless {
285323 private _suspendProcessingUntil :Date ;
286324 private _discardQueuedItemsUntil :Date ;
287325 private _processingQueue :boolean = false ;
288- private _queueTimer :number = setInterval ( ( ) => this . onProcessQueue ( ) , 10000 ) ;
326+ private _queueTimer :number ;
289327
290328 constructor ( config :Configuration ) {
291329 this . _config = config ;
292330 }
293331
294332 public enqueue ( event :IEvent ) {
333+ this . ensureQueueTimer ( ) ;
334+
295335 if ( this . areQueuedItemsDiscarded ( ) ) {
296336 this . _config . log . info ( 'Queue items are currently being discarded. The event will not be queued.' ) ;
297337 return ;
@@ -303,6 +343,8 @@ module Exceptionless {
303343 }
304344
305345 public process ( ) {
346+ this . ensureQueueTimer ( ) ;
347+
306348 if ( this . _processingQueue ) {
307349 return ;
308350 }
@@ -392,13 +434,19 @@ module Exceptionless {
392434 }
393435 }
394436
395- private onProcessQueue ( ) {
437+ private ensureQueueTimer ( ) : void {
438+ if ( ! this . _queueTimer ) {
439+ this . _queueTimer = setInterval ( ( ) => this . onProcessQueue ( ) , 10000 ) ;
440+ }
441+ }
442+
443+ private onProcessQueue ( ) : void {
396444 if ( ! this . isQueueProcessingSuspended ( ) && ! this . _processingQueue ) {
397445 this . process ( ) ;
398446 }
399447 }
400448
401- public suspendProcessing ( durationInMinutes ?:number , discardFutureQueuedItems ?:boolean , clearQueue ?:boolean ) {
449+ public suspendProcessing ( durationInMinutes ?:number , discardFutureQueuedItems ?:boolean , clearQueue ?:boolean ) : void {
402450 if ( ! durationInMinutes || durationInMinutes <= 0 ) {
403451 durationInMinutes = 5 ;
404452 }
@@ -420,7 +468,7 @@ module Exceptionless {
420468 } catch ( Exception ) { }
421469 }
422470
423- private requeueEvents ( events :IEvent [ ] ) {
471+ private requeueEvents ( events :IEvent [ ] ) : void {
424472 this . _config . log . info ( 'Requeuing ' + events . length + ' events.' ) ;
425473
426474 for ( var index = 0 ; index < events . length ; index ++ ) {
@@ -907,21 +955,6 @@ module Exceptionless {
907955 return plugin . run ( context ) ;
908956 } ) ;
909957 } , Promise . resolve ( ) ) ;
910-
911- /*
912- for (var index = 0; index < context.client.config.plugins.length; index++) {
913- try {
914- var plugin = context.client.config.plugins[index];
915- plugin.run(context);
916- if (context.cancel) {
917- context.log.info('Event submission cancelled by plugin "' + plugin.name + '": id=' + context.event.reference_id + ' type=' + context.event.type);
918- return;
919- }
920- } catch (e) {
921- context.log.error('An error occurred while running ' + plugin.name + '.run(): ' + e.message);
922- }
923- }
924- */
925958 }
926959
927960 public static addDefaultPlugins ( config :Configuration ) : void {
@@ -961,23 +994,30 @@ module Exceptionless {
961994 }
962995
963996 context . event . type = 'error' ;
997+ if ( ! ! context . event . data [ '@error' ] ) {
998+ return Promise . resolve ( ) ;
999+ }
9641000
9651001 return StackTrace . fromError ( exception ) . then (
966- ( stackFrames : any [ ] ) => this . processError ( context , exception , stackFrames ) ,
967- ( ) => {
968- context . cancel = true ;
969- return Promise . reject ( new Error ( 'Unable to parse the exceptions stack trace. This exception will be discarded.' ) )
970- } ) ;
1002+ ( stackFrames : StackTrace . StackFrame [ ] ) => this . processError ( context , exception , stackFrames ) ,
1003+ ( ) => this . onParseError ( context )
1004+ ) ;
9711005 }
9721006
973- private processError ( context :Exceptionless . EventPluginContext , exception :Error , stackFrames : StackTrace . StackFrame [ ] ) {
1007+ private processError ( context :Exceptionless . EventPluginContext , exception :Error , stackFrames : StackTrace . StackFrame [ ] ) : Promise < any > {
9741008 var error :IError = {
9751009 message : exception . message ,
9761010 stack_trace : this . getStackFrames ( context , stackFrames || [ ] ) ,
977- modules : this . getModules ( context )
9781011 } ;
9791012
9801013 context . event . data [ '@error' ] = error ;
1014+
1015+ return Promise . resolve ( ) ;
1016+ }
1017+
1018+ private onParseError ( context :Exceptionless . EventPluginContext ) : Promise < any > {
1019+ context . cancel = true ;
1020+ return Promise . reject ( new Error ( 'Unable to parse the exceptions stack trace. This exception will be discarded.' ) )
9811021 }
9821022
9831023 private getStackFrames ( context :Exceptionless . EventPluginContext , stackFrames :StackTrace . StackFrame [ ] ) : IStackFrame [ ] {
@@ -995,11 +1035,6 @@ module Exceptionless {
9951035
9961036 return frames ;
9971037 }
998-
999- private getModules ( context :Exceptionless . EventPluginContext ) : IModule [ ] {
1000- // TODO Get a list of all loaded scripts.
1001- return [ ] ;
1002- }
10031038 }
10041039
10051040 interface IParameter {
0 commit comments