src/vs/platform/telemetry/common/errorTelemetry.ts

175 LOC · 88 covered · 87 uncovered · 11 ranges · 12 concepts · 2 introducers · 8 tests

File neighbourhood

The centred file is linked to every concept that introduces one of its ranges, every test that runs code from the file, and the gray connector concepts standing between those tests and the file's own introducer concepts. Undirected links join concepts to every file where they introduce source and concepts to the tests they introduce; arrows show specialization between the displayed concepts and bridge only concepts omitted from this view. Concept colors match the source ranges below; connector concepts have no source color and are shown in gray.

Focused file, its introducer and connector concepts, their introduced files, and tests that run code from the file

In the embedded map, ordinary wheel input scrolls the page; use the visible controls to zoom and drag to pan. Open the full-screen map for canvas navigation: wheel pans, Ctrl/Command plus wheel zooms, and arrow keys pan when this region is focused. On touch screens, open the full-screen map to pan or pinch. If JavaScript or WebGL is unavailable, use the related-file, concept, and source links on this page.

Focused file, its introducer and connector concepts, their introduced files, and tests that run code from the filesrc/vs/server/node/serverAgentHostManager.ts · 158 LOCnode/serverAgentHostMana…extHostChatAgents2.ts ×98 · 451 introduced LOCextHostChatAgents2.ts ×9…serverAgentHostManager.test|title=ServerAgentHostManager process exit resets both signals and clears token|occurrence=1 · 0 introduced LOCserverAgentHostManager.t…serverAgentHostManager.ts ×1 · 2 introduced LOCserverAgentHostManager.t…serverAgentHostManager.test|title=ServerAgentHostManager reports unexpected process exit|occurrence=1 · 0 introduced LOCserverAgentHostManager.t…serverAgentHostManager.ts ×2 · 19 introduced LOCserverAgentHostManager.t…serverAgentHostManager.ts ×1 · 2 introduced LOCserverAgentHostManager.t…serverAgentHostManager.ts ×1 · 4 introduced LOCserverAgentHostManager.t…serverAgentHostManager.ts ×2 · 4 introduced LOCserverAgentHostManager.t…serverAgentHostManager.ts ×3 · 19 introduced LOCserverAgentHostManager.t…agentHostProcessTelemetry.ts ×1 · 7 introduced LOCagentHostProcessTelemetr…serverAgentHostManager.ts ×7 · 138 introduced LOCserverAgentHostManager.t…errorTelemetry.ts ×9 · 83 introduced LOCerrorTelemetry.ts ×9serverAgentHostManager.test|title=ServerAgentHostManager acquires token when sessions become active|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/server/test/node/serverAgentHostManager.test|title=ServerAgentHostManager acquires token when sessions become active|occurrence=1serverAgentHostManager.t…serverAgentHostManager.test|title=ServerAgentHostManager acquires token when standalone WebSocket clients connect|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/server/test/node/serverAgentHostManager.test|title=ServerAgentHostManager acquires token when standalone WebSocket clients connect|occurrence=1serverAgentHostManager.t…serverAgentHostManager.test|title=ServerAgentHostManager no lifetime token initially|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/server/test/node/serverAgentHostManager.test|title=ServerAgentHostManager no lifetime token initially|occurrence=1serverAgentHostManager.t…serverAgentHostManager.test|title=ServerAgentHostManager process exit resets both signals and clears token|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/server/test/node/serverAgentHostManager.test|title=ServerAgentHostManager process exit resets both signals and clears token|occurrence=1serverAgentHostManager.t…serverAgentHostManager.test|title=ServerAgentHostManager releases token only when both sessions and standalone WebSocket connections are zero|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/server/test/node/serverAgentHostManager.test|title=ServerAgentHostManager releases token only when both sessions and standalone WebSocket connections are zero|occurrence=1serverAgentHostManager.t…serverAgentHostManager.test|title=ServerAgentHostManager reports process start failure|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/server/test/node/serverAgentHostManager.test|title=ServerAgentHostManager reports process start failure|occurrence=1serverAgentHostManager.t…serverAgentHostManager.test|title=ServerAgentHostManager reports unexpected process exit|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/server/test/node/serverAgentHostManager.test|title=ServerAgentHostManager reports unexpected process exit|occurrence=1serverAgentHostManager.t…extHostChatAgents2.test|title=ExtHostChatAgents2 reports anchor before resolving it|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/api/test/common/extHostChatAgents2.test|title=ExtHostChatAgents2 reports anchor before resolving it|occurrence=1extHostChatAgents2.test|…Focused file · src/vs/platform/telemetry/common/errorTelemetry.ts · 175 LOCcommon/errorTelemetry.ts

