Import log instead of using it off of window

This commit is contained in:
Josh Perez 2021-09-17 14:27:53 -04:00 committed by GitHub
parent 8eb0dd3116
commit 65ddf0a9e8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
155 changed files with 3654 additions and 3433 deletions

View file

@ -6,7 +6,6 @@
/* eslint-disable no-console */
import { ipcRenderer as ipc } from 'electron';
import _ from 'lodash';
import * as path from 'path';
import pino from 'pino';
import { createStream } from 'rotating-file-stream';
@ -16,28 +15,15 @@ import {
LogLevel as SignalClientLogLevel,
} from '@signalapp/signal-client';
import { uploadDebugLogs } from './debuglogs';
import { redactAll } from '../util/privacy';
import {
FetchLogIpcData,
LogEntryType,
LogLevel,
cleanArgs,
getLogLevelString,
isFetchLogIpcData,
isLogEntry,
levelMaxLength,
} from './shared';
import * as log from './log';
import { reallyJsonStringify } from '../util/reallyJsonStringify';
import { Environment, getEnvironment } from '../environment';
// To make it easier to visually scan logs, we make all levels the same length
const levelFromName = pino().levels.values;
const levelMaxLength: number = Object.keys(levelFromName).reduce(
(maxLength, level) => Math.max(maxLength, level.length),
0
);
// Backwards-compatible logging, simple strings and no level (defaulted to INFO)
function now() {
const date = new Date();
@ -53,91 +39,6 @@ if (window.console) {
console.log = consoleLog;
}
// The mechanics of preparing a log for publish
const headerSectionTitle = (title: string) => `========= ${title} =========`;
const headerSection = (
title: string,
data: Readonly<Record<string, unknown>>
): string => {
const sortedEntries = _.sortBy(Object.entries(data), ([key]) => key);
return [
headerSectionTitle(title),
...sortedEntries.map(
([key, value]) => `${key}: ${redactAll(String(value))}`
),
'',
].join('\n');
};
const getHeader = ({
capabilities,
remoteConfig,
statistics,
user,
}: Omit<FetchLogIpcData, 'logEntries'>): string =>
[
headerSection('System info', {
Time: Date.now(),
'User agent': window.navigator.userAgent,
'Node version': window.getNodeVersion(),
Environment: getEnvironment(),
'App version': window.getVersion(),
}),
headerSection('User info', user),
headerSection('Capabilities', capabilities),
headerSection('Remote config', remoteConfig),
headerSection('Statistics', statistics),
headerSectionTitle('Logs'),
].join('\n');
const getLevel = _.memoize((level: LogLevel): string => {
const text = getLogLevelString(level);
return text.toUpperCase().padEnd(levelMaxLength, ' ');
});
function formatLine(mightBeEntry: unknown): string {
const entry: LogEntryType = isLogEntry(mightBeEntry)
? mightBeEntry
: {
level: LogLevel.Error,
msg: `Invalid IPC data when fetching logs. Here's what we could recover: ${reallyJsonStringify(
mightBeEntry
)}`,
time: new Date().toISOString(),
};
return `${getLevel(entry.level)} ${entry.time} ${entry.msg}`;
}
function fetch(): Promise<string> {
return new Promise(resolve => {
ipc.send('fetch-log');
ipc.on('fetched-log', (_event, data: unknown) => {
let header: string;
let body: string;
if (isFetchLogIpcData(data)) {
const { logEntries } = data;
header = getHeader(data);
body = logEntries.map(formatLine).join('\n');
} else {
header = headerSectionTitle('Partial logs');
const entry: LogEntryType = {
level: LogLevel.Error,
msg: 'Invalid IPC data when fetching logs; dropping all logs',
time: new Date().toISOString(),
};
body = formatLine(entry);
}
const result = `${header}\n${body}`;
resolve(result);
});
});
}
let globalLogger: undefined | pino.Logger;
let shouldRestart = false;
@ -176,8 +77,6 @@ export function initialize(): void {
);
}
const publish = uploadDebugLogs;
// A modern logging interface for the browser
function logAtLevel(level: LogLevel, ...args: ReadonlyArray<unknown>): void {
@ -201,27 +100,26 @@ function logAtLevel(level: LogLevel, ...args: ReadonlyArray<unknown>): void {
log.setLogAtLevel(logAtLevel);
window.log = {
window.SignalWindow = window.SignalWindow || {};
window.SignalWindow.log = {
fatal: log.fatal,
error: log.error,
warn: log.warn,
info: log.info,
debug: log.debug,
trace: log.trace,
fetch,
publish,
};
window.onerror = (_message, _script, _line, _col, error) => {
const errorInfo = error && error.stack ? error.stack : JSON.stringify(error);
window.log.error(`Top-level unhandled error: ${errorInfo}`);
log.error(`Top-level unhandled error: ${errorInfo}`);
};
window.addEventListener('unhandledrejection', rejectionEvent => {
const error = rejectionEvent.reason;
const errorString =
error && error.stack ? error.stack : JSON.stringify(error);
window.log.error(`Top-level unhandled promise rejection: ${errorString}`);
log.error(`Top-level unhandled promise rejection: ${errorString}`);
});
initLogger(