Skip to content

Profiler start session on load#21074

Open
allancascante wants to merge 25 commits intomainfrom
dev/allancascante/profiler_start_session_on_load
Open

Profiler start session on load#21074
allancascante wants to merge 25 commits intomainfrom
dev/allancascante/profiler_start_session_on_load

Conversation

@allancascante
Copy link
Contributor

@allancascante allancascante commented Feb 2, 2026

Description

When starting a profiler session, user must select a template and session to start; added also a way to detect if the session is for Azure to filter the templates that can be selected to only those available for Azure. Also added an error if the connection is for Fabric to let the user know it is not supported. Also, for Azure display the database names if the connection doesn't include one so the user can pick the database to be used when starting the session, fixed an error with the Azure templates and added logic to start the session selected if it exists, and to create it if it doesn't.

Code Changes Checklist

  • New or updated unit tests added
  • All existing tests pass (npm run test)
  • Code follows contributing guidelines
  • Telemetry/logging updated if relevant
  • No regressions or UX breakage

Reviewers: Please read our reviewer guidelines

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request enhances the profiler functionality by adding template and session selection during launch, implementing server type detection to handle Azure SQL and Fabric connections appropriately, and auto-starting profiler sessions after creation. The changes include fixing Azure SQL Extended Events templates by removing unsupported actions, adding database selection for Azure SQL connections, and improving the overall user experience when starting profiler sessions.

Changes:

  • Added server type detection to filter available templates by engine type (Azure vs on-premises) and block Fabric connections
  • Implemented database selection for Azure SQL connections when no user database is specified
  • Changed profiler session flow to prompt for template and session name on launch, then auto-create and start the session
  • Fixed Azure SQL Extended Events templates by removing sqlserver.server_principal_name action which is not supported in Azure SQL Database

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
localization/xliff/vscode-mssql.xlf Added localization strings for Fabric warning, database selection prompt, and session started message
extensions/mssql/l10n/bundle.l10n.json Added English translations for new localization strings
extensions/mssql/src/constants/locConstants.ts Defined new localization constants for profiler database selection and Fabric warning
extensions/mssql/src/profiler/profilerDefaultConfig.ts Renamed template names to include engine type suffix and removed unsupported server_principal_name action from Azure templates
extensions/mssql/src/profiler/profilerController.ts Implemented server type detection, Azure database selection, template filtering by engine type, and auto-start session logic
extensions/mssql/test/unit/profiler/profilerController.test.ts Added comprehensive tests for server type handling, database selection, template selection, and session auto-start

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@allancascante allancascante self-assigned this Feb 2, 2026
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Base automatically changed from dev/allancascante/profiler_integration to main February 5, 2026 18:45
@github-actions
Copy link

github-actions bot commented Feb 5, 2026

PR Changes

Category Target Branch PR Branch Difference
vscode-mssql VSIX 5911 KB 5912 KB ⚪ 1 KB ( 0% )
sql-database-projects VSIX 7877 KB 7877 KB ⚪ 0 KB ( 0% )
data-workspace VSIX 544 KB 544 KB ⚪ 0 KB ( 0% )

@codecov-commenter
Copy link

codecov-commenter commented Feb 5, 2026

Codecov Report

❌ Patch coverage is 89.76378% with 13 lines in your changes missing coverage. Please review.
✅ Project coverage is 68.60%. Comparing base (8c2a6a9) to head (9b1ede7).

Files with missing lines Patch % Lines
...xtensions/mssql/src/profiler/profilerController.ts 89.34% 13 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main   #21074      +/-   ##
==========================================
+ Coverage   68.29%   68.60%   +0.31%     
==========================================
  Files         242      242              
  Lines       23543    23661     +118     
  Branches     3114     3131      +17     
==========================================
+ Hits        16078    16233     +155     
+ Misses       7336     7299      -37     
  Partials      129      129              
Files with missing lines Coverage Δ
extensions/mssql/src/constants/locConstants.ts 87.94% <100.00%> (+0.22%) ⬆️
...nsions/mssql/src/profiler/profilerDefaultConfig.ts 100.00% <ø> (ø)
...xtensions/mssql/src/profiler/profilerController.ts 63.78% <89.34%> (+27.08%) ⬆️

... and 3 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@github-actions
Copy link

github-actions bot commented Feb 5, 2026

Updates to localized strings required

