@@ -6,11 +6,14 @@ import { dirname, toSystemSlashes } from '@joplin/lib/path-utils';
6
6
import { fileUriToPath } from '@joplin/utils/url' ;
7
7
import { urlDecode } from '@joplin/lib/string-utils' ;
8
8
import * as Sentry from '@sentry/electron/main' ;
9
+ import { ErrorEvent } from '@sentry/types/types' ;
9
10
import { homedir } from 'os' ;
10
11
import { msleep } from '@joplin/utils/time' ;
11
- import { pathExists , writeFileSync } from 'fs-extra' ;
12
+ import { pathExists , pathExistsSync , writeFileSync } from 'fs-extra' ;
12
13
import { extname , normalize } from 'path' ;
13
14
import isSafeToOpen from './utils/isSafeToOpen' ;
15
+ import { closeSync , openSync , readSync , statSync } from 'fs' ;
16
+ import { KB } from '@joplin/utils/bytes' ;
14
17
15
18
interface LastSelectedPath {
16
19
file : string ;
@@ -38,6 +41,7 @@ export class Bridge {
38
41
private rootProfileDir_ : string ;
39
42
private appName_ : string ;
40
43
private appId_ : string ;
44
+ private logFilePath_ = '' ;
41
45
42
46
private extraAllowedExtensions_ : string [ ] = [ ] ;
43
47
private onAllowedExtensionsChangeListener_ : OnAllowedExtensionsChange = ( ) => { } ;
@@ -56,12 +60,53 @@ export class Bridge {
56
60
this . sentryInit ( ) ;
57
61
}
58
62
63
+ public setLogFilePath ( v : string ) {
64
+ this . logFilePath_ = v ;
65
+ }
66
+
59
67
private sentryInit ( ) {
68
+ const getLogLines = ( ) => {
69
+ try {
70
+ if ( ! this . logFilePath_ || ! pathExistsSync ( this . logFilePath_ ) ) return '' ;
71
+ const { size } = statSync ( this . logFilePath_ ) ;
72
+ if ( ! size ) return '' ;
73
+
74
+ const bytesToRead = Math . min ( size , 100 * KB ) ;
75
+ const handle = openSync ( this . logFilePath_ , 'r' ) ;
76
+ const position = size - bytesToRead ;
77
+ const buffer = Buffer . alloc ( bytesToRead ) ;
78
+ readSync ( handle , buffer , 0 , bytesToRead , position ) ;
79
+ closeSync ( handle ) ;
80
+ return buffer . toString ( 'utf-8' ) ;
81
+ } catch ( error ) {
82
+ // Can't do anything in this context
83
+ return '' ;
84
+ }
85
+ } ;
86
+
87
+ const getLogAttachment = ( ) => {
88
+ const lines = getLogLines ( ) ;
89
+ if ( ! lines ) return null ;
90
+ return { filename : 'joplin-log.txt' , data : lines } ;
91
+ } ;
92
+
60
93
const options : Sentry . ElectronMainOptions = {
61
- beforeSend : event => {
94
+ beforeSend : ( event , hint ) => {
62
95
try {
96
+ const logAttachment = getLogAttachment ( ) ;
97
+ if ( logAttachment ) hint . attachments = [ logAttachment ] ;
63
98
const date = ( new Date ( ) ) . toISOString ( ) . replace ( / [: -] / g, '' ) . split ( '.' ) [ 0 ] ;
64
- writeFileSync ( `${ homedir ( ) } /joplin_crash_dump_${ date } .json` , JSON . stringify ( event , null , '\t' ) , 'utf-8' ) ;
99
+
100
+ interface ErrorEventWithLog extends ErrorEvent {
101
+ log : string [ ] ;
102
+ }
103
+
104
+ const errorEventWithLog : ErrorEventWithLog = {
105
+ ...event ,
106
+ log : logAttachment ? logAttachment . data . trim ( ) . split ( '\n' ) : [ ] ,
107
+ } ;
108
+
109
+ writeFileSync ( `${ homedir ( ) } /joplin_crash_dump_${ date } .json` , JSON . stringify ( errorEventWithLog , null , '\t' ) , 'utf-8' ) ;
65
110
} catch ( error ) {
66
111
// Ignore the error since we can't handle it here
67
112
}
0 commit comments