Skip to content

Commit eec9dde

Browse files
committed
Added the ability to register to window.onerror.
There are some bugs with window.onerror: stacktracejs/stacktrace.js#117
1 parent 166b9ad commit eec9dde

File tree

7 files changed

+96
-70
lines changed

7 files changed

+96
-70
lines changed

src/StackTrace.d.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22

33
declare module StackTrace {
44
interface StackTraceOptions {
5-
filter: (stackFrame:StackFrame) => boolean;
5+
filter?: (stackFrame:StackFrame) => boolean;
6+
sourceCache?: { URL:string };
7+
offline?: boolean;
68
}
79

810
interface StackFrame {

src/example/index.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
function getNonexistentData() {
2+
/* random comment */ nonexistentArray[arguments[0]]; // second random comment;
3+
}
4+
5+
function throwDivisionByZero() {
6+
return divide(10, 0);
7+
}
8+
9+
function throwIndexOutOfRange(indexer) {
10+
try {
11+
getNonexistentData(indexer);
12+
} catch (e) {
13+
Exceptionless.ExceptionlessClient.default.submitException(e);
14+
}
15+
}

src/example/math.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
function divide(numerator, denominator) {
2+
if (denominator == 0) {
3+
throw( "Division by zero." );
4+
}
5+
6+
return numerator / denominator;
7+
}

src/exceptionless.ts

Lines changed: 69 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
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

911
module 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 {

src/gulpfile.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ gulp.task('scripts', function() {
2727

2828
return eventStream.merge(
2929
tsResult.dts.pipe(gulp.dest('dist')),
30-
tsResult.js.pipe(sourcemaps.write())
30+
tsResult.js.pipe(sourcemaps.write('/'))
3131
.pipe(gulp.dest('dist'))
3232
);
3333
});

src/index.html

Lines changed: 0 additions & 34 deletions
This file was deleted.

src/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
"gulp-sourcemaps": "^1.5.1",
2626
"gulp-typescript": "^2.6.0",
2727
"gulp-util": "~3.0.4",
28+
"jasmine-core": "^2.2.0",
2829
"karma": "~0.12.31",
2930
"karma-chrome-launcher": "^0.1.7",
3031
"karma-cli": "0.0.4",

0 commit comments

Comments
 (0)