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);
|
await sql.sqlRead('finishGetKnownMessageAttachments', cursor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log.info(
|
log.info(
|
||||||
`cleanupOrphanedAttachments: ${totalAttachmentsFound} message ` +
|
`cleanupOrphanedAttachments: ${totalAttachmentsFound} attachments and \
|
||||||
`attachments; ${orphanedAttachments.size} remain`
|
${totalDownloadsFound} downloads found on disk`
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (orphanedAttachments.size > 0) {
|
||||||
|
log.error(`${orphanedAttachments.size} orphaned attachment(s) found`);
|
||||||
|
}
|
||||||
|
|
||||||
if (totalMissing > 0) {
|
if (totalMissing > 0) {
|
||||||
log.warn(
|
log.warn(
|
||||||
`cleanupOrphanedAttachments: ${totalMissing} message attachments were not found on disk`
|
`cleanupOrphanedAttachments: ${totalMissing} message attachments were not found on disk`
|
||||||
@@ -460,10 +463,10 @@ function deleteOrphanedAttachments({
|
|||||||
attachments: Array.from(orphanedAttachments),
|
attachments: Array.from(orphanedAttachments),
|
||||||
});
|
});
|
||||||
|
|
||||||
log.info(
|
if (orphanedDownloads.size > 0) {
|
||||||
`cleanupOrphanedAttachments: found ${totalDownloadsFound} downloads ` +
|
log.error(`${orphanedDownloads.size} orphaned download(s) found`);
|
||||||
`${orphanedDownloads.size} remain`
|
}
|
||||||
);
|
|
||||||
await deleteAllDownloads({
|
await deleteAllDownloads({
|
||||||
userDataPath,
|
userDataPath,
|
||||||
downloads: Array.from(orphanedDownloads),
|
downloads: Array.from(orphanedDownloads),
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ const KnownConfigKeys = [
|
|||||||
'desktop.donations',
|
'desktop.donations',
|
||||||
'desktop.donations.prod',
|
'desktop.donations.prod',
|
||||||
'desktop.internalUser',
|
'desktop.internalUser',
|
||||||
|
'desktop.loggingErrorToasts',
|
||||||
'desktop.mediaQuality.levels',
|
'desktop.mediaQuality.levels',
|
||||||
'desktop.messageCleanup',
|
'desktop.messageCleanup',
|
||||||
'desktop.retryRespondMaxAge',
|
'desktop.retryRespondMaxAge',
|
||||||
|
|||||||
@@ -152,6 +152,11 @@ function getToast(toastType: ToastType): AnyToast {
|
|||||||
return { toastType: ToastType.LinkCopied };
|
return { toastType: ToastType.LinkCopied };
|
||||||
case ToastType.LoadingFullLogs:
|
case ToastType.LoadingFullLogs:
|
||||||
return { toastType: ToastType.LoadingFullLogs };
|
return { toastType: ToastType.LoadingFullLogs };
|
||||||
|
case ToastType._InternalMainProcessLoggingError:
|
||||||
|
return {
|
||||||
|
toastType: ToastType._InternalMainProcessLoggingError,
|
||||||
|
parameters: { logLines: ['error1', 'error2'], count: 2 },
|
||||||
|
};
|
||||||
case ToastType.MaxAttachments:
|
case ToastType.MaxAttachments:
|
||||||
return { toastType: ToastType.MaxAttachments };
|
return { toastType: ToastType.MaxAttachments };
|
||||||
case ToastType.MediaNoLongerAvailable:
|
case ToastType.MediaNoLongerAvailable:
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import type { LocalizerType } from '../types/Util.js';
|
|||||||
import type { AnyToast } from '../types/Toast.js';
|
import type { AnyToast } from '../types/Toast.js';
|
||||||
import type { AnyActionableMegaphone } from '../types/Megaphone.js';
|
import type { AnyActionableMegaphone } from '../types/Megaphone.js';
|
||||||
import type { Location } from '../types/Nav.js';
|
import type { Location } from '../types/Nav.js';
|
||||||
|
import { tw } from '../axo/tw.js';
|
||||||
|
|
||||||
export type PropsType = {
|
export type PropsType = {
|
||||||
changeLocation: (newLocation: Location) => unknown;
|
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) {
|
if (toastType === ToastType.PinnedConversationsFull) {
|
||||||
return (
|
return (
|
||||||
<Toast onClose={hideToast}>{i18n('icu:pinnedConversationsFull')}</Toast>
|
<Toast onClose={hideToast}>{i18n('icu:pinnedConversationsFull')}</Toast>
|
||||||
|
|||||||
@@ -38,6 +38,13 @@ const SUBSYSTEM_COLORS = new LRUCache<string, string>({
|
|||||||
max: 500,
|
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
|
// Only for unpackaged app
|
||||||
function getSubsystemColor(name: string): string {
|
function getSubsystemColor(name: string): string {
|
||||||
const cached = SUBSYSTEM_COLORS.get(name);
|
const cached = SUBSYSTEM_COLORS.get(name);
|
||||||
@@ -168,6 +175,8 @@ const pinoInstance = pino(
|
|||||||
typeof item === 'string' ? item : reallyJsonStringify(item)
|
typeof item === 'string' ? item : reallyJsonStringify(item)
|
||||||
)
|
)
|
||||||
.join(' ');
|
.join(' ');
|
||||||
|
onLogCallback?.(level, line, this.msgPrefix);
|
||||||
|
|
||||||
return method.call(this, line);
|
return method.call(this, line);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -27,10 +27,11 @@ import * as Errors from '../types/errors.js';
|
|||||||
import { createRotatingPinoDest } from '../util/rotatingPinoDest.js';
|
import { createRotatingPinoDest } from '../util/rotatingPinoDest.js';
|
||||||
import { redactAll } from '../util/privacy.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 type { FetchLogIpcData, LogEntryType } from './shared.js';
|
||||||
import { LogLevel, isLogEntry } from './shared.js';
|
import { LogLevel, isLogEntry } from './shared.js';
|
||||||
|
import { isProduction } from '../util/version.js';
|
||||||
|
|
||||||
const { filter, flatten, map, pick, sortBy } = lodash;
|
const { filter, flatten, map, pick, sortBy } = lodash;
|
||||||
|
|
||||||
@@ -47,6 +48,17 @@ export async function initialize(
|
|||||||
}
|
}
|
||||||
isInitialized = true;
|
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 basePath = app.getPath('userData');
|
||||||
const logPath = join(basePath, 'logs');
|
const logPath = join(basePath, 'logs');
|
||||||
mkdirSync(logPath, { recursive: true });
|
mkdirSync(logPath, { recursive: true });
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ export enum ToastType {
|
|||||||
LeftGroup = 'LeftGroup',
|
LeftGroup = 'LeftGroup',
|
||||||
LinkCopied = 'LinkCopied',
|
LinkCopied = 'LinkCopied',
|
||||||
LoadingFullLogs = 'LoadingFullLogs',
|
LoadingFullLogs = 'LoadingFullLogs',
|
||||||
|
_InternalMainProcessLoggingError = '_InternalMainProcessLoggingError',
|
||||||
MaxAttachments = 'MaxAttachments',
|
MaxAttachments = 'MaxAttachments',
|
||||||
MediaNoLongerAvailable = 'MediaNoLongerAvailable',
|
MediaNoLongerAvailable = 'MediaNoLongerAvailable',
|
||||||
MessageBodyTooLong = 'MessageBodyTooLong',
|
MessageBodyTooLong = 'MessageBodyTooLong',
|
||||||
@@ -165,6 +166,10 @@ export type AnyToast =
|
|||||||
| { toastType: ToastType.LeftGroup }
|
| { toastType: ToastType.LeftGroup }
|
||||||
| { toastType: ToastType.LinkCopied }
|
| { toastType: ToastType.LinkCopied }
|
||||||
| { toastType: ToastType.LoadingFullLogs }
|
| { toastType: ToastType.LoadingFullLogs }
|
||||||
|
| {
|
||||||
|
toastType: ToastType._InternalMainProcessLoggingError;
|
||||||
|
parameters: { count: number; logLines: Array<string> };
|
||||||
|
}
|
||||||
| { toastType: ToastType.MaxAttachments }
|
| { toastType: ToastType.MaxAttachments }
|
||||||
| { toastType: ToastType.MediaNoLongerAvailable }
|
| { toastType: ToastType.MediaNoLongerAvailable }
|
||||||
| { toastType: ToastType.MessageBodyTooLong }
|
| { toastType: ToastType.MessageBodyTooLong }
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
import EventEmitter from 'node:events';
|
import EventEmitter from 'node:events';
|
||||||
import { ipcRenderer as ipc } from 'electron';
|
import { ipcRenderer as ipc } from 'electron';
|
||||||
import * as semver from 'semver';
|
import * as semver from 'semver';
|
||||||
import lodash from 'lodash';
|
import lodash, { throttle } from 'lodash';
|
||||||
import PQueue from 'p-queue';
|
import PQueue from 'p-queue';
|
||||||
|
|
||||||
import type { IPCType } from '../../window.d.ts';
|
import type { IPCType } from '../../window.d.ts';
|
||||||
@@ -35,6 +35,7 @@ import {
|
|||||||
conversationJobQueue,
|
conversationJobQueue,
|
||||||
conversationQueueJobEnum,
|
conversationQueueJobEnum,
|
||||||
} from '../../jobs/conversationJobQueue.js';
|
} from '../../jobs/conversationJobQueue.js';
|
||||||
|
import { isEnabled } from '../../RemoteConfig.js';
|
||||||
|
|
||||||
const { groupBy, mapValues } = lodash;
|
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(
|
ipc.on(
|
||||||
'art-creator:uploadStickerPack',
|
'art-creator:uploadStickerPack',
|
||||||
async (
|
async (
|
||||||
|
|||||||
Reference in New Issue
Block a user