mirror of
https://github.com/zhigang1992/react-native.git
synced 2026-05-27 22:24:38 +08:00
Add function name, url, line, column to heap capture
Reviewed By: bnham Differential Revision: D3703012 fbshipit-source-id: 8e15deeeabe15da2a87a71c2baf0fa72d5bc6568
This commit is contained in:
committed by
Facebook Github Bot 7
parent
30847b2b35
commit
1199c5ade9
@@ -12,6 +12,100 @@
|
||||
const spawn = require('child_process').spawn;
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const http = require('http');
|
||||
const urlLib = require('url');
|
||||
const SourceMapConsumer = require('source-map').SourceMapConsumer;
|
||||
|
||||
|
||||
// url: string
|
||||
// onSuccess: function (SourceMapConsumer)
|
||||
// onFailure: function (string)
|
||||
function getSourceMapForUrl(url, onFailure, onSuccess) {
|
||||
if (!url) {
|
||||
onFailure('must provide a URL');
|
||||
return;
|
||||
}
|
||||
|
||||
const parsedUrl = urlLib.parse(url);
|
||||
const options = {
|
||||
host: 'localhost',
|
||||
port: parsedUrl.port,
|
||||
path: parsedUrl.pathname.replace(/\.bundle$/, '.map') + parsedUrl.search,
|
||||
};
|
||||
|
||||
http.get(options, (res) => {
|
||||
res.setEncoding('utf8');
|
||||
let sawEnd = false;
|
||||
let resBody = '';
|
||||
res.on('data', (chunk) => {
|
||||
resBody += chunk;
|
||||
}).on('end', () => {
|
||||
sawEnd = true;
|
||||
onSuccess(new SourceMapConsumer(resBody));
|
||||
}).on('close', (err) => {
|
||||
if (!sawEnd) {
|
||||
onFailure('Connection terminated prematurely because of: '
|
||||
+ err.code + ' for url: ' + url);
|
||||
}
|
||||
});
|
||||
}).on('error', (err) => {
|
||||
onFailure('Could not get response from: ' + url + ', error: ' + err.message);
|
||||
});
|
||||
}
|
||||
|
||||
// capture: capture object
|
||||
// onSuccess: function (Map of url -> SourceMapConsumer)
|
||||
// onFailure: function (string)
|
||||
function getSourceMapsForCapture(capture, onFailure, onSuccess) {
|
||||
const urls = new Set();
|
||||
const sourcemaps = new Map();
|
||||
for (const id in capture.refs) {
|
||||
const ref = capture.refs[id];
|
||||
if (ref.type === 'Function' && ref.value && !!ref.value.url) {
|
||||
urls.add(ref.value.url);
|
||||
}
|
||||
}
|
||||
urls.forEach((url) => {
|
||||
getSourceMapForUrl(url, onFailure, (sourcemap) => {
|
||||
sourcemaps.set(url, sourcemap);
|
||||
urls.delete(url);
|
||||
if (urls.size === 0) {
|
||||
onSuccess(sourcemaps);
|
||||
}
|
||||
});
|
||||
});
|
||||
if (urls.size === 0) {
|
||||
console.warn('No source information found in capture');
|
||||
onSuccess(sourcemaps);
|
||||
}
|
||||
}
|
||||
|
||||
// capture: capture object
|
||||
// onSuccess: function (capture object)
|
||||
// onFailure: function (string)
|
||||
function symbolocateHeapCaptureFunctions(capture, onFailure, onSuccess) {
|
||||
getSourceMapsForCapture(capture, onFailure, (sourcemaps) => {
|
||||
for (const id in capture.refs) {
|
||||
const ref = capture.refs[id];
|
||||
if (ref.type === 'Function' && ref.value && !!ref.value.url) {
|
||||
const sourcemap = sourcemaps.get(ref.value.url);
|
||||
const original = sourcemap.originalPositionFor({
|
||||
line: ref.value.line,
|
||||
column: ref.value.col,
|
||||
});
|
||||
if (original.name) {
|
||||
ref.value.name = original.name;
|
||||
} else if (!ref.value.name) {
|
||||
ref.value.name = path.posix.basename(original.source) + ':' + original.line;
|
||||
}
|
||||
ref.value.url = 'file://' + original.source;
|
||||
ref.value.line = original.line;
|
||||
ref.value.col = original.column;
|
||||
}
|
||||
}
|
||||
onSuccess(capture);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = function(req, res, next) {
|
||||
if (req.url !== '/jscheapcaptureupload') {
|
||||
@@ -19,35 +113,41 @@ module.exports = function(req, res, next) {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('Downloading Heap Capture');
|
||||
var preload = path.join(__dirname, 'heapCapture/preLoadedCapture.js');
|
||||
fs.writeFileSync(preload, 'var preLoadedCapture = ');
|
||||
fs.appendFileSync(preload, req.rawBody);
|
||||
fs.appendFileSync(preload, ';');
|
||||
res.end();
|
||||
const captureDir = path.join(__dirname, 'heapCapture/captures');
|
||||
if (!fs.existsSync(captureDir)) {
|
||||
fs.mkdirSync(captureDir);
|
||||
}
|
||||
console.log('Packaging Trace');
|
||||
var captureHtml = captureDir + '/capture_' + Date.now() + '.html';
|
||||
var capture = fs.createWriteStream(captureHtml);
|
||||
var inliner = spawn(
|
||||
'inliner',
|
||||
['--nocompress', 'heapCapture.html'],
|
||||
{ cwd: path.join(__dirname, '/heapCapture/'),
|
||||
stdio: [ process.stdin, 'pipe', process.stderr ],
|
||||
});
|
||||
inliner.stdout.pipe(capture);
|
||||
inliner.on('error', (err) => {
|
||||
console.error('Error processing heap capture: ' + err.message);
|
||||
console.error('make sure you have installed inliner with \'npm install inliner -g\'');
|
||||
});
|
||||
inliner.on('exit', (code, signal) => {
|
||||
if (code === 0) {
|
||||
console.log('Heap capture written to: ' + captureHtml);
|
||||
} else {
|
||||
console.error('Error processing heap capture, inliner returned code: ' + code);
|
||||
console.log('Symbolocating Heap Capture');
|
||||
symbolocateHeapCaptureFunctions(JSON.parse(req.rawBody), (err) => {
|
||||
console.error('Error when symbolicating: ' + err);
|
||||
},
|
||||
(capture) => {
|
||||
res.end();
|
||||
const preload = path.join(__dirname, 'heapCapture/preLoadedCapture.js');
|
||||
fs.writeFileSync(preload, 'var preLoadedCapture = ');
|
||||
fs.appendFileSync(preload, JSON.stringify(capture));
|
||||
fs.appendFileSync(preload, ';');
|
||||
const captureDir = path.join(__dirname, 'heapCapture/captures');
|
||||
if (!fs.existsSync(captureDir)) {
|
||||
fs.mkdirSync(captureDir);
|
||||
}
|
||||
console.log('Packaging Trace');
|
||||
var captureHtml = captureDir + '/capture_' + Date.now() + '.html';
|
||||
var capture = fs.createWriteStream(captureHtml);
|
||||
var inliner = spawn(
|
||||
'inliner',
|
||||
['--nocompress', 'heapCapture.html'],
|
||||
{ cwd: path.join(__dirname, '/heapCapture/'),
|
||||
stdio: [ process.stdin, 'pipe', process.stderr ],
|
||||
});
|
||||
inliner.stdout.pipe(capture);
|
||||
inliner.on('error', (err) => {
|
||||
console.error('Error processing heap capture: ' + err.message);
|
||||
console.error('make sure you have installed inliner with \'npm install inliner -g\'');
|
||||
});
|
||||
inliner.on('exit', (code, signal) => {
|
||||
if (code === 0) {
|
||||
console.log('Heap capture written to: ' + captureHtml);
|
||||
} else {
|
||||
console.error('Error processing heap capture, inliner returned code: ' + code);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user