Skip to content

Commit dde0561

Browse files
authored
watcher - log telemetry when watcher fails (microsoft#210570)
1 parent 66ce26e commit dde0561

File tree

4 files changed

+32
-6
lines changed

4 files changed

+32
-6
lines changed

src/vs/platform/files/node/watcher/watcherClient.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ export class UniversalWatcherClient extends AbstractUniversalWatcherClient {
4040
));
4141

4242
// React on unexpected termination of the watcher process
43-
disposables.add(client.onDidProcessExit(({ code, signal }) => this.onError(`terminated by itself with code ${code}, signal: ${signal}`)));
43+
disposables.add(client.onDidProcessExit(({ code, signal }) => this.onError(`terminated by itself with code ${code}, signal: ${signal} (ETERM)`)));
4444

4545
return ProxyChannel.toService<IUniversalWatcher>(getNextTickChannel(client.getChannel('watcher')));
4646
}

src/vs/workbench/contrib/files/browser/files.contribution.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import * as nls from 'vs/nls';
77
import { sep } from 'vs/base/common/path';
88
import { Registry } from 'vs/platform/registry/common/platform';
99
import { IConfigurationRegistry, Extensions as ConfigurationExtensions, ConfigurationScope, IConfigurationPropertySchema } from 'vs/platform/configuration/common/configurationRegistry';
10-
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions, IWorkbenchContribution, WorkbenchPhase, registerWorkbenchContribution2 } from 'vs/workbench/common/contributions';
10+
import { IWorkbenchContribution, WorkbenchPhase, registerWorkbenchContribution2 } from 'vs/workbench/common/contributions';
1111
import { IFileEditorInput, IEditorFactoryRegistry, EditorExtensions } from 'vs/workbench/common/editor';
1212
import { AutoSaveConfiguration, HotExitConfiguration, FILES_EXCLUDE_CONFIG, FILES_ASSOCIATIONS_CONFIG, FILES_READONLY_INCLUDE_CONFIG, FILES_READONLY_EXCLUDE_CONFIG, FILES_READONLY_FROM_PERMISSIONS_CONFIG } from 'vs/platform/files/common/files';
1313
import { SortOrder, LexicographicOptions, FILE_EDITOR_INPUT_ID, BINARY_TEXT_FILE_MODE, UndoConfirmLevel, IFilesConfiguration } from 'vs/workbench/contrib/files/common/files';
@@ -20,7 +20,6 @@ import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
2020
import { isNative, isWeb, isWindows } from 'vs/base/common/platform';
2121
import { ExplorerViewletViewsContribution } from 'vs/workbench/contrib/files/browser/explorerViewlet';
2222
import { IEditorPaneRegistry, EditorPaneDescriptor } from 'vs/workbench/browser/editor';
23-
import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle';
2423
import { ILabelService } from 'vs/platform/label/common/label';
2524
import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions';
2625
import { ExplorerService, UNDO_REDO_SOURCE } from 'vs/workbench/contrib/files/browser/explorerService';
@@ -113,7 +112,7 @@ registerWorkbenchContribution2(TextFileSaveErrorHandler.ID, TextFileSaveErrorHan
113112
registerWorkbenchContribution2(FileUriLabelContribution.ID, FileUriLabelContribution, WorkbenchPhase.BlockStartup);
114113

115114
// Register Workspace Watcher
116-
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(WorkspaceWatcher, LifecyclePhase.Restored);
115+
registerWorkbenchContribution2(WorkspaceWatcher.ID, WorkspaceWatcher, WorkbenchPhase.AfterRestored);
117116

118117
// Register Dirty Files Indicator
119118
registerWorkbenchContribution2(DirtyFilesIndicator.ID, DirtyFilesIndicator, WorkbenchPhase.BlockStartup);

src/vs/workbench/contrib/files/browser/workspaceWatcher.ts

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,12 @@ import { IOpenerService } from 'vs/platform/opener/common/opener';
1515
import { isAbsolute } from 'vs/base/common/path';
1616
import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity';
1717
import { IHostService } from 'vs/workbench/services/host/browser/host';
18+
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
1819

1920
export class WorkspaceWatcher extends Disposable {
2021

22+
static readonly ID = 'workbench.contrib.workspaceWatcher';
23+
2124
private readonly watchedWorkspaces = new ResourceMap<IDisposable>(resource => this.uriIdentityService.extUri.getComparisonKey(resource));
2225

2326
constructor(
@@ -27,7 +30,8 @@ export class WorkspaceWatcher extends Disposable {
2730
@INotificationService private readonly notificationService: INotificationService,
2831
@IOpenerService private readonly openerService: IOpenerService,
2932
@IUriIdentityService private readonly uriIdentityService: IUriIdentityService,
30-
@IHostService private readonly hostService: IHostService
33+
@IHostService private readonly hostService: IHostService,
34+
@ITelemetryService private readonly telemetryService: ITelemetryService
3135
) {
3236
super();
3337

@@ -68,9 +72,12 @@ export class WorkspaceWatcher extends Disposable {
6872

6973
private onDidWatchError(error: Error): void {
7074
const msg = error.toString();
75+
let reason: 'ENOSPC' | 'EUNKNOWN' | 'ETERM' | undefined = undefined;
7176

7277
// Detect if we run into ENOSPC issues
7378
if (msg.indexOf('ENOSPC') >= 0) {
79+
reason = 'ENOSPC';
80+
7481
this.notificationService.prompt(
7582
Severity.Warning,
7683
localize('enospcError', "Unable to watch for file changes. Please follow the instructions link to resolve this issue."),
@@ -87,6 +94,8 @@ export class WorkspaceWatcher extends Disposable {
8794

8895
// Detect when the watcher throws an error unexpectedly
8996
else if (msg.indexOf('EUNKNOWN') >= 0) {
97+
reason = 'EUNKNOWN';
98+
9099
this.notificationService.prompt(
91100
Severity.Warning,
92101
localize('eshutdownError', "File changes watcher stopped unexpectedly. A reload of the window may enable the watcher again unless the workspace cannot be watched for file changes."),
@@ -100,6 +109,24 @@ export class WorkspaceWatcher extends Disposable {
100109
}
101110
);
102111
}
112+
113+
// Detect unexpected termination
114+
else if (msg.indexOf('ETERM') >= 0) {
115+
reason = 'ETERM';
116+
}
117+
118+
// Log telemetry if we gathered a reason
119+
if (reason) {
120+
type WatchErrorClassification = {
121+
owner: 'bpasero';
122+
comment: 'An event that fires when a watcher errors';
123+
reason: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; comment: 'The watcher error reason.' };
124+
};
125+
type WatchErrorEvent = {
126+
reason: string;
127+
};
128+
this.telemetryService.publicLog2<WatchErrorEvent, WatchErrorClassification>('fileWatcherError', { reason });
129+
}
103130
}
104131

105132
private watchWorkspace(workspace: IWorkspaceFolder): void {

src/vs/workbench/services/files/electron-sandbox/watcherClient.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ export class UniversalWatcherClient extends AbstractUniversalWatcherClient {
4646
if (reason?.code === 0) {
4747
this.trace(`terminated by itself with code ${reason.code}, signal: ${reason.signal}`);
4848
} else {
49-
this.onError(`terminated by itself unexpectedly with code ${reason?.code}, signal: ${reason?.signal}`);
49+
this.onError(`terminated by itself unexpectedly with code ${reason?.code}, signal: ${reason?.signal} (ETERM)`);
5050
}
5151
});
5252

0 commit comments

Comments
 (0)