Skip to content

Commit

Permalink
Add instrumentation support to the typescript code (#12991)
Browse files Browse the repository at this point in the history
* add instrumentation support to the typescript code

* fix linter

* missed file

* update to a newer image?

* merged

* work around webpack

* webpack! Arg!

* cleanup

* cleanups

* remove spaces

* must use eval to work around webpack

* need vscode in here

* fix line endings?

* fix line endings?

* Add comment

* Added instrumentation to copilothoverprovider

* inject instrumentation code via perfecto instead

* Ensure that everything is instrumented where we can.

* extra comma
  • Loading branch information
fearthecowboy authored Feb 26, 2025
1 parent 388a81c commit a2b7383
Show file tree
Hide file tree
Showing 8 changed files with 140 additions and 80 deletions.
9 changes: 5 additions & 4 deletions Extension/src/Debugger/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { TargetLeafNode, setActiveSshTarget } from '../SSH/TargetsView/targetNod
import { sshCommandToConfig } from '../SSH/sshCommandToConfig';
import { getSshConfiguration, getSshConfigurationFiles, parseFailures, writeSshConfiguration } from '../SSH/sshHosts';
import { pathAccessible } from '../common';
import { instrument } from '../instrumentation';
import { getSshChannel } from '../logger';
import { AttachItemsProvider, AttachPicker, RemoteAttachPicker } from './attachToProcess';
import { ConfigurationAssetProviderFactory, ConfigurationSnippetProvider, DebugConfigurationProvider, IConfigurationAssetProvider } from './configurationProvider';
Expand Down Expand Up @@ -46,10 +47,10 @@ export async function initialize(context: vscode.ExtensionContext): Promise<void
let cppVsDebugProvider: DebugConfigurationProvider | null = null;
if (os.platform() === 'win32') {
cppVsDebugProvider = new DebugConfigurationProvider(assetProvider, DebuggerType.cppvsdbg);
disposables.push(vscode.debug.registerDebugConfigurationProvider(DebuggerType.cppvsdbg, cppVsDebugProvider, vscode.DebugConfigurationProviderTriggerKind.Dynamic));
disposables.push(vscode.debug.registerDebugConfigurationProvider(DebuggerType.cppvsdbg, instrument(cppVsDebugProvider), vscode.DebugConfigurationProviderTriggerKind.Dynamic));
}
const cppDebugProvider: DebugConfigurationProvider = new DebugConfigurationProvider(assetProvider, DebuggerType.cppdbg);
disposables.push(vscode.debug.registerDebugConfigurationProvider(DebuggerType.cppdbg, cppDebugProvider, vscode.DebugConfigurationProviderTriggerKind.Dynamic));
disposables.push(vscode.debug.registerDebugConfigurationProvider(DebuggerType.cppdbg, instrument(cppDebugProvider), vscode.DebugConfigurationProviderTriggerKind.Dynamic));

// Register DebugConfigurationProviders for "Run and Debug" play button.
const debugProvider: DebugConfigurationProvider = new DebugConfigurationProvider(assetProvider, DebuggerType.all);
Expand All @@ -75,7 +76,7 @@ export async function initialize(context: vscode.ExtensionContext): Promise<void
}];

// ConfigurationSnippetProvider needs to be initiallized after configurationProvider calls getConfigurationSnippets.
disposables.push(vscode.languages.registerCompletionItemProvider(launchJsonDocumentSelector, new ConfigurationSnippetProvider(assetProvider)));
disposables.push(vscode.languages.registerCompletionItemProvider(launchJsonDocumentSelector, instrument(new ConfigurationSnippetProvider(assetProvider))));

