1
0
mirror of https://github.com/laurent22/joplin.git synced 2024-12-24 10:27:10 +02:00

Desktop: Attach log to crash dump when the application crashes

This commit is contained in:
Laurent Cozic 2024-04-26 16:07:16 +01:00
parent 74bc9b36aa
commit c5dfa4c055
6 changed files with 81 additions and 48 deletions

View File

@ -390,6 +390,8 @@ class Application extends BaseApplication {
argv = await super.start(argv, startOptions);
bridge().setLogFilePath(Logger.globalLogger.logFilePath());
await this.applySettingsSideEffects();
if (Setting.value('sync.upgradeState') === Setting.SYNC_UPGRADE_STATE_MUST_DO) {

View File

@ -6,11 +6,14 @@ import { dirname, toSystemSlashes } from '@joplin/lib/path-utils';
import { fileUriToPath } from '@joplin/utils/url';
import { urlDecode } from '@joplin/lib/string-utils';
import * as Sentry from '@sentry/electron/main';
import { ErrorEvent } from '@sentry/types/types';
import { homedir } from 'os';
import { msleep } from '@joplin/utils/time';
import { pathExists, writeFileSync } from 'fs-extra';
import { pathExists, pathExistsSync, writeFileSync } from 'fs-extra';
import { extname, normalize } from 'path';
import isSafeToOpen from './utils/isSafeToOpen';
import { closeSync, openSync, readSync, statSync } from 'fs';
import { KB } from '@joplin/utils/bytes';
interface LastSelectedPath {
file: string;
@ -38,6 +41,7 @@ export class Bridge {
private rootProfileDir_: string;
private appName_: string;
private appId_: string;
private logFilePath_ = '';
private extraAllowedExtensions_: string[] = [];
private onAllowedExtensionsChangeListener_: OnAllowedExtensionsChange = ()=>{};
@ -56,12 +60,53 @@ export class Bridge {
this.sentryInit();
}
public setLogFilePath(v: string) {
this.logFilePath_ = v;
}
private sentryInit() {
const getLogLines = () => {
try {
if (!this.logFilePath_ || !pathExistsSync(this.logFilePath_)) return '';
const { size } = statSync(this.logFilePath_);
if (!size) return '';
const bytesToRead = Math.min(size, 100 * KB);
const handle = openSync(this.logFilePath_, 'r');
const position = size - bytesToRead;
const buffer = Buffer.alloc(bytesToRead);
readSync(handle, buffer, 0, bytesToRead, position);
closeSync(handle);
return buffer.toString('utf-8');
} catch (error) {
// Can't do anything in this context
return '';
}
};
const getLogAttachment = () => {
const lines = getLogLines();
if (!lines) return null;
return { filename: 'joplin-log.txt', data: lines };
};
const options: Sentry.ElectronMainOptions = {
beforeSend: event => {
beforeSend: (event, hint) => {
try {
const logAttachment = getLogAttachment();
if (logAttachment) hint.attachments = [logAttachment];
const date = (new Date()).toISOString().replace(/[:-]/g, '').split('.')[0];
writeFileSync(`${homedir()}/joplin_crash_dump_${date}.json`, JSON.stringify(event, null, '\t'), 'utf-8');
interface ErrorEventWithLog extends ErrorEvent {
log: string[];
}
const errorEventWithLog: ErrorEventWithLog = {
...event,
log: logAttachment ? logAttachment.data.trim().split('\n') : [],
};
writeFileSync(`${homedir()}/joplin_crash_dump_${date}.json`, JSON.stringify(errorEventWithLog, null, '\t'), 'utf-8');
} catch (error) {
// Ignore the error since we can't handle it here
}

View File

@ -54,36 +54,33 @@ describe('Logger', () => {
'',
].join('\n'));
// Shouldn't have kept any line, since keptLineCount was not set
expect(logger.keptLines).toEqual([]);
jest.useRealTimers();
});
it('should keep the last lines', async () => {
jest.useFakeTimers().setSystemTime(new Date('2020-01-01'));
// it('should keep the last lines', async () => {
// jest.useFakeTimers().setSystemTime(new Date('2020-01-01'));
const logger = createLogger();
logger.keptLineCount = 2;
logger.info('one');
logger.info('two');
logger.info('three');
// const logger = createLogger();
// logger.keptLineCount = 2;
// logger.info('one');
// logger.info('two');
// logger.info('three');
await logger.waitForFileWritesToComplete_();
// await logger.waitForFileWritesToComplete_();
expect(await getLogContent()).toBe([
'2020-01-01 00:00:00: testing: one',
'2020-01-01 00:00:00: testing: two',
'2020-01-01 00:00:00: testing: three',
'',
].join('\n'));
// expect(await getLogContent()).toBe([
// '2020-01-01 00:00:00: testing: one',
// '2020-01-01 00:00:00: testing: two',
// '2020-01-01 00:00:00: testing: three',
// '',
// ].join('\n'));
expect(logger.keptLines).toEqual([
'2020-01-01 00:00:00: testing: two',
'2020-01-01 00:00:00: testing: three',
]);
// expect(logger.keptLines).toEqual([
// '2020-01-01 00:00:00: testing: two',
// '2020-01-01 00:00:00: testing: three',
// ]);
jest.useRealTimers();
});
// jest.useRealTimers();
// });
});

View File

@ -78,8 +78,6 @@ class Logger {
private level_: LogLevel = LogLevel.Info;
private lastDbCleanup_: number = Date.now();
private enabled_ = true;
private keptLineCount_ = 0;
private keptLines_: string[] = [];
public static fsDriver() {
if (!Logger.fsDriver_) Logger.fsDriver_ = dummyFsDriver;
@ -94,18 +92,6 @@ class Logger {
this.enabled_ = v;
}
public get keptLineCount() {
return this.keptLineCount_;
}
public set keptLineCount(v: number) {
this.keptLineCount_ = v;
}
public get keptLines() {
return this.keptLines_;
}
public status(): string {
const output: string[] = [];
output.push(`Enabled: ${this.enabled}`);
@ -118,6 +104,12 @@ class Logger {
this.globalLogger_ = logger;
}
public logFilePath() {
const fileTarget = this.targets().find(t => t.type === TargetType.File);
if (!fileTarget) return '';
return fileTarget.path || '';
}
public static get globalLogger(): Logger {
if (!this.globalLogger_) {
// The global logger normally is initialized early, so we shouldn't
@ -361,13 +353,6 @@ class Logger {
target.database.transactionExecBatch(queries);
}
}
if (this.keptLineCount) {
if (!logLine) logLine = this.logInfoToString(level, prefix, ...object);
this.keptLines_.push(logLine);
const toDelete = this.keptLines_.length - this.keptLineCount;
if (toDelete >= 0) this.keptLines_.splice(0, toDelete);
}
}
// For tests

View File

@ -1,4 +1,7 @@
// eslint-disable-next-line import/prefer-default-export
export const KB = 1024;
export const MB = KB * KB;
export const GB = KB * MB;
export const bytesToHuman = (bytes: number) => {
const units = ['Bytes', 'KB', 'MB', 'GB'];
let unitIndex = 0;

View File

@ -5,6 +5,7 @@
"repository": "https://github.com/laurent22/joplin/tree/dev/packages/utils",
"exports": {
".": "./dist/index.js",
"./bytes": "./dist/bytes.js",
"./dom": "./dist/dom.js",
"./env": "./dist/env.js",
"./object": "./dist/object.js",