mirror of
https://github.com/signalapp/Signal-Desktop.git
synced 2025-12-20 02:08:57 +00:00
Toast on main process errors
This commit is contained in:
@@ -443,12 +443,15 @@ function deleteOrphanedAttachments({
|
||||
await sql.sqlRead('finishGetKnownMessageAttachments', cursor);
|
||||
}
|
||||
}
|
||||
|
||||
log.info(
|
||||
`cleanupOrphanedAttachments: ${totalAttachmentsFound} message ` +
|
||||
`attachments; ${orphanedAttachments.size} remain`
|
||||
`cleanupOrphanedAttachments: ${totalAttachmentsFound} attachments and \
|
||||
${totalDownloadsFound} downloads found on disk`
|
||||
);
|
||||
|
||||
if (orphanedAttachments.size > 0) {
|
||||
log.error(`${orphanedAttachments.size} orphaned attachment(s) found`);
|
||||
}
|
||||
|
||||
if (totalMissing > 0) {
|
||||
log.warn(
|
||||
`cleanupOrphanedAttachments: ${totalMissing} message attachments were not found on disk`
|
||||
@@ -460,10 +463,10 @@ function deleteOrphanedAttachments({
|
||||
attachments: Array.from(orphanedAttachments),
|
||||
});
|
||||
|
||||
log.info(
|
||||
`cleanupOrphanedAttachments: found ${totalDownloadsFound} downloads ` +
|
||||
`${orphanedDownloads.size} remain`
|
||||
);
|
||||
if (orphanedDownloads.size > 0) {
|
||||
log.error(`${orphanedDownloads.size} orphaned download(s) found`);
|
||||
}
|
||||
|
||||
await deleteAllDownloads({
|
||||
userDataPath,
|
||||
downloads: Array.from(orphanedDownloads),
|
||||
|
||||
@@ -28,6 +28,7 @@ const KnownConfigKeys = [
|
||||
'desktop.donations',
|
||||
'desktop.donations.prod',
|
||||
'desktop.internalUser',
|
||||
'desktop.loggingErrorToasts',
|
||||
'desktop.mediaQuality.levels',
|
||||
'desktop.messageCleanup',
|
||||
'desktop.retryRespondMaxAge',
|
||||
|
||||
@@ -152,6 +152,11 @@ function getToast(toastType: ToastType): AnyToast {
|
||||
return { toastType: ToastType.LinkCopied };
|
||||
case ToastType.LoadingFullLogs:
|
||||
return { toastType: ToastType.LoadingFullLogs };
|
||||
case ToastType._InternalMainProcessLoggingError:
|
||||
return {
|
||||
toastType: ToastType._InternalMainProcessLoggingError,
|
||||
parameters: { logLines: ['error1', 'error2'], count: 2 },
|
||||
};
|
||||
case ToastType.MaxAttachments:
|
||||
return { toastType: ToastType.MaxAttachments };
|
||||
case ToastType.MediaNoLongerAvailable:
|
||||
|
||||
@@ -19,6 +19,7 @@ import type { LocalizerType } from '../types/Util.js';
|
||||
import type { AnyToast } from '../types/Toast.js';
|
||||
import type { AnyActionableMegaphone } from '../types/Megaphone.js';
|
||||
import type { Location } from '../types/Nav.js';
|
||||
import { tw } from '../axo/tw.js';
|
||||
|
||||
export type PropsType = {
|
||||
changeLocation: (newLocation: Location) => unknown;
|
||||
@@ -586,6 +587,40 @@ export function renderToast({
|
||||
);
|
||||
}
|
||||
|
||||
if (toastType === ToastType._InternalMainProcessLoggingError) {
|
||||
return (
|
||||
<Toast
|
||||
autoDismissDisabled
|
||||
onClose={hideToast}
|
||||
toastAction={{
|
||||
label: i18n('icu:Toast__ActionLabel--SubmitLog'),
|
||||
onClick: onShowDebugLog,
|
||||
}}
|
||||
// eslint-disable-next-line better-tailwindcss/no-restricted-classes
|
||||
className={tw('max-w-[640px]!')}
|
||||
>
|
||||
<h2>
|
||||
[INTERNAL]: {toast.parameters.count} error(s) from main process,
|
||||
please submit log.
|
||||
</h2>
|
||||
|
||||
{toast.parameters.count > toast.parameters.logLines.length ? (
|
||||
<h3
|
||||
className={tw('my-2')}
|
||||
>{`Showing only last ${toast.parameters.logLines.length} errors`}</h3>
|
||||
) : null}
|
||||
|
||||
<pre
|
||||
className={tw(
|
||||
'my-2 max-h-48 min-h-24 max-w-[520px] overflow-auto border-1 border-solid p-2'
|
||||
)}
|
||||
>
|
||||
{toast.parameters.logLines.join('\n')}
|
||||
</pre>
|
||||
</Toast>
|
||||
);
|
||||
}
|
||||
|
||||
if (toastType === ToastType.PinnedConversationsFull) {
|
||||
return (
|
||||
<Toast onClose={hideToast}>{i18n('icu:pinnedConversationsFull')}</Toast>
|
||||
|
||||
@@ -38,6 +38,13 @@ const SUBSYSTEM_COLORS = new LRUCache<string, string>({
|
||||
max: 500,
|
||||
});
|
||||
|
||||
let onLogCallback: (level: number, logLine: string, msgPrefix?: string) => void;
|
||||
export function setOnLogCallback(
|
||||
cb: (level: number, logLine: string, msgPrefix?: string) => void
|
||||
): void {
|
||||
onLogCallback = cb;
|
||||
}
|
||||
|
||||
// Only for unpackaged app
|
||||
function getSubsystemColor(name: string): string {
|
||||
const cached = SUBSYSTEM_COLORS.get(name);
|
||||
@@ -168,6 +175,8 @@ const pinoInstance = pino(
|
||||
typeof item === 'string' ? item : reallyJsonStringify(item)
|
||||
)
|
||||
.join(' ');
|
||||
onLogCallback?.(level, line, this.msgPrefix);
|
||||
|
||||
return method.call(this, line);
|
||||
},
|
||||
},
|
||||
|
||||
@@ -27,10 +27,11 @@ import * as Errors from '../types/errors.js';
|
||||
import { createRotatingPinoDest } from '../util/rotatingPinoDest.js';
|
||||
import { redactAll } from '../util/privacy.js';
|
||||
|
||||
import { setPinoDestination, log } from './log.js';
|
||||
import { setPinoDestination, log, setOnLogCallback } from './log.js';
|
||||
|
||||
import type { FetchLogIpcData, LogEntryType } from './shared.js';
|
||||
import { LogLevel, isLogEntry } from './shared.js';
|
||||
import { isProduction } from '../util/version.js';
|
||||
|
||||
const { filter, flatten, map, pick, sortBy } = lodash;
|
||||
|
||||
@@ -47,6 +48,17 @@ export async function initialize(
|
||||
}
|
||||
isInitialized = true;
|
||||
|
||||
if (!isProduction(app.getVersion())) {
|
||||
setOnLogCallback((level, logLine, msgPrefix) => {
|
||||
if (level >= LogLevel.Error) {
|
||||
getMainWindow()?.webContents.send(
|
||||
'logging-error',
|
||||
`${msgPrefix ? `${msgPrefix}` : ''}${logLine}`
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const basePath = app.getPath('userData');
|
||||
const logPath = join(basePath, 'logs');
|
||||
mkdirSync(logPath, { recursive: true });
|
||||
|
||||
@@ -54,6 +54,7 @@ export enum ToastType {
|
||||
LeftGroup = 'LeftGroup',
|
||||
LinkCopied = 'LinkCopied',
|
||||
LoadingFullLogs = 'LoadingFullLogs',
|
||||
_InternalMainProcessLoggingError = '_InternalMainProcessLoggingError',
|
||||
MaxAttachments = 'MaxAttachments',
|
||||
MediaNoLongerAvailable = 'MediaNoLongerAvailable',
|
||||
MessageBodyTooLong = 'MessageBodyTooLong',
|
||||
@@ -165,6 +166,10 @@ export type AnyToast =
|
||||
| { toastType: ToastType.LeftGroup }
|
||||
| { toastType: ToastType.LinkCopied }
|
||||
| { toastType: ToastType.LoadingFullLogs }
|
||||
| {
|
||||
toastType: ToastType._InternalMainProcessLoggingError;
|
||||
parameters: { count: number; logLines: Array<string> };
|
||||
}
|
||||
| { toastType: ToastType.MaxAttachments }
|
||||
| { toastType: ToastType.MediaNoLongerAvailable }
|
||||
| { toastType: ToastType.MessageBodyTooLong }
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
import EventEmitter from 'node:events';
|
||||
import { ipcRenderer as ipc } from 'electron';
|
||||
import * as semver from 'semver';
|
||||
import lodash from 'lodash';
|
||||
import lodash, { throttle } from 'lodash';
|
||||
import PQueue from 'p-queue';
|
||||
|
||||
import type { IPCType } from '../../window.d.ts';
|
||||
@@ -35,6 +35,7 @@ import {
|
||||
conversationJobQueue,
|
||||
conversationQueueJobEnum,
|
||||
} from '../../jobs/conversationJobQueue.js';
|
||||
import { isEnabled } from '../../RemoteConfig.js';
|
||||
|
||||
const { groupBy, mapValues } = lodash;
|
||||
|
||||
@@ -499,6 +500,56 @@ ipc.on('sql-error', () => {
|
||||
});
|
||||
});
|
||||
|
||||
let untoastedMainProcessErrorLogCount = 0;
|
||||
let untoastedMainProcessErrorLogs: Array<string> = [];
|
||||
const MAX_MAIN_PROCESS_ERROR_LOGS_TO_CACHE = 5;
|
||||
|
||||
ipc.on('logging-error', (_event, logLine) => {
|
||||
if (isProduction(window.getVersion())) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isEnabled('desktop.loggingErrorToasts')) {
|
||||
return;
|
||||
}
|
||||
|
||||
untoastedMainProcessErrorLogCount += 1;
|
||||
const numCached = untoastedMainProcessErrorLogs.unshift(logLine);
|
||||
if (numCached > MAX_MAIN_PROCESS_ERROR_LOGS_TO_CACHE) {
|
||||
untoastedMainProcessErrorLogs.pop();
|
||||
}
|
||||
|
||||
throttledHandleMainProcessErrors();
|
||||
});
|
||||
|
||||
const throttledHandleMainProcessErrors = throttle(
|
||||
_handleMainProcessErrors,
|
||||
5000
|
||||
);
|
||||
|
||||
function _handleMainProcessErrors() {
|
||||
if (!window.reduxActions) {
|
||||
// Try again in a bit!
|
||||
throttledHandleMainProcessErrors();
|
||||
return;
|
||||
}
|
||||
|
||||
if (untoastedMainProcessErrorLogs.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
window.reduxActions.toast.showToast({
|
||||
toastType: ToastType._InternalMainProcessLoggingError,
|
||||
parameters: {
|
||||
count: untoastedMainProcessErrorLogCount,
|
||||
logLines: untoastedMainProcessErrorLogs,
|
||||
},
|
||||
});
|
||||
|
||||
untoastedMainProcessErrorLogCount = 0;
|
||||
untoastedMainProcessErrorLogs = [];
|
||||
}
|
||||
|
||||
ipc.on(
|
||||
'art-creator:uploadStickerPack',
|
||||
async (
|
||||
|
||||
Reference in New Issue
Block a user