Reputation: 151
When I have an error in my React Native app, the stack trace that is printed to the console points to index.bundle
instead of the original source code (see example below). Is there a way to configure React Native to use source maps so that the logs show up correctly?
This problem only occurs when throwing an error from an asynchronous callback or something outside of rendering. If I throw an error inside a component, then the error shows the correct stack trace in the console. Interestingly, the error shows the correct stack trace all the time in LogBox.
I am running this with react-native run-android
and viewing the logs through Metro. To clarify, I am trying to get this working for local debug builds, not production/release builds. Ideally the logs would show the correct stack in the console so that I do not have to symbolicate them manually or find the error in LogBox.
Example result from console.error:
Error: Connection closed
at anonymous (http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.myapp.local&modulesOnly=false&runModule=true:261835:40)
at forEach (native)
at flushVolatile (http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.myapp.local&modulesOnly=false&runModule=true:261833:33)
at anonymous (http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.myapp.local&modulesOnly=false&runModule=true:262065:20)
at apply (native)
Thank you in advance!
Upvotes: 12
Views: 3970
Reputation: 151
Answering my own question. I dug into the react-native code and discovered that LogBox symbolicates stack traces by making calls to the metro development server. Instead of replicating that logic, I made the hacky solution below that ties into LogBox. I'm sure there are better ways to do this, but it works.
import { observe as observeLogBoxLogs, symbolicateLogNow } from 'react-native/Libraries/LogBox/Data/LogBoxData';
// LogBox keeps all logs that you have not viewed yet.
// When a new log comes in, we only want to print out the new ones.
let lastCount = 0;
observeLogBoxLogs(data => {
const logs = Array.from(data.logs);
const symbolicatedLogs = logs.filter(log => log.symbolicated.stack?.length);
for (let i = lastCount; i < symbolicatedLogs.length; i++) {
// use log instead of warn/error to prevent resending error to LogBox
console.log(formatLog(symbolicatedLogs[i]));
}
lastCount = symbolicatedLogs.length;
// Trigger symbolication on remaining logs because
// logs do not symbolicate until you click on LogBox
logs.filter(log => log.symbolicated.status === 'NONE').forEach(log => symbolicateLogNow(log));
});
function formatLog(log) {
const stackLines = (log.symbolicated.stack || [])
.filter(line => !line.collapse)
.map(line => ` at ${line.methodName} (${line.file}:${line.lineNumber}:${line.column})`)
.join('\n');
return `Error has been symbolicated\nError: ${log.message.content}\n${stackLines}`;
}
The error appears twice in console, first as the original, second as the symbolicated version. Here's an example of the log output now:
WARN Error: Connection closed
Error: Connection closed
at anonymous (http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.logtest.local&modulesOnly=false&runModule=true:334491:50)
at forEach (native)
at flushVolatile (http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.logtest.local&modulesOnly=false&runModule=true:334489:43)
at anonymous (http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.logtest.local&modulesOnly=false&runModule=true:334721:30)
at call (native)
at emitNone (http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.logtest.local&modulesOnly=false&runModule=true:340110:33)
at emit (http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.logtest.local&modulesOnly=false&runModule=true:340191:23)
at anonymous (http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.logtest.local&modulesOnly=false&runModule=true:339907:24)
at anonymous (http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.logtest.local&modulesOnly=false&runModule=true:339889:30)
at apply (native)
at anonymous (http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.logtest.local&modulesOnly=false&runModule=true:347770:25)
at drainQueue (http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.logtest.local&modulesOnly=false&runModule=true:347735:45)
at apply (native)
at anonymous (http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.logtest.local&modulesOnly=false&runModule=true:31681:26)
at _callTimer (http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.logtest.local&modulesOnly=false&runModule=true:31605:17)
at callTimers (http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.logtest.local&modulesOnly=false&runModule=true:31801:19)
at apply (native)
at __callFunction (http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.logtest.local&modulesOnly=false&runModule=true:25085:36)
at anonymous (http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.logtest.local&modulesOnly=false&runModule=true:24813:31)
at __guard (http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.logtest.local&modulesOnly=false&runModule=true:25039:15)
at callFunctionReturnFlushedQueue (http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.logtest.local&modulesOnly=false&runModule=true:24812:21)
LOG Error has been symbolicated
Error: Connection closed
at Object.keys.forEach$argument_0 (/Users/georgeflug/projects/logtest/node_modules/mqtt/dist/mqtt.js:208:28)
at flushVolatile (/Users/georgeflug/projects/logtest/node_modules/mqtt/dist/mqtt.js:206:4)
at stream.on$argument_1 (/Users/georgeflug/projects/logtest/node_modules/mqtt/dist/mqtt.js:477:17)
at emitNone (/Users/georgeflug/projects/logtest/node_modules/mqtt/dist/mqtt.js:6471:4)
at emit (/Users/georgeflug/projects/logtest/node_modules/mqtt/dist/mqtt.js:6556:14)
at Duplexify.prototype._destroy (/Users/georgeflug/projects/logtest/node_modules/mqtt/dist/mqtt.js:6239:2)
at process.nextTick$argument_0 (/Users/georgeflug/projects/logteste/node_modules/mqtt/dist/mqtt.js:6221:4)
at Item.prototype.run (/Users/georgeflug/projects/logtest/node_modules/mqtt/dist/mqtt.js:13143:4)
at drainQueue (/Users/georgeflug/projects/logtest/node_modules/mqtt/dist/mqtt.js:13113:16)
Upvotes: 3
Reputation: 55
If you click on the stacktrace (for example in terminal) will it pull up your vscode with all the associated files and to this location? At least that you might be able to back where the issue is in code?
Upvotes: 0