2017-09-25 22:00:19 +00:00
|
|
|
const electron = require('electron');
|
|
|
|
const bunyan = require('bunyan');
|
|
|
|
const _ = require('lodash');
|
|
|
|
|
|
|
|
|
|
|
|
const ipc = electron.ipcRenderer;
|
|
|
|
const PHONE_REGEX = /\+\d{7,12}(\d{3})/g;
|
2017-09-25 23:41:57 +00:00
|
|
|
const GROUP_REGEX = /(group\()([^)]+)(\))/g;
|
2017-09-25 22:00:19 +00:00
|
|
|
|
|
|
|
// Default Bunyan levels: https://github.com/trentm/node-bunyan#levels
|
|
|
|
// To make it easier to visually scan logs, we make all levels the same length
|
|
|
|
const BLANK_LEVEL = ' ';
|
|
|
|
const LEVELS = {
|
|
|
|
60: 'fatal',
|
|
|
|
50: 'error',
|
|
|
|
40: 'warn ',
|
|
|
|
30: 'info ',
|
|
|
|
20: 'debug',
|
|
|
|
10: 'trace',
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// Backwards-compatible logging, simple strings and no level (defaulted to INFO)
|
|
|
|
|
2017-09-25 23:41:57 +00:00
|
|
|
function redactPhone(text) {
|
|
|
|
return text.replace(PHONE_REGEX, "+[REDACTED]$1");
|
|
|
|
}
|
|
|
|
|
|
|
|
function redactGroup(text) {
|
|
|
|
return text.replace(GROUP_REGEX, function(match, before, id, after) {
|
|
|
|
return before + '[REDACTED]' + id.slice(-3) + after;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2017-09-25 22:00:19 +00:00
|
|
|
function now() {
|
|
|
|
const date = new Date();
|
|
|
|
return date.toJSON();
|
|
|
|
}
|
|
|
|
|
|
|
|
function log() {
|
|
|
|
const args = Array.prototype.slice.call(arguments, 0);
|
|
|
|
|
|
|
|
const consoleArgs = ['INFO ', now()].concat(args);
|
|
|
|
console._log.apply(console, consoleArgs);
|
|
|
|
|
2017-10-04 21:03:59 +00:00
|
|
|
// To avoid [Object object] in our log since console.log handles non-strings smoothly
|
|
|
|
const str = args.map(function(item) {
|
|
|
|
if (typeof item !== 'string') {
|
|
|
|
try {
|
|
|
|
return JSON.stringify(item);
|
|
|
|
}
|
|
|
|
catch (e) {
|
|
|
|
return item;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return item;
|
|
|
|
});
|
|
|
|
const toSend = redactGroup(redactPhone(str.join(' ')));
|
|
|
|
ipc.send('log-info', toSend);
|
2017-09-25 22:00:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (window.console) {
|
|
|
|
console._log = console.log;
|
|
|
|
console.log = log;
|
2017-09-25 22:32:31 +00:00
|
|
|
}
|
2017-09-25 22:00:19 +00:00
|
|
|
|
|
|
|
|
|
|
|
// The mechanics of preparing a log for publish
|
|
|
|
|
|
|
|
function getHeader() {
|
|
|
|
return window.navigator.userAgent + ' node/' + window.config.node_version;
|
|
|
|
}
|
|
|
|
|
|
|
|
function getLevel(level) {
|
|
|
|
var text = LEVELS[level];
|
|
|
|
if (!text) {
|
|
|
|
return BLANK_LEVEL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return text.toUpperCase();
|
|
|
|
}
|
|
|
|
|
|
|
|
function formatLine(entry) {
|
|
|
|
return getLevel(entry.level) + ' ' + entry.time + ' ' + entry.msg;
|
|
|
|
}
|
|
|
|
|
|
|
|
function format(entries) {
|
2017-09-25 23:41:57 +00:00
|
|
|
return redactGroup(redactPhone(entries.map(formatLine).join('\n')));
|
2017-09-25 22:00:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function fetch() {
|
2017-10-04 21:40:35 +00:00
|
|
|
return new Promise(function(resolve) {
|
|
|
|
ipc.send('fetch-log');
|
|
|
|
|
|
|
|
ipc.on('fetched-log', function(event, text) {
|
|
|
|
var result = getHeader() + '\n' + format(text);
|
|
|
|
resolve(result);
|
|
|
|
});
|
|
|
|
});
|
2017-09-25 22:32:31 +00:00
|
|
|
}
|
2017-09-25 22:00:19 +00:00
|
|
|
|
|
|
|
function publish(log) {
|
|
|
|
log = log || fetch();
|
|
|
|
|
|
|
|
return new Promise(function(resolve) {
|
|
|
|
const payload = textsecure.utils.jsonThing({
|
|
|
|
files: {
|
|
|
|
'debugLog.txt': {
|
|
|
|
content: log
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
$.post('https://api.github.com/gists', payload)
|
|
|
|
.then(function(response) {
|
|
|
|
console._log('Posted debug log to ', response.html_url);
|
|
|
|
resolve(response.html_url);
|
|
|
|
})
|
|
|
|
.fail(resolve);
|
|
|
|
});
|
2017-09-25 22:32:31 +00:00
|
|
|
}
|
2017-09-25 22:00:19 +00:00
|
|
|
|
|
|
|
|
|
|
|
// A modern logging interface for the browser
|
|
|
|
|
|
|
|
// We create our own stream because we don't want to output JSON to the devtools console.
|
|
|
|
// Anyway, the default process.stdout stream goes to the command-line, not the devtools.
|
|
|
|
const logger = bunyan.createLogger({
|
|
|
|
name: 'log',
|
|
|
|
streams: [{
|
|
|
|
level: 'debug',
|
|
|
|
stream: {
|
|
|
|
write: function(entry) {
|
|
|
|
console._log(formatLine(JSON.parse(entry)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}]
|
|
|
|
});
|
|
|
|
|
|
|
|
// The Bunyan API: https://github.com/trentm/node-bunyan#log-method-api
|
|
|
|
function logAtLevel() {
|
|
|
|
const level = arguments[0];
|
|
|
|
const args = Array.prototype.slice.call(arguments, 1);
|
|
|
|
|
|
|
|
const ipcArgs = ['log-' + level].concat(args);
|
|
|
|
ipc.send.apply(ipc, ipcArgs);
|
|
|
|
|
|
|
|
logger[level].apply(logger, args);
|
|
|
|
}
|
|
|
|
|
|
|
|
window.log = {
|
|
|
|
fatal: _.partial(logAtLevel, 'fatal'),
|
|
|
|
error: _.partial(logAtLevel, 'error'),
|
|
|
|
warn: _.partial(logAtLevel, 'warn'),
|
|
|
|
info: _.partial(logAtLevel, 'info'),
|
|
|
|
debug: _.partial(logAtLevel, 'debug'),
|
|
|
|
trace: _.partial(logAtLevel, 'trace'),
|
|
|
|
fetch,
|
|
|
|
publish,
|
2017-09-25 22:32:31 +00:00
|
|
|
};
|
2017-09-25 22:00:19 +00:00
|
|
|
|
|
|
|
window.onerror = function(message, script, line, col, error) {
|
2017-10-02 21:13:27 +00:00
|
|
|
window.log.error(error.stack);
|
2017-09-25 22:00:19 +00:00
|
|
|
};
|
|
|
|
|