mirror of
https://github.com/appium/appium.git
synced 2026-04-29 23:09:31 -05:00
180 lines
5.5 KiB
JavaScript
180 lines
5.5 KiB
JavaScript
"use strict";
|
|
|
|
var spawn = require('win-spawn')
|
|
, through = require('through')
|
|
, path = require('path')
|
|
, fs = require('fs')
|
|
, _ = require('underscore')
|
|
, glob = require('glob')
|
|
, logger = require('../../server/logger.js').get('appium');
|
|
|
|
// Date-Utils: Polyfills for the Date object
|
|
require('date-utils');
|
|
|
|
var IosLog = function (opts) {
|
|
this.udid = opts.udid;
|
|
this.xcodeVersion = opts.xcodeVersion;
|
|
this.debugMode = opts.debug;
|
|
this.debugTrace = opts.debugTrace;
|
|
this.proc = null;
|
|
this.onIosLogStart = null;
|
|
this.iosLogStarted = false;
|
|
this.iosLogStartTime = null;
|
|
this.calledBack = false;
|
|
this.logs = [];
|
|
this.logRow = "";
|
|
this.logsSinceLastRequest = [];
|
|
|
|
if (this.xcodeVersion === null) {
|
|
logger.warn("Xcode version passed into log capture code as null, assuming Xcode 5");
|
|
this.xcodeVersion = '5.0';
|
|
}
|
|
|
|
};
|
|
|
|
IosLog.prototype.debug = function (msg) {
|
|
if (this.debugMode) {
|
|
var log = "[IOS_SYSLOG_CAPTURE] " + msg;
|
|
logger.debug(log.grey);
|
|
}
|
|
};
|
|
|
|
IosLog.prototype.startCapture = function (cb) {
|
|
this.onIosLogStart = cb;
|
|
// Select cmd for log capture
|
|
if (this.udid) {
|
|
var spawnEnv = _.clone(process.env);
|
|
var limdDir = path.resolve(__dirname,
|
|
"../../../build/libimobiledevice-macosx/");
|
|
spawnEnv.PATH = process.env.PATH + ":" + limdDir;
|
|
spawnEnv.DYLD_LIBRARY_PATH = limdDir + ":" + process.env.DYLD_LIBRARY_PATH;
|
|
logger.info("Starting iOS device log capture via idevicesyslog");
|
|
this.proc = spawn("idevicesyslog", ["-u", this.udid], {env: spawnEnv});
|
|
this.finishStartingLogCapture(cb);
|
|
} else {
|
|
if (parseInt(this.xcodeVersion.split(".")[0], 10) >= 5) {
|
|
logger.info("Starting iOS 7.* simulator log capture");
|
|
var sim7LogsPath = path.resolve(process.env.HOME, "Library", "Logs", "iOS Simulator");
|
|
glob(sim7LogsPath + "/7.*/system.log", function (err, files) {
|
|
if (err || files.length < 1) {
|
|
logger.error("Could not start log capture because no iOS 7 " +
|
|
"simulator logs could be found at " + sim7LogsPath + "/7.*. " +
|
|
"Logging will not be functional for this run");
|
|
return cb();
|
|
} else {
|
|
var lastModifiedLogPath = files[0]
|
|
, lastModifiedLogTime = fs.statSync(files[0]).mtime;
|
|
_.each(files, function (file) {
|
|
var mtime = fs.statSync(file).mtime;
|
|
if (mtime > lastModifiedLogTime) {
|
|
lastModifiedLogPath = file;
|
|
lastModifiedLogTime = mtime;
|
|
}
|
|
});
|
|
this.proc = spawn("tail", ["-f", "-n", "1", lastModifiedLogPath]);
|
|
// -n 1 is used so that tail returns a line that lets this process know that the
|
|
// first line returned wasn't from stderr so it can tell the tailing was successful
|
|
this.finishStartingLogCapture(cb);
|
|
}
|
|
}.bind(this));
|
|
} else {
|
|
logger.info("Starting iOS 6.* simulator log capture");
|
|
this.proc = spawn("tail", ["-f", "-n", "1", "/var/log/system.log"]);
|
|
this.finishStartingLogCapture(cb);
|
|
}
|
|
}
|
|
};
|
|
|
|
IosLog.prototype.finishStartingLogCapture = function (cb) {
|
|
this.proc.stdout.setEncoding('utf8');
|
|
this.proc.stderr.setEncoding('utf8');
|
|
this.proc.on('error', function (err) {
|
|
logger.error("iOS log capture failed: " + err.message);
|
|
if (!this.calledBack) {
|
|
this.calledBack = true;
|
|
cb(err);
|
|
}
|
|
}.bind(this));
|
|
this.proc.stdout.pipe(through(this.onStdout.bind(this)));
|
|
this.proc.stderr.pipe(through(this.onStderr.bind(this)));
|
|
};
|
|
|
|
IosLog.prototype.stopCapture = function () {
|
|
logger.info("Stopping iOS log capture");
|
|
this.proc.kill();
|
|
this.proc = null;
|
|
};
|
|
|
|
IosLog.prototype.onStdout = function (data) {
|
|
if (!this.calledBack) {
|
|
// don't store the first line of the log because it came before the sim or device was launched
|
|
this.onOutput(data);
|
|
} else {
|
|
this.logRow += data;
|
|
if (data.substr(-1, 1) === "\n") {
|
|
this.onOutput(data, "");
|
|
this.logRow = "";
|
|
}
|
|
}
|
|
};
|
|
|
|
IosLog.prototype.onStderr = function (data) {
|
|
if (/execvp\(\)/.test(data)) {
|
|
logger.error("iOS log capture process failed to start");
|
|
if (!this.calledBack) {
|
|
this.calledBack = true;
|
|
this.onIosLogStart(new Error("iOS log capture process failed to start"));
|
|
return;
|
|
}
|
|
}
|
|
this.onOutput(data, ' STDERR');
|
|
};
|
|
|
|
IosLog.prototype.onOutput = function (data, prefix) {
|
|
if (!this.iosLogStarted) {
|
|
this.iosLogStarted = true;
|
|
this.iosLogStartTime = new Date();
|
|
if (!this.calledBack) {
|
|
this.calledBack = true;
|
|
this.onIosLogStart();
|
|
}
|
|
}
|
|
var logs = this.logRow.split("\n");
|
|
_.each(logs, function (log) {
|
|
log = log.trim();
|
|
if (log) {
|
|
// Filter old log rows
|
|
var logRowParts = log.split(" ");
|
|
var logRowDate = new Date(
|
|
Date.parse(this.iosLogStartTime.getFullYear() + " " + logRowParts[0] + " " + logRowParts[1] + " " + logRowParts[2])
|
|
);
|
|
if (!this.udid || logRowDate.isAfter(this.iosLogStartTime)) {
|
|
var logObj = {
|
|
timestamp: Date.now()
|
|
, level: 'ALL'
|
|
, message: log
|
|
};
|
|
this.logs.push(logObj);
|
|
this.logsSinceLastRequest.push(logObj);
|
|
if (this.debugMode || this.debugTrace) {
|
|
logger.debug('[IOS_SYSLOG_ROW ' + prefix + '] ' + log);
|
|
}
|
|
}
|
|
}
|
|
}.bind(this));
|
|
};
|
|
|
|
IosLog.prototype.getLogs = function () {
|
|
var ret = this.logsSinceLastRequest;
|
|
this.logsSinceLastRequest = [];
|
|
return ret;
|
|
};
|
|
|
|
IosLog.prototype.getAllLogs = function () {
|
|
return this.logs;
|
|
};
|
|
|
|
module.exports = function (opts) {
|
|
return new IosLog(opts);
|
|
};
|