stacktracejs / stacktrace-gps Goto Github PK
View Code? Open in Web Editor NEWTurns partial code location into precise code location
Home Page: https://www.stacktracejs.com/#!/docs/stacktrace-gps
License: MIT License
Turns partial code location into precise code location
Home Page: https://www.stacktracejs.com/#!/docs/stacktrace-gps
License: MIT License
When doing bower install stacktrace-gps
the dist folder should be included, since the bower.json main property points to the js-file in the dist-folder
when doing bower install stacktrace-gps
there is no dist-folder. There is no folder structure, everything is in the root folder
When using wiredep this package's main file is not automatically injected in my index.html. I'm using stacktrace-js that have this package as a dependency, and the other packages it has as dependency is correctly injected but not this one.
Set main to not be dist/{file}.js but just ./{file}.js. I'm not sure why dist folder is not included, could be the ignore of **/.* ? If it is, maybe rethink that part so that dist-folder is included.
Currently we only fetch sources when the location.hostname
matches the domain of the source file.
Perhaps _getSource()
should utilize nodeJS flavor of resource fetching.
Seems that a dependency (source-map) is breaking this library
ReferenceError: identity is not defined
pointing to https://github.com/mozilla/source-map/blob/7c4905497b5f0a62fd6a3d3f786ba8eac0db4615/lib/util.js#L258Currently, the function declaration regex is too lenient and prone to matching invalid function names.
An example:
true ? warning(ReactCurrentOwner.current == null, '_renderNewRootComponent(): Render methods should be a pure function ' + 'of props and state; triggering nested component updates from ' + 'render is not allowed. If necessary, trigger nested updates in ' + 'componentDidUpdate. Check the render method of %s.', ReactCurrentOwner.current && ReactCurrentOwner.current.getName() || 'ReactCompositeComponent') : void 0;
yields
' + 'of props and state; triggering nested component updates from ' + 'render is not allowed. If necessary, trigger nested updates in ' + 'componentDidUpdate. Check the render method of %s.', ReactCurrentOwner.current && ReactCurrentOwner.current.getName
Proposed PR in #47.
I concatenate and minimize my JavaScript files with UglifyJS. I want to use StackTraceGPS to get the original file names and line numbers.
If I use the attached v2a.min.js and v2a.min.js.map (which includes the StackTraceJS distribution) and I want to get the information for that StackFrame:
gps.pinpoint({fileName:"http://localhost:8280/testmarvin/js/v2a.min.js", lineNumber:2, columnNumber:10174}).then(res => console.log(res), err=> console.error(err));
I expect to get the correct filename and line number
The pinpoint method returns the Error message "Found a source and line, but no column". I did not find any information to that error, I don't even find it in your source files... So what is wrong?
Use the attached minified JavaScript and SourceMap and call
var gps = new StackTraceGPS();
gps.pinpoint({fileName:"http://localhost:8280/testmarvin/js/v2a.min.js", lineNumber:2, columnNumber:10174}).then(res => console.log(res), err=> console.error(err));
This bug prevents me from using StackTraceGPS at all, because it does not give me any useful information. And it would be exactly what I need, because the stacktraces of the minified JavaScript files say nothing
chrome sometimes evaluates JS in a VM and js that is evaled or crammed into a script tag manually will have filename anonymous. this results in an invalid network request for the source. would be best to just check for filename === '' and not do the fetches
Hi,
i have a js bundle minified by ASP.NET Web Optimization and source maps generated by AspNetBundling. Mapped stack trace (after exception thrown) is working fine in Chrome but when i try to pinpoint a stackframe it gives me "sourceMappingURL not found" error.
Code for getting a stack:
var callback = function (stackframes) {
var gps = new StackTraceGPS();
_.each(stackframes, function (stackframe) {
console.info("Unpinned:");
console.log(stackframe);
gps.pinpoint(stackframe)
.then(function (pinned) {
console.log(pinned);
})
.catch(function (err) {
console.error(err);
});
});
};
var errback = function (err) {
console.log(err.message);
};
StackTrace.get().then(callback).catch(errback);
Single stackframe looks like this:
t {
fileName: "http://suzi/bundles/suzi?v=hf2njH4HOG6YMOecHaDuOrRx2tvdViVb8O5gT54rOzg1",
lineNumber: 1,
columnNumber: 211552,
source: " at http://suzi/bundles/suzi?v=hf2njH4HOG6YMOecHaDuOrRx2tvdViVb8O5gT54rOzg1:1:211552"}
Bundle is accessible and has proper sourceMappingURL attached:
This change 2004283#diff-a14450dbe613721f5b4d8361cc0e5ec0R244 has broken the inline source map support, as it causes the inline-source map to be fetched from the network with the base url prefixed.
Actual:
sourceMappingURL: "http://localhost:7000/sourcemapsexample/build/data:application/json;base64,eyJ2Z
Expected:
sourceMappingURL : "data:application/json;base64,e"
Every time pinpoint
is called a new SourceMap.SourceMapConsumer
object is created. Loading the source map into the consumer object is slow, so for multiple pinpoint
calls the mapConsumer should be re-used.
This change could be made without any changes to the API. However, caching the mapConsumer uses a lot of memory, so maybe this behavior should be opt-in only.
Maybe a cacheMapConsumers
boolean could be passed into the StacktraceGPS
constructor?
I can submit a PR if we can agree on an API.
I use StackTraceGPS. pinpoint to get the un-uglified stack but got error when stacktracegps starts to find my vendor code (REACT) from webpack.
Error:
Error: HTTP status: 0 retrieving webpack:///~/react/lib/ReactCompositeComponent.js at XMLHttpRequest.r.onreadystatechange
Webpack config: devtool: 'source-map', entry: './src/index', target: 'web', output: { path: __dirname + '/dist', // Note: Physical files are only output by the production build task
npm run build`.
publicPath: '/myapp/',
filename: 'bundle.js'
},
devServer: {
contentBase: './dist'
},
plugins: [
new webpack.DefinePlugin(GLOBALS),
new webpack.optimize.UglifyJsPlugin({
compress: { warnings: false },
output: { comments: false },
sourceMap: true
}),
new BundleAnalyzerPlugin({analyzerMode: 'static', generateStatsFile: true, openAnalyzer: false}),
extractSass
],
`
The source map should be used to locate the original source files and locations
If original source files cannot be obtained, an error is thrown which causes the entire source map to be ignored.
Have a setup where there is a source map, but the original source files are not available (only the bundled JS)
Trying to map errors before reporting them to Rollbar in an Electron app
https://github.com/stacktracejs/stacktrace-gps/compare/master...shadow-light:custom?expand=1
I' wondering why this is attempting to download all the sources, when it is embedded in the source map.
I first tried this lib, https://github.com/evanw/node-source-map-support which works fine in chrome, so I'm wondering can the same be done for safari, etc. with stacktrace.js?
The problem: often times file names in the source map are artificial, e.g. webpack://[name]/packages/client/src/layout/ModalPageLayout.tsx
. If the source map contains only line/column numbers and not the source code per se, then stacktrace-gps runs a separate XHR request to fetch such artificial files and of course fails. (Even if filenames are not artificial, it's unlikely that anyone will have source code files in production at all.)
A solution could be to have an option to turn off function name resolution if this resolution implies a network request. It sounds similar to offline:true
, but it's actually not: with offline:true
, even the *.map file won't be fetched, whilst for this particular issue, we need to fetch *.map and not to fetch individual source files.
I have a work-around for this though, but it's ugly:
const stackFrames = await StackTrace.fromError(error, {
// StackTract d.ts file is stale, it doesn't include ajax() hook
// supported by stacktrace-gps library, but we can use it actually.
ajax: async (location: string, opts: any) =>
location.startsWith("webpack://")
? ""
: fetch(location, opts).then(async (res) =>
res.status === 200 ? res.text() : ""
),
} as any);
Would it be possible to include the source maps dependency in the dist folder. I've had issues building it: mozilla/source-map#179 and it's not even included in their build (I can't just pull it in). This would be a huge help..
Also, I was wondering what all that library supports, it looks like it does everything but at the expense of being 25kb minified (which is pretty big to be sending down over the wire).
Is it possible to use stacktrace-gps as a standalone client to enhance stackframe in json format? How can i provide minified js app and relative source map to this standalone client(no browser)?
var fs = require('fs');
var StackTraceGPS = require('stacktrace-gps');
var obj = JSON.parse(fs.readFileSync('prova.json', 'utf8'));
console.log(obj);
var gps = new StackTraceGPS();
for (var i in obj){
var stackframe = obj[i];
var result = gps.getMappedLocation(stackframe);
console.log(result);
}
The current pattern used to locate sourceMappingURL is:
///[#@] ?sourceMappingURL=([^\s'"]+)\s*$/
It assumes that the line with sourceMappingURL is the last line in the file.
However, some libraries (like RequireJS most likely) append additional information labeled sourceURL at the end of the file so in my case it looks like below (the top of the file has been truncated):
[ng:cloak],[ng-cloak],[data-ng-cloak],[x-ng-cloak],.ng-cloak,.x-ng-cloak,.ng-hide:not(.ng-hide-animate){display:none !important;}ng:form{display:block;}.ng-animate-shim{visibility:hidden;}.ng-anchor{position:absolute;}</style>');
//# sourceMappingURL=angular.min.js.map
//# sourceURL=http://localhost:63342/AppRoot/public/libs/js/angular.min.js
In this case the current RegEx pattern does not work.
My temporary fix is to remove $ from the RegEx expression. It is not ideal but it works for me at this point. I hope that this issue will be addressed somehow in a future version.
Prevent network requests and use sensible defaults where possible.
_extractLocationInfoFromSourceMap
applies loc.name
for functionName blindly.
That function should generally take what's best of the original + source-mapped.
Not sure if doing something wrong, but it appears SourceMap is cased as sourceMap. For this reason
https://github.com/stacktracejs/stacktrace-gps/blob/master/dist/stacktrace-gps.js#L108 fails for me.
As a workaround Im currently renaming sourceMap to SourceMap. Btw, Im doing this in browser.
Hi,
Previous issue : #10
Something is still missing: the *.map
files are correctly resolved to be relative to the minified file, but the *.src
files are not resolved relative to their sourcemap files (they are resolved relative to the current directory, and end up 404ing).
Attempting to log and debug live errors on a site generated by create-react-app.
The gps object created with new StackTraceGPS() looks to be fine (sourceCache and sourceMapConsumerCache promises are fulfilled).
When using pinpoint it just returns original line and column with an added name of w:
source: main.c8f4e493.chunk.js line: 1 column 255531
source: /static/js/main.c8f4e493.chunk.js line: 1 column 255531 name: w
source: main.c8f4e493.chunk.js line: 1 column 6959
source: /static/js/main.c8f4e493.chunk.js line: 1 column 6959 name: w
source: main.c8f4e493.chunk.js line: 1 column 318036
source: /static/js/main.c8f4e493.chunk.js line: 1 column 318036 name: w
Any suggestions?
Identify cases where esprima could be utilized. May have to vet how OSS licensing works.
We would still have to fallback to conventional parsing for envs not supported by esprima.
Hi,
Suppose my location.href
is http://localhost/foo/
and I'm loading /bundle.js
which references a source map bundle.js.map
using just this relative path (e.g. just the filename).
stacktrace-gps currently resolves the sourcemap URL relative to the current page (implicitly, from what I can see) and will therefore try to load http://localhost/foo/bundle.js.map
. However, the URL should be resolved relative to the resource, i.e. to http://localhost/bundle.js.map
.
stacktrace-js depends on stack-generator, stacktrace-gps and error-stack-parser, but they are not encoded in the dependencies, so bower does not download them when you add a dependency on stacktrace-js.
Is there a reason why the dependencies are left out?
If _parseJson
(and internal JSON.parse
) throws an error, it will not be passed to reject
, so outer getMappedLocation
(and StackTrace.fromError
from stacktrace-js
) will never resolve/reject.
https://github.com/stacktracejs/stacktrace-gps/blob/v3.0.4/stacktrace-gps.js#L240-L251
var sourceMapConsumerPromise = new Promise(function(resolve, reject) {
return this._get(sourceMappingURL).then(function(sourceMapSource) {
if (typeof sourceMapSource === 'string') {
// throws from here vvv
sourceMapSource = _parseJson(sourceMapSource.replace(/^\)\]\}'/, ''));
}
if (typeof sourceMapSource.sourceRoot === 'undefined') {
sourceMapSource.sourceRoot = defaultSourceRoot;
}
resolve(new SourceMap.SourceMapConsumer(sourceMapSource));
}, reject); //<- not caught in here
}.bind(this));
Invalid source map errors can be caught by StackTrace.fromError(...).catch
an others.
Error becomes unhandled rejection and can not be caught.
Try to getMappedLocation
for source map with some invalid JSON content (for example <html
).
I'm trying to catch every possible error with addEventListener('error'
and addEventListener('unhandledrejection'
, enhance stack trace and send it to server. Currently, server is configured to respond with index.html
for non-exiting paths. If .map
file is missing for some reason, stacktrace-js
receives some HTML instead of JSON, fails and no error is sent at all.
What is worse, this unhandled rejection is caught by 'unhandledrejection'
handler and passed it to StackTrace.fromError
again, which results in an infinite loop.
- return this._get(sourceMappingURL).then(..., reject);
+ return this._get(sourceMappingURL).then(...).catch(reject);
The latest minor or point release of source-map
can be used
A specific version is installed
Install stacktrace-gps
This often results in multiple versions of source-map
being installed since many packages require a version later than the currently pinned version
Use ^
or ~
for the version specifier
Given an app hosted on example.com
referencing a javascript file script.js
hosted on cdn.example.com
. The html file on example.com
loads cdn.example.com/script.js
. An error is thrown, and stacktrace-gps is used to map the stacktrace with the sourcemap.
script.js
contains a source mapping url reference which is root relative.
//# sourceMappingURL=/script.js.map
The source map is loaded from cdn.example.com/script.js.map
.
The source map is attempted to be loaded from example.com/script.js.map
.
I managed to provoke a similar bug in the test suite.
it('should resolve a root relative url to a source map on the same hostname as the referencing asset', function(done) {
var source = 'var foo=function(){};function bar(){}var baz=eval("XXX");\n//# sourceMappingURL=/test.js.map';
jasmine.Ajax.stubRequest('http://localhost:9999/some/folder/test.js').andReturn({responseText: source});
jasmine.Ajax.stubRequest('http://localhost:9999/test.js.map').andReturn({status: 404});
var stackframe = new StackFrame({args: [], fileName: 'http://localhost:9999/some/folder/test.js', lineNumber: 23, columnNumber: 0});
new StackTraceGPS().getMappedLocation(stackframe).then(done.fail, done);
});
The test is adapted from #getMappedLocation rejects if source map file 404s
. It would pass if the URL to the source map was resolved correctly, but it will timeout as the code base is now.
This is not involving a CDN, but shows another example of how a root relative url should be resolved.
I used stacktrace-js when implementing crash reporting functionality for a large webapp I'm working on. I was trying to implement the mapping of errors client side, and this bug meant that none of the errors I ship back to my monitoring endpoint is mapped.
This section of getMappedLocation
should be extended to properly resolve root relative urls:
stacktrace-gps/stacktrace-gps.js
Lines 321 to 327 in 1b80f11
I can think of a few approaches:
A
-tag to parse the url: https://evanhahn.com/parse-urls-with-a-tags/Option 1 is probably not the most attractive option for client-side use of stacktrace-gps, and option 2 is problematic when dealing with node.js where the document apis are not available.
A hybrid approach would work well, but I'm not sure how we would go about doing that, as it really quickly gets in to specifics about build tools and process.
I would love to provide a PR instead of an issue, but I don't think that there's an obviously right solution here, so I'd like to consult you first.
In TypeScript, when using stacktrace-gps, the _findFunctionName
method's regular expression fails to match method names if a return type is specified.
The method name should be correctly identified in the stack trace, regardless of the presence of a typed return value in TypeScript.
method name is not correctly identified in the stack trace, , maybe I can get the name of the last method without the return type when lineNum less 20.
methodName(): ReturnType
I can't get the method name anymore, maybe I can get the name of the last method without the return type. My temporary solution is to drop the return type and use Typescript's automatic inference feature. But I would prefer to add a regular expression for this case directly in the _findFunctionName
syntaxes
add a regular expression for this case directly in the _findFunctionName
syntaxes
Say I have the return value of ErrorStackParser.parse()
and the related source map file, how do I combine those into a gps.pinpoint(frames[1])
call without just getting a bunch of errors?
I assume I'd need to use offline: true
in combination with sourceCache: something
, but how? It looks like it's trying to fetch the original, minified source file as well. Is this actually even needed, if I have the stack frames and the source map?
Finally, [ReferenceError: XMLHttpRequest is not defined]
tells me this may not have been designed to run on node. Would it be possible if sourceCache
made HTTP requests unnecessary?
https://sentry.engineering/blog/the-case-for-debug-ids
Detect debugId
instead of just sourceMappingURL
.
Related to #4, support multi-level source maps for dart, coffeescript or similar.
In angular9, I am getting the following error after installing StackTrace-Gps as a separate package to get unminifed location.
Uncaught Error: define cannot be used indirect
at push../node_modules/webpack/buildin/amd-define.js.module.exports (amd-define.js:2)
at Object. (source-map-generator.js:8)
at Object../node_modules/source-map/lib/source-map/source-map-generator.js (source-map-generator.js:399)
at webpack_require (bootstrap:79)
at Object../node_modules/source-map/lib/source-map.js (source-map.js:6)
at webpack_require (bootstrap:79)
at stacktrace-gps.js:7
at Object../node_modules/stacktrace-gps/stacktrace-gps.js (stacktrace-gps.js:13)
at webpack_require (bootstrap:79)
at stacktrace.js:7
code :
var gps = new StackTraceGPS();
// Pinpoint actual function name and source-mapped location
gps.findFunctionName(stackframes[0]).then((gpsStackFrame) => {
console.log(gpsStackFrame);
});
Here is how I am importing
import * as StackTrace from "stacktrace-js";
import * as StackTraceGPS from "stacktrace-gps";
The "fn_name() {" regex
โ/\b(?!(?:if|for|switch|while|with|catch)\b)(?:(?:static)\s+)?(\S+)\s*(.?)\s{/
should match code like
"fn_name() { stuff"
The regex matches this code
if (a) { foo(); } else if (b) { bar(); }
Falsely indicating that foo wraps bar.
Should be easy to reproduce with a new unit test.
Producing un-minifed stack-traces
I'm not familiar with this notation. Suggest removing this regex from the list.
This library should consume inline source maps in addition to those in separate files.
Ajax method should be updated to allow making cross-domain requests.
Hi,
When I try this (via stacktrace.js) with webpack + bluebird promise I see the following warning:
"Warning: a promise was created in a handler but was not returned from it"
The warning seems to think its coming from:
https://github.com/stacktracejs/stacktrace-gps/blob/master/stacktrace-gps.js#L172
StackTraceGPS: this._get = function _get(location) {
If this code is correct, can be it explicit so make bluebird not warn?
I have been using the 0.6 versions of stacktrace-js, but I was getting a warning from chrome about synchronous requests from the main thread being deprecated, so I am investigating updating to the new version.
The case I have is I want to augment a logging module to prefix the file:line:column to each log message, but because of the asynchronous nature of the interface that stacktrace-js exposes, it doesn't seem possible to do it.
I have hacked at the fromError method to remove the asynchronous interface and just return the stack frame array, and it seems to work, but I am no longer calling into the GPS module. I guess it's the GPS module that needs to download the source map.
It would be good to also provide an synchronous interface, e.g.:
70 /**
71 * Given an error object, parse it synchronously without source mapping.
72 * @param error Error object
73 * @param opts Object for options
74 * @return Array[StackFrame]
75 */
76 getStackFrames: function StackTrack$$getStackFrames(error, opts) {
77 opts = _merge(_options, opts);
78
79 var stackframes = ErrorStackParser.parse(error);
80
81 if (typeof opts.filter === 'function') {
82 stackframes = stackframes.filter(opts.filter);
83 }
84
85 return stackframes;
86 },
Sorry, I meant to file this issue against stacktrace-js, not stacktrace-gps.
I have many //# sourceMappingURL
throughout my webpack bundle, but the important one is the last one.
https://github.com/stacktracejs/stacktrace-gps/blob/master/stacktrace-gps.js#L129:
var m = /\/\/[#@] ?sourceMappingURL=([^\s'"]+)\s*$/m.exec(source);
It looks like the issue is the /m
multi-line matcher. Removing this will correctly use the last match in the file. Otherwise it will use the first one.
You can try it in http://www.regexr.com
\/\/[#@] ?sourceMappingURL=([^\s'"]+)\s*$
//# sourceMappingURL=index.js.map
//# sourceMappingURL=main.bundle.js.map
Version 3.0.0.
With a method that throws an error like:
static generate() {
throw new Error('Boom');
}
the function name generate
should be returned from _findFunctionName
Currently undefined
is returned from _findFunctionName
and a stack frame with an already populated function name from error.stack
is replaced as
{anonymous}()@webpack:///src/main/lib/foo.js:15:10
I'm glad to see you're exposing the source cache, but its not enough to allow source caches to inter-operate. This has been really giving me issues in chrome lately, which seems to have some weird issue where it waits for a long time (like 20seconds) before it fulfills the second request for the same file (really odd - kind of the opposite of how caching is supposed to work).
But in any case, something is needed to allow other libraries to know if a request has been begun already, so they know to wait for that request to finish and use its result. The way I would do this is set values in the cache to the promise rather than the returned string. That way, the cache is filled immediately upon request, and other viewers of the cache can simply wait on that promise instead of making their own duplicate request.
I'd be willing to help make that change if you'd like.
When using stacktrace-gps, sourcemaps should be fetched correctly, even from the filesystem.
AJAX of sourcemaps only works for HTTP.
file:///
My real-world situation is trying to use stacktrace-gps in a Cordova app. But I can imagine people might want to use the filesystem in other situations, too.
The issue is that stacktrace-gps depends on HTTP status codes. I fixed this issue for myself with a change to this line, simply assuming a success if the protocol was file:///
and there was responseText
. That's probably not the best solution, but it should be a start.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.