Skip to content

Commit 4fb6434

Browse files
authored
Improves logging (microsoft#232842)
1 parent d9d07c4 commit 4fb6434

File tree

4 files changed

+92
-7
lines changed

4 files changed

+92
-7
lines changed

src/vs/editor/browser/widget/codeEditor/codeEditorWidget.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,9 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE
197197
private readonly _onEndUpdate: Emitter<void> = this._register(new Emitter<void>());
198198
public readonly onEndUpdate: Event<void> = this._onEndUpdate.event;
199199

200+
private readonly _onBeforeExecuteEdit = this._register(new Emitter<{ source: string | undefined }>());
201+
public readonly onBeforeExecuteEdit = this._onBeforeExecuteEdit.event;
202+
200203
//#endregion
201204

202205
public get isSimpleWidget(): boolean {
@@ -1232,6 +1235,8 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE
12321235
cursorStateComputer = endCursorState;
12331236
}
12341237

1238+
this._onBeforeExecuteEdit.fire({ source: source ?? undefined });
1239+
12351240
this._modelData.viewModel.executeEdits(source, edits, cursorStateComputer);
12361241
return true;
12371242
}

src/vs/editor/contrib/inlineCompletions/browser/controller/inlineCompletionsController.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import { CursorChangeReason } from '../../../../common/cursorEvents.js';
3030
import { ILanguageFeatureDebounceService } from '../../../../common/services/languageFeatureDebounce.js';
3131
import { ILanguageFeaturesService } from '../../../../common/services/languageFeatures.js';
3232
import { InlineCompletionsHintsWidget, InlineSuggestionHintsContentWidget } from '../hintsWidget/inlineCompletionsHintsWidget.js';
33+
import { TextModelChangeRecorder } from '../model/changeRecorder.js';
3334
import { InlineCompletionsModel } from '../model/inlineCompletionsModel.js';
3435
import { SuggestWidgetAdaptor } from '../model/suggestWidgetAdaptor.js';
3536
import { convertItemsToStableObservables, ObservableContextKeyService } from '../utils.js';
@@ -301,6 +302,8 @@ export class InlineCompletionsController extends Disposable {
301302
})));
302303
this._register(contextKeySvcObs.bind(InlineCompletionContextKeys.tabShouldAcceptInlineEdit, this.model.map((m, r) => !!m?.tabShouldAcceptInlineEdit.read(r))));
303304
this._register(contextKeySvcObs.bind(InlineCompletionContextKeys.tabShouldJumpToInlineEdit, this.model.map((m, r) => !!m?.tabShouldJumpToInlineEdit.read(r))));
305+
306+
this._register(this._instantiationService.createInstance(TextModelChangeRecorder, this.editor));
304307
}
305308

