diff --git a/src/apps.js b/src/apps.js index 219250dc8..5ea977031 100644 --- a/src/apps.js +++ b/src/apps.js @@ -41,6 +41,7 @@ exports = module.exports = { backup: backup, listBackups: listBackups, + getLocalLogfilePaths: getLocalLogfilePaths, getLogs: getLogs, start: start, @@ -1365,6 +1366,19 @@ function update(app, data, auditSource, callback) { }); } +function getLocalLogfilePaths(app) { + assert.strictEqual(typeof app, 'object'); + + const appId = app.id; + + var filePaths = []; + filePaths.push(path.join(paths.LOG_DIR, appId, 'apptask.log')); + filePaths.push(path.join(paths.LOG_DIR, appId, 'app.log')); + if (app.manifest.addons && app.manifest.addons.redis) filePaths.push(path.join(paths.LOG_DIR, `redis-${appId}/app.log`)); + + return filePaths; +} + function getLogs(app, options, callback) { assert.strictEqual(typeof app, 'object'); assert(options && typeof options === 'object'); @@ -1384,11 +1398,8 @@ function getLogs(app, options, callback) { var args = [ '--lines=' + lines ]; if (follow) args.push('--follow', '--retry', '--quiet'); // same as -F. to make it work if file doesn't exist, --quiet to not output file headers, which are no logs - args.push(path.join(paths.LOG_DIR, appId, 'apptask.log')); - args.push(path.join(paths.LOG_DIR, appId, 'app.log')); - if (app.manifest.addons && app.manifest.addons.redis) args.push(path.join(paths.LOG_DIR, `redis-${appId}/app.log`)); - var cp = spawn('/usr/bin/tail', args); + var cp = spawn('/usr/bin/tail', args.concat(getLocalLogfilePaths(app))); var transformStream = split(function mapper(line) { if (format !== 'json') return line + '\n'; diff --git a/src/appstore.js b/src/appstore.js index 575735fe2..bfbcf044b 100644 --- a/src/appstore.js +++ b/src/appstore.js @@ -32,6 +32,7 @@ var apps = require('./apps.js'), constants = require('./constants.js'), debug = require('debug')('box:appstore'), eventlog = require('./eventlog.js'), + path = require('path'), paths = require('./paths.js'), safe = require('safetydance'), semver = require('semver'), @@ -424,13 +425,28 @@ function createTicket(info, auditSource, callback) { enableSshIfNeeded(function (error) { if (error) return callback(error); - collectAppInfoIfNeeded(function (error, result) { + collectAppInfoIfNeeded(function (error, app) { if (error) return callback(error); - if (result) info.app = result; + if (app) info.app = app; info.supportEmail = constants.SUPPORT_EMAIL; // destination address for tickets - superagent.post(`${settings.apiServerOrigin()}/api/v1/ticket`).query({ accessToken: token }).send(info).timeout(10 * 1000).end(function (error, result) { + var req = superagent.post(`${settings.apiServerOrigin()}/api/v1/ticket`) + .query({ accessToken: token }) + .timeout(20 * 1000); + + // either send as JSON through body or as multipart, depending on attachments + if (info.app) { + req.field('infoJSON', JSON.stringify(info)); + + apps.getLocalLogfilePaths(info.app).forEach(function (filePath) { + req.attach(path.basename(filePath), filePath); + }); + } else { + req.send(info); + } + + req.end(function (error, result) { if (error && !error.response) return callback(new BoxError(BoxError.NETWORK_ERROR, error.message)); if (result.statusCode === 401) return callback(new BoxError(BoxError.INVALID_CREDENTIALS)); if (result.statusCode === 422) return callback(new BoxError(BoxError.LICENSE_ERROR, result.body.message));