// Register Debug Adapters
disposables.push(vscode.debug.registerDebugAdapterDescriptorFactory(DebuggerType.cppvsdbg, new CppvsdbgDebugAdapterDescriptorFactory(context)));
Expand All @@ -84,7 +85,7 @@ export async function initialize(context: vscode.ExtensionContext): Promise<void
// SSH Targets View
await initializeSshTargets();
const sshTargetsProvider: SshTargetsProvider = new SshTargetsProvider();
disposables.push(vscode.window.registerTreeDataProvider('CppSshTargetsView', sshTargetsProvider));
disposables.push(vscode.window.registerTreeDataProvider('CppSshTargetsView', instrument(sshTargetsProvider)));
disposables.push(vscode.commands.registerCommand(addSshTargetCmd, () => enableSshTargetsViewAndRun(addSshTargetImpl)));
disposables.push(vscode.commands.registerCommand('C_Cpp.removeSshTarget', (node?: BaseNode) => enableSshTargetsViewAndRun(removeSshTargetImpl, node)));
disposables.push(vscode.commands.registerCommand(refreshCppSshTargetsViewCmd, (node?: BaseNode) => enableSshTargetsViewAndRun((node?: BaseNode) => sshTargetsProvider.refresh(node), node)));
Expand Down
68 changes: 33 additions & 35 deletions Extension/src/LanguageServer/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import { logAndReturn } from '../Utility/Async/returns';
import { is } from '../Utility/System/guards';
import * as util from '../common';
import { isWindows } from '../constants';
import { instrument, isInstrumentationEnabled } from '../instrumentation';
import { DebugProtocolParams, Logger, ShowWarningParams, getDiagnosticsChannel, getOutputChannelLogger, logDebugProtocol, logLocalized, showWarning } from '../logger';
import { localizedStringCount, lookupString } from '../nativeStrings';
import { SessionState } from '../sessionState';
Expand Down Expand Up @@ -840,6 +841,16 @@ export interface Client {
}

export function createClient(workspaceFolder?: vscode.WorkspaceFolder): Client {
if (isInstrumentationEnabled) {
instrument(vscode.languages, { name: "languages" });
instrument(vscode.window, { name: "window" });
instrument(vscode.workspace, { name: "workspace" });
instrument(vscode.commands, { name: "commands" });
instrument(vscode.debug, { name: "debug" });
instrument(vscode.env, { name: "env" });
instrument(vscode.extensions, { name: "extensions" });
return instrument(new DefaultClient(workspaceFolder), { ignore: ["enqueue", "onInterval", "logTelemetry"] });
}
return new DefaultClient(workspaceFolder);
}