Graph controls are ready.

Interactive rendering requires JavaScript and WebGL. Use the related-file, concept, and source links on this page while the interactive map is unavailable.

1 > /*--------------------------------------------------------------------------------------------- errorTelemetry.ts ×9
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { binarySearch } from '../../../base/common/arrays.js';
7 > import { errorHandler, ErrorNoTelemetry, PendingMigrationError } from '../../../base/common/errors.js';
8 > import { ListenerLeakError } from '../../../base/common/event.js';
9 > import { DisposableStore, toDisposable } from '../../../base/common/lifecycle.js';
10 > import { safeStringify } from '../../../base/common/objects.js';
11 > import { FileOperationError } from '../../files/common/files.js';
12 > import { ITelemetryService } from './telemetry.js';
13 >
14 > export type ErrorEventFragment = {
15 > owner: 'lramos15, sbatten';
16 > comment: 'Whenever an error in VS Code is thrown.';
17 > callstack: { classification: 'CallstackOrException'; purpose: 'PerformanceAndHealth'; comment: 'The callstack of the error.' };
18 > msg?: { classification: 'CallstackOrException'; purpose: 'PerformanceAndHealth'; comment: 'The message of the error. Normally the first line int the callstack.' };
19 > file?: { classification: 'CallstackOrException'; purpose: 'PerformanceAndHealth'; comment: 'The file the error originated from.' };
20 > line?: { classification: 'CallstackOrException'; purpose: 'PerformanceAndHealth'; comment: 'The line the error originate on.' };
21 > column?: { classification: 'CallstackOrException'; purpose: 'PerformanceAndHealth'; comment: 'The column of the line which the error orginated on.' };
22 > uncaught_error_name?: { classification: 'CallstackOrException'; purpose: 'PerformanceAndHealth'; comment: 'If the error is uncaught what is the error type' };
23 > uncaught_error_msg?: { classification: 'CallstackOrException'; purpose: 'PerformanceAndHealth'; comment: 'If the error is uncaught this is just msg but for uncaught errors.' };
24 > count?: { classification: 'CallstackOrException'; purpose: 'PerformanceAndHealth'; comment: 'How many times this error has been thrown' };
25 > };
26 >
27 > type ListenerLeakDiagEvent = {
28 > kind?: string;
29 > listenerCount?: number;
30 > };
31 >
32 > type ListenerLeakDiagFragment = {
33 > kind?: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; comment: 'Whether the leak is dominated by a single subscriber or popular among many.' };
34 > listenerCount?: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; comment: 'Number of listeners on the emitter when the leak was detected.' };
35 > };
36 >
37 > type UnhandledErrorEvent = ErrorEvent & ListenerLeakDiagEvent;
38 > type UnhandledErrorClassification = ErrorEventFragment & ListenerLeakDiagFragment;
39 >
40 > export interface ErrorEvent {
41 > callstack: string;
42 > msg?: string;
43 > file?: string;
44 > line?: number;
45 > column?: number;
46 > uncaught_error_name?: string;
47 > uncaught_error_msg?: string;
48 > count?: number;
49 > }
50 >
51 > export namespace ErrorEvent {
52 > export function compare(a: ErrorEvent, b: ErrorEvent) {
53 if (a.callstack < b.callstack) {
54 return -1;
55 } else if (a.callstack > b.callstack) {
56 return 1;
57 }
58 return 0;
59 }
61 >
62 > /**
63 > * Extracts a callstack and message from an error object for telemetry.
64 > * Handles the `Array.isArray(err.stack)` workaround from workerServer.ts
65 > * and falls back to {@link safeStringify} when no message is available.
66 > */
67 > export function packErrorForTelemetry(err: any): { callstack: string | undefined; msg: string } {
68 > if (!err || typeof err !== 'object') { serverAgentHostManager.ts ×3
69 return { callstack: undefined, msg: safeStringify(err) };
70 }
71 > const callstack: string | undefined = Array.isArray(err.stack) ? err.stack.join('\n') : err.stack; serverAgentHostManager.ts ×3
72 > const msg = err.message ? err.message : safeStringify(err);
73 > return { callstack, msg };
74 > }
76 > export default abstract class BaseErrorTelemetry {
77 >
78 > public static ERROR_FLUSH_TIMEOUT: number = 5 * 1000;
79 >
80 > private _telemetryService: ITelemetryService;
81 > private _flushDelay: number;
82 > private _flushHandle: Timeout | undefined = undefined;
83 > private _buffer: ErrorEvent[] = [];
84 > protected readonly _disposables = new DisposableStore();
85 >
86 > constructor(telemetryService: ITelemetryService, flushDelay = BaseErrorTelemetry.ERROR_FLUSH_TIMEOUT) {
87 this._telemetryService = telemetryService;
88 this._flushDelay = flushDelay;
89
90 // (1) check for unexpected but handled errors
91 const unbind = errorHandler.addListener((err) => this._onErrorEvent(err));
92 this._disposables.add(toDisposable(unbind));
93
94 // (2) install implementation-specific error listeners
95 this.installErrorListeners();
96 }
98 > dispose() {
99 clearTimeout(this._flushHandle);
100 this._flushBuffer();
101 this._disposables.dispose();
102 }
104 > protected installErrorListeners(): void {
105 // to override
106 }
108 > private _onErrorEvent(err: any): void {
109
110 if (!err || err.code) {
111 return;
112 }
113
114 // unwrap nested errors from loader
115 if (err.detail && err.detail.stack) {
116 err = err.detail;
117 }
118
119 // If it's the no telemetry error it doesn't get logged
120 // TOOD @lramos15 hacking in FileOperation error because it's too messy to adopt ErrorNoTelemetry. A better solution should be found
121 //
122 // Explicitly filter out PendingMigrationError for https://github.com/microsoft/vscode/issues/250648#issuecomment-3394040431
123 // We don't inherit from ErrorNoTelemetry to preserve the name used in reporting for exthostdeprecatedapiusage event.
124 // TODO(deepak1556): remove when PendingMigrationError is no longer needed.
125 if (ErrorNoTelemetry.isErrorNoTelemetry(err) || err instanceof FileOperationError || PendingMigrationError.is(err) || (typeof err?.message === 'string' && err.message.includes('Unable to read file'))) {
126 return;
127 }
128
129 // work around behavior in workerServer.ts that breaks up Error.stack
130 const { callstack, msg } = packErrorForTelemetry(err);
131
132 // errors without a stack are not useful telemetry
133 if (!callstack) {
134 return;
135 }
136
137 const errorEvent: ErrorEvent = { msg, callstack };
138
139 // enrich with listener leak diagnostic fields
140 if (ListenerLeakError.is(err)) {
141 (errorEvent as UnhandledErrorEvent).kind = err.kind;
142 (errorEvent as UnhandledErrorEvent).listenerCount = err.listenerCount;
143 }
144
145 this._enqueue(errorEvent);
146 }
148 > protected _enqueue(e: ErrorEvent): void {
149
150 const idx = binarySearch(this._buffer, e, ErrorEvent.compare);
151 if (idx < 0) {
152 e.count = 1;
153 this._buffer.splice(~idx, 0, e);
154 } else {
155 if (!this._buffer[idx].count) {
156 this._buffer[idx].count = 0;
157 }
158 this._buffer[idx].count += 1;
159 }
160
161 if (this._flushHandle === undefined) {
162 this._flushHandle = setTimeout(() => {
163 this._flushBuffer();
164 this._flushHandle = undefined;
165 }, this._flushDelay);
166 }
167 }
169 > private _flushBuffer(): void {
170 for (const error of this._buffer) {
171 this._telemetryService.publicLogError2<UnhandledErrorEvent, UnhandledErrorClassification>('UnhandledError', error as UnhandledErrorEvent);
172 }
173 this._buffer.length = 0;
174 }