Skip to content
This repository was archived by the owner on Apr 4, 2023. It is now read-only.

Commit 60e7dc7

Browse files
author
Dick Smith
committed
Add improved iOS logging
This addition adds more insight into iOS crashes, especially for failures in JS that result in the crash. Using this logging we were able to identify this issue: NativeScript/NativeScript#5475 which otherwise would have been impossible to trace, as it had a 5% repro among users but never occurred internally.
1 parent 9332d66 commit 60e7dc7

File tree

3 files changed

+274
-80
lines changed

3 files changed

+274
-80
lines changed

publish/scripts/installer.js

Lines changed: 97 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -292,28 +292,109 @@ function writeBuildscriptHook(enable) {
292292
console.log("Install Crashlytics buildscript hook.");
293293
try {
294294
var scriptContent =
295-
`var fs = require('fs-extra');
296-
var path = require('path');
297-
var xcode = require('xcode');
295+
`const fs = require('fs-extra');
296+
const path = require('path');
297+
const xcode = require('xcode');
298+
299+
const pattern1 = /\\n\\s*\\/\\/Crashlytics 1 BEGIN[\\s\\w]*\\/\\/Crashlytics 1 END.*\\n/m;
300+
const pattern2 = /\\n\\s*\\/\\/Crashlytics 2 BEGIN[\\s\\w]*\\/\\/Crashlytics 2 END.*\\n/m;
301+
const pattern3 = /\\n\\s*\\/\\/Crashlytics 3 BEGIN[\\s\\w]*\\/\\/Crashlytics 3 END.*\\n/m;
302+
303+
const string1 = \`
304+
//Crashlytics 1 BEGIN
305+
#else
306+
#import <Crashlytics/CLSLogging.h>
307+
#endif
308+
//Crashlytics 1 END
309+
\`;
310+
311+
const string2 = \`
312+
#if DEBUG
313+
#else
314+
//Crashlytics 2 BEGIN
315+
static int redirect_cls(const char *prefix, const char *buffer, int size) {
316+
CLSLog(@"%s: %.*s", prefix, size, buffer);
317+
return size;
318+
}
319+
320+
static int stderr_redirect(void *inFD, const char *buffer, int size) {
321+
return redirect_cls("stderr", buffer, size);
322+
}
298323
324+
static int stdout_redirect(void *inFD, const char *buffer, int size) {
325+
return redirect_cls("stdout", buffer, size);
326+
}
327+
//Crashlytics 2 END
328+
#endif
329+
\`;
330+
331+
const string3 = \`
332+
//Crashlytics 3 BEGIN
333+
#if DEBUG
334+
#else
335+
// Per https://docs.fabric.io/apple/crashlytics/enhanced-reports.html#custom-logs :
336+
// Crashlytics ensures that all log entries are recorded, even if the very next line of code crashes.
337+
// This means that logging must incur some IO. Be careful when logging in performance-critical areas.
338+
339+
// As per the note above, enabling this can affect performance if too much logging is present.
340+
// stdout->_write = stdout_redirect;
341+
342+
// stderr usually only occurs during critical failures;
343+
// so it is usually essential to identifying crashes, especially in JS
344+
stderr->_write = stderr_redirect;
345+
//Crashlytics 3 END
346+
#endif
347+
\`;
299348
300349
module.exports = function($logger, $projectData, hookArgs) {
301-
var platform = hookArgs.platform.toLowerCase();
350+
const platform = hookArgs.platform.toLowerCase();
302351
return new Promise(function(resolve, reject) {
303-
var isNativeProjectPrepared = !hookArgs.nativePrepare || !hookArgs.nativePrepare.skipNativePrepare;
352+
const isNativeProjectPrepared = !hookArgs.nativePrepare || !hookArgs.nativePrepare.skipNativePrepare;
304353
if (isNativeProjectPrepared) {
305354
try {
306355
if (platform === 'ios') {
307-
var appName = path.basename($projectData.projectDir);
308-
var sanitizedName = appName.split('').filter(function(c) { return /[a-zA-Z0-9]/.test(c); }).join('');
309-
var projectPath = path.join($projectData.platformsDir, 'ios', sanitizedName + '.xcodeproj', 'project.pbxproj');
310-
$logger.trace('Using Xcode project', projectPath);
311-
var xcodeProject = xcode.project(projectPath);
312-
xcodeProject.parseSync();
313-
var options = { shellPath: '/bin/sh', shellScript: '\${PODS_ROOT}/Fabric/run' };
314-
var buildPhase = xcodeProject.addBuildPhase([], 'PBXShellScriptBuildPhase', 'Configure Crashlytics', xcodeProject.getFirstTarget().uuid, options).buildPhase;
315-
fs.writeFileSync(projectPath, xcodeProject.writeSync());
316-
$logger.trace('Xcode project written');
356+
const sanitizedAppName = path.basename($projectData.projectDir).split('').filter((c) => /[a-zA-Z0-9]/.test(c)).join('');
357+
358+
// write buildscript for dSYM upload
359+
const xcodeProjectPath = path.join($projectData.platformsDir, 'ios', sanitizedAppName + '.xcodeproj', 'project.pbxproj');
360+
$logger.trace('Using Xcode project', xcodeProjectPath);
361+
if (fs.existsSync(xcodeProjectPath)) {
362+
var xcodeProject = xcode.project(xcodeProjectPath);
363+
xcodeProject.parseSync();
364+
var options = { shellPath: '/bin/sh', shellScript: '\${PODS_ROOT}/Fabric/run' };
365+
xcodeProject.addBuildPhase(
366+
[], 'PBXShellScriptBuildPhase', 'Configure Crashlytics', xcodeProject.getFirstTarget().uuid, options
367+
).buildPhase;
368+
fs.writeFileSync(xcodeProjectPath, xcodeProject.writeSync());
369+
$logger.trace('Xcode project written');
370+
} else {
371+
$logger.error(xcodeProjectPath + ' is missing.');
372+
reject()
373+
}
374+
375+
// Logging from stdout/stderr
376+
$logger.out('Add iOS crash logging');
377+
const mainmPath = path.join($projectData.platformsDir, 'ios', 'internal', 'main.m');
378+
if (fs.existsSync(mainmPath)) {
379+
let mainmContent = fs.readFileSync(mainmPath).toString();
380+
// string1
381+
mainmContent = pattern1.test(mainmPath)
382+
? mainmContent.replace(pattern1, string1)
383+
: mainmContent.replace(/(\\n#endif\\n)/, string1);
384+
// string2
385+
mainmContent = pattern2.test(mainmPath)
386+
? mainmContent.replace(pattern2, string2)
387+
: mainmContent.replace(/(\\nint main.*)/, string2 + '$1');
388+
// string3
389+
mainmContent = pattern3.test(mainmPath)
390+
? mainmContent.replace(pattern3, string3)
391+
: mainmContent.replace(/(int main.*\\n)/, '$1' + string3 + '\\n');
392+
fs.writeFileSync(mainmPath, mainmContent);
393+
} else {
394+
$logger.error(mainmPath + ' is missing.');
395+
reject()
396+
}
397+
317398
resolve();
318399
} else {
319400
resolve();
@@ -515,7 +596,7 @@ module.exports = function($logger, $projectData) {
515596
});
516597
};
517598
`;
518-
console.log("Writing 'firebase-build-gradle.js' to " + appRoot + "/hooks/after-prepare");
599+
console.log("Writing 'firebase-build-gradle.js' to " + appRoot + "hooks/after-prepare");
519600
var scriptPath = path.join(appRoot, "hooks", "after-prepare", "firebase-build-gradle.js");
520601
fs.writeFileSync(scriptPath, scriptContent);
521602
} catch(e) {

src/package-lock.json

Lines changed: 80 additions & 48 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)