Expand Down Expand Up @@ -1323,31 +1334,33 @@ export class DefaultClient implements Client {
this.currentCopilotHoverEnabled = new PersistentWorkspaceState<string>("cpp.copilotHover", settings.copilotHover);
if (settings.copilotHover !== "disabled") {
this.copilotHoverProvider = new CopilotHoverProvider(this);
this.disposables.push(vscode.languages.registerHoverProvider(util.documentSelector, this.copilotHoverProvider));
this.disposables.push(vscode.languages.registerHoverProvider(util.documentSelector, instrument(this.copilotHoverProvider)));
}

if (settings.copilotHover !== this.currentCopilotHoverEnabled.Value) {
this.currentCopilotHoverEnabled.Value = settings.copilotHover;
}
this.disposables.push(vscode.languages.registerHoverProvider(util.documentSelector, this.hoverProvider));
this.disposables.push(vscode.languages.registerInlayHintsProvider(util.documentSelector, this.inlayHintsProvider));
this.disposables.push(vscode.languages.registerRenameProvider(util.documentSelector, new RenameProvider(this)));
this.disposables.push(vscode.languages.registerReferenceProvider(util.documentSelector, new FindAllReferencesProvider(this)));
this.disposables.push(vscode.languages.registerWorkspaceSymbolProvider(new WorkspaceSymbolProvider(this)));
this.disposables.push(vscode.languages.registerDocumentSymbolProvider(util.documentSelector, new DocumentSymbolProvider(), undefined));
this.disposables.push(vscode.languages.registerCodeActionsProvider(util.documentSelector, new CodeActionProvider(this), undefined));
this.disposables.push(vscode.languages.registerCallHierarchyProvider(util.documentSelector, new CallHierarchyProvider(this)));
this.disposables.push(vscode.languages.registerHoverProvider(util.documentSelector, instrument(this.hoverProvider)));
this.disposables.push(vscode.languages.registerInlayHintsProvider(util.documentSelector, instrument(this.inlayHintsProvider)));
this.disposables.push(vscode.languages.registerRenameProvider(util.documentSelector, instrument(new RenameProvider(this))));
this.disposables.push(vscode.languages.registerReferenceProvider(util.documentSelector, instrument(new FindAllReferencesProvider(this))));
this.disposables.push(vscode.languages.registerWorkspaceSymbolProvider(instrument(new WorkspaceSymbolProvider(this))));
this.disposables.push(vscode.languages.registerDocumentSymbolProvider(util.documentSelector, instrument(new DocumentSymbolProvider()), undefined));
this.disposables.push(vscode.languages.registerCodeActionsProvider(util.documentSelector, instrument(new CodeActionProvider(this)), undefined));
this.disposables.push(vscode.languages.registerCallHierarchyProvider(util.documentSelector, instrument(new CallHierarchyProvider(this))));

// Because formatting and codeFolding can vary per folder, we need to register these providers once
// and leave them registered. The decision of whether to provide results needs to be made on a per folder basis,
// within the providers themselves.
this.documentFormattingProviderDisposable = vscode.languages.registerDocumentFormattingEditProvider(util.documentSelector, new DocumentFormattingEditProvider(this));
this.formattingRangeProviderDisposable = vscode.languages.registerDocumentRangeFormattingEditProvider(util.documentSelector, new DocumentRangeFormattingEditProvider(this));
this.onTypeFormattingProviderDisposable = vscode.languages.registerOnTypeFormattingEditProvider(util.documentSelector, new OnTypeFormattingEditProvider(this), ";", "}", "\n");
this.documentFormattingProviderDisposable = vscode.languages.registerDocumentFormattingEditProvider(util.documentSelector, instrument(new DocumentFormattingEditProvider(this)));
this.formattingRangeProviderDisposable = vscode.languages.registerDocumentRangeFormattingEditProvider(util.documentSelector, instrument(new DocumentRangeFormattingEditProvider(this)));
this.onTypeFormattingProviderDisposable = vscode.languages.registerOnTypeFormattingEditProvider(util.documentSelector, instrument(new OnTypeFormattingEditProvider(this)), ";", "}", "\n");

this.codeFoldingProvider = new FoldingRangeProvider(this);
this.codeFoldingProviderDisposable = vscode.languages.registerFoldingRangeProvider(util.documentSelector, this.codeFoldingProvider);
this.codeFoldingProviderDisposable = vscode.languages.registerFoldingRangeProvider(util.documentSelector, instrument(this.codeFoldingProvider));

if (settings.isEnhancedColorizationEnabled && semanticTokensLegend) {
this.semanticTokensProvider = new SemanticTokensProvider();
this.semanticTokensProvider = instrument(new SemanticTokensProvider());
this.semanticTokensProviderDisposable = vscode.languages.registerDocumentSemanticTokensProvider(util.documentSelector, this.semanticTokensProvider, semanticTokensLegend);
}

Expand Down Expand Up @@ -1730,8 +1743,7 @@ export class DefaultClient implements Client {
const oldLoggingLevelLogged: boolean = this.loggingLevel > 1;
this.loggingLevel = util.getNumericLoggingLevel(changedSettings.loggingLevel);
if (oldLoggingLevelLogged || this.loggingLevel > 1) {
const out: Logger = getOutputChannelLogger();
out.appendLine(localize({ key: "loggingLevel.changed", comment: ["{0} is the setting name 'loggingLevel', {1} is a string value such as 'Debug'"] }, "{0} has changed to: {1}", "loggingLevel", changedSettings.loggingLevel));
getOutputChannelLogger().appendLine(localize({ key: "loggingLevel.changed", comment: ["{0} is the setting name 'loggingLevel', {1} is a string value such as 'Debug'"] }, "{0} has changed to: {1}", "loggingLevel", changedSettings.loggingLevel));
}
}
const settings: CppSettings = new CppSettings();
Expand Down Expand Up @@ -2746,12 +2758,7 @@ export class DefaultClient implements Client {
const status: IntelliSenseStatus = { status: Status.IntelliSenseCompiling };
testHook.updateStatus(status);
} else if (message.endsWith("IntelliSense done")) {
const settings: CppSettings = new CppSettings();
if (util.getNumericLoggingLevel(settings.loggingLevel) >= 6) {
const out: Logger = getOutputChannelLogger();
const duration: number = Date.now() - timeStamp;
out.appendLine(localize("update.intellisense.time", "Update IntelliSense time (sec): {0}", duration / 1000));
}
getOutputChannelLogger().appendLineAtLevel(6, localize("update.intellisense.time", "Update IntelliSense time (sec): {0}", (Date.now() - timeStamp) / 1000));
this.model.isUpdatingIntelliSense.Value = false;
const status: IntelliSenseStatus = { status: Status.IntelliSenseReady };
testHook.updateStatus(status);
Expand Down Expand Up @@ -3183,11 +3190,8 @@ export class DefaultClient implements Client {
return;
}

const settings: CppSettings = new CppSettings();
const out: Logger = getOutputChannelLogger();
if (util.getNumericLoggingLevel(settings.loggingLevel) >= 6) {
out.appendLine(localize("configurations.received", "Custom configurations received:"));
}
out.appendLineAtLevel(6, localize("configurations.received", "Custom configurations received:"));
const sanitized: SourceFileConfigurationItemAdapter[] = [];
configs.forEach(item => {
if (this.isSourceFileConfigurationItem(item, providerVersion)) {
Expand All @@ -3199,10 +3203,8 @@ export class DefaultClient implements Client {
uri = item.uri.toString();
}
this.configurationLogging.set(uri, JSON.stringify(item.configuration, null, 4));
if (util.getNumericLoggingLevel(settings.loggingLevel) >= 6) {
out.appendLine(` uri: ${uri}`);
out.appendLine(` config: ${JSON.stringify(item.configuration, null, 2)}`);
}
out.appendLineAtLevel(6, ` uri: ${uri}`);
out.appendLineAtLevel(6, ` config: ${JSON.stringify(item.configuration, null, 2)}`);
if (item.configuration.includePath.some(path => path.endsWith('**'))) {
console.warn("custom include paths should not use recursive includes ('**')");
}
Expand Down Expand Up @@ -3306,11 +3308,7 @@ export class DefaultClient implements Client {
return;
}

const settings: CppSettings = new CppSettings();
if (util.getNumericLoggingLevel(settings.loggingLevel) >= 6) {
const out: Logger = getOutputChannelLogger();
out.appendLine(localize("browse.configuration.received", "Custom browse configuration received: {0}", JSON.stringify(sanitized, null, 2)));
}
getOutputChannelLogger().appendLineAtLevel(6, localize("browse.configuration.received", "Custom browse configuration received: {0}", JSON.stringify(sanitized, null, 2)));

// Separate compiler path and args before sending to language client
if (util.isString(sanitized.compilerPath)) {
Expand Down
11 changes: 5 additions & 6 deletions Extension/src/LanguageServer/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import * as which from 'which';
import { logAndReturn } from '../Utility/Async/returns';
import * as util from '../common';
import { modelSelector } from '../constants';
import { instrument } from '../instrumentation';
import { getCrashCallStacksChannel } from '../logger';
import { PlatformInformation } from '../platform';
import * as telemetry from '../telemetry';
Expand Down Expand Up @@ -222,7 +223,7 @@ export async function activate(): Promise<void> {
{ scheme: 'file', language: 'cpp' },
{ scheme: 'file', language: 'cuda-cpp' }
];
codeActionProvider = vscode.languages.registerCodeActionsProvider(selector, {
codeActionProvider = vscode.languages.registerCodeActionsProvider(selector, instrument({
provideCodeActions: async (document: vscode.TextDocument, range: vscode.Range, context: vscode.CodeActionContext): Promise<vscode.CodeAction[]> => {

if (!await clients.ActiveClient.getVcpkgEnabled()) {
Expand All @@ -248,7 +249,7 @@ export async function activate(): Promise<void> {
const actions: vscode.CodeAction[] = ports.map<vscode.CodeAction>(getVcpkgClipboardInstallAction);
return actions;
}
});
}));

await vscode.commands.executeCommand('setContext', 'cpptools.msvcEnvironmentFound', util.hasMsvcEnvironment());

Expand Down Expand Up @@ -1280,10 +1281,8 @@ async function handleCrashFileRead(crashDirectory: string, crashFile: string, cr
if (crashCallStack !== prevCppCrashCallStackData) {
prevCppCrashCallStackData = crashCallStack;

const settings: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("C_Cpp", null);
if (lines.length >= 6 && util.getNumericLoggingLevel(settings.get<string>("loggingLevel")) >= 1) {
const out: vscode.OutputChannel = getCrashCallStacksChannel();
out.appendLine(`\n${isCppToolsSrv ? "cpptools-srv" : "cpptools"}\n${crashDate.toLocaleString()}\n${signalType}${crashCallStack}`);
if (lines.length >= 6 && util.getLoggingLevel() >= 1) {
getCrashCallStacksChannel().appendLine(`\n${isCppToolsSrv ? "cpptools-srv" : "cpptools"}\n${crashDate.toLocaleString()}\n${signalType}${crashCallStack}`);
}
}

Expand Down
17 changes: 7 additions & 10 deletions Extension/src/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -759,10 +759,7 @@ export interface ProcessReturnType {
export async function spawnChildProcess(program: string, args: string[] = [], continueOn?: string, skipLogging?: boolean, cancellationToken?: vscode.CancellationToken): Promise<ProcessReturnType> {
// Do not use CppSettings to avoid circular require()
if (skipLogging === undefined || !skipLogging) {
const settings: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("C_Cpp", null);
if (getNumericLoggingLevel(settings.get<string>("loggingLevel")) >= 5) {
getOutputChannelLogger().appendLine(`$ ${program} ${args.join(' ')}`);
}
getOutputChannelLogger().appendLineAtLevel(5, `$ ${program} ${args.join(' ')}`);
}
const programOutput: ProcessOutput = await spawnChildProcessImpl(program, args, continueOn, skipLogging, cancellationToken);
const exitCode: number | NodeJS.Signals | undefined = programOutput.exitCode;
Expand All @@ -789,10 +786,6 @@ interface ProcessOutput {
async function spawnChildProcessImpl(program: string, args: string[], continueOn?: string, skipLogging?: boolean, cancellationToken?: vscode.CancellationToken): Promise<ProcessOutput> {
const result = new ManualPromise<ProcessOutput>();

// Do not use CppSettings to avoid circular require()
const settings: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("C_Cpp", null);
const loggingLevel: number = (skipLogging === undefined || !skipLogging) ? getNumericLoggingLevel(settings.get<string>("loggingLevel")) : 0;

let proc: child_process.ChildProcess;
if (await isExecutable(program)) {
proc = child_process.spawn(`.${isWindows ? '\\' : '/'}${path.basename(program)}`, args, { shell: true, cwd: path.dirname(program) });
Expand All @@ -817,8 +810,8 @@ async function spawnChildProcessImpl(program: string, args: string[], continueOn
if (proc.stdout) {
proc.stdout.on('data', data => {
const str: string = data.toString();
if (loggingLevel > 0) {
getOutputChannelLogger().append(str);
if (skipLogging === undefined || !skipLogging) {
getOutputChannelLogger().appendAtLevel(1, str);
}
stdout += str;
if (continueOn) {
Expand Down Expand Up @@ -1576,6 +1569,10 @@ function isIntegral(str: string): boolean {
return regex.test(str);
}

export function getLoggingLevel() {
return getNumericLoggingLevel(vscode.workspace.getConfiguration("C_Cpp", null).get<string>("loggingLevel"));
}

export function getNumericLoggingLevel(loggingLevel: string | undefined): number {
if (!loggingLevel) {
return 1;
Expand Down
Loading

0 comments on commit a2b7383

Please sign in to comment.