Please update the localized strings in the PR with following steps:

  1. Run yarn localization from the root directory of the PR branch.
  2. Commit the updated localization files:
    • XLIFF files: localization/xliff/*.xlf
    • Bundle files: extensions/mssql/l10n/bundle.l10n.json and extensions/sql-database-projects/l10n/bundle.l10n.json

The localization system extracts strings from both extensions to a centralized location.

Copilot AI review requested due to automatic review settings February 6, 2026 16:23
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 10 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +703 to +706
this._logger.verbose(`Session '${sessionName}' created successfully`);

// Auto-start the session
await this.startSession(sessionName, webviewController);
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The UI is now driven by user-selected templates, but startSession still creates ProfilerSession instances with templateName: "Standard" (hard-coded). This makes the session metadata inconsistent with the selected template and can lead to incorrect UI state/telemetry if anything relies on templateName. Pass the selected template name/id through to startSession and into createSession instead of hard-coding.

Copilot uses AI. Check for mistakes.
this._logger.verbose(`Server types detected: ${serverTypes.join(", ")}`);

// Determine engine type based on server type
this._currentEngineType = serverTypes.includes(ServerType.Azure)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please move this to some sort of shared util.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

@aasimkhan30 aasimkhan30 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. Please do the cleanup as a follow up PR.

Copilot AI review requested due to automatic review settings February 7, 2026 02:08
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 7 comments.

Comments suppressed due to low confidence (1)

extensions/mssql/src/profiler/profilerController.ts:536

  • setupProfilerUI performs several awaited operations (template selection, session name input, getXEventSessions) before the webview dispose override is installed. If any of these throw, the profiler connection and _profilerEngineTypes entry created in launchProfilerWithConnection can be leaked. Wrap the body in a try/catch/finally (or catch around getXEventSessions) that disconnects profilerUri and deletes the engine-type mapping on failure.
    private async setupProfilerUI(profilerUri: string, engineType: EngineType): Promise<void> {
        this._profilerUri = profilerUri;

        // Step 1: Show template selection quick pick (filtered by engine type)
        const configService = getProfilerConfigService();
        const templates = configService.getTemplatesForEngine(engineType);
        this._logger.verbose(
            `Filtered templates for engine ${engineType}: ${templates.length} available`,
        );

        if (templates.length === 0) {
            vscode.window.showWarningMessage(LocProfiler.noTemplatesAvailable);
            // Disconnect since no templates are available and we can't proceed
            await this._connectionManager.disconnect(profilerUri);
            return;
        }

        const templateItems = templates.map((t) => ({
            label: t.name,
            description: t.description,
            detail: LocProfiler.engineLabel(t.engineType),
            template: t,
        }));

        const selectedTemplate = await vscode.window.showQuickPick(templateItems, {
            placeHolder: LocProfiler.selectTemplate,
            ignoreFocusOut: true,
            title: LocProfiler.newSessionSelectTemplate,
        });

        if (!selectedTemplate) {
            this._logger.verbose("User cancelled template selection");
            // Disconnect since user cancelled
            await this._connectionManager.disconnect(profilerUri);
            return;
        }

        this._logger.verbose(`Selected template: ${selectedTemplate.template.name}`);

        // Step 2: Show session name input (default to template name)
        const sessionName = await vscode.window.showInputBox({
            prompt: LocProfiler.enterSessionName,
            placeHolder: LocProfiler.sessionNamePlaceholder,
            value: selectedTemplate.template.name.replace(/\s+/g, "_"), // Default to template name with underscores
            title: LocProfiler.newSessionEnterName,
            ignoreFocusOut: true,
            validateInput: (value) => {
                if (!value || value.trim().length === 0) {
                    return LocProfiler.sessionNameEmpty;
                }
                if (value.length > SESSION_NAME_MAX_LENGTH) {
                    return LocProfiler.sessionNameTooLong(SESSION_NAME_MAX_LENGTH);
                }
                // Check for invalid characters (basic validation)
                if (!/^[a-zA-Z0-9_-]+$/.test(value)) {
                    return LocProfiler.sessionNameInvalidChars;
                }
                return undefined;
            },
        });

        if (!sessionName) {
            this._logger.verbose("User cancelled session name input");
            // Disconnect since user cancelled
            await this._connectionManager.disconnect(profilerUri);
            return;
        }

        this._logger.verbose(`Session name: ${sessionName}`);

        // Fetch available XEvent sessions from the server
        this._logger.verbose("Fetching available XEvent sessions...");
        const xeventSessions = await this._sessionManager.getXEventSessions(profilerUri);
        this._logger.verbose(`Found ${xeventSessions.length} available XEvent sessions`);


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +323 to +326
// Get the engine type for the current profiler URI
const engineType =
this._profilerEngineTypes.get(this._profilerUri) ?? EngineType.Standalone;
const templates = configService.getTemplatesForEngine(engineType);
Copy link

Copilot AI Feb 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

handleCreateSession looks up the engine type using this._profilerUri (a single mutable field) instead of the specific URI for the webview that invoked the action. If multiple profiler webviews are opened, actions from an older webview can end up using the most recently assigned _profilerUri, leading to wrong template filtering and RPC calls against the wrong connection. Consider threading the owning profilerUri through the webview event handlers (capture it in the closure in setupProfilerUI) and remove reliance on the global _profilerUri for per-webview operations.

Copilot uses AI. Check for mistakes.
Comment on lines +74 to +78
// Block Fabric connections - profiler is not supported
if (serverTypes.includes(ServerType.Fabric)) {
this._logger.verbose("Profiler not supported on Fabric");
vscode.window.showWarningMessage(LocProfiler.profilerNotSupportedOnFabric);
return;
Copy link

Copilot AI Feb 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR description says Fabric connections should show an error, but the implementation uses showWarningMessage. Either update the description or switch to showErrorMessage if this is intended to be an error-level UX.

Copilot uses AI. Check for mistakes.
{
id: TEMPLATE_ID_TSQL_ONPREM,
name: "TSQL",
name: "TSQL_OnPrem",
Copy link

Copilot AI Feb 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Template name values appear user-facing (used as quick-pick labels and exposed to the webview). Renaming them to Standard_OnPrem / Standard_Azure / TSQL_OnPrem / TSQL_Azure makes the UI less readable and inconsistent with the other templates (e.g. TSQL_Locks). Consider keeping a friendly display name (e.g. “Standard”, “TSQL”) and using id (or a separate internal key) for disambiguation/default session naming instead.

Suggested change
name: "TSQL_OnPrem",
name: "TSQL",

Copilot uses AI. Check for mistakes.
Comment on lines +670 to +706
test("should prompt for database when Azure SQL has no database selected", async () => {
const mockTreeNodeInfo = {
connectionProfile: {
server: "testserver.database.windows.net",
authenticationType: "AzureMFA",
database: "", // No database selected
},
};

showQuickPickStub.resolves("UserDB1");

createController();
const launchCommand = registeredCommands.get("mssql.profiler.launchFromObjectExplorer");

await launchCommand!(mockTreeNodeInfo);

expect(showQuickPickStub).to.have.been.called;
});

test("should prompt for database when Azure SQL has system database selected", async () => {
const mockTreeNodeInfo = {
connectionProfile: {
server: "testserver.database.windows.net",
authenticationType: "AzureMFA",
database: "master", // System database
},
};

showQuickPickStub.resolves("UserDB1");

createController();
const launchCommand = registeredCommands.get("mssql.profiler.launchFromObjectExplorer");

await launchCommand!(mockTreeNodeInfo);

expect(showQuickPickStub).to.have.been.called;
});
Copy link

Copilot AI Feb 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These Azure database-selection tests stub showQuickPick to return a string (e.g. "UserDB1"), but the launch flow subsequently uses showQuickPick again for template selection and expects an object with a .template property. This causes the code under test to go down the error path (caught by launchProfilerWithConnection) and the assertions no longer validate the intended behavior. Update the stubs to return different values per call (e.g. onFirstCall() for DB selection, onSecondCall() for template selection, and stub showInputBox accordingly), and add assertions for call count/args so the tests fail if the flow regresses.

Copilot uses AI. Check for mistakes.
Comment on lines +244 to +253
// Set up session created handler to resolve immediately
(mockProfilerService.onSessionCreated as sinon.SinonStub).callsFake(
(_ownerUri: string, handler: (params: unknown) => void) => {
// Simulate session created notification after a short delay
setTimeout(() => {
handler({ sessionName: "TestSession", templateName: "Standard" });
}, 10);
return { dispose: sandbox.stub() };
},
);
Copy link

Copilot AI Feb 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Several tests simulate onSessionCreated via setTimeout(..., 10), which can introduce timing flakiness in CI. Prefer using Sinon fake timers or invoking the handler synchronously / via Promise.resolve().then(...) so the test outcome doesn’t depend on real timeouts.

Copilot uses AI. Check for mistakes.
"Select a database for profiling (Azure SQL requires a specific database)",
);
public static noDatabasesFound = l10n.t(
"No databases found on the server. Please check your connection.",
Copy link

Copilot AI Feb 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The warning text noDatabasesFound is shown when no user databases remain after filtering out system DBs, but the message says “No databases found on the server…”. This can be misleading when the server only returns system databases. Consider adjusting the string to explicitly mention “no user databases found” (or similar) to match the actual condition.

Suggested change
"No databases found on the server. Please check your connection.",
"No user databases found on the server. If this is unexpected, please check your connection or permissions.",

Copilot uses AI. Check for mistakes.
Comment on lines +668 to +686
// Register handler for session created notification
const sessionCreatedPromise = new Promise<void>((resolve, reject) => {
const timeout = setTimeout(() => {
disposable.dispose();
reject(new Error(LocProfiler.sessionCreationTimedOut));
}, 30000); // 30 second timeout

const disposable = this._sessionManager.onSessionCreated(
profilerUri,
(params) => {
clearTimeout(timeout);
disposable.dispose();
this._logger.verbose(
`Session created notification received: ${params.sessionName}`,
);
resolve();
},
);
});
Copy link

Copilot AI Feb 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same issue as above: disposable is referenced in the timeout callback before it’s declared inside the Promise executor, which can fail TypeScript compilation. Refactor to declare let disposable first (and use optional chaining when disposing) so this compiles cleanly.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants