mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-14 12:08:36 -05:00
Merge from vscode 3d67364fbfcf676d93be64f949e9b33e7f1b969e (#5028)
This commit is contained in:
@@ -3,69 +3,12 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { binarySearch } from 'vs/base/common/arrays';
|
||||
import { toDisposable } from 'vs/base/common/lifecycle';
|
||||
import { globals } from 'vs/base/common/platform';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IDisposable, toDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import * as Errors from 'vs/base/common/errors';
|
||||
import { safeStringify } from 'vs/base/common/objects';
|
||||
import BaseErrorTelemetry, { ErrorEvent } from '../common/errorTelemetry';
|
||||
|
||||
/* __GDPR__FRAGMENT__
|
||||
"ErrorEvent" : {
|
||||
"stack": { "classification": "CustomerContent", "purpose": "PerformanceAndHealth" },
|
||||
"message" : { "classification": "CustomerContent", "purpose": "PerformanceAndHealth" },
|
||||
"filename" : { "classification": "CustomerContent", "purpose": "PerformanceAndHealth" },
|
||||
"callstack": { "classification": "CallstackOrException", "purpose": "PerformanceAndHealth" },
|
||||
"msg" : { "classification": "CallstackOrException", "purpose": "PerformanceAndHealth" },
|
||||
"file" : { "classification": "CallstackOrException", "purpose": "PerformanceAndHealth" },
|
||||
"line": { "classification": "CallstackOrException", "purpose": "PerformanceAndHealth", "isMeasurement": true },
|
||||
"column": { "classification": "CallstackOrException", "purpose": "PerformanceAndHealth", "isMeasurement": true },
|
||||
"uncaught_error_name": { "classification": "CallstackOrException", "purpose": "PerformanceAndHealth" },
|
||||
"uncaught_error_msg": { "classification": "CallstackOrException", "purpose": "PerformanceAndHealth" },
|
||||
"count": { "classification": "CallstackOrException", "purpose": "PerformanceAndHealth", "isMeasurement": true }
|
||||
}
|
||||
*/
|
||||
interface ErrorEvent {
|
||||
callstack: string;
|
||||
msg?: string;
|
||||
file?: string;
|
||||
line?: number;
|
||||
column?: number;
|
||||
uncaught_error_name?: string;
|
||||
uncaught_error_msg?: string;
|
||||
count?: number;
|
||||
}
|
||||
|
||||
namespace ErrorEvent {
|
||||
export function compare(a: ErrorEvent, b: ErrorEvent) {
|
||||
if (a.callstack < b.callstack) {
|
||||
return -1;
|
||||
} else if (a.callstack > b.callstack) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
export default class ErrorTelemetry {
|
||||
|
||||
public static ERROR_FLUSH_TIMEOUT: number = 5 * 1000;
|
||||
|
||||
private _telemetryService: ITelemetryService;
|
||||
private _flushDelay: number;
|
||||
private _flushHandle: any = -1;
|
||||
private _buffer: ErrorEvent[] = [];
|
||||
private _disposables: IDisposable[] = [];
|
||||
|
||||
constructor(telemetryService: ITelemetryService, flushDelay = ErrorTelemetry.ERROR_FLUSH_TIMEOUT) {
|
||||
this._telemetryService = telemetryService;
|
||||
this._flushDelay = flushDelay;
|
||||
|
||||
// (1) check for unexpected but handled errors
|
||||
const unbind = Errors.errorHandler.addListener((err) => this._onErrorEvent(err));
|
||||
this._disposables.push(toDisposable(unbind));
|
||||
|
||||
// (2) check for uncaught global errors
|
||||
export default class ErrorTelemetry extends BaseErrorTelemetry {
|
||||
protected installErrorListeners(): void {
|
||||
let oldOnError: Function;
|
||||
let that = this;
|
||||
if (typeof globals.onerror === 'function') {
|
||||
@@ -84,37 +27,7 @@ export default class ErrorTelemetry {
|
||||
}));
|
||||
}
|
||||
|
||||
dispose() {
|
||||
clearTimeout(this._flushHandle);
|
||||
this._flushBuffer();
|
||||
this._disposables = dispose(this._disposables);
|
||||
}
|
||||
|
||||
private _onErrorEvent(err: any): void {
|
||||
|
||||
if (!err) {
|
||||
return;
|
||||
}
|
||||
|
||||
// unwrap nested errors from loader
|
||||
if (err.detail && err.detail.stack) {
|
||||
err = err.detail;
|
||||
}
|
||||
|
||||
// work around behavior in workerServer.ts that breaks up Error.stack
|
||||
let callstack = Array.isArray(err.stack) ? err.stack.join('\n') : err.stack;
|
||||
let msg = err.message ? err.message : safeStringify(err);
|
||||
|
||||
// errors without a stack are not useful telemetry
|
||||
if (!callstack) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._enqueue({ msg, callstack });
|
||||
}
|
||||
|
||||
private _onUncaughtError(msg: string, file: string, line: number, column?: number, err?: any): void {
|
||||
|
||||
let data: ErrorEvent = {
|
||||
callstack: msg,
|
||||
msg,
|
||||
@@ -138,38 +51,4 @@ export default class ErrorTelemetry {
|
||||
|
||||
this._enqueue(data);
|
||||
}
|
||||
|
||||
private _enqueue(e: ErrorEvent): void {
|
||||
|
||||
const idx = binarySearch(this._buffer, e, ErrorEvent.compare);
|
||||
if (idx < 0) {
|
||||
e.count = 1;
|
||||
this._buffer.splice(~idx, 0, e);
|
||||
} else {
|
||||
if (!this._buffer[idx].count) {
|
||||
this._buffer[idx].count = 0;
|
||||
}
|
||||
this._buffer[idx].count! += 1;
|
||||
}
|
||||
|
||||
if (this._flushHandle === -1) {
|
||||
this._flushHandle = setTimeout(() => {
|
||||
this._flushBuffer();
|
||||
this._flushHandle = -1;
|
||||
}, this._flushDelay);
|
||||
}
|
||||
}
|
||||
|
||||
private _flushBuffer(): void {
|
||||
for (let error of this._buffer) {
|
||||
/* __GDPR__
|
||||
"UnhandledError" : {
|
||||
"${include}": [ "${ErrorEvent}" ]
|
||||
}
|
||||
*/
|
||||
// {{SQL CARBON EDIT}}
|
||||
//this._telemetryService.publicLog('UnhandledError', error, true);
|
||||
}
|
||||
this._buffer.length = 0;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user