306309
public playAccessibilitySignal(tx: ITransaction) {
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*---------------------------------------------------------------------------------------------
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 { Disposable } from '../../../../../base/common/lifecycle.js';
7+
import { autorunWithStore } from '../../../../../base/common/observable.js';
8+
import { IContextKeyService } from '../../../../../platform/contextkey/common/contextkey.js';
9+
import { ILogService } from '../../../../../platform/log/common/log.js';
10+
import { ICodeEditor } from '../../../../browser/editorBrowser.js';
11+
import { CodeEditorWidget } from '../../../../browser/widget/codeEditor/codeEditorWidget.js';
12+
import { formatRecordableLogEntry, IRecordableEditorLogEntry, observableContextKey } from './inlineCompletionsSource.js';
13+
14+
export class TextModelChangeRecorder extends Disposable {
15+
private readonly _recordingLoggingEnabled = observableContextKey('editor.inlineSuggest.logChangeReason', this._contextKeyService).recomputeInitiallyAndOnChange(this._store);
16+
17+
constructor(
18+
private readonly _editor: ICodeEditor,
19+
@IContextKeyService private readonly _contextKeyService: IContextKeyService,
20+
@ILogService private readonly _logService: ILogService
21+
) {
22+
super();
23+
this._register(autorunWithStore((reader, store) => {
24+
if (!(this._editor instanceof CodeEditorWidget)) { return; }
25+
if (!this._recordingLoggingEnabled.read(reader)) { return; }
26+
27+
const sources: string[] = [];
28+
29+
store.add(this._editor.onBeforeExecuteEdit(({ source }) => {
30+
if (source) {
31+
sources.push(source);
32+
}
33+
}));
34+
35+
store.add(this._editor.onDidChangeModelContent(e => {
36+
const tm = this._editor.getModel();
37+
if (!tm) { return; }
38+
for (const source of sources) {
39+
this._logService.info(formatRecordableLogEntry<IRecordableEditorLogEntry & { source: string }>('TextModel.setChangeReason', {
40+
time: Date.now(),
41+
modelUri: tm.uri.toString(),
42+
modelVersion: tm.getVersionId(),
43+
source: source,
44+
}));
45+
}
46+
sources.length = 0;
47+
}));
48+
49+
}));
50+
}
51+
}

src/vs/editor/contrib/inlineCompletions/browser/model/inlineCompletionsSource.ts

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@ import { CancellationToken, CancellationTokenSource } from '../../../../../base/
77
import { equalsIfDefined, itemEquals } from '../../../../../base/common/equals.js';
88
import { matchesSubString } from '../../../../../base/common/filters.js';
99
import { Disposable, IDisposable, MutableDisposable } from '../../../../../base/common/lifecycle.js';
10-
import { IObservable, IReader, ITransaction, derivedOpts, disposableObservableValue, observableValue, transaction } from '../../../../../base/common/observable.js';
10+
import { IObservable, IReader, ITransaction, derivedOpts, disposableObservableValue, observableFromEvent, observableValue, transaction } from '../../../../../base/common/observable.js';
1111
import { IConfigurationService } from '../../../../../platform/configuration/common/configuration.js';
12+
import { IContextKeyService } from '../../../../../platform/contextkey/common/contextkey.js';
1213
import { ILogService } from '../../../../../platform/log/common/log.js';
1314
import { observableConfigValue } from '../../../../../platform/observable/common/platformObservableUtils.js';
1415
import { Position } from '../../../../common/core/position.js';
@@ -31,6 +32,7 @@ export class InlineCompletionsSource extends Disposable {
3132
public readonly suggestWidgetInlineCompletions = disposableObservableValue<UpToDateInlineCompletions | undefined>('suggestWidgetInlineCompletions', undefined);
3233

3334
private readonly _loggingEnabled = observableConfigValue('editor.inlineSuggest.logFetch', false, this._configurationService).recomputeInitiallyAndOnChange(this._store);
35+
private readonly _recordingLoggingEnabled = observableContextKey('editor.inlineSuggest.logFetch', this._contextKeyService).recomputeInitiallyAndOnChange(this._store);
3436

3537
constructor(
3638
private readonly _textModel: ITextModel,
@@ -40,6 +42,7 @@ export class InlineCompletionsSource extends Disposable {
4042
@ILanguageConfigurationService private readonly _languageConfigurationService: ILanguageConfigurationService,
4143
@ILogService private readonly _logService: ILogService,
4244
@IConfigurationService private readonly _configurationService: IConfigurationService,
45+
@IContextKeyService private readonly _contextKeyService: IContextKeyService,
4346
) {
4447
super();
4548

@@ -48,8 +51,11 @@ export class InlineCompletionsSource extends Disposable {
4851
}));
4952
}
5053

51-
private _log(entry: { kind: 'start'; uri: string; modelVersion: number; requestId: number; context: unknown } | { kind: 'end'; error: any; durationMs: number; result: unknown; requestId: number }) {
52-
this._logService.info('InlineCompletionsSource.fetch ' + JSON.stringify(entry));
54+
private _log(entry:
55+
{ kind: 'start'; requestId: number; context: unknown } & IRecordableEditorLogEntry
56+
| { kind: 'end'; error: any; durationMs: number; result: unknown; requestId: number } & IRecordableLogEntry
57+
) {
58+
this._logService.info(formatRecordableLogEntry('InlineCompletions.fetch', entry));
5359
}
5460

5561
public readonly loading = observableValue(this, false);
@@ -84,8 +90,8 @@ export class InlineCompletionsSource extends Disposable {
8490
}
8591

8692
const requestId = InlineCompletionsSource._requestId++;
87-
if (this._loggingEnabled.get()) {
88-
this._log({ kind: 'start', requestId, uri: this._textModel.uri.toString(), modelVersion: this._textModel.getVersionId(), context: { triggerKind: context.triggerKind } });
93+
if (this._loggingEnabled.get() || this._recordingLoggingEnabled.get()) {
94+
this._log({ kind: 'start', requestId, modelUri: this._textModel.uri.toString(), modelVersion: this._textModel.getVersionId(), context: { triggerKind: context.triggerKind }, time: Date.now() });
8995
}
9096

9197
const startTime = new Date();
@@ -104,7 +110,7 @@ export class InlineCompletionsSource extends Disposable {
104110
error = e;
105111
throw e;
106112
} finally {
107-
if (this._loggingEnabled.get()) {
113+
if (this._loggingEnabled.get() || this._recordingLoggingEnabled.get()) {
108114
if (source.token.isCancellationRequested) {
109115
error = 'canceled';
110116
}
@@ -114,7 +120,7 @@ export class InlineCompletionsSource extends Disposable {
114120
isInlineEdit: !!c.sourceInlineCompletion.isInlineEdit,
115121
source: c.source.provider.groupId,
116122
}));
117-
this._log({ kind: 'end', requestId, durationMs: (Date.now() - startTime.getTime()), error, result });
123+
this._log({ kind: 'end', requestId, durationMs: (Date.now() - startTime.getTime()), error, result, time: Date.now() });
118124
}
119125
}
120126

@@ -367,3 +373,23 @@ export class InlineCompletionWithUpdatedRange {
367373
}
368374

369375
const emptyRange = new Range(1, 1, 1, 1);
376+
377+
interface IRecordableLogEntry {
378+
time: number;
379+
}
380+
381+
export interface IRecordableEditorLogEntry extends IRecordableLogEntry {
382+
modelUri: string;
383+
modelVersion: number;
384+
}
385+
386+
/**
387+
* The sourceLabel must not contain '@'!
388+
*/
389+
export function formatRecordableLogEntry<T extends IRecordableLogEntry>(sourceId: string, entry: T): string {
390+
return sourceId + ' @@ ' + JSON.stringify(entry);
391+
}
392+
393+
export function observableContextKey(key: string, contextKeyService: IContextKeyService): IObservable<unknown> {
394+
return observableFromEvent(contextKeyService.onDidChangeContext, () => contextKeyService.getContextKeyValue(key));
395+
}

0 commit comments

Comments
 (0)