2021-01-27 21:13:33 +00:00
|
|
|
// Copyright 2017-2021 Signal Messenger, LLC
|
|
|
|
// SPDX-License-Identifier: AGPL-3.0-only
|
|
|
|
|
|
|
|
/* eslint-env node */
|
|
|
|
|
|
|
|
/* eslint-disable no-console */
|
|
|
|
|
|
|
|
import { ipcRenderer as ipc } from 'electron';
|
2021-03-04 21:44:57 +00:00
|
|
|
import * as path from 'path';
|
2021-03-10 22:41:38 +00:00
|
|
|
import pino from 'pino';
|
|
|
|
import { createStream } from 'rotating-file-stream';
|
2021-01-27 21:13:33 +00:00
|
|
|
|
2021-05-14 01:18:43 +00:00
|
|
|
import {
|
|
|
|
initLogger,
|
|
|
|
LogLevel as SignalClientLogLevel,
|
|
|
|
} from '@signalapp/signal-client';
|
2021-04-16 23:13:13 +00:00
|
|
|
|
2021-01-27 21:13:33 +00:00
|
|
|
import {
|
|
|
|
LogLevel,
|
|
|
|
cleanArgs,
|
|
|
|
getLogLevelString,
|
2021-09-17 18:27:53 +00:00
|
|
|
levelMaxLength,
|
2021-01-27 21:13:33 +00:00
|
|
|
} from './shared';
|
2021-02-04 19:54:03 +00:00
|
|
|
import * as log from './log';
|
2021-08-18 20:08:14 +00:00
|
|
|
import { Environment, getEnvironment } from '../environment';
|
2021-01-27 21:13:33 +00:00
|
|
|
|
|
|
|
// Backwards-compatible logging, simple strings and no level (defaulted to INFO)
|
|
|
|
function now() {
|
|
|
|
const date = new Date();
|
|
|
|
return date.toJSON();
|
|
|
|
}
|
|
|
|
|
2021-02-04 19:54:03 +00:00
|
|
|
function consoleLog(...args: ReadonlyArray<unknown>) {
|
2021-01-27 21:13:33 +00:00
|
|
|
logAtLevel(LogLevel.Info, ...args);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (window.console) {
|
|
|
|
console._log = console.log;
|
2021-02-04 19:54:03 +00:00
|
|
|
console.log = consoleLog;
|
2021-01-27 21:13:33 +00:00
|
|
|
}
|
|
|
|
|
2021-03-10 22:41:38 +00:00
|
|
|
let globalLogger: undefined | pino.Logger;
|
2021-05-13 20:54:54 +00:00
|
|
|
let shouldRestart = false;
|
|
|
|
|
|
|
|
export function beforeRestart(): void {
|
|
|
|
shouldRestart = true;
|
|
|
|
}
|
2021-03-04 21:44:57 +00:00
|
|
|
|
|
|
|
export function initialize(): void {
|
|
|
|
if (globalLogger) {
|
|
|
|
throw new Error('Already called initialize!');
|
|
|
|
}
|
|
|
|
|
|
|
|
const basePath = ipc.sendSync('get-user-data-path');
|
|
|
|
const logFile = path.join(basePath, 'logs', 'app.log');
|
2021-03-10 22:41:38 +00:00
|
|
|
const stream = createStream(logFile, {
|
|
|
|
interval: '1d',
|
2021-03-12 00:40:59 +00:00
|
|
|
rotate: 3,
|
2021-03-10 22:41:38 +00:00
|
|
|
});
|
|
|
|
|
2021-05-13 20:54:54 +00:00
|
|
|
const onClose = () => {
|
2021-03-26 16:48:46 +00:00
|
|
|
globalLogger = undefined;
|
|
|
|
|
2021-05-13 20:54:54 +00:00
|
|
|
if (shouldRestart) {
|
|
|
|
initialize();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
stream.on('close', onClose);
|
|
|
|
stream.on('error', onClose);
|
2021-03-26 16:48:46 +00:00
|
|
|
|
2021-03-10 22:41:38 +00:00
|
|
|
globalLogger = pino(
|
|
|
|
{
|
|
|
|
timestamp: pino.stdTimeFunctions.isoTime,
|
|
|
|
},
|
|
|
|
stream
|
|
|
|
);
|
2021-03-04 21:44:57 +00:00
|
|
|
}
|
|
|
|
|
2021-01-27 21:13:33 +00:00
|
|
|
// A modern logging interface for the browser
|
|
|
|
|
|
|
|
function logAtLevel(level: LogLevel, ...args: ReadonlyArray<unknown>): void {
|
2021-08-18 20:08:14 +00:00
|
|
|
if (getEnvironment() !== Environment.Production) {
|
2021-01-27 21:13:33 +00:00
|
|
|
const prefix = getLogLevelString(level)
|
|
|
|
.toUpperCase()
|
|
|
|
.padEnd(levelMaxLength, ' ');
|
|
|
|
console._log(prefix, now(), ...args);
|
|
|
|
}
|
|
|
|
|
2021-03-04 21:44:57 +00:00
|
|
|
const levelString = getLogLevelString(level);
|
|
|
|
const msg = cleanArgs(args);
|
|
|
|
|
|
|
|
if (!globalLogger) {
|
|
|
|
throw new Error('Logger has not been initialized yet');
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-03-10 22:41:38 +00:00
|
|
|
globalLogger[levelString](msg);
|
2021-01-27 21:13:33 +00:00
|
|
|
}
|
|
|
|
|
2021-02-04 19:54:03 +00:00
|
|
|
log.setLogAtLevel(logAtLevel);
|
|
|
|
|
2021-10-07 23:28:47 +00:00
|
|
|
window.SignalContext = window.SignalContext || {};
|
|
|
|
window.SignalContext.log = {
|
2021-02-04 19:54:03 +00:00
|
|
|
fatal: log.fatal,
|
|
|
|
error: log.error,
|
|
|
|
warn: log.warn,
|
|
|
|
info: log.info,
|
|
|
|
debug: log.debug,
|
|
|
|
trace: log.trace,
|
2021-01-27 21:13:33 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
window.onerror = (_message, _script, _line, _col, error) => {
|
|
|
|
const errorInfo = error && error.stack ? error.stack : JSON.stringify(error);
|
2021-09-17 18:27:53 +00:00
|
|
|
log.error(`Top-level unhandled error: ${errorInfo}`);
|
2021-01-27 21:13:33 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
window.addEventListener('unhandledrejection', rejectionEvent => {
|
|
|
|
const error = rejectionEvent.reason;
|
|
|
|
const errorString =
|
|
|
|
error && error.stack ? error.stack : JSON.stringify(error);
|
2021-09-17 18:27:53 +00:00
|
|
|
log.error(`Top-level unhandled promise rejection: ${errorString}`);
|
2021-01-27 21:13:33 +00:00
|
|
|
});
|
2021-04-16 23:13:13 +00:00
|
|
|
|
|
|
|
initLogger(
|
2021-09-20 18:51:30 +00:00
|
|
|
SignalClientLogLevel.Info,
|
2021-04-16 23:13:13 +00:00
|
|
|
(
|
|
|
|
level: unknown,
|
|
|
|
target: string,
|
|
|
|
file: string | null,
|
|
|
|
line: number | null,
|
|
|
|
message: string
|
|
|
|
) => {
|
|
|
|
let fileString = '';
|
|
|
|
if (file && line) {
|
|
|
|
fileString = ` ${file}:${line}`;
|
|
|
|
} else if (file) {
|
|
|
|
fileString = ` ${file}`;
|
|
|
|
}
|
2021-05-14 01:18:43 +00:00
|
|
|
const logString = `@signalapp/signal-client ${message} ${target}${fileString}`;
|
2021-04-16 23:13:13 +00:00
|
|
|
|
|
|
|
if (level === SignalClientLogLevel.Trace) {
|
|
|
|
log.trace(logString);
|
|
|
|
} else if (level === SignalClientLogLevel.Debug) {
|
|
|
|
log.debug(logString);
|
|
|
|
} else if (level === SignalClientLogLevel.Info) {
|
|
|
|
log.info(logString);
|
|
|
|
} else if (level === SignalClientLogLevel.Warn) {
|
|
|
|
log.warn(logString);
|
|
|
|
} else if (level === SignalClientLogLevel.Error) {
|
|
|
|
log.error(logString);
|
|
|
|
} else {
|
|
|
|
log.error(`${logString} (unknown log level ${level})`);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
);
|