Skip to content

Commit 4c9683d

Browse files
author
Eric Wendelin
committed
Add StackTrace.instrument and StackTrace.deinstrument.
1 parent d3b31d4 commit 4c9683d

File tree

5 files changed

+196
-20
lines changed

5 files changed

+196
-20
lines changed

dist/stacktrace.js

Lines changed: 62 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,15 @@
5252
* @return Array[StackFrame]
5353
*/
5454
get: function StackTrace$$get(opts) {
55-
var err = new Error();
56-
if (err.stack || err['opera#sourceloc']) {
57-
return this.fromError(err, opts);
58-
} else {
59-
return this.generateArtificially(opts);
55+
try {
56+
// Error must be thrown to get stack in IE
57+
throw new Error();
58+
} catch (err) {
59+
if (err.stack || err['opera#sourceloc']) {
60+
return this.fromError(err, opts);
61+
} else {
62+
return this.generateArtificially(opts);
63+
}
6064
}
6165
},
6266

@@ -73,9 +77,12 @@
7377
if (typeof opts.filter === 'function') {
7478
stackframes = stackframes.filter(opts.filter);
7579
}
76-
resolve(Promise.all(stackframes.map(function(sf) {
80+
resolve(Promise.all(stackframes.map(function (sf) {
7781
return new Promise(function (resolve) {
78-
function resolveOriginal(_) { resolve(sf); }
82+
function resolveOriginal(_) {
83+
resolve(sf);
84+
}
85+
7986
new StackTraceGPS(opts).pinpoint(sf)
8087
.then(resolve, resolveOriginal)['catch'](resolveOriginal);
8188
});
@@ -95,6 +102,54 @@
95102
stackFrames = stackFrames.filter(opts.filter);
96103
}
97104
return Promise.resolve(stackFrames);
105+
},
106+
107+
/**
108+
* Given a function, wrap it such that invocations trigger a callback that
109+
* is called with a stack trace.
110+
*
111+
* @param {Function} fn to be instrumented
112+
* @param {Function} callback function to call with a stack trace on invocation
113+
* @param {Function} errback optional function to call with error if unable to get stack trace.
114+
* @param {Object} thisArg optional context object (e.g. window)
115+
*/
116+
instrument: function StackTrace$$instrument(fn, callback, errback, thisArg) {
117+
if (typeof fn !== 'function') {
118+
throw new Error('Cannot instrument non-function object');
119+
} else if (typeof fn.__stacktraceOriginalFn === 'function') {
120+
// Already instrumented, return given Function
121+
return fn;
122+
}
123+
124+
var instrumented = function StackTrace$$instrumented() {
125+
try {
126+
this.get().then(callback, errback)['catch'](errback);
127+
fn.apply(thisArg || this, arguments);
128+
} catch (e) {
129+
this.fromError(e).then(callback, errback)['catch'](errback);
130+
throw e;
131+
}
132+
}.bind(this);
133+
instrumented.__stacktraceOriginalFn = fn;
134+
135+
return instrumented;
136+
},
137+
138+
/**
139+
* Given a function that has been instrumented,
140+
* revert the function to it's original (non-instrumented) state.
141+
*
142+
* @param fn {Function}
143+
*/
144+
deinstrument: function StackTrace$$deinstrument(fn) {
145+
if (typeof fn !== 'function') {
146+
throw new Error('Cannot de-instrument non-function object');
147+
} else if (typeof fn.__stacktraceOriginalFn === 'function') {
148+
return fn.__stacktraceOriginalFn;
149+
} else {
150+
// Function not instrumented, return original
151+
return fn;
152+
}
98153
}
99154
};
100155
}));

0 commit comments

Comments
 (0)