2018-03-05 21:05:43 +00:00
|
|
|
/* eslint-env node */
|
|
|
|
|
2018-07-21 19:00:08 +00:00
|
|
|
/* eslint-disable no-console */
|
2018-03-05 21:07:06 +00:00
|
|
|
|
2017-09-25 22:00:19 +00:00
|
|
|
const electron = require('electron');
|
|
|
|
const _ = require('lodash');
|
2018-03-06 23:58:01 +00:00
|
|
|
|
|
|
|
const debuglogs = require('./modules/debuglogs');
|
2018-03-06 21:20:04 +00:00
|
|
|
const Privacy = require('./modules/privacy');
|
2019-09-26 19:56:31 +00:00
|
|
|
const { createBatcher } = require('../ts/util/batcher');
|
2017-09-25 22:00:19 +00:00
|
|
|
|
|
|
|
const ipc = electron.ipcRenderer;
|
|
|
|
|
|
|
|
// 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)
|
|
|
|
function now() {
|
|
|
|
const date = new Date();
|
|
|
|
return date.toJSON();
|
|
|
|
}
|
|
|
|
|
2018-07-21 19:00:08 +00:00
|
|
|
// To avoid [Object object] in our log since console.log handles non-strings smoothly
|
|
|
|
function cleanArgsForIPC(args) {
|
2018-04-27 21:25:04 +00:00
|
|
|
const str = args.map(item => {
|
2017-10-04 21:03:59 +00:00
|
|
|
if (typeof item !== 'string') {
|
|
|
|
try {
|
|
|
|
return JSON.stringify(item);
|
2018-03-05 21:14:22 +00:00
|
|
|
} catch (error) {
|
2017-10-04 21:03:59 +00:00
|
|
|
return item;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return item;
|
|
|
|
});
|
2018-03-06 17:46:38 +00:00
|
|
|
|
2018-07-21 19:00:08 +00:00
|
|
|
return str.join(' ');
|
|
|
|
}
|
|
|
|
|
|
|
|
function log(...args) {
|
|
|
|
logAtLevel('info', 'INFO ', ...args);
|
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() {
|
Beta versions support: SxS support, in-app env/instance display (#1606)
* Script for beta config; unique data dir, in-app env/type display
To release a beta build, increment the version and add -beta-N to the
end, then go through all the standard release activities.
The prepare-build npm script then updates key bits of the package.json
to ensure that the beta build can be installed alongside a production
build. This includes a new name ('Signal Beta') and a different location
for application data.
Note: Beta builds can be installed alongside production builds.
As part of this, a couple new bits of data are shown across the app:
- Environment (development or test, not shown if production)
- App Instance (disabled in production; used for multiple accounts)
These are shown in:
- The window title - both environment and app instance. You can tell
beta builds because the app name, preceding these data bits, is
different.
- The about window - both environment and app instance. You can tell
beta builds from the version number.
- The header added to the debug log - just environment. The version
number will tell us if it's a beta build, and app instance isn't
helpful.
* Turn on single-window mode in non-production modes
Because it's really frightening when you see 'unable to read from db'
errors in the console.
* aply.sh: More instructions for initial setup and testing
* Gruntfile: Get consistent with use of package.json datas
* Linux: manually update desktop keys, since macros not available
2017-10-30 20:57:13 +00:00
|
|
|
let header = window.navigator.userAgent;
|
|
|
|
|
2018-06-02 00:55:35 +00:00
|
|
|
header += ` node/${window.getNodeVersion()}`;
|
|
|
|
header += ` env/${window.getEnvironment()}`;
|
Beta versions support: SxS support, in-app env/instance display (#1606)
* Script for beta config; unique data dir, in-app env/type display
To release a beta build, increment the version and add -beta-N to the
end, then go through all the standard release activities.
The prepare-build npm script then updates key bits of the package.json
to ensure that the beta build can be installed alongside a production
build. This includes a new name ('Signal Beta') and a different location
for application data.
Note: Beta builds can be installed alongside production builds.
As part of this, a couple new bits of data are shown across the app:
- Environment (development or test, not shown if production)
- App Instance (disabled in production; used for multiple accounts)
These are shown in:
- The window title - both environment and app instance. You can tell
beta builds because the app name, preceding these data bits, is
different.
- The about window - both environment and app instance. You can tell
beta builds from the version number.
- The header added to the debug log - just environment. The version
number will tell us if it's a beta build, and app instance isn't
helpful.
* Turn on single-window mode in non-production modes
Because it's really frightening when you see 'unable to read from db'
errors in the console.
* aply.sh: More instructions for initial setup and testing
* Gruntfile: Get consistent with use of package.json datas
* Linux: manually update desktop keys, since macros not available
2017-10-30 20:57:13 +00:00
|
|
|
|
|
|
|
return header;
|
2017-09-25 22:00:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function getLevel(level) {
|
2018-03-05 21:05:10 +00:00
|
|
|
const text = LEVELS[level];
|
2017-09-25 22:00:19 +00:00
|
|
|
if (!text) {
|
|
|
|
return BLANK_LEVEL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return text.toUpperCase();
|
|
|
|
}
|
|
|
|
|
|
|
|
function formatLine(entry) {
|
2018-03-05 21:05:10 +00:00
|
|
|
return `${getLevel(entry.level)} ${entry.time} ${entry.msg}`;
|
2017-09-25 22:00:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function format(entries) {
|
2018-03-06 21:20:04 +00:00
|
|
|
return Privacy.redactAll(entries.map(formatLine).join('\n'));
|
2017-09-25 22:00:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function fetch() {
|
2018-04-27 21:25:04 +00:00
|
|
|
return new Promise(resolve => {
|
2017-10-04 21:40:35 +00:00
|
|
|
ipc.send('fetch-log');
|
|
|
|
|
2018-03-05 21:05:10 +00:00
|
|
|
ipc.on('fetched-log', (event, text) => {
|
|
|
|
const result = `${getHeader()}\n${format(text)}`;
|
2017-10-04 21:40:35 +00:00
|
|
|
resolve(result);
|
|
|
|
});
|
2018-03-08 18:45:22 +00:00
|
|
|
});
|
2017-09-25 22:32:31 +00:00
|
|
|
}
|
2017-09-25 22:00:19 +00:00
|
|
|
|
2018-03-06 23:58:01 +00:00
|
|
|
const publish = debuglogs.upload;
|
2017-09-25 22:00:19 +00:00
|
|
|
|
|
|
|
// A modern logging interface for the browser
|
|
|
|
|
2019-09-26 19:56:31 +00:00
|
|
|
const env = window.getEnvironment();
|
|
|
|
const IS_PRODUCTION = env === 'production';
|
|
|
|
|
|
|
|
const ipcBatcher = createBatcher({
|
|
|
|
wait: 500,
|
|
|
|
size: 20,
|
|
|
|
processBatch: items => {
|
|
|
|
ipc.send('batch-log', items);
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
2017-09-25 22:00:19 +00:00
|
|
|
// The Bunyan API: https://github.com/trentm/node-bunyan#log-method-api
|
2018-07-21 19:00:08 +00:00
|
|
|
function logAtLevel(level, prefix, ...args) {
|
2019-09-26 19:56:31 +00:00
|
|
|
if (!IS_PRODUCTION) {
|
|
|
|
console._log(prefix, now(), ...args);
|
|
|
|
}
|
2017-09-25 22:00:19 +00:00
|
|
|
|
2018-07-21 19:00:08 +00:00
|
|
|
const str = cleanArgsForIPC(args);
|
|
|
|
const logText = Privacy.redactAll(str);
|
2019-09-26 19:56:31 +00:00
|
|
|
|
|
|
|
ipcBatcher.add({
|
|
|
|
timestamp: Date.now(),
|
|
|
|
level,
|
|
|
|
logText,
|
|
|
|
});
|
2017-09-25 22:00:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
window.log = {
|
2018-07-21 19:00:08 +00:00
|
|
|
fatal: _.partial(logAtLevel, 'fatal', 'FATAL'),
|
|
|
|
error: _.partial(logAtLevel, 'error', 'ERROR'),
|
|
|
|
warn: _.partial(logAtLevel, 'warn', 'WARN '),
|
|
|
|
info: _.partial(logAtLevel, 'info', 'INFO '),
|
|
|
|
debug: _.partial(logAtLevel, 'debug', 'DEBUG'),
|
|
|
|
trace: _.partial(logAtLevel, 'trace', 'TRACE'),
|
2017-09-25 22:00:19 +00:00
|
|
|
fetch,
|
|
|
|
publish,
|
2017-09-25 22:32:31 +00:00
|
|
|
};
|
2017-09-25 22:00:19 +00:00
|
|
|
|
2018-03-05 21:14:22 +00:00
|
|
|
window.onerror = (message, script, line, col, error) => {
|
2017-11-30 19:56:29 +00:00
|
|
|
const errorInfo = error && error.stack ? error.stack : JSON.stringify(error);
|
2018-03-05 21:05:10 +00:00
|
|
|
window.log.error(`Top-level unhandled error: ${errorInfo}`);
|
2017-09-25 22:00:19 +00:00
|
|
|
};
|
|
|
|
|
2018-04-27 21:25:04 +00:00
|
|
|
window.addEventListener('unhandledrejection', rejectionEvent => {
|
2020-09-18 20:40:41 +00:00
|
|
|
const error = rejectionEvent.reason;
|
|
|
|
const errorString =
|
|
|
|
error && error.stack ? error.stack : JSON.stringify(error);
|
|
|
|
window.log.error(`Top-level unhandled promise rejection: ${errorString}`);
|
2017-11-30 19:56:29 +00:00
|
|
|
});
|