33 * Licensed under the MIT License. See License.txt in the project root for license information.
44 *--------------------------------------------------------------------------------------------*/
55
6- import { binarySearch } from 'vs/base/common/arrays ' ;
6+ import { toDisposable } from 'vs/base/common/lifecycle ' ;
77import { globals } from 'vs/base/common/platform' ;
8- import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry' ;
9- import { IDisposable , toDisposable , dispose } from 'vs/base/common/lifecycle' ;
10- import * as Errors from 'vs/base/common/errors' ;
11- import { safeStringify } from 'vs/base/common/objects' ;
8+ import BaseErrorTelemetry , { ErrorEvent } from '../common/errorTelemetry' ;
129
13- /* __GDPR__FRAGMENT__
14- "ErrorEvent" : {
15- "stack": { "classification": "CustomerContent", "purpose": "PerformanceAndHealth" },
16- "message" : { "classification": "CustomerContent", "purpose": "PerformanceAndHealth" },
17- "filename" : { "classification": "CustomerContent", "purpose": "PerformanceAndHealth" },
18- "callstack": { "classification": "CallstackOrException", "purpose": "PerformanceAndHealth" },
19- "msg" : { "classification": "CallstackOrException", "purpose": "PerformanceAndHealth" },
20- "file" : { "classification": "CallstackOrException", "purpose": "PerformanceAndHealth" },
21- "line": { "classification": "CallstackOrException", "purpose": "PerformanceAndHealth", "isMeasurement": true },
22- "column": { "classification": "CallstackOrException", "purpose": "PerformanceAndHealth", "isMeasurement": true },
23- "uncaught_error_name": { "classification": "CallstackOrException", "purpose": "PerformanceAndHealth" },
24- "uncaught_error_msg": { "classification": "CallstackOrException", "purpose": "PerformanceAndHealth" },
25- "count": { "classification": "CallstackOrException", "purpose": "PerformanceAndHealth", "isMeasurement": true }
26- }
27- */
28- interface ErrorEvent {
29- callstack : string ;
30- msg ?: string ;
31- file ?: string ;
32- line ?: number ;
33- column ?: number ;
34- uncaught_error_name ?: string ;
35- uncaught_error_msg ?: string ;
36- count ?: number ;
37- }
38-
39- namespace ErrorEvent {
40- export function compare ( a : ErrorEvent , b : ErrorEvent ) {
41- if ( a . callstack < b . callstack ) {
42- return - 1 ;
43- } else if ( a . callstack > b . callstack ) {
44- return 1 ;
45- }
46- return 0 ;
47- }
48- }
49-
50- export default class ErrorTelemetry {
51-
52- public static ERROR_FLUSH_TIMEOUT : number = 5 * 1000 ;
53-
54- private _telemetryService : ITelemetryService ;
55- private _flushDelay : number ;
56- private _flushHandle : any = - 1 ;
57- private _buffer : ErrorEvent [ ] = [ ] ;
58- private _disposables : IDisposable [ ] = [ ] ;
59-
60- constructor ( telemetryService : ITelemetryService , flushDelay = ErrorTelemetry . ERROR_FLUSH_TIMEOUT ) {
61- this . _telemetryService = telemetryService ;
62- this . _flushDelay = flushDelay ;
63-
64- // (1) check for unexpected but handled errors
65- const unbind = Errors . errorHandler . addListener ( ( err ) => this . _onErrorEvent ( err ) ) ;
66- this . _disposables . push ( toDisposable ( unbind ) ) ;
67-
68- // (2) check for uncaught global errors
10+ export default class ErrorTelemetry extends BaseErrorTelemetry {
11+ protected installErrorListeners ( ) : void {
6912 let oldOnError : Function ;
7013 let that = this ;
7114 if ( typeof globals . onerror === 'function' ) {
@@ -84,37 +27,7 @@ export default class ErrorTelemetry {
8427 } ) ) ;
8528 }
8629
87- dispose ( ) {
88- clearTimeout ( this . _flushHandle ) ;
89- this . _flushBuffer ( ) ;
90- this . _disposables = dispose ( this . _disposables ) ;
91- }
92-
93- private _onErrorEvent ( err : any ) : void {
94-
95- if ( ! err ) {
96- return ;
97- }
98-
99- // unwrap nested errors from loader
100- if ( err . detail && err . detail . stack ) {
101- err = err . detail ;
102- }
103-
104- // work around behavior in workerServer.ts that breaks up Error.stack
105- let callstack = Array . isArray ( err . stack ) ? err . stack . join ( '\n' ) : err . stack ;
106- let msg = err . message ? err . message : safeStringify ( err ) ;
107-
108- // errors without a stack are not useful telemetry
109- if ( ! callstack ) {
110- return ;
111- }
112-
113- this . _enqueue ( { msg, callstack } ) ;
114- }
115-
11630 private _onUncaughtError ( msg : string , file : string , line : number , column ?: number , err ?: any ) : void {
117-
11831 let data : ErrorEvent = {
11932 callstack : msg ,
12033 msg,
@@ -138,37 +51,4 @@ export default class ErrorTelemetry {
13851
13952 this . _enqueue ( data ) ;
14053 }
141-
142- private _enqueue ( e : ErrorEvent ) : void {
143-
144- const idx = binarySearch ( this . _buffer , e , ErrorEvent . compare ) ;
145- if ( idx < 0 ) {
146- e . count = 1 ;
147- this . _buffer . splice ( ~ idx , 0 , e ) ;
148- } else {
149- if ( ! this . _buffer [ idx ] . count ) {
150- this . _buffer [ idx ] . count = 0 ;
151- }
152- this . _buffer [ idx ] . count ! += 1 ;
153- }
154-
155- if ( this . _flushHandle === - 1 ) {
156- this . _flushHandle = setTimeout ( ( ) => {
157- this . _flushBuffer ( ) ;
158- this . _flushHandle = - 1 ;
159- } , this . _flushDelay ) ;
160- }
161- }
162-
163- private _flushBuffer ( ) : void {
164- for ( let error of this . _buffer ) {
165- /* __GDPR__
166- "UnhandledError" : {
167- "${include}": [ "${ErrorEvent}" ]
168- }
169- */
170- this . _telemetryService . publicLog ( 'UnhandledError' , error , true ) ;
171- }
172- this . _buffer . length = 0 ;
173- }
17454}
0 commit comments