diff --git a/docs/Debugging.md b/docs/Debugging.md index a1163438fb..9431fec45d 100644 --- a/docs/Debugging.md +++ b/docs/Debugging.md @@ -54,9 +54,11 @@ YellowBoxes can be disabled during development by using `console.disableYellowBo ## Accessing logs -To view detailed logs on iOS, open your app in Xcode, then Build and Run your app on a device or the iPhone Simulator. The console should appear automatically after the app launches. If your app is failing to build, check the Issues Navigator in Xcode. +Run `react-native log-ios` in a terminal to display the logs for an iOS app running on a device or a simulator. -Run `adb logcat *:S ReactNative:V ReactNativeJS:V` in a terminal to display the logs for an Android app running on a device or an emulator. +You can also view the iOS logs in Xcode: open your app in Xcode, then Build and Run your app on a device or the iPhone Simulator. The console should appear automatically after the app launches. If your app is failing to build, check the Issues Navigator in Xcode. + +Run `react-native log-android` in a terminal to display the logs for an Android app running on a device or an emulator. ## Chrome Developer Tools diff --git a/local-cli/cliEntry.js b/local-cli/cliEntry.js index 3e726c5a4f..dd1c06dd87 100644 --- a/local-cli/cliEntry.js +++ b/local-cli/cliEntry.js @@ -19,7 +19,9 @@ const link = require('./rnpm/link/src/link'); const path = require('path'); const Promise = require('promise'); const runAndroid = require('./runAndroid/runAndroid'); +const logAndroid = require('./logAndroid/logAndroid'); const runIOS = require('./runIOS/runIOS'); +const logIOS = require('./logIOS/logIOS'); const server = require('./server/server'); const TerminalAdapter = require('yeoman-environment/lib/adapter.js'); const yeoman = require('yeoman-environment'); @@ -49,7 +51,9 @@ const documentedCommands = { 'new-library': [library, 'generates a native library bridge'], 'android': [generateWrapper, 'generates an Android project for your app'], 'run-android': [runAndroid, 'builds your app and starts it on a connected Android emulator or device'], + 'log-android': [logAndroid, 'print Android logs'], 'run-ios': [runIOS, 'builds your app and starts it on iOS simulator'], + 'log-ios': [logIOS, 'print iOS logs'], 'upgrade': [upgrade, 'upgrade your app\'s template files to the latest version; run this after ' + 'updating the react-native version in your package.json and running npm install'], 'link': [linkWrapper, 'link a library'], diff --git a/local-cli/logAndroid/logAndroid.js b/local-cli/logAndroid/logAndroid.js new file mode 100644 index 0000000000..ddb60fca0d --- /dev/null +++ b/local-cli/logAndroid/logAndroid.js @@ -0,0 +1,51 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ +'use strict'; + +const chalk = require('chalk'); +const child_process = require('child_process'); +const Promise = require('promise'); + +/** + * Starts adb logcat + */ +function logAndroid() { + return new Promise((resolve, reject) => { + _logAndroid(resolve, reject); + }); +} + +function _logAndroid(resolve, reject) { + try { + const adbPath = process.env.ANDROID_HOME + ? process.env.ANDROID_HOME + '/platform-tools/adb' + : 'adb'; + + const adbArgs = ['logcat', '*:S', 'ReactNative:V', 'ReactNativeJS:V']; + + console.log(chalk.bold( + `Starting the logger (${adbPath} ${adbArgs.join(' ')})...` + )); + + const log = child_process.spawnSync(adbPath, adbArgs, {stdio: 'inherit'}); + + if (log.error !== null) { + throw log.error; + } + + } catch (e) { + console.log(chalk.red( + 'adb invocation failed. Do you have adb in your PATH?' + )); + reject(); + return; + } +} + +module.exports = logAndroid; diff --git a/local-cli/logIOS/logIOS.js b/local-cli/logIOS/logIOS.js new file mode 100644 index 0000000000..728a060b24 --- /dev/null +++ b/local-cli/logIOS/logIOS.js @@ -0,0 +1,77 @@ +'use strict'; + +const chalk = require('chalk'); +const child_process = require('child_process'); +const os = require('os'); +const path = require('path'); +const Promise = require('promise'); + +/** + * Starts iOS device syslog tail + */ +function logIOS() { + return new Promise((resolve, reject) => { + _logIOS(resolve, reject); + }); +} + +function _logIOS(resolve, reject) { + let rawDevices; + + try { + rawDevices = child_process.execFileSync( + 'xcrun', ['simctl', 'list', 'devices', '--json'], {encoding: 'utf8'} + ); + } catch (e) { + console.log(chalk.red( + 'xcrun invocation failed. Please check that Xcode is installed.' + )); + reject(e); + return; + } + + const { devices } = JSON.parse(rawDevices); + + const device = _findAvailableDevice(devices); + if (device === undefined) { + console.log(chalk.red( + 'No active iOS device found' + )); + reject(); + } + + tailDeviceLogs(device.udid, reject); +} + +function _findAvailableDevice(devices) { + for (const key of Object.keys(devices)) { + for (const device of devices[key]) { + if (device.availability === '(available)' && device.state === 'Booted') { + return device; + } + } + } +} + +function tailDeviceLogs(udid, reject) { + const logDir = path.join( + os.homedir(), + 'Library', + 'Logs', + 'CoreSimulator', + udid, + 'asl', + ); + + const log = + child_process.spawnSync('syslog', ['-w', '-F', 'std', '-d', logDir], {stdio: 'inherit'}); + + if (log.error !== null) { + console.log(chalk.red( + 'syslog invocation failed.' + )); + reject(log.error); + } +} + +module.exports = logIOS;