diff --git a/extensions/mssql/src/azure/accountStore.ts b/extensions/mssql/src/azure/accountStore.ts index 62efb0e98a..932a98270d 100644 --- a/extensions/mssql/src/azure/accountStore.ts +++ b/extensions/mssql/src/azure/accountStore.ts @@ -8,20 +8,20 @@ import * as vscode from "vscode"; import * as Constants from "../constants/constants"; import * as Loc from "../constants/locConstants"; import { IAccount } from "../models/contracts/azure"; -import { Logger } from "../models/logger"; +import { ILogger, logger } from "../models/logger"; import { Deferred } from "../protocol"; import { getErrorMessage } from "../utils/utils"; import VscodeWrapper from "../controllers/vscodeWrapper"; export class AccountStore { public readonly initialized: Deferred = new Deferred(); - private readonly _logger: Logger; + private readonly _logger: ILogger; constructor( private _context: vscode.ExtensionContext, private _vscodeWrapper: VscodeWrapper, ) { - this._logger = Logger.create(this._vscodeWrapper.outputChannel, "AccountStore"); + this._logger = logger.withPrefix("AccountStore"); void this.initialize().then(() => { this.initialized.resolve(); diff --git a/extensions/mssql/src/azure/azureController.ts b/extensions/mssql/src/azure/azureController.ts index 30ba98857e..332a5bcc97 100644 --- a/extensions/mssql/src/azure/azureController.ts +++ b/extensions/mssql/src/azure/azureController.ts @@ -16,7 +16,7 @@ import { getCloudProviderSettings } from "./providerSettings"; import VscodeWrapper from "../controllers/vscodeWrapper"; import { ConnectionProfile } from "../models/connectionProfile"; import { AzureAuthType, IAADResource, IAccount, ITenant, IToken } from "../models/contracts/azure"; -import { Logger } from "../models/logger"; +import { ILogger, Logger } from "../models/logger"; import { INameValueChoice, IPrompter, IQuestion, QuestionTypes } from "../prompts/question"; import { AccountStore } from "./accountStore"; import { ICredentialStore } from "../credentialstore/icredentialstore"; @@ -24,7 +24,7 @@ import { ICredentialStore } from "../credentialstore/icredentialstore"; export abstract class AzureController { protected _vscodeWrapper: VscodeWrapper; protected _credentialStoreInitialized = false; - protected logger: Logger; + protected logger: ILogger; constructor( protected context: vscode.ExtensionContext, @@ -36,12 +36,10 @@ export abstract class AzureController { this._vscodeWrapper = new VscodeWrapper(); } - // Setup Logger - - let channel = this._vscodeWrapper.createOutputChannel( + this.logger = Logger.forChannelName( LocalizedConstants.azureLogChannelName, + "AzureController", ); - this.logger = Logger.create(channel); vscode.workspace.onDidChangeConfiguration((changeEvent) => { const impactsProvider = changeEvent.affectsConfiguration( @@ -88,7 +86,7 @@ export abstract class AzureController { let config = azureUtils.getAzureActiveDirectoryConfig(); let account = await this.login(config!); await accountStore.addAccount(account!); - this.logger.verbose("Account added successfully."); + this.logger.debug("Account added successfully."); return account; } @@ -103,7 +101,7 @@ export abstract class AzureController { await this._vscodeWrapper.showErrorMessage(LocalizedConstants.msgAccountNotFound); throw new Error(LocalizedConstants.msgAccountNotFound); } - this.logger.verbose( + this.logger.debug( "Account found and SQL Authentication Provider is enabled, access token will not be refreshed by extension.", ); return profile; @@ -162,9 +160,9 @@ export abstract class AzureController { getCloudProviderSettings(session.account.key.providerId).settings.armResource, ); session.token = token!; - this.logger.verbose(`Access Token refreshed for account: ${session?.account?.key.id}`); + this.logger.debug(`Access Token refreshed for account: ${session?.account?.key.id}`); } else { - this.logger.verbose( + this.logger.debug( `Access Token not refreshed for account: ${session?.account?.key.id}`, ); } @@ -242,7 +240,7 @@ export abstract class AzureController { } } - this.logger.log("Initialized vscode-mssql storage."); + this.logger.trace("Initialized vscode-mssql storage."); return storagePath; } diff --git a/extensions/mssql/src/azure/fileEncryptionHelper.ts b/extensions/mssql/src/azure/fileEncryptionHelper.ts index 62844105eb..a5a6b6d596 100644 --- a/extensions/mssql/src/azure/fileEncryptionHelper.ts +++ b/extensions/mssql/src/azure/fileEncryptionHelper.ts @@ -13,7 +13,7 @@ import { DidChangeEncryptionIVKeyParams, EncryptionKeysChangedNotification, } from "../models/contracts/connection"; -import { Logger } from "../models/logger"; +import { ILogger } from "../models/logger"; import SqlToolsServerClient from "../languageservice/serviceclient"; import { azureAccountProviderCredentials } from "./constants"; @@ -21,7 +21,7 @@ export class FileEncryptionHelper { constructor( private readonly _credentialStore: ICredentialStore, private readonly _vscodeWrapper: VscodeWrapper, - protected readonly _logger: Logger, + protected readonly _logger: ILogger, protected readonly _fileName: string, ) { this._algorithm = "aes-256-cbc"; diff --git a/extensions/mssql/src/azure/msal/msalAzureAuth.ts b/extensions/mssql/src/azure/msal/msalAzureAuth.ts index 6a5cf24413..9e87e659d1 100644 --- a/extensions/mssql/src/azure/msal/msalAzureAuth.ts +++ b/extensions/mssql/src/azure/msal/msalAzureAuth.ts @@ -26,7 +26,7 @@ import { LoginResult, } from "../../models/contracts/azure"; import { IDeferred } from "../../models/interfaces"; -import { Logger } from "../../models/logger"; +import { ILogger } from "../../models/logger"; import { AzureAuthError } from "../azureAuthError"; import * as Constants from "../constants"; import { ErrorResponseBody } from "@azure/arm-subscriptions"; @@ -53,7 +53,7 @@ export abstract class MsalAzureAuth { protected clientApplication: PublicClientApplication, protected readonly authType: AzureAuthType, protected readonly vscodeWrapper: VscodeWrapper, - protected readonly logger: Logger, + protected readonly logger: ILogger, ) { this.loginEndpointUrl = this.providerSettings.loginEndpoint ?? "https://login.microsoftonline.com/"; @@ -68,7 +68,7 @@ export abstract class MsalAzureAuth { public async startLogin(): Promise { let loginComplete: IDeferred | undefined = undefined; try { - this.logger.verbose("Starting login"); + this.logger.debug("Starting login"); if (!this.providerSettings.settings.windowsManagementResource) { throw new Error( LocalizedConstants.azureNoMicrosoftResource(this.providerSettings.displayName), @@ -106,13 +106,13 @@ export abstract class MsalAzureAuth { if (ex instanceof AzureAuthError) { if (loginComplete) { loginComplete.reject(ex); - this.logger.error(ex); + this.logger.error(ex.message); } else { void vscode.window.showErrorMessage(ex.message); this.logger.error(ex.originalMessageAndException); } } else { - this.logger.error(ex); + this.logger.error(String(ex)); } return { success: false, @@ -210,7 +210,7 @@ export abstract class MsalAzureAuth { }; return this.handleInteractionRequired(tenant, settings); } else if (e.name === "ClientAuthError") { - this.logger.verbose("[ClientAuthError] Failed to silently acquire token"); + this.logger.debug("[ClientAuthError] Failed to silently acquire token"); } this.logger.error( @@ -308,7 +308,7 @@ export abstract class MsalAzureAuth { "tenants?api-version=2019-11-01", ); try { - this.logger.verbose("Fetching tenants with uri {0}", tenantUri); + this.logger.debug("Fetching tenants with uri {0}", tenantUri); let tenantList: string[] = []; const tenantResponse = await this._httpHelper.makeGetRequest( tenantUri, @@ -337,7 +337,7 @@ export abstract class MsalAzureAuth { tenantCategory: tenantInfo.tenantCategory, } as ITenant; }); - this.logger.verbose(`Tenants: ${tenantList}`); + this.logger.debug(`Tenants: ${tenantList}`); const homeTenantIndex = tenants.findIndex( (tenant) => tenant.tenantCategory === Constants.homeCategory, ); @@ -346,7 +346,7 @@ export abstract class MsalAzureAuth { const homeTenant = tenants.splice(homeTenantIndex, 1); tenants.unshift(homeTenant[0]); } - this.logger.verbose(`Filtered Tenants: ${tenantList}`); + this.logger.debug(`Filtered Tenants: ${tenantList}`); return tenants; } catch (ex) { this.logger.error(`Error fetching tenants :${ex}`); @@ -442,9 +442,9 @@ export abstract class MsalAzureAuth { //#region data modeling public createAccount(tokenClaims: ITokenClaims, key: string, tenants: ITenant[]): IAccount { - this.logger.verbose(`Token Claims acccount: ${tokenClaims.name}, TID: ${tokenClaims.tid}`); + this.logger.debug(`Token Claims acccount: ${tokenClaims.name}, TID: ${tokenClaims.tid}`); tenants.forEach((tenant) => { - this.logger.verbose(`Tenant ID: ${tenant.id}, Tenant Name: ${tenant.displayName}`); + this.logger.debug(`Tenant ID: ${tenant.id}, Tenant Name: ${tenant.displayName}`); }); // Determine if this is a microsoft account diff --git a/extensions/mssql/src/azure/msal/msalAzureCodeGrant.ts b/extensions/mssql/src/azure/msal/msalAzureCodeGrant.ts index 74855c3879..f5d3d6a819 100644 --- a/extensions/mssql/src/azure/msal/msalAzureCodeGrant.ts +++ b/extensions/mssql/src/azure/msal/msalAzureCodeGrant.ts @@ -13,7 +13,7 @@ import { } from "@azure/msal-node"; import { ITenant, AzureAuthType, IProviderSettings } from "../../models/contracts/azure"; import { IDeferred } from "../../models/interfaces"; -import { Logger } from "../../models/logger"; +import { ILogger } from "../../models/logger"; import { MsalAzureAuth } from "./msalAzureAuth"; import { SimpleWebServer } from "../simpleWebServer"; import { AzureAuthError } from "../azureAuthError"; @@ -40,7 +40,7 @@ export class MsalAzureCodeGrant extends MsalAzureAuth { protected readonly context: vscode.ExtensionContext, protected clientApplication: PublicClientApplication, protected readonly vscodeWrapper: VscodeWrapper, - protected readonly logger: Logger, + protected readonly logger: ILogger, ) { super( providerSettings, diff --git a/extensions/mssql/src/azure/msal/msalAzureController.ts b/extensions/mssql/src/azure/msal/msalAzureController.ts index a3859f80f1..3f3e9d562d 100644 --- a/extensions/mssql/src/azure/msal/msalAzureController.ts +++ b/extensions/mssql/src/azure/msal/msalAzureController.ts @@ -32,7 +32,7 @@ import { IPrompter } from "../../prompts/question"; import { ICredentialStore } from "../../credentialstore/icredentialstore"; import * as azureUtils from "../utils"; import VscodeWrapper from "../../controllers/vscodeWrapper"; -import { Logger } from "../../models/logger"; +import { ILogger } from "../../models/logger"; import { sendActionEvent } from "../../telemetry/telemetry"; import { TelemetryActions, TelemetryViews } from "../../sharedInterfaces/telemetry"; @@ -53,11 +53,11 @@ export class MsalAzureController extends AzureController { break; case MsalLogLevel.Verbose: default: - this.logger.verbose(message); + this.logger.debug(message); break; } } else { - this.logger.pii(message); + this.logger.piiSanitized(message, [], []); } }; } @@ -142,10 +142,10 @@ export class MsalAzureController extends AzureController { try { await fsPromises.access(filePath); await fsPromises.rm(filePath); - this.logger.verbose(`Old cache file removed successfully.`); + this.logger.debug(`Old cache file removed successfully.`); } catch (e) { if (e.code !== "ENOENT") { - this.logger.verbose(`Error occurred while removing old cache file: ${e}`); + this.logger.debug(`Error occurred while removing old cache file: ${e}`); } // else file doesn't exist. } } @@ -328,7 +328,7 @@ export class MsalAzureController extends AzureController { profile.user = account!.displayInfo.displayName; profile.email = account!.displayInfo.email; profile.accountId = account!.key.id; - this.logger.verbose( + this.logger.debug( "SQL Authentication Provider is enabled, access token will not be acquired by extension.", ); return profile; @@ -404,7 +404,7 @@ export class CloudAuthApplication { private loggerCallback: ILoggerCallback, private readonly context: vscode.ExtensionContext, private readonly vscodeWrapper: VscodeWrapper, - private readonly logger: Logger, + private readonly logger: ILogger, ) { this._authMappings = new Map(); this.createClientApplication(); diff --git a/extensions/mssql/src/azure/msal/msalAzureDeviceCode.ts b/extensions/mssql/src/azure/msal/msalAzureDeviceCode.ts index e292cd3a9e..93bc5e9794 100644 --- a/extensions/mssql/src/azure/msal/msalAzureDeviceCode.ts +++ b/extensions/mssql/src/azure/msal/msalAzureDeviceCode.ts @@ -9,7 +9,7 @@ import * as LocalizedConstants from "../../constants/locConstants"; import VscodeWrapper from "../../controllers/vscodeWrapper"; import { AzureAuthType, IProviderSettings, ITenant } from "../../models/contracts/azure"; import { IDeferred } from "../../models/interfaces"; -import { Logger } from "../../models/logger"; +import { ILogger } from "../../models/logger"; import { MsalAzureAuth } from "./msalAzureAuth"; export class MsalAzureDeviceCode extends MsalAzureAuth { @@ -18,7 +18,7 @@ export class MsalAzureDeviceCode extends MsalAzureAuth { protected readonly context: vscode.ExtensionContext, protected clientApplication: PublicClientApplication, protected readonly vscodeWrapper: VscodeWrapper, - protected readonly logger: Logger, + protected readonly logger: ILogger, ) { super( providerSettings, @@ -60,10 +60,14 @@ export class MsalAzureDeviceCode extends MsalAzureAuth { }; const authResult = await this.clientApplication.acquireTokenByDeviceCode(deviceCodeRequest); - this.logger.pii( + this.logger.piiSanitized( `Authentication completed for account: ${authResult?.account!.name}, tenant: ${authResult?.tenantId}`, + [], + [], + ); + this.closeOnceComplete(authCompletePromise).catch((error) => + this.logger.error("Error waiting for device code auth completion", error), ); - this.closeOnceComplete(authCompletePromise).catch(this.logger.error); return { response: authResult!, @@ -88,9 +92,7 @@ export class MsalAzureDeviceCode extends MsalAzureAuth { if (selection === LocalizedConstants.msgCopyAndOpenWebpage) { this.vscodeWrapper.clipboardWriteText(userCode); await vscode.env.openExternal(vscode.Uri.parse(verificationUrl)); - console.log(msg); - console.log(userCode); - console.log(verificationUrl); + this.logger.debug("Opened device code verification URL."); } return; } diff --git a/extensions/mssql/src/azure/msal/msalCachePlugin.ts b/extensions/mssql/src/azure/msal/msalCachePlugin.ts index 82af192950..f76067f070 100644 --- a/extensions/mssql/src/azure/msal/msalCachePlugin.ts +++ b/extensions/mssql/src/azure/msal/msalCachePlugin.ts @@ -10,7 +10,7 @@ import * as lockFile from "lockfile"; import * as path from "path"; import VscodeWrapper from "../../controllers/vscodeWrapper"; import { ICredentialStore } from "../../credentialstore/icredentialstore"; -import { Logger } from "../../models/logger"; +import { ILogger } from "../../models/logger"; import { FileEncryptionHelper } from "../fileEncryptionHelper"; export class MsalCachePluginProvider { @@ -18,7 +18,7 @@ export class MsalCachePluginProvider { private readonly _serviceName: string, private readonly _msalFilePath: string, private readonly _vscodeWrapper: VscodeWrapper, - private readonly _logger: Logger, + private readonly _logger: ILogger, private readonly _credentialStore: ICredentialStore, ) { this._msalFilePath = path.join(this._msalFilePath, this._serviceName); @@ -29,7 +29,7 @@ export class MsalCachePluginProvider { this._logger, this._serviceName, ); - this._logger.verbose( + this._logger.debug( `MsalCachePluginProvider: Using cache path ${_msalFilePath} and serviceName ${_serviceName}`, ); } @@ -66,18 +66,16 @@ export class MsalCachePluginProvider { } catch (e) { // Handle deserialization error in cache file in case file gets corrupted. // Clearing cache here will ensure account is marked stale so re-authentication can be triggered. - this._logger.verbose( + this._logger.warn( `MsalCachePlugin: Error occurred when trying to read cache file, file contents will be cleared: ${e.message}`, ); await fsPromises.unlink(this._msalFilePath); } - this._logger.verbose(`MsalCachePlugin: Token read from cache successfully.`); + this._logger.debug(`MsalCachePlugin: Token read from cache successfully.`); } catch (e) { if (e.code === "ENOENT") { // File doesn't exist, log and continue - this._logger.verbose( - `MsalCachePlugin: Cache file not found on disk: ${e.code}`, - ); + this._logger.debug(`MsalCachePlugin: Cache file not found on disk: ${e.code}`); } else { this._logger.error( `MsalCachePlugin: Failed to read from cache file, file contents will be cleared : ${e}`, @@ -99,7 +97,7 @@ export class MsalCachePluginProvider { await fsPromises.writeFile(this._msalFilePath, encryptedCache, { encoding: "utf8", }); - this._logger.verbose(`MsalCachePlugin: Token written to cache successfully.`); + this._logger.debug(`MsalCachePlugin: Token written to cache successfully.`); } catch (e) { this._logger.error(`MsalCachePlugin: Failed to write to cache file. ${e}`); throw e; @@ -130,7 +128,7 @@ export class MsalCachePluginProvider { // so we check if the lockfile exists and if it does, calling unlockSync() will clear it. if (lockFile.checkSync(lockFilePath) && !this._lockTaken) { lockFile.unlockSync(lockFilePath); - this._logger.verbose(`MsalCachePlugin: Stale lockfile found and has been removed.`); + this._logger.debug(`MsalCachePlugin: Stale lockfile found and has been removed.`); } let retryAttempt = 0; @@ -151,7 +149,7 @@ export class MsalCachePluginProvider { ); } retryAttempt++; - this._logger.verbose( + this._logger.trace( `MsalCachePlugin: Failed to acquire lock on cache file. Retrying in ${retryWait} ms.`, ); diff --git a/extensions/mssql/src/backgroundTasks/backgroundTasksService.ts b/extensions/mssql/src/backgroundTasks/backgroundTasksService.ts index 414ee0ee8c..250628e186 100644 --- a/extensions/mssql/src/backgroundTasks/backgroundTasksService.ts +++ b/extensions/mssql/src/backgroundTasks/backgroundTasksService.ts @@ -5,8 +5,8 @@ import * as vscode from "vscode"; import * as localizedConstants from "../constants/locConstants"; +import logger from "../models/logger"; import { uuid } from "../utils/utils"; -import logger2 from "../models/logger2"; export enum BackgroundTaskState { NotStarted = "NotStarted", @@ -104,12 +104,11 @@ export interface BackgroundTaskLog { export const DEFAULT_MAX_FINISHED_BACKGROUND_TASKS = 25; -const logger = logger2.withPrefix("BackgroundTasksService"); - export class BackgroundTasksService { private _tasks = new Map(); private _taskLogs = new Map(); private readonly _onDidChangeTaskLog = new vscode.EventEmitter(); + private readonly _logger = logger.withPrefix("BackgroundTasksService"); private _nextSequence = 0; constructor( @@ -154,6 +153,7 @@ export class BackgroundTasksService { this.trimFinishedTasks(); this._refreshCallback(); this._revealCallback?.(); + this._logger.debug("Registered background task", getTaskLogContext(entry)); return { id, @@ -173,15 +173,18 @@ export class BackgroundTasksService { public clearFinished(): void { let changed = false; + let clearedCount = 0; for (const [id, task] of this._tasks.entries()) { if (isBackgroundTaskCompleted(task.state)) { this.deleteTaskLog(id); this._tasks.delete(id); changed = true; + clearedCount++; } } if (changed) { + this._logger.debug("Cleared finished background tasks", { clearedCount }); this._refreshCallback(); } } @@ -189,15 +192,21 @@ export class BackgroundTasksService { public async openTask(taskId: string): Promise { const task = this._tasks.get(taskId); if (!task?.open) { + this._logger.trace("Ignoring open request for background task", { taskId }); return; } + this._logger.debug("Opening background task", getTaskLogContext(task)); await Promise.resolve(task.open()); } public async cancelTask(taskId: string): Promise { const task = this._tasks.get(taskId); if (!task || !task.cancel || !task.canCancel || isBackgroundTaskCompleted(task.state)) { + this._logger.trace("Ignoring cancel request for background task", { + taskId, + reason: getCancelIgnoredReason(task), + }); return; } @@ -210,9 +219,14 @@ export class BackgroundTasksService { canCancel: false, cancel: undefined, }); + this._logger.debug("Canceling background task", getTaskLogContext(task)); try { await Promise.resolve(cancelCallback()); + this._logger.debug( + "Background task cancel callback completed", + getTaskLogContext(task), + ); } catch (error) { const currentTask = this._tasks.get(taskId); if (currentTask) { @@ -232,6 +246,10 @@ export class BackgroundTasksService { this._refreshCallback(); } + this._logger.error("Background task cancel callback failed", { + taskId, + error: String(error), + }); throw error; } } @@ -239,6 +257,7 @@ export class BackgroundTasksService { private updateTask(taskId: string, update: BackgroundTaskUpdate): void { const task = this._tasks.get(taskId); if (!task) { + this._logger.trace("Ignoring update for missing background task", { taskId }); return; } @@ -259,6 +278,11 @@ export class BackgroundTasksService { this.trimFinishedTasks(); this._refreshCallback(); + this._logger.trace("Updated background task", { + ...getTaskLogContext(task), + previousState: previousTask.state, + previousPercent: previousTask.percent, + }); } private completeTask( @@ -268,6 +292,10 @@ export class BackgroundTasksService { ): void { const task = this._tasks.get(taskId); if (!task) { + this._logger.trace("Ignoring completion for missing background task", { + taskId, + finalState, + }); return; } @@ -294,12 +322,23 @@ export class BackgroundTasksService { this.trimFinishedTasks(); this._refreshCallback(); + this._logger.info("Completed background task", { + ...getTaskLogContext(task), + finalState, + }); } private removeTask(taskId: string): void { + const task = this._tasks.get(taskId); if (this._tasks.delete(taskId)) { this.deleteTaskLog(taskId); this._refreshCallback(); + this._logger.debug( + "Removed background task", + task ? getTaskLogContext(task) : { taskId }, + ); + } else { + this._logger.trace("Ignoring remove for missing background task", { taskId }); } } @@ -355,6 +394,12 @@ export class BackgroundTasksService { this.deleteTaskLog(task.id); this._tasks.delete(task.id); } + if (tasksToRemove.length > 0) { + this._logger.trace("Trimmed finished background tasks", { + removedCount: tasksToRemove.length, + maxFinishedTasks: this._maxFinishedTasks, + }); + } } private deleteTaskLog(taskId: string): void { @@ -397,7 +442,6 @@ export function toBackgroundTaskStateDisplayString(state: BackgroundTaskState): case BackgroundTaskState.NotStarted: return localizedConstants.notStarted; default: - logger.warn(`Unexpected background task state: ${state}`); return state; } } @@ -449,6 +493,37 @@ function snapshotTask(task: BackgroundTaskEntry): BackgroundTaskProgressSnapshot }; } +function getTaskLogContext(task: BackgroundTaskEntry): object { + return { + taskId: task.id, + displayText: task.displayText, + state: task.state, + percent: task.percent, + source: task.source, + target: task.target, + }; +} + +function getCancelIgnoredReason(task?: BackgroundTaskEntry): string { + if (!task) { + return "missingTask"; + } + + if (isBackgroundTaskCompleted(task.state)) { + return "alreadyCompleted"; + } + + if (!task.canCancel) { + return "cannotCancel"; + } + + if (!task.cancel) { + return "missingCancelCallback"; + } + + return "unknown"; +} + function createTaskLog(task: BackgroundTaskEntry): BackgroundTaskLog { return { displayText: task.displayText, diff --git a/extensions/mssql/src/connectionSharing/connectionSharingService.ts b/extensions/mssql/src/connectionSharing/connectionSharingService.ts index de413b3b31..1ab0ad3040 100644 --- a/extensions/mssql/src/connectionSharing/connectionSharingService.ts +++ b/extensions/mssql/src/connectionSharing/connectionSharingService.ts @@ -11,7 +11,7 @@ import { IConnectionProfile } from "../models/interfaces"; import SqlToolsServiceClient from "../languageservice/serviceclient"; import { RequestType } from "vscode-languageclient"; import VscodeWrapper from "../controllers/vscodeWrapper"; -import { Logger } from "../models/logger"; +import { ILogger, logger } from "../models/logger"; import * as Constants from "../constants/constants"; import { ScriptingService } from "../scripting/scriptingService"; import { ScriptOperation } from "../models/contracts/scripting/scriptingRequest"; @@ -48,15 +48,15 @@ export class ConnectionSharingError extends Error { } export class ConnectionSharingService implements mssql.IConnectionSharingService { - private _logger: Logger; + private _logger: ILogger; constructor( private readonly _context: vscode.ExtensionContext, private readonly _client: SqlToolsServiceClient, private readonly _connectionManager: ConnectionManager, - private readonly _vscodeWrapper: VscodeWrapper, + _vscodeWrapper: VscodeWrapper, private readonly _scriptingService: ScriptingService, ) { - this._logger = Logger.create(this._vscodeWrapper.outputChannel, "ConnectionSharingService"); + this._logger = logger.withPrefix("ConnectionSharingService"); this.registerCommands(); } @@ -438,7 +438,7 @@ export class ConnectionSharingService implements mssql.IConnectionSharingService connectionId, ); } - this._logger.info( + this._logger.debug( `Successfully connected to database with ID "${connectionId}" for extension "${extensionId}".`, ); return connectionUri; // Return the connection URI @@ -466,7 +466,7 @@ export class ConnectionSharingService implements mssql.IConnectionSharingService queryString: string, ): Promise { if (!connectionUri) { - this._logger.error("Invalid connection URI provided for query execution."); + this._logger.warn("Invalid connection URI provided for query execution."); throw new ConnectionSharingError( ConnectionSharingErrorCode.INVALID_CONNECTION_URI, LocalizedConstants.ConnectionSharing.invalidConnectionUri, @@ -505,14 +505,14 @@ export class ConnectionSharingService implements mssql.IConnectionSharingService } public getServerInfo(connectionUri: string): mssql.IServerInfo { - this._logger.info(`Retrieving server info for connection URI: ${connectionUri}`); + this._logger.debug(`Retrieving server info for connection URI: ${connectionUri}`); this.validateConnection(connectionUri); const connectionDetails = this._connectionManager.getConnectionInfoFromUri(connectionUri); return this._connectionManager.getServerInfo(connectionDetails); } public async listDatabases(connectionUri: string): Promise { - this._logger.info(`Listing databases for connection URI: ${connectionUri}`); + this._logger.debug(`Listing databases for connection URI: ${connectionUri}`); this.validateConnection(connectionUri); return await this._connectionManager.listDatabases(connectionUri); } @@ -522,7 +522,7 @@ export class ConnectionSharingService implements mssql.IConnectionSharingService operation: ScriptOperation, scriptingObject: mssql.IScriptingObject, ) { - this._logger.info( + this._logger.debug( `Executing script operation "${operation}" for connection URI: ${connectionUri}`, ); this.validateConnection(connectionUri); @@ -545,7 +545,7 @@ export class ConnectionSharingService implements mssql.IConnectionSharingService `Editing connection sharing permissions for extension: ${extensionId ?? "not specified"}`, ); if (!extensionId) { - this._logger.info("No extension ID provided, prompting user to select an extension."); + this._logger.debug("No extension ID provided, prompting user to select an extension."); const extensionQuickPickItems: vscode.QuickPickItem[] = vscode.extensions.all .filter((ext) => ext.id !== Constants.extensionId) // Exclude self .map((extension) => ({ @@ -561,17 +561,17 @@ export class ConnectionSharingService implements mssql.IConnectionSharingService }); if (!selectedExtension?.detail) { - this._logger.info("User cancelled the extension selection."); + this._logger.debug("User cancelled the extension selection."); return undefined; // User cancelled selection } - this._logger.info(`User selected extension: ${selectedExtension.detail}`); + this._logger.debug(`User selected extension: ${selectedExtension.detail}`); extensionId = selectedExtension.detail; } const currentPermission = await this.getExtensionPermission(extensionId); const extensionDisplayName = this.getExtensionDisplayName(extensionId); - this._logger.info( + this._logger.debug( `Current permission for extension "${extensionDisplayName}" (${extensionId}): ${currentPermission}`, ); @@ -604,7 +604,7 @@ export class ConnectionSharingService implements mssql.IConnectionSharingService }, ); - this._logger.info(`User selected new permission: ${newPermission?.detail}`); + this._logger.debug(`User selected new permission: ${newPermission?.detail}`); if (!newPermission) { return; // User canceled the selection @@ -648,7 +648,7 @@ export class ConnectionSharingService implements mssql.IConnectionSharingService false, // do not include appName ); - this._logger.info( + this._logger.debug( `Retrieved connection string for connection ID "${connectionId}" for extension "${extensionId}".`, ); return connectionString; diff --git a/extensions/mssql/src/connectionconfig/azureHelpers.ts b/extensions/mssql/src/connectionconfig/azureHelpers.ts index 555e60b755..5cf4650499 100644 --- a/extensions/mssql/src/connectionconfig/azureHelpers.ts +++ b/extensions/mssql/src/connectionconfig/azureHelpers.ts @@ -31,7 +31,7 @@ import { https, user, } from "../constants/constants"; -import { Logger } from "../models/logger"; +import { ILogger } from "../models/logger"; import { groupQuickPickItems, MssqlQuickPickItem } from "../utils/quickpickHelpers"; import { AlwaysEncryptedEnclaveType, @@ -865,7 +865,7 @@ export const VsCodeAzureAuth = { */ export async function promptForAzureSubscriptionFilter( state: ConnectionDialogWebviewState, - logger: Logger, + logger: ILogger, ): Promise { try { const result = await VsCodeAzureHelper.signIn(); @@ -948,7 +948,7 @@ export enum MaintenanceSchedule { export async function getAccounts( azureAccountService: AzureAccountService, - logger: Logger, + logger: ILogger, ): Promise { let accounts: IAccount[] = []; try { @@ -990,7 +990,7 @@ export async function getAccounts( export async function getTenants( azureAccountService: AzureAccountService, accountId: string, - logger: Logger, + logger: ILogger, ): Promise { let tenants: ITenant[] = []; diff --git a/extensions/mssql/src/connectionconfig/browseProvider.ts b/extensions/mssql/src/connectionconfig/browseProvider.ts index bfa9fbbc33..a020963988 100644 --- a/extensions/mssql/src/connectionconfig/browseProvider.ts +++ b/extensions/mssql/src/connectionconfig/browseProvider.ts @@ -24,7 +24,7 @@ import { ActivityStatus, TelemetryActions, TelemetryViews } from "../sharedInter import { FabricHelper } from "../fabric/fabricHelper"; import { VsCodeAzureHelper } from "./azureHelpers"; -import { Logger } from "../models/logger"; +import { ILogger } from "../models/logger"; import { getCloudId } from "../azure/providerSettings"; import { startActivity } from "../telemetry/telemetry"; import { getErrorMessage } from "../utils/utils"; @@ -40,7 +40,7 @@ export const FABRIC_WORKSPACE_AUTOLOAD_LIMIT = 7; export interface BrowseProviderHost { /** Live state object owned by the controller; used by providers for stale-result guards. */ readonly state: ConnectionDialogWebviewState; - readonly logger: Logger; + readonly logger: ILogger; /** Push a state update to the webview. */ updateState(state?: ConnectionDialogWebviewState): void; /** Refresh tenant-sign-in status data; called as part of the Azure cache priming flow. */ @@ -265,7 +265,7 @@ export class AzureBrowseProvider extends BrowseProvider { this.refreshFavoritesIntoState(state); this.host.updateState(state); - this.host.logger.log( + this.host.logger.trace( `Loaded ${subsForTenant.length} Azure subscriptions for tenant ${tenantId}`, ); @@ -321,7 +321,7 @@ export class AzureBrowseProvider extends BrowseProvider { ); subscription.loadStatus = { status: ApiStatus.Loaded }; this.host.updateState(state); - this.host.logger.log( + this.host.logger.trace( `Loaded ${servers.length} servers for subscription ${azSub.name} (${azSub.subscriptionId})`, ); @@ -519,7 +519,7 @@ export class FabricBrowseProvider extends BrowseProvider { this.refreshFavoritesIntoState(state); this.host.updateState(state); - this.host.logger.log( + this.host.logger.trace( `Loaded ${cachedWorkspaces.length} Fabric workspaces for tenant ${tenantId}`, ); @@ -614,7 +614,7 @@ export class FabricBrowseProvider extends BrowseProvider { const totalCount = workspace.databases.length; const warehouseCount = totalCount - sqlDbCount - sqlEndpointCount; - this.host.logger.log( + this.host.logger.trace( `Loaded ${sqlDbCount} Fabric databases, ${sqlEndpointCount} SQL endpoints, and ${warehouseCount} warehouses for workspace ${workspace.id}`, ); diff --git a/extensions/mssql/src/connectionconfig/connectionDialogWebviewController.ts b/extensions/mssql/src/connectionconfig/connectionDialogWebviewController.ts index 2049a8c1b7..47c35bb73d 100644 --- a/extensions/mssql/src/connectionconfig/connectionDialogWebviewController.ts +++ b/extensions/mssql/src/connectionconfig/connectionDialogWebviewController.ts @@ -1910,7 +1910,7 @@ export class ConnectionDialogWebviewController extends FormWebviewController< connection.password = password; } } else { - this.logger.logDebug( + this.logger.debug( "Connection string connection found in Connection Dialog initialization; should have been converted.", ); } @@ -1982,7 +1982,7 @@ export class ConnectionDialogWebviewController extends FormWebviewController< ); } - this.logger.verbose( + this.logger.debug( `Read ${this._cachedEntraAccounts.length} Azure accounts: ${this._cachedEntraAccounts.map((a) => a.value).join(", ")}`, ); @@ -2089,7 +2089,7 @@ export class ConnectionDialogWebviewController extends FormWebviewController< await this.handleAzureMFAEdits("accountId"); } else { const account = await this._mainController.azureAccountService.addAccount(); - this.logger.verbose( + this.logger.debug( `Added Azure account '${account.displayInfo?.displayName}', ${account.key.id}`, ); @@ -2097,7 +2097,7 @@ export class ConnectionDialogWebviewController extends FormWebviewController< this.state.connectionProfile.accountId = account.key.id; - this.logger.verbose(`Selecting '${account.key.id}'`); + this.logger.debug(`Selecting '${account.key.id}'`); this.updateState(); await this.handleAzureMFAEdits("accountId"); diff --git a/extensions/mssql/src/connectionconfig/connectionconfig.ts b/extensions/mssql/src/connectionconfig/connectionconfig.ts index 466824e5cb..36ca9c15bd 100644 --- a/extensions/mssql/src/connectionconfig/connectionconfig.ts +++ b/extensions/mssql/src/connectionconfig/connectionconfig.ts @@ -14,7 +14,7 @@ import VscodeWrapper from "../controllers/vscodeWrapper"; import { ConnectionProfile } from "../models/connectionProfile"; import { getConnectionDisplayName } from "../models/connectionInfo"; import { Deferred } from "../protocol"; -import { Logger } from "../models/logger"; +import { ILogger, logger } from "../models/logger"; import { ConfigurationTarget } from "vscode"; export type ConfigTarget = ConfigurationTarget.Global | ConfigurationTarget.Workspace; @@ -23,7 +23,7 @@ export type ConfigTarget = ConfigurationTarget.Global | ConfigurationTarget.Work * Implements connection profile file storage. */ export class ConnectionConfig implements IConnectionConfig { - protected _logger: Logger; + protected _logger: ILogger; public initialized: Deferred = new Deferred(); /** Root group ID and name */ @@ -40,7 +40,7 @@ export class ConnectionConfig implements IConnectionConfig { this._vscodeWrapper = new VscodeWrapper(); } - this._logger = Logger.create(this._vscodeWrapper.outputChannel, "ConnectionConfig"); + this._logger = logger.withPrefix("ConnectionConfig"); void this.initialize(); } @@ -375,7 +375,7 @@ export class ConnectionConfig implements IConnectionConfig { // Remove all connections in the groups being removed remainingConnections = connections.filter((conn) => { if (groupsToRemove.has(conn.groupId)) { - this._logger.verbose( + this._logger.debug( `Removing connection '${conn.id}' because its group '${conn.groupId}' was removed`, ); connectionModified = true; @@ -390,7 +390,7 @@ export class ConnectionConfig implements IConnectionConfig { // Move immediate child connections to root remainingConnections = connections.map((conn) => { if (conn.groupId === id) { - this._logger.verbose( + this._logger.debug( `Moving connection '${conn.id}' to root group because its immediate parent group '${id}' was removed`, ); connectionModified = true; @@ -405,7 +405,7 @@ export class ConnectionConfig implements IConnectionConfig { // Then reparent immediate children to root remainingGroups = remainingGroups.map((g) => { if (g.parentId === id) { - this._logger.verbose( + this._logger.debug( `Moving group '${g.id}' to root group because its immediate parent group '${id}' was removed`, ); return { ...g, parentId: rootGroup.id }; @@ -546,7 +546,7 @@ export class ConnectionConfig implements IConnectionConfig { if (group.parentId === legacyRootId) { group.parentId = ConnectionConfig.ROOT_GROUP_ID; madeGroupChanges = true; - this._logger.verbose( + this._logger.debug( `Updating parentId for group '${group.name}' (${group.id}) to '${ConnectionConfig.ROOT_GROUP_ID}'`, ); } @@ -558,7 +558,7 @@ export class ConnectionConfig implements IConnectionConfig { if (profile.groupId === legacyRootId) { profile.groupId = ConnectionConfig.ROOT_GROUP_ID; connectionsChanged = true; - this._logger.verbose( + this._logger.debug( `Updating groupId for connection '${getConnectionDisplayName(profile)}' to '${ConnectionConfig.ROOT_GROUP_ID}'`, ); } @@ -595,20 +595,20 @@ export class ConnectionConfig implements IConnectionConfig { if (!group.id) { group.id = uuid(); madeGroupChanges = true; - this._logger.logDebug(`Adding missing ID to connection group '${group.name}'`); + this._logger.debug(`Adding missing ID to connection group '${group.name}'`); } // ensure each group is in a group if (!group.parentId) { group.parentId = ConnectionConfig.ROOT_GROUP_ID; madeGroupChanges = true; - this._logger.logDebug(`Adding missing parentId to connection '${group.name}'`); + this._logger.debug(`Adding missing parentId to connection '${group.name}'`); } } // Save the changes to settings if (madeGroupChanges) { - this._logger.logDebug( + this._logger.debug( `Updates made to connection groups. Writing all ${groups.length} group(s) to settings.`, ); @@ -625,7 +625,7 @@ export class ConnectionConfig implements IConnectionConfig { for (const profile of profiles) { if (this.populateMissingConnectionMetadata(profile)) { madeChanges = true; - this._logger.logDebug( + this._logger.debug( `Adding missing group ID or connection ID to connection '${getConnectionDisplayName(profile)}' from ${ConfigurationTarget[profile.configSource]}`, ); } @@ -633,7 +633,7 @@ export class ConnectionConfig implements IConnectionConfig { // Save the changes to settings if (madeChanges) { - this._logger.logDebug( + this._logger.debug( `Updates made to connection profiles. Writing all ${profiles.length} profile(s) to settings.`, ); diff --git a/extensions/mssql/src/controllers/connectionGroupWebviewController.ts b/extensions/mssql/src/controllers/connectionGroupWebviewController.ts index 90d5eb9fb0..e8b63f877b 100644 --- a/extensions/mssql/src/controllers/connectionGroupWebviewController.ts +++ b/extensions/mssql/src/controllers/connectionGroupWebviewController.ts @@ -87,7 +87,7 @@ export class ConnectionGroupWebviewController extends WebviewPanelController< this.registerReducer("saveConnectionGroup", async (state, payload) => { try { if (this.connectionGroupToEdit) { - this.logger.verbose("Updating existing connection group", payload); + this.logger.debug("Updating existing connection group", payload); await this.connectionConfig.updateGroup({ ...this.connectionGroupToEdit, name: payload.name, @@ -95,7 +95,7 @@ export class ConnectionGroupWebviewController extends WebviewPanelController< color: payload.color, }); } else { - this.logger.verbose("Creating new connection group", payload); + this.logger.debug("Creating new connection group", payload); await this.connectionConfig.addGroup(createConnectionGroupFromSpec(payload)); } diff --git a/extensions/mssql/src/controllers/connectionManager.ts b/extensions/mssql/src/controllers/connectionManager.ts index 14ed53d808..7abcc6e972 100644 --- a/extensions/mssql/src/controllers/connectionManager.ts +++ b/extensions/mssql/src/controllers/connectionManager.ts @@ -53,7 +53,7 @@ import { ObjectExplorerUtils } from "../objectExplorer/objectExplorerUtils"; import { changeLanguageServiceForFile } from "../languageservice/utils"; import { AddFirewallRuleWebviewController } from "./addFirewallRuleWebviewController"; import { getErrorMessage, uuid } from "../utils/utils"; -import { Logger } from "../models/logger"; +import { ILogger, logger } from "../models/logger"; import { getServerTypes } from "../models/connectionInfo"; import * as AzureConstants from "../azure/constants"; import { ChangePasswordService } from "../services/changePasswordService"; @@ -148,7 +148,7 @@ export default class ConnectionManager { private context: vscode.ExtensionContext, statusView: StatusView, prompter: IPrompter, - private _logger?: Logger, + private _logger?: ILogger, private _client?: SqlToolsServerClient, private _vscodeWrapper?: VscodeWrapper, private _connectionStore?: ConnectionStore, @@ -172,7 +172,7 @@ export default class ConnectionManager { } if (!this._logger) { - this._logger = Logger.create(this._vscodeWrapper.outputChannel, "ConnectionManager"); + this._logger = logger.withPrefix("ConnectionManager"); } if (!this._credentialStore) { @@ -653,7 +653,7 @@ export default class ConnectionManager { expiresOn = tokenInfo.token.expiresOn; } else { if (!params.accountId) { - self._logger?.verbose( + self._logger?.debug( `Cannot refresh token: no accountId provided in refresh request for URI ${params.uri}`, ); sendErrorEvent( @@ -680,7 +680,7 @@ export default class ConnectionManager { const account = await self.accountStore.getAccount(params.accountId); if (!account) { - self._logger?.verbose( + self._logger?.debug( `Cannot refresh token: account ${params.accountId} not found in account store`, ); sendErrorEvent( @@ -792,7 +792,7 @@ export default class ConnectionManager { }, ); } catch (error) { - self._logger?.verbose( + self._logger?.debug( `Failed to refresh token for URI ${params.uri}: ${getErrorMessage(error)}`, ); @@ -1257,7 +1257,7 @@ export default class ConnectionManager { connectionInfo.expiresOn, ) ) { - this._logger?.verbose( + this._logger?.debug( `Entra token for account ${connectionInfo.user} (${connectionInfo.email}) is still valid until ${connectionInfo.expiresOn}. No refresh needed.`, ); return; @@ -1298,7 +1298,7 @@ export default class ConnectionManager { } if (!account) { - this._logger?.verbose( + this._logger?.debug( `No account found in account store for accountId ${connectionInfo.accountId}. Cannot refresh Entra token.`, ); @@ -1331,7 +1331,7 @@ export default class ConnectionManager { connectionInfo.azureAccountToken = undefined; connectionInfo.expiresOn = undefined; - this._logger?.verbose( + this._logger?.debug( `Using SQL Authentication Provider for MSAL Entra account ${connectionInfo.user} and tenant ${connectionInfo.tenantId}.`, ); } @@ -2120,7 +2120,7 @@ export default class ConnectionManager { } private async migrateLegacyConnectionProfiles(): Promise { - this._logger.logDebug("Beginning migration of legacy connections"); + this._logger.debug("Beginning migration of legacy connections"); const connections: IConnectionProfile[] = await this.connectionStore.readAllConnections(false); @@ -2137,11 +2137,11 @@ export default class ConnectionManager { } if (tally.migrated > 0) { - this._logger.verbose( + this._logger.debug( `Completed migration of legacy Connection String connections. (${tally.migrated} migrated, ${tally.notNeeded} not needed, ${tally.error} errored)`, ); } else { - this._logger.verbose( + this._logger.debug( `No legacy Connection String connections found to migrate. (${tally.notNeeded} not needed, ${tally.error} errored)`, ); } @@ -2259,14 +2259,14 @@ export default class ConnectionManager { params: RequestSecurityTokenParams, ): Promise { if (params.accountId) { - this._logger.verbose("VS Code accounts token request received"); + this._logger.debug("VS Code accounts token request received"); try { const tokenInfo = await acquireTokenFromVscodeAccountForResource( getCloudResourceEndpoint("sqlResource"), params.accountId, params.tenantId, ); - this._logger.verbose("VS Code accounts token acquired successfully"); + this._logger.debug("VS Code accounts token acquired successfully"); return { accountKey: params.accountId, token: tokenInfo.token.token, @@ -2318,7 +2318,7 @@ export default class ConnectionManager { let onSignIn: () => Promise; if (previewService.isFeatureEnabled(PreviewFeature.UseVscodeAccountsForEntraMFA)) { - this._logger.verbose("AKV token request received (VS Code accounts path)"); + this._logger.debug("AKV token request received (VS Code accounts path)"); getAccounts = async () => { const accounts = await VsCodeAzureHelper.getAccounts(); return accounts.map((a) => ({ diff --git a/extensions/mssql/src/controllers/dacpacDialogWebviewController.ts b/extensions/mssql/src/controllers/dacpacDialogWebviewController.ts index 482d344d50..b7b4cc3d6f 100644 --- a/extensions/mssql/src/controllers/dacpacDialogWebviewController.ts +++ b/extensions/mssql/src/controllers/dacpacDialogWebviewController.ts @@ -303,7 +303,7 @@ export class DacpacDialogWebviewController extends WebviewPanelController< private async handleDeployDacpac( params: dacpacDialog.DeployDacpacParams, ): Promise { - this.logger.verbose("Starting Deploy DACPAC operation"); + this.logger.debug("Starting Deploy DACPAC operation"); const activity = startActivity( TelemetryViews.DacpacDialog, @@ -330,7 +330,7 @@ export class DacpacDialogWebviewController extends WebviewPanelController< }; if (result.success) { - this.logger.verbose("Deploy DACPAC operation completed successfully"); + this.logger.debug("Deploy DACPAC operation completed successfully"); activity.end(ActivityStatus.Succeeded); // Prompt user for NPS survey feedback UserSurvey.getInstance().promptUserForNPSFeedback( @@ -367,7 +367,7 @@ export class DacpacDialogWebviewController extends WebviewPanelController< private async handleExtractDacpac( params: dacpacDialog.ExtractDacpacParams, ): Promise { - this.logger.verbose("Starting Extract DACPAC operation"); + this.logger.debug("Starting Extract DACPAC operation"); const activity = startActivity( TelemetryViews.DacpacDialog, @@ -391,7 +391,7 @@ export class DacpacDialogWebviewController extends WebviewPanelController< }; if (result.success) { - this.logger.verbose("Extract DACPAC operation completed successfully"); + this.logger.debug("Extract DACPAC operation completed successfully"); activity.end(ActivityStatus.Succeeded); // Prompt user for NPS survey feedback UserSurvey.getInstance().promptUserForNPSFeedback( @@ -428,7 +428,7 @@ export class DacpacDialogWebviewController extends WebviewPanelController< private async handleImportBacpac( params: dacpacDialog.ImportBacpacParams, ): Promise { - this.logger.verbose("Starting Import BACPAC operation"); + this.logger.debug("Starting Import BACPAC operation"); const activity = startActivity( TelemetryViews.DacpacDialog, @@ -450,7 +450,7 @@ export class DacpacDialogWebviewController extends WebviewPanelController< }; if (result.success) { - this.logger.verbose("Import BACPAC operation completed successfully"); + this.logger.debug("Import BACPAC operation completed successfully"); activity.end(ActivityStatus.Succeeded); // Prompt user for NPS survey feedback UserSurvey.getInstance().promptUserForNPSFeedback( @@ -487,7 +487,7 @@ export class DacpacDialogWebviewController extends WebviewPanelController< private async handleExportBacpac( params: dacpacDialog.ExportBacpacParams, ): Promise { - this.logger.verbose("Starting Export BACPAC operation"); + this.logger.debug("Starting Export BACPAC operation"); const activity = startActivity( TelemetryViews.DacpacDialog, @@ -509,7 +509,7 @@ export class DacpacDialogWebviewController extends WebviewPanelController< }; if (result.success) { - this.logger.verbose("Export BACPAC operation completed successfully"); + this.logger.debug("Export BACPAC operation completed successfully"); activity.end(ActivityStatus.Succeeded); // Prompt user for NPS survey feedback UserSurvey.getInstance().promptUserForNPSFeedback( @@ -728,7 +728,7 @@ export class DacpacDialogWebviewController extends WebviewPanelController< if (!matchingConnection.profile) { // No match found - return all connections, let user choose - this.logger.verbose("No matching connection found in initial state"); + this.logger.debug("No matching connection found in initial state"); return { connections, autoConnected: false, @@ -772,7 +772,7 @@ export class DacpacDialogWebviewController extends WebviewPanelController< ownerUri: string; autoConnected: boolean; } { - this.logger.verbose(`Using existing connection from Object Explorer: ${ownerUri}`); + this.logger.debug(`Using existing connection from Object Explorer: ${ownerUri}`); return { selectedConnection: matchingConnection, ownerUri, @@ -789,7 +789,7 @@ export class DacpacDialogWebviewController extends WebviewPanelController< autoConnected: boolean; errorMessage?: string; }> { - this.logger.verbose(`Connecting to profile: ${matchingConnection.id}`); + this.logger.debug(`Connecting to profile: ${matchingConnection.id}`); try { const connectResult = await this.connectToServer(matchingConnection.id!); diff --git a/extensions/mssql/src/controllers/mainController.ts b/extensions/mssql/src/controllers/mainController.ts index 82ea4f023f..bfc445082a 100644 --- a/extensions/mssql/src/controllers/mainController.ts +++ b/extensions/mssql/src/controllers/mainController.ts @@ -117,7 +117,7 @@ import { SearchDatabaseWebViewController } from "../searchDatabase/searchDatabas import { ChangelogWebviewController } from "./changelogWebviewController"; import { AzureDataStudioMigrationWebviewController } from "./azureDataStudioMigrationWebviewController"; import { HttpClient } from "../http/httpClient"; -import { Logger } from "../models/logger"; +import { ILogger, logger } from "../models/logger"; import { FileBrowserService } from "../services/fileBrowserService"; import { BackupDatabaseWebviewController } from "./backupDatabaseWebviewController"; import { AzureBlobService } from "../services/azureBlobService"; @@ -149,7 +149,7 @@ export default class MainController implements vscode.Disposable { private _scriptingService: ScriptingService; private _queryHistoryRegistered: boolean = false; private _availableCommands: string[] | undefined; - private _logger: Logger; + private _logger: ILogger; private _lastBackgroundTaskClickTime = 0; private _lastBackgroundTaskId: string | undefined; @@ -191,7 +191,7 @@ export default class MainController implements vscode.Disposable { this._connectionMgr = connectionManager; } this._vscodeWrapper = vscodeWrapper ?? new VscodeWrapper(); - this._logger = Logger.create(this._vscodeWrapper.outputChannel, "MainController"); + this._logger = logger.withPrefix("MainController"); this.configuration = vscode.workspace.getConfiguration(); UserSurvey.createInstance(this._context, this._vscodeWrapper); @@ -3360,13 +3360,10 @@ export default class MainController implements vscode.Disposable { } /** - * Updates Pii Logging configuration for Logger. + * PII logging is read from configuration at log time by ILogger. */ private updatePiiLoggingLevel(): void { - const piiLogging: boolean = vscode.workspace - .getConfiguration(Constants.extensionName) - .get(Constants.piiLogging, false); - SqlToolsServerClient.instance.logger.piiLogging = piiLogging; + // no-op } /** diff --git a/extensions/mssql/src/controllers/sqlDocumentService.ts b/extensions/mssql/src/controllers/sqlDocumentService.ts index 4a58d77b7e..2c23b81f7e 100644 --- a/extensions/mssql/src/controllers/sqlDocumentService.ts +++ b/extensions/mssql/src/controllers/sqlDocumentService.ts @@ -20,7 +20,7 @@ import { sendActionEvent } from "../telemetry/telemetry"; import { TreeNodeInfo } from "../objectExplorer/nodes/treeNodeInfo"; import { TelemetryActions, TelemetryViews } from "../sharedInterfaces/telemetry"; import { IConnectionProfile } from "../models/interfaces"; -import { logger2 } from "../models/logger2"; +import { logger } from "../models/logger"; /** * Time to wait after opening a document to check if it's the @@ -44,7 +44,7 @@ function getDocumentSignature(document: vscode.TextDocument): string { * Service for creating untitled documents for SQL query */ export default class SqlDocumentService implements vscode.Disposable { - private readonly _logger = logger2.withPrefix("SqlDocumentService"); + private readonly _logger = logger.withPrefix("SqlDocumentService"); private _disposables: vscode.Disposable[] = []; // Track documents created by this service to avoid auto-connecting them on open. // WeakSet ensures entries are garbage collected with the documents. diff --git a/extensions/mssql/src/controllers/webviewBaseController.ts b/extensions/mssql/src/controllers/webviewBaseController.ts index de38f1e075..59b3a191a7 100644 --- a/extensions/mssql/src/controllers/webviewBaseController.ts +++ b/extensions/mssql/src/controllers/webviewBaseController.ts @@ -20,6 +20,7 @@ import { LoadStatsNotification, LogEvent, LogNotification, + LoggerLevel, ReducerRequest, SendActionEventNotification, SendErrorEventNotification, @@ -31,7 +32,7 @@ import { import { sendActionEvent, sendErrorEvent, startActivity } from "../telemetry/telemetry"; import { getEditorEOL, getErrorMessage, getNonce } from "../utils/utils"; -import { Logger } from "../models/logger"; +import { ILogger, logger } from "../models/logger"; import VscodeWrapper from "./vscodeWrapper"; import { AbstractMessageReader, @@ -56,6 +57,22 @@ import { getLocalizationFileContentsCached } from "./localizationCache"; export const WEBVIEW_INIT_TIMEOUT_MS = 5_000; +type LoggerMethod = "trace" | "debug" | "info" | "warn" | "error"; + +function mapWebviewLoggerLevel(level?: LoggerLevel): LoggerMethod { + switch (level) { + case "critical": + return "error"; + case "verbose": + return "debug"; + case "log": + case undefined: + return "trace"; + default: + return level; + } +} + class WebviewControllerMessageReader extends AbstractMessageReader implements MessageReader { private _onData: Emitter; private _disposables: vscode.Disposable[] = []; @@ -87,7 +104,7 @@ class WebviewControllerMessageReader extends AbstractMessageReader implements Me class WebviewControllerMessageWriter extends AbstractMessageWriter implements MessageWriter { private _webview: vscode.Webview; - constructor(private logger: Logger) { + constructor(private logger: ILogger) { super(); } updateWebview(webview: vscode.Webview) { @@ -140,7 +157,7 @@ export abstract class WebviewBaseController implements vscode.D (state: State, payload: Reducers[keyof Reducers]) => ReducerResponse >(); - protected logger: Logger; + protected logger: ILogger; /** * Creates a new WebviewPanelController @@ -159,7 +176,7 @@ export abstract class WebviewBaseController implements vscode.D vscodeWrapper = new VscodeWrapper(); } - this.logger = Logger.create(vscodeWrapper.outputChannel, viewId); + this.logger = logger.withPrefix(viewId ?? "WebviewBaseController"); this._connectionReader = new WebviewControllerMessageReader(); this._connectionWriter = new WebviewControllerMessageWriter(this.logger); @@ -296,7 +313,7 @@ export abstract class WebviewBaseController implements vscode.D ); this.onNotification(LogNotification.type, async (message: LogEvent) => { - this.logger[message.level ?? "log"](message.message); + this.logger[mapWebviewLoggerLevel(message.level)](message.message); }); this.onNotification(LoadStatsNotification.type, (message) => { @@ -314,7 +331,7 @@ export abstract class WebviewBaseController implements vscode.D } this._webviewReady.resolve(); - console.log( + this.logger.trace( `Load stats for ${this._sourceFile}` + "\n" + `Total time: ${timeToLoad} ms`, ); this._endLoadActivity.end(ActivityStatus.Succeeded, { @@ -350,7 +367,7 @@ export abstract class WebviewBaseController implements vscode.D this.onRequest(ExecuteCommandRequest.type, async (params: ExecuteCommandParams) => { if (!params?.command) { - this.logger.log("No command provided to execute"); + this.logger.trace("No command provided to execute"); return; } const args = params?.args ?? []; @@ -362,7 +379,7 @@ export abstract class WebviewBaseController implements vscode.D }); this.onRequest(ReducerRequest.type(), async (action) => { - this.logger.verbose(`Reducer action received from webview: ${action.type as string}`); + this.logger.debug(`Reducer action received from webview: ${action.type as string}`); const reducerActivity = startActivity( TelemetryViews.WebviewController, TelemetryActions.Reducer, @@ -380,7 +397,7 @@ export abstract class WebviewBaseController implements vscode.D if (reducer) { try { this.state = await reducer(this.state, action.payload); - this.logger.verbose(`Reducer action succeeded: ${action.type as string}`); + this.logger.debug(`Reducer action succeeded: ${action.type as string}`); reducerActivity.end(ActivityStatus.Succeeded); } catch (error) { this.logger.error( @@ -438,7 +455,7 @@ export abstract class WebviewBaseController implements vscode.D params: TParam, token: CancellationToken, ) => { - this.logger.verbose(`Request received from webview: ${type.method}`); + this.logger.debug(`Request received from webview: ${type.method}`); const handlerActivity = startActivity( TelemetryViews.WebviewController, TelemetryActions.OnRequest, @@ -457,7 +474,7 @@ export abstract class WebviewBaseController implements vscode.D if (result instanceof Promise) { return result.then( (res) => { - this.logger.verbose(`Request succeeded: ${type.method}`); + this.logger.debug(`Request succeeded: ${type.method}`); handlerActivity.end(ActivityStatus.Succeeded); return res; }, @@ -470,7 +487,7 @@ export abstract class WebviewBaseController implements vscode.D }, ); } else { - this.logger.verbose(`Request succeeded: ${type.method}`); + this.logger.debug(`Request succeeded: ${type.method}`); handlerActivity.end(ActivityStatus.Succeeded); return result; } diff --git a/extensions/mssql/src/copilot/chatAgentRequestHandler.ts b/extensions/mssql/src/copilot/chatAgentRequestHandler.ts index 670b6981d8..a635d2c148 100644 --- a/extensions/mssql/src/copilot/chatAgentRequestHandler.ts +++ b/extensions/mssql/src/copilot/chatAgentRequestHandler.ts @@ -24,7 +24,7 @@ import { import { getErrorMessage, uuid } from "../utils/utils"; import { MssqlChatAgent as loc } from "../constants/locConstants"; import MainController from "../controllers/mainController"; -import { Logger } from "../models/logger"; +import { ILogger, logger as baseLogger } from "../models/logger"; import { handleChatCommand, commandSkipsConnectionLabels, @@ -58,7 +58,7 @@ export const createSqlAgentRequestHandler = ( })(); const getLogger = (() => { - const logger = Logger.create(vscodeWrapper.outputChannel, "MssqlCopilot"); + const logger = baseLogger.withPrefix("MssqlCopilot"); return () => logger; })(); @@ -73,8 +73,8 @@ export const createSqlAgentRequestHandler = ( const logger = getLogger(); let conversationUri = getNextConversationUri(); let connectionUri = vscodeWrapper.activeTextEditorUri; - logger.verbose("In handler"); - logger.logDebug( + logger.debug("In handler"); + logger.debug( `Starting new chat conversation: conversion '${conversationUri}' with connection '${connectionUri}'`, ); @@ -89,29 +89,29 @@ export const createSqlAgentRequestHandler = ( let referenceTexts: string[] = []; const activeEditor = vscode.window.activeTextEditor; - logger.logDebug(activeEditor ? "Active editor found." : "No active editor found."); + logger.debug(activeEditor ? "Active editor found." : "No active editor found."); async function findEditorFromReferences( references: readonly vscode.ChatPromptReference[], ): Promise { - logger.verbose("in findEditorFromReferences"); + logger.debug("in findEditorFromReferences"); const tabGroups = vscode.window.tabGroups.all; // Function to check if document is SQL function isSqlDocument(document: vscode.TextDocument): boolean { - logger.verbose("in isSqlDocument"); - logger.logDebug(`Checking if document is SQL: ${document.languageId}`); + logger.debug("in isSqlDocument"); + logger.debug(`Checking if document is SQL: ${document.languageId}`); // Check if the document is an SQL file // You can add more language IDs as needed // For example, you might want to include "sql" or "mssql" for SQL files const sqlLanguageIds = ["sql", "mssql"]; const isSql = sqlLanguageIds.includes(document.languageId); - logger.logDebug(`Is SQL document: ${isSql ? "Yes" : "No"}`); - logger.verbose("Exiting isSqlDocument"); + logger.debug(`Is SQL document: ${isSql ? "Yes" : "No"}`); + logger.debug("Exiting isSqlDocument"); return isSql; } - logger.info("Checking references..."); + logger.debug("Checking references..."); for (const reference of references) { const value = reference.value; let referenceUri: vscode.Uri | undefined; @@ -122,12 +122,10 @@ export const createSqlAgentRequestHandler = ( referenceUri = value; } - logger.logDebug( - referenceUri ? "Found a reference URI." : "No reference URI found.", - ); + logger.debug(referenceUri ? "Found a reference URI." : "No reference URI found."); if (referenceUri) { - logger.info("Looking for matching visible editor..."); + logger.debug("Looking for matching visible editor..."); // Try to find this URI in the visible editors, but only if it's an SQL file const matchingEditor = vscode.window.visibleTextEditors.find( @@ -137,11 +135,11 @@ export const createSqlAgentRequestHandler = ( ); if (matchingEditor) { - logger.info("Returning matching visible editor."); + logger.debug("Returning matching visible editor."); return matchingEditor; } - logger.info("No matching visible editor found. Checking tab groups..."); + logger.debug("No matching visible editor found. Checking tab groups..."); // Try to find this URI in tab groups for (const group of tabGroups) { const activeTab = group.activeTab; @@ -154,13 +152,13 @@ export const createSqlAgentRequestHandler = ( /* eslint-enable @typescript-eslint/no-explicit-any */ if (tabUri && tabUri.toString() === referenceUri.toString()) { - logger.info("Found tab URI that matches reference URI."); + logger.debug("Found tab URI that matches reference URI."); const editor = vscode.window.visibleTextEditors.find( (ed) => ed.document.uri.toString() === tabUri.toString(), ); // Only return the editor if it's an SQL document if (editor && isSqlDocument(editor.document)) { - logger.info("Returning matching SQL editor."); + logger.debug("Returning matching SQL editor."); return editor; } } @@ -172,7 +170,7 @@ export const createSqlAgentRequestHandler = ( } } - logger.info("No matching editor found in references. Checking tab groups..."); + logger.debug("No matching editor found in references. Checking tab groups..."); // If no match found, try to get any active SQL tab from tab groups for (const group of tabGroups) { const activeTab = group.activeTab; @@ -191,7 +189,7 @@ export const createSqlAgentRequestHandler = ( ); // Only return the editor if it's an SQL document if (editor && isSqlDocument(editor.document)) { - logger.info("Returning active SQL editor from tab group."); + logger.debug("Returning active SQL editor from tab group."); return editor; } } @@ -201,22 +199,22 @@ export const createSqlAgentRequestHandler = ( } } - logger.verbose("Exiting findEditorFromReferences"); - logger.logDebug("No matching editor found in tab groups. Returning undefined."); + logger.debug("Exiting findEditorFromReferences"); + logger.debug("No matching editor found in tab groups. Returning undefined."); return undefined; } // Process references using the appropriate editor - logger.info("Process references using the appropriate editor..."); + logger.debug("Process references using the appropriate editor..."); if (request.references) { // Use activeEditor if available, otherwise try to find one from references const editorToUse = activeEditor || (await findEditorFromReferences(request.references)); - logger.info(editorToUse ? "Using editor found." : "No editor found."); + logger.debug(editorToUse ? "Using editor found." : "No editor found."); // Use the preferred editor's URI if available connectionUri = editorToUse?.document.uri.toString() ?? connectionUri; - logger.info( + logger.debug( connectionUri ? "Using the preferred editor's connection URI." : "No connection URI found.", @@ -226,7 +224,7 @@ export const createSqlAgentRequestHandler = ( const value = reference.value; if (value instanceof vscode.Location) { // Could be a document / selection in the current editor - logger.info("value is a Location"); + logger.trace("value is a Location"); if ( editorToUse && value.uri.toString() === editorToUse.document.uri.toString() @@ -235,22 +233,22 @@ export const createSqlAgentRequestHandler = ( `${reference.modelDescription ?? "ChatResponseReference"}: ${editorToUse.document.getText(value.range)}`, ); } else { - logger.info("Opening text document"); + logger.trace("Opening text document"); const doc = await vscode.workspace.openTextDocument(value.uri); referenceTexts.push( `${reference.modelDescription ?? "ChatResponseReference"}: ${doc.getText(value.range)}`, ); } } else if (value instanceof vscode.Uri) { - logger.info("Value is a URI"); + logger.trace("Value is a URI"); // Could be a file/document - logger.info("Opening text document"); + logger.trace("Opening text document"); const doc = await vscode.workspace.openTextDocument(value); referenceTexts.push( `${reference.modelDescription ?? "ChatResponseReference"}: ${doc.getText()}`, ); } else if (typeof reference.value === "string") { - logger.info("reference value is a string)"); + logger.trace("reference value is a string)"); // Could be a string referenceTexts.push( `${reference.modelDescription ?? "ChatResponseReference"}: ${reference.value}`, @@ -281,7 +279,9 @@ export const createSqlAgentRequestHandler = ( const copilotDebugLogging = vscodeWrapper .getConfiguration() .get(Constants.copilotDebugLogging, false); - logger.info(copilotDebugLogging ? "Debug logging enabled." : "Debug logging disabled."); + logger.debug( + copilotDebugLogging ? "Debug logging enabled." : "Debug logging disabled.", + ); if (copilotDebugLogging) { stream.progress( loc.usingModel( @@ -293,7 +293,7 @@ export const createSqlAgentRequestHandler = ( const connection = controller.connectionManager.getConnectionInfo(connectionUri); if (!connectionUri || !connection) { - logger.info( + logger.debug( "No connection URI/connection was found. Sending prompt to default language model.", ); @@ -397,7 +397,7 @@ export const createSqlAgentRequestHandler = ( prompt, ); if (!success) { - logger.info( + logger.warn( "Failed to start conversation. Sending prompt to default language model.", ); activity.update({ @@ -425,7 +425,7 @@ export const createSqlAgentRequestHandler = ( let printTextout = false; while (continuePollingMessages) { - logger.logDebug(`Continue polling messages for '${conversationUri}'`); + logger.debug(`Continue polling messages for '${conversationUri}'`); // Default continuePollingMessages to true at the start of each loop continuePollingMessages = true; @@ -436,7 +436,7 @@ export const createSqlAgentRequestHandler = ( } // Process tool calls and get the result - logger.info("Processing tool calls and awaiting for the result..."); + logger.debug("Processing tool calls and awaiting for the result..."); const result = await processToolCalls( stream, sqlTools, @@ -455,7 +455,7 @@ export const createSqlAgentRequestHandler = ( // Handle different message types switch (result.messageType) { case MessageType.Complete: - logger.info("Processing complete message..."); + logger.debug("Processing complete message..."); activity.end(ActivityStatus.Succeeded, { correlationId: correlationId, }); @@ -469,7 +469,7 @@ export const createSqlAgentRequestHandler = ( case MessageType.RequestLLM: case MessageType.RequestDirectLLM: - logger.info("Processing LLM message..."); + logger.debug("Processing LLM message..."); const { text, tools, print } = await handleRequestLLMMessage( conversationUri, result, @@ -506,7 +506,7 @@ export const createSqlAgentRequestHandler = ( break; } - logger.logDebug(`Done processing message for '${conversationUri}'`); + logger.debug(`Done processing message for '${conversationUri}'`); // Output reply text if needed if (printTextout) { UserSurvey.getInstance().promptUserForNPSFeedback("copilot_askMode"); @@ -541,9 +541,9 @@ export const createSqlAgentRequestHandler = ( replyText: string, copilotService: CopilotService, correlationId: string, - logger: Logger, + logger: ILogger, ): Promise { - logger.verbose("in processToolCalls"); + logger.debug("in processToolCalls"); if (sqlTools.length === 0) { sendErrorEvent( @@ -563,7 +563,7 @@ export const createSqlAgentRequestHandler = ( let result: GetNextMessageResponse; for (const toolCall of sqlTools) { try { - logger.logDebug(`Getting next message for conversationUri: ${conversationUri}`); + logger.debug(`Getting next message for conversationUri: ${conversationUri}`); result = await withTimeout( copilotService.getNextMessage( @@ -576,7 +576,7 @@ export const createSqlAgentRequestHandler = ( ); if (result.messageType === MessageType.Complete) { - logger.logDebug( + logger.debug( `Message type is complete for conversationUri: ${conversationUri}`, ); break; @@ -612,7 +612,7 @@ export const createSqlAgentRequestHandler = ( throw new Error("All tool calls failed or timed out."); } - logger.logDebug(`Finished processing tool calls for conversationUri: ${conversationUri}`); + logger.debug(`Finished processing tool calls for conversationUri: ${conversationUri}`); return result; } @@ -620,9 +620,9 @@ export const createSqlAgentRequestHandler = ( result: GetNextMessageResponse, context: vscode.ChatContext, referenceTexts: string[], - logger: Logger, + logger: ILogger, ): vscode.LanguageModelChatMessage[] { - logger.verbose("in prepareRequestMessages"); + logger.debug("in prepareRequestMessages"); // Get all messages from requestMessages const requestMessages = result.requestMessages; @@ -632,7 +632,7 @@ export const createSqlAgentRequestHandler = ( (message: LanguageModelRequestMessage) => message.role !== MessageRole.System, ); - logger.info("Getting initial system messages"); + logger.trace("Getting initial system messages"); // Extract initial system messages (ones that appear before any user message) const initialSystemMessages = requestMessages @@ -641,7 +641,7 @@ export const createSqlAgentRequestHandler = ( vscode.LanguageModelChatMessage.Assistant(message.text), ); - logger.info("Getting history messages"); + logger.trace("Getting history messages"); // Convert history messages with optional prefix marker const historyPrefix = "[HISTORY] "; // Can be empty string if no marker is desired @@ -702,7 +702,7 @@ export const createSqlAgentRequestHandler = ( }) .filter((msg): msg is vscode.LanguageModelChatMessage => msg !== undefined); - logger.info("Getting reference messages"); + logger.trace("Getting reference messages"); // Include reference messages with optional marker const referencePrefix = "[REFERENCE] "; // Can be empty string if no marker is desired const referenceMessages = referenceTexts @@ -716,7 +716,7 @@ export const createSqlAgentRequestHandler = ( return [...initialSystemMessages, ...historyMessages, ...referenceMessages]; } - logger.info("Getting remaining messages..."); + logger.trace("Getting remaining messages..."); // Process the remaining messages, preserving their original order const remainingMessages = requestMessages .slice(firstNonSystemIndex) @@ -728,7 +728,7 @@ export const createSqlAgentRequestHandler = ( } }); - logger.info("Returning combined messages..."); + logger.trace("Returning combined messages..."); // Combine messages in the desired order return [ ...initialSystemMessages, @@ -740,9 +740,9 @@ export const createSqlAgentRequestHandler = ( function mapRequestTools( tools: LanguageModelChatTool[], - logger: Logger, + logger: ILogger, ): vscode.LanguageModelChatTool[] { - logger.verbose("in mapRequestTools..."); + logger.debug("in mapRequestTools..."); return tools.map((tool, index): vscode.LanguageModelChatTool => { try { @@ -783,13 +783,13 @@ export const createSqlAgentRequestHandler = ( chatResponse: vscode.LanguageModelChatResponse, tools: LanguageModelChatTool[], correlationId: string, - logger: Logger, + logger: ILogger, ): Promise<{ replyText: string; toolsCalled: { tool: LanguageModelChatTool; parameters: string }[]; printTextout: boolean; }> { - logger.verbose("in processResponseParts..."); + logger.debug("in processResponseParts..."); const toolsCalled: { tool: LanguageModelChatTool; parameters: string; @@ -799,11 +799,11 @@ export const createSqlAgentRequestHandler = ( for await (const part of chatResponse.stream) { if (part instanceof vscode.LanguageModelTextPart) { - logger.info("Part is a language model text part."); + logger.trace("Part is a language model text part."); replyText += part.value; printTextout = true; } else if (part instanceof vscode.LanguageModelToolCallPart) { - logger.info("Part is a language model tool call part."); + logger.trace("Part is a language model tool call part."); const { sqlTool: tool, sqlToolParameters: parameters } = await processToolCall( tools, part, @@ -812,13 +812,13 @@ export const createSqlAgentRequestHandler = ( logger, ); if (tool) { - logger.logDebug(`Pushing ${tool.functionName} to toolsCalled`); + logger.debug(`Pushing ${tool.functionName} to toolsCalled`); toolsCalled.push({ tool, parameters }); } } } - logger.info("Finished processing response parts."); + logger.debug("Finished processing response parts."); return { replyText, toolsCalled, printTextout }; } @@ -831,13 +831,13 @@ export const createSqlAgentRequestHandler = ( context: vscode.ChatContext, // pass this context from above referenceTexts: string[], correlationId: string, - logger: Logger, + logger: ILogger, ): Promise<{ text: string; tools: { tool: LanguageModelChatTool; parameters: string }[]; print: boolean; }> { - logger.verbose("in handleRequestLLMMessage"); + logger.debug("in handleRequestLLMMessage"); const requestTools = mapRequestTools(result.tools, logger); const options: vscode.LanguageModelChatRequestOptions = { justification: "Azure SQL Copilot agent requires access to language model.", @@ -845,7 +845,7 @@ export const createSqlAgentRequestHandler = ( }; if (result.messageType === MessageType.RequestLLM) { - logger.info("result.messageType is RequestLLM"); + logger.debug("result.messageType is RequestLLM"); options.tools = requestTools; } @@ -860,7 +860,7 @@ export const createSqlAgentRequestHandler = ( logger, ); - logger.info("Finished handling request LLM message."); + logger.debug("Finished handling request LLM message."); return { text: replyText, tools: toolsCalled, @@ -874,12 +874,12 @@ export const createSqlAgentRequestHandler = ( part: vscode.LanguageModelToolCallPart, stream: vscode.ChatResponseStream, correlationId: string, - logger: Logger, + logger: ILogger, ): Promise<{ sqlTool: LanguageModelChatTool | undefined; sqlToolParameters: string | undefined; }> { - logger.verbose("in processToolCall"); + logger.debug("in processToolCall"); // Initialize variables to return let sqlTool: LanguageModelChatTool | undefined; let sqlToolParameters: string | undefined; @@ -889,10 +889,10 @@ export const createSqlAgentRequestHandler = ( .getConfiguration() .get(Constants.copilotDebugLogging, false); - logger.info("Looking up tool"); + logger.trace("Looking up tool"); const tool = resultTools.find((tool) => tool.functionName === part.name); if (!tool) { - logger.logDebug(`No tool was found for: ${part.name} - ${JSON.stringify(part.input)}}`); + logger.debug(`No tool was found for: ${part.name} - ${JSON.stringify(part.input)}}`); if (copilotDebugLogging) { stream.markdown(loc.toolLookupFor(part.name, JSON.stringify(part.input))); } @@ -928,7 +928,7 @@ export const createSqlAgentRequestHandler = ( } // Log tool call - logger.logDebug(`Calling tool: ${tool.functionName} with ${sqlToolParameters}`); + logger.debug(`Calling tool: ${tool.functionName} with ${sqlToolParameters}`); if (copilotDebugLogging) { stream.progress(loc.callingTool(tool.functionName, sqlToolParameters)); } @@ -939,7 +939,7 @@ export const createSqlAgentRequestHandler = ( correlationId: correlationId, }); - logger.info("Finished processing tool call."); + logger.debug("Finished processing tool call."); return { sqlTool, sqlToolParameters }; } @@ -948,9 +948,9 @@ export const createSqlAgentRequestHandler = ( err: vscode.LanguageModelError, stream: vscode.ChatResponseStream, correlationId: string, - logger: Logger, + logger: ILogger, ): void { - logger.verbose("in handleLanguageModelError"); + logger.debug("in handleLanguageModelError"); logger.error("Language Model Error:", getErrorMessage(err), "Code:", err.code); const errorMessages: Record = { @@ -984,9 +984,9 @@ export const createSqlAgentRequestHandler = ( token: vscode.CancellationToken, activity: ActivityObject, correlationId: string, - logger: Logger, + logger: ILogger, ): Promise { - logger.verbose("in sendToDefaultLanguageModel"); + logger.debug("in sendToDefaultLanguageModel"); try { logger.info(`Using ${model.name} to process your request...`); stream.progress(loc.usingModelToProcessRequest(model.name)); @@ -997,7 +997,7 @@ export const createSqlAgentRequestHandler = ( tools: [], // No tools involved for this fallback }; - logger.info("Sending request to default language model."); + logger.debug("Sending request to default language model."); const chatResponse = await model.sendRequest(messages, options, token); let replyText = ""; @@ -1008,14 +1008,14 @@ export const createSqlAgentRequestHandler = ( } if (replyText) { - logger.info("Received response from default language model."); + logger.debug("Received response from default language model."); activity.end(ActivityStatus.Succeeded, { correlationId: correlationId, message: "The default language model succeeded.", }); stream.markdown(replyText); } else { - logger.info("No output from the default language model."); + logger.warn("No output from the default language model."); activity.end(ActivityStatus.Succeeded, { correlationId: correlationId, message: "The default language model did not return any output.", @@ -1030,16 +1030,16 @@ export const createSqlAgentRequestHandler = ( logger.error("Error in fallback language model call:", getErrorMessage(err)); stream.markdown(loc.errorOccurredWhileProcessingRequest); } - logger.info("Finished sending request to default language model."); + logger.debug("Finished sending request to default language model."); } function handleError( err: unknown, stream: vscode.ChatResponseStream, correlationId: string, - logger: Logger, + logger: ILogger, ): void { - logger.verbose("in handleError"); + logger.debug("in handleError"); if (err instanceof vscode.LanguageModelError) { handleLanguageModelError(err, stream, correlationId, logger); diff --git a/extensions/mssql/src/credentialstore/credentialstore.ts b/extensions/mssql/src/credentialstore/credentialstore.ts index b6824e5d66..2a376582b3 100644 --- a/extensions/mssql/src/credentialstore/credentialstore.ts +++ b/extensions/mssql/src/credentialstore/credentialstore.ts @@ -5,7 +5,7 @@ import * as vscode from "vscode"; import { ICredentialStore, Credential } from "./icredentialstore"; -import { Logger } from "../models/logger"; +import { ILogger, logger } from "../models/logger"; import VscodeWrapper from "../controllers/vscodeWrapper"; /** @@ -14,14 +14,14 @@ import VscodeWrapper from "../controllers/vscodeWrapper"; */ export class CredentialStore implements ICredentialStore { private _secretStorage: vscode.SecretStorage; - private _logger: Logger; + private _logger: ILogger; constructor( private _context: vscode.ExtensionContext, - private _vscodeWrapper: VscodeWrapper, + _vscodeWrapper: VscodeWrapper, ) { this._secretStorage = this._context.secrets; - this._logger = Logger.create(this._vscodeWrapper.outputChannel, "CredentialStore"); + this._logger = logger.withPrefix("CredentialStore"); } /** diff --git a/extensions/mssql/src/dab/dabContainer.ts b/extensions/mssql/src/dab/dabContainer.ts index e18d7987e5..9ddf19541b 100644 --- a/extensions/mssql/src/dab/dabContainer.ts +++ b/extensions/mssql/src/dab/dabContainer.ts @@ -145,7 +145,7 @@ export async function startDabDockerContainer( configFilePath: string, ): Promise { try { - dockerLogger.appendLine( + dockerLogger.info( `Starting DAB container: ${containerName} on port ${port} with config ${configFilePath}`, ); @@ -190,13 +190,13 @@ export async function startDabDockerContainer( await container.start(); - dockerLogger.appendLine(`DAB container ${containerName} started successfully.`); + dockerLogger.info(`DAB container ${containerName} started successfully.`); return { success: true, port, }; } catch (e) { - dockerLogger.appendLine(`Failed to start DAB container: ${getErrorMessage(e)}`); + dockerLogger.info(`Failed to start DAB container: ${getErrorMessage(e)}`); return { success: false, error: LocalContainers.dabStartContainerError, @@ -220,9 +220,7 @@ export async function checkIfDabContainerIsReady( const intervalMs = 1000; const start = Date.now(); - dockerLogger.appendLine( - `Checking if DAB container ${containerName} is ready on port ${port}...`, - ); + dockerLogger.info(`Checking if DAB container ${containerName} is ready on port ${port}...`); const logStream = await startContainerLogStream(containerName).catch(() => undefined); @@ -231,7 +229,7 @@ export async function checkIfDabContainerIsReady( const filteredLogs = filterDabContainerLogsForDisplay(logs); if (logStream?.hasLaunchFailure()) { - dockerLogger.appendLine(`DAB container logs:\n${logs}`); + dockerLogger.info(`DAB container logs:\n${logs}`); return { success: false, error: dabLaunchFailureText, @@ -243,7 +241,7 @@ export async function checkIfDabContainerIsReady( // Check timeout before polling if (Date.now() - start > timeoutMs) { if (logs) { - dockerLogger.appendLine(`DAB container logs:\n${logs}`); + dockerLogger.info(`DAB container logs:\n${logs}`); } return { success: false, @@ -262,7 +260,7 @@ export async function checkIfDabContainerIsReady( // DAB returns various status codes, but any response means it's running if (response.status >= 200 && response.status < 500) { - dockerLogger.appendLine( + dockerLogger.info( `DAB container ${containerName} is ready! (HTTP ${response.status})`, ); return { success: true, port }; @@ -293,24 +291,24 @@ export async function stopAndRemoveDabContainer( try { const container = await getContainerByName(containerName); if (!container) { - dockerLogger.appendLine(`DAB container ${containerName} does not exist.`); + dockerLogger.info(`DAB container ${containerName} does not exist.`); return { success: true }; // Container doesn't exist, consider it removed } - dockerLogger.appendLine(`Stopping DAB container: ${containerName}`); + dockerLogger.info(`Stopping DAB container: ${containerName}`); try { await container.stop(); } catch { // Container might already be stopped } - dockerLogger.appendLine(`Removing DAB container: ${containerName}`); + dockerLogger.info(`Removing DAB container: ${containerName}`); await container.remove(); - dockerLogger.appendLine(`DAB container ${containerName} stopped and removed.`); + dockerLogger.info(`DAB container ${containerName} stopped and removed.`); return { success: true }; } catch (e) { - dockerLogger.appendLine(`Failed to stop/remove DAB container: ${getErrorMessage(e)}`); + dockerLogger.info(`Failed to stop/remove DAB container: ${getErrorMessage(e)}`); return { success: false, error: LocalContainers.dabStopContainerError, diff --git a/extensions/mssql/src/deployment/azureSqlDatabaseHelpers.ts b/extensions/mssql/src/deployment/azureSqlDatabaseHelpers.ts index d7edea9b07..09e935c3cb 100644 --- a/extensions/mssql/src/deployment/azureSqlDatabaseHelpers.ts +++ b/extensions/mssql/src/deployment/azureSqlDatabaseHelpers.ts @@ -13,7 +13,7 @@ import { import { getDefaultTenantId, VsCodeAzureHelper } from "../connectionconfig/azureHelpers"; import { getGroupIdFormItem } from "../connectionconfig/formComponentHelpers"; import { AzureSqlDatabase, ConnectionDialog } from "../constants/locConstants"; -import { Logger } from "../models/logger"; +import { ILogger } from "../models/logger"; import * as asd from "../sharedInterfaces/azureSqlDatabase"; import { AuthenticationType, IConnectionDialogProfile } from "../sharedInterfaces/connectionDialog"; import { FormItemActionButton, FormItemOptions, FormItemType } from "../sharedInterfaces/form"; @@ -33,7 +33,7 @@ import { // Cached logger reference for use in helper functions that don't have // direct access to the controller's protected logger. -let cachedLogger: Logger | undefined; +let cachedLogger: ILogger | undefined; const FIREWALL_ERROR_CODE = 40615; @@ -187,7 +187,7 @@ export function applyServerAuthSettings( export async function initializeAzureSqlDatabaseState( deploymentController: DeploymentWebviewController, groupOptions: FormItemOptions[], - logger: Logger, + logger: ILogger, selectedGroupId: string | undefined, ): Promise { cachedLogger = logger; @@ -839,7 +839,7 @@ export async function connectToAzureSqlDatabase( firewallRuleCreated = true; } - cachedLogger?.log( + cachedLogger?.trace( `Connection attempt ${attempt}/${maxRetries} failed (firewall not yet propagated), retrying in ${retryDelayMs / 1000}s...`, ); await new Promise((resolve) => setTimeout(resolve, retryDelayMs)); diff --git a/extensions/mssql/src/deployment/fabricProvisioningHelpers.ts b/extensions/mssql/src/deployment/fabricProvisioningHelpers.ts index cddd20bcca..9c8e960fec 100644 --- a/extensions/mssql/src/deployment/fabricProvisioningHelpers.ts +++ b/extensions/mssql/src/deployment/fabricProvisioningHelpers.ts @@ -7,7 +7,7 @@ import { getDefaultTenantId, VsCodeAzureHelper } from "../connectionconfig/azure import { getGroupIdFormItem } from "../connectionconfig/formComponentHelpers"; import { ConnectionDialog, Fabric, FabricProvisioning } from "../constants/locConstants"; import { FabricHelper } from "../fabric/fabricHelper"; -import { Logger } from "../models/logger"; +import { ILogger } from "../models/logger"; import { hasWorkspacePermission, IWorkspace, @@ -37,7 +37,7 @@ export const WORKSPACE_ROLE_REQUEST_LIMIT = 20; export async function initializeFabricProvisioningState( deploymentController: DeploymentWebviewController, groupOptions: FormItemOptions[], - logger: Logger, + logger: ILogger, selectedGroupId: string | undefined, ): Promise { const startTime = Date.now(); @@ -294,7 +294,7 @@ export function setFabricProvisioningFormComponents( export async function getAzureActionButton( deploymentController: DeploymentWebviewController, - logger: Logger, + logger: ILogger, ): Promise { const accountFormComponentId = "accountId"; const state = deploymentController.state.deploymentTypeState as fp.FabricProvisioningState; @@ -322,14 +322,14 @@ export async function getAzureActionButton( value: account.id, })); - logger.verbose( + logger.debug( `Read ${accountsComponent.options.length} Azure accounts: ${accountsComponent.options.map((a) => a.value).join(", ")}`, ); // There should always be at least one account, because the user just went through the sign in workflow if (azureAccounts.length > 0) { state.formState.accountId = azureAccounts[0].id; - logger.verbose(`Selecting '${azureAccounts[0].id}'`); + logger.debug(`Selecting '${azureAccounts[0].id}'`); } updateFabricProvisioningState(deploymentController, state); @@ -341,7 +341,7 @@ export async function getAzureActionButton( export async function loadComponentsAfterSignIn( deploymentController: DeploymentWebviewController, - logger: Logger, + logger: ILogger, ) { const state = deploymentController.state.deploymentTypeState as fp.FabricProvisioningState; diff --git a/extensions/mssql/src/deployment/sqlServerContainer.ts b/extensions/mssql/src/deployment/sqlServerContainer.ts index 6ff90df608..e6993c5570 100644 --- a/extensions/mssql/src/deployment/sqlServerContainer.ts +++ b/extensions/mssql/src/deployment/sqlServerContainer.ts @@ -216,7 +216,7 @@ export async function startSqlServerDockerContainer( const container = await dockerClient.createContainer(createContainerOptions); await container.start(); - dockerLogger.append(`SQL Server container ${containerName} started on port ${port}.`); + dockerLogger.trace(`SQL Server container ${containerName} started on port ${port}.`); return { success: true, port, @@ -261,14 +261,14 @@ export async function restartSqlServerContainer( if (isContainerRunning) return true; // Container is already running containerNode.loadingLabel = LocalContainers.startingContainerLoadingLabel; await objectExplorerService.setLoadingUiForNode(containerNode); - dockerLogger.appendLine(`Restarting container: ${containerName}`); + dockerLogger.info(`Restarting container: ${containerName}`); const container = await getContainerByName(containerName); if (!container) { throw new Error(`Container ${containerName} does not exist.`); } await container.start(); - dockerLogger.appendLine(`Container ${containerName} restarted successfully.`); + dockerLogger.info(`Container ${containerName} restarted successfully.`); containerNode.loadingLabel = LocalContainers.readyingContainerLoadingLabel; await objectExplorerService.setLoadingUiForNode(containerNode); @@ -303,7 +303,7 @@ export async function checkIfSqlServerContainerIsReadyForConnections( const timeoutMs = 300_000; // 5 minutes const readyMessage = SQL_SERVER_COMMANDS.CHECK_CONTAINER_READY; - dockerLogger.appendLine(`Checking if container ${containerName} is ready for connections...`); + dockerLogger.info(`Checking if container ${containerName} is ready for connections...`); try { const container = await getContainerByName(containerName); @@ -328,11 +328,11 @@ export async function checkIfSqlServerContainerIsReadyForConnections( logMonitor.dispose(); } if (isReady) { - dockerLogger.appendLine(`${containerName} is ready for connections!`); + dockerLogger.info(`${containerName} is ready for connections!`); return { success: true }; } } catch (e) { - dockerLogger.appendLine( + dockerLogger.info( `Error while checking readiness for ${containerName}: ${getErrorMessage(e)}`, ); } @@ -355,7 +355,7 @@ export async function getAllSqlServerContainerTags(): Promise { const parsed = JSON.parse(stdout); return (parsed.tags ?? []).filter((tag: string) => tag); } catch (e) { - dockerLogger.appendLine(`Error fetching SQL Server container tags: ${getErrorMessage(e)}`); + dockerLogger.error(`Error fetching SQL Server container tags: ${getErrorMessage(e)}`); return []; } } @@ -386,9 +386,7 @@ export async function getSqlServerContainerVersions(): Promise { try { - dockerLogger.appendLine(`Pulling container image: ${imageName}`); + dockerLogger.info(`Pulling container image: ${imageName}`); const dockerClient = getDockerodeClient(); const pullStream = platform ? await dockerClient.pull(imageName, { platform }) @@ -571,12 +569,10 @@ export async function pullContainerImage( error ? reject(error) : resolve(), ); }); - dockerLogger.appendLine(`Container image ${imageName} pulled successfully.`); + dockerLogger.info(`Container image ${imageName} pulled successfully.`); return { success: true }; } catch (e) { - dockerLogger.appendLine( - `Failed to pull container image ${imageName}: ${getErrorMessage(e)}`, - ); + dockerLogger.error(`Failed to pull container image ${imageName}: ${getErrorMessage(e)}`); return { success: false, error: errorMessage, @@ -642,7 +638,7 @@ export async function startDocker( } try { - dockerLogger.appendLine("Waiting for Docker to start..."); + dockerLogger.info("Waiting for Docker to start..."); await execDockerCommand(startCommand); let attempts = 0; @@ -654,7 +650,7 @@ export async function startDocker( try { await execDockerCommand(COMMANDS.CHECK_DOCKER_RUNNING()); clearInterval(checkDocker); - dockerLogger.appendLine("Docker started successfully."); + dockerLogger.info("Docker started successfully."); sendActionEvent(TelemetryViews.LocalContainers, TelemetryActions.StartDocker, { dockerStartedThroughExtension: "true", }); @@ -851,7 +847,7 @@ export async function checkContainerExists(name: string): Promise { const container = await getContainerByName(name); return container !== undefined; } catch (e) { - dockerLogger.appendLine(`Error checking if container exists: ${getErrorMessage(e)}`); + dockerLogger.error(`Error checking if container exists: ${getErrorMessage(e)}`); return false; } } diff --git a/extensions/mssql/src/fabric/fabricHelper.ts b/extensions/mssql/src/fabric/fabricHelper.ts index 3be7468703..2759e5b162 100644 --- a/extensions/mssql/src/fabric/fabricHelper.ts +++ b/extensions/mssql/src/fabric/fabricHelper.ts @@ -21,8 +21,7 @@ import { AxiosResponse } from "axios"; import { getErrorMessage } from "../utils/utils"; import { Fabric as Loc } from "../constants/locConstants"; import { getCloudProviderSettings } from "../azure/providerSettings"; -import { Logger } from "../models/logger"; -import VscodeWrapper from "../controllers/vscodeWrapper"; +import { ILogger, logger } from "../models/logger"; export class FabricHelper { static getFabricApiUriBase(): vscode.Uri { @@ -60,9 +59,8 @@ export class FabricHelper { static readonly defaultScope = ".default"; constructor() {} - static getFabricLogger(): Logger { - const vscodeWrapper = new VscodeWrapper(); - return Logger.create(vscodeWrapper.outputChannel, "Fabric Requests"); + static getFabricLogger(): ILogger { + return logger.withPrefix("Fabric Requests"); } public static async getFabricCapacities(tenantId: string): Promise { @@ -368,10 +366,10 @@ export class FabricHelper { const result = response.data; if (isFabricError(result)) { - fabricLogger.verbose(`Fabric API error: ${result.errorCode} - ${result.message}`); + fabricLogger.debug(`Fabric API error: ${result.errorCode} - ${result.message}`); throw new Error(Loc.fabricApiError(result.errorCode, result.message)); } - fabricLogger.verbose(`Fabric fetch API call successful: ${api}`); + fabricLogger.debug(`Fabric fetch API call successful: ${api}`); return result; } @@ -397,7 +395,7 @@ export class FabricHelper { ); if (response.status === this.longRunningOperationCode) { - fabricLogger.verbose(`Handling long-running Fabric operation for API: ${api}`); + fabricLogger.debug(`Handling long-running Fabric operation for API: ${api}`); response = await this.handleLongRunningOperation( response.headers["retry-after"] as string, response.headers["location"], @@ -409,11 +407,11 @@ export class FabricHelper { const result = response.data; if (isFabricError(result)) { - fabricLogger.verbose(`Fabric API error: ${result.errorCode} - ${result.message}`); + fabricLogger.debug(`Fabric API error: ${result.errorCode} - ${result.message}`); throw new Error(Loc.fabricApiError(result.errorCode, result.message)); } - fabricLogger.verbose(`Fabric post API call successful: ${api}`); + fabricLogger.debug(`Fabric post API call successful: ${api}`); return result; } @@ -424,7 +422,7 @@ export class FabricHelper { retryAfter: string, location: string, httpHelper: HttpClient, - fabricLogger: Logger, + fabricLogger: ILogger, token?: string, // eslint-disable-next-line @typescript-eslint/no-explicit-any ): Promise> { @@ -436,7 +434,7 @@ export class FabricHelper { longRunningResponse.data.status === IOperationStatus.Running || longRunningResponse.data.status === IOperationStatus.NotStarted ) { - fabricLogger.verbose( + fabricLogger.debug( `Long-running operation in progress. Waiting ${retryAfterInMs} seconds before next poll...`, ); await new Promise((resolve) => setTimeout(resolve, retryAfterInMs * 1000)); @@ -444,7 +442,7 @@ export class FabricHelper { } if (longRunningResponse.data.status === IOperationStatus.Failed) { - fabricLogger.verbose(`Long-running operation failed`); + fabricLogger.debug(`Long-running operation failed`); throw new Error( Loc.fabricLongRunningApiError( longRunningResponse.status.toString(), @@ -453,7 +451,7 @@ export class FabricHelper { ); } - fabricLogger.verbose( + fabricLogger.debug( `Long-running operation completed successfully. Fetching final result...`, ); diff --git a/extensions/mssql/src/http/httpClient.ts b/extensions/mssql/src/http/httpClient.ts index 8ca4d9b64e..69a30a1da5 100644 --- a/extensions/mssql/src/http/httpClient.ts +++ b/extensions/mssql/src/http/httpClient.ts @@ -5,7 +5,7 @@ import * as vscode from "vscode"; import * as LocalizedConstants from "../constants/locConstants"; -import { ILogger } from "../models/interfaces"; +import { ILogger } from "../models/logger"; import { getErrorMessage } from "../utils/utils"; import { HttpClientCore, diff --git a/extensions/mssql/src/http/httpClientCore.ts b/extensions/mssql/src/http/httpClientCore.ts index d5cd905c4d..42fb2bb13b 100644 --- a/extensions/mssql/src/http/httpClientCore.ts +++ b/extensions/mssql/src/http/httpClientCore.ts @@ -9,7 +9,7 @@ import * as https from "https"; import * as fs from "fs"; import axios, { AxiosRequestConfig, AxiosResponse, RawAxiosResponseHeaders } from "axios"; import { Readable } from "stream"; -import { ILogger } from "../models/interfaces"; +import { ILogger } from "../models/logger"; const UnableToGetProxyAgentOptionsMessage = "Unable to read proxy agent options to get tenants."; const HTTPS_PORT = 443; @@ -245,7 +245,7 @@ export class HttpClientCore { const proxy = this.loadProxyConfig(); if (proxy) { - this.logger?.verbose( + this.logger?.debug( "Proxy endpoint found in environment variables or workspace configuration.", ); @@ -277,7 +277,7 @@ export class HttpClientCore { let proxy: string | undefined = this.dependencies.getProxyConfig?.(); if (!proxy) { - this.logger?.verbose( + this.logger?.debug( "Workspace HTTP config didn't contain a proxy endpoint. Checking environment variables.", ); proxy = this.loadEnvironmentProxyValue(); @@ -317,23 +317,23 @@ export class HttpClientCore { const HTTPS_PROXY = "HTTPS_PROXY"; if (!process) { - this.logger?.verbose( + this.logger?.debug( "No process object found, unable to read environment variables for proxy.", ); return undefined; } if (process.env[HTTP_PROXY] || process.env[HTTP_PROXY.toLowerCase()]) { - this.logger?.verbose("Loading proxy value from HTTP_PROXY environment variable."); + this.logger?.debug("Loading proxy value from HTTP_PROXY environment variable."); return process.env[HTTP_PROXY] || process.env[HTTP_PROXY.toLowerCase()]; } else if (process.env[HTTPS_PROXY] || process.env[HTTPS_PROXY.toLowerCase()]) { - this.logger?.verbose("Loading proxy value from HTTPS_PROXY environment variable."); + this.logger?.debug("Loading proxy value from HTTPS_PROXY environment variable."); return process.env[HTTPS_PROXY] || process.env[HTTPS_PROXY.toLowerCase()]; } - this.logger?.verbose( + this.logger?.debug( "No proxy value found in either HTTPS_PROXY or HTTP_PROXY environment variables.", ); @@ -386,16 +386,16 @@ export class HttpClientCore { tunnelOptions: tunnel.HttpsOverHttpsOptions, ): http.Agent | https.Agent { if (isHttpsRequest && isHttpsProxy) { - this.logger?.verbose("Creating https request over https proxy tunneling agent"); + this.logger?.debug("Creating https request over https proxy tunneling agent"); return tunnel.httpsOverHttps(tunnelOptions); } else if (isHttpsRequest && !isHttpsProxy) { - this.logger?.verbose("Creating https request over http proxy tunneling agent"); + this.logger?.debug("Creating https request over http proxy tunneling agent"); return tunnel.httpsOverHttp(tunnelOptions); } else if (!isHttpsRequest && isHttpsProxy) { - this.logger?.verbose("Creating http request over https proxy tunneling agent"); + this.logger?.debug("Creating http request over https proxy tunneling agent"); return tunnel.httpOverHttps(tunnelOptions); } else { - this.logger?.verbose("Creating http request over http proxy tunneling agent"); + this.logger?.debug("Creating http request over http proxy tunneling agent"); return tunnel.httpOverHttp(tunnelOptions); } } diff --git a/extensions/mssql/src/languageservice/decompressProvider.ts b/extensions/mssql/src/languageservice/decompressProvider.ts index f78a67320d..c72da016eb 100644 --- a/extensions/mssql/src/languageservice/decompressProvider.ts +++ b/extensions/mssql/src/languageservice/decompressProvider.ts @@ -9,14 +9,14 @@ import * as fs from "fs"; import * as path from "path"; import { IDecompressProvider, IPackage } from "./interfaces"; -import { ILogger } from "../models/interfaces"; +import { ILogger } from "../models/logger"; export default class DecompressProvider implements IDecompressProvider { private decompressZip(pkg: IPackage, logger: ILogger): Promise { return new Promise((resolve, reject) => { yauzl.open(pkg.tmpFile.name, { lazyEntries: true }, (err, zipfile) => { if (err) { - logger.appendLine(`[ERROR] ${err}`); + logger.info(`[ERROR] ${err}`); reject(err); return; } @@ -31,7 +31,7 @@ export default class DecompressProvider implements IDecompressProvider { // Create directory fs.mkdir(dirPath, { recursive: true }, (err) => { if (err) { - logger.appendLine( + logger.info( `[ERROR] Failed to create directory ${dirPath}: ${err}`, ); reject(err); @@ -47,7 +47,7 @@ export default class DecompressProvider implements IDecompressProvider { // Ensure parent directory exists first fs.mkdir(dirPath, { recursive: true }, (err) => { if (err) { - logger.appendLine( + logger.info( `[ERROR] Failed to create directory ${dirPath}: ${err}`, ); reject(err); @@ -57,7 +57,7 @@ export default class DecompressProvider implements IDecompressProvider { // Now extract the file zipfile.openReadStream(entry, (err, readStream) => { if (err) { - logger.appendLine(`[ERROR] ${err}`); + logger.info(`[ERROR] ${err}`); reject(err); return; } @@ -66,23 +66,19 @@ export default class DecompressProvider implements IDecompressProvider { // Handle write stream errors writeStream.on("error", (err) => { - logger.appendLine( - `[ERROR] Failed to write ${filePath}: ${err}`, - ); + logger.info(`[ERROR] Failed to write ${filePath}: ${err}`); reject(err); }); // Wait for write stream to finish, not just read stream writeStream.on("close", () => { - logger.appendLine(`Extracted: ${entry.fileName}`); + logger.info(`Extracted: ${entry.fileName}`); zipfile.readEntry(); }); // Handle read stream errors readStream.on("error", (err) => { - logger.appendLine( - `[ERROR] Read error for ${entry.fileName}: ${err}`, - ); + logger.info(`[ERROR] Read error for ${entry.fileName}: ${err}`); reject(err); }); @@ -93,12 +89,12 @@ export default class DecompressProvider implements IDecompressProvider { }); zipfile.on("end", () => { - logger.appendLine(`Done! Files unpacked.\n`); + logger.info(`Done! Files unpacked.\n`); resolve(); }); zipfile.on("error", (err) => { - logger.appendLine(`[ERROR] Zipfile error: ${err}`); + logger.info(`[ERROR] Zipfile error: ${err}`); reject(err); }); }); @@ -115,11 +111,11 @@ export default class DecompressProvider implements IDecompressProvider { totalFiles++; }, onwarn: (warn) => { - logger.appendLine(`[ERROR] ${warn}`); + logger.info(`[ERROR] ${warn}`); }, }, () => { - logger.appendLine(`Done! ${totalFiles} files unpacked.\n`); + logger.info(`Done! ${totalFiles} files unpacked.\n`); }, ); } diff --git a/extensions/mssql/src/languageservice/dotnetRuntimeProvider.ts b/extensions/mssql/src/languageservice/dotnetRuntimeProvider.ts index affd0ef46e..67c72c5d7c 100644 --- a/extensions/mssql/src/languageservice/dotnetRuntimeProvider.ts +++ b/extensions/mssql/src/languageservice/dotnetRuntimeProvider.ts @@ -5,7 +5,7 @@ import * as vscode from "vscode"; import * as fs from "fs/promises"; -import { ILogger } from "../models/interfaces"; +import { ILogger } from "../models/logger"; import * as Constants from "../constants/constants"; import { ServiceClient } from "../constants/locConstants"; import { getErrorMessage } from "../utils/utils"; @@ -45,7 +45,7 @@ export default class DotnetRuntimeProvider { ); if (result?.dotnetPath) { await fs.access(result.dotnetPath); - this._logger.verbose("Acquired .NET runtime via command: " + result.dotnetPath); + this._logger.debug("Acquired .NET runtime via command: " + result.dotnetPath); return result.dotnetPath; } } catch (err) { diff --git a/extensions/mssql/src/languageservice/downloadHelper.ts b/extensions/mssql/src/languageservice/downloadHelper.ts index 6594a4661c..2f4b92d5be 100644 --- a/extensions/mssql/src/languageservice/downloadHelper.ts +++ b/extensions/mssql/src/languageservice/downloadHelper.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { ILogger } from "../models/interfaces"; +import { ILogger } from "../models/logger"; import { HttpDownloadError, HttpClientCore, IDownloadFileResult } from "../http/httpClientCore"; import { IPackage, IStatusView, PackageError } from "./interfaces"; @@ -50,7 +50,7 @@ export default class DownloadHelper { onHeaders: (headers) => { progress.packageSize = this.getPackageSize(headers["content-length"]); if (progress.packageSize > 0) { - logger.verbose( + logger.debug( `Package size: ${this.formatBytes(progress.packageSize)} (${Math.ceil(progress.packageSize / 1024)} KB)`, ); } diff --git a/extensions/mssql/src/languageservice/interfaces.ts b/extensions/mssql/src/languageservice/interfaces.ts index 86134ebbc8..d7c9d4d549 100644 --- a/extensions/mssql/src/languageservice/interfaces.ts +++ b/extensions/mssql/src/languageservice/interfaces.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as tmp from "tmp"; -import { ILogger } from "../models/interfaces"; +import { ILogger } from "../models/logger"; import * as vscodeMssql from "vscode-mssql"; export interface IStatusView { diff --git a/extensions/mssql/src/languageservice/serviceDownloadProvider.ts b/extensions/mssql/src/languageservice/serviceDownloadProvider.ts index 9b10a435d4..a5674dea90 100644 --- a/extensions/mssql/src/languageservice/serviceDownloadProvider.ts +++ b/extensions/mssql/src/languageservice/serviceDownloadProvider.ts @@ -15,7 +15,7 @@ import { } from "./interfaces"; import * as Constants from "../constants/constants"; import * as fs from "fs/promises"; -import { ILogger } from "../models/interfaces"; +import { ILogger } from "../models/logger"; import DownloadHelper from "./downloadHelper"; import { getServiceExecutablePath, ServiceExecutable } from "./serviceExecutablePaths"; @@ -104,7 +104,7 @@ export default class ServiceDownloadProvider { if (await this.tryGetInstallDirectory(platform)) { return basePath; } - this._logger.verbose( + this._logger.debug( `Creating install directory for platform ${platform} at path ${basePath}`, ); try { @@ -139,12 +139,12 @@ export default class ServiceDownloadProvider { const fileName = this.getRuntimeDownloadPackageFileName(platform); const installDirectory = await this.getOrCreateInstallDirectory(platform); - this._logger.appendLine(`${Constants.serviceInstallingTo} ${installDirectory}.`); + this._logger.info(`${Constants.serviceInstallingTo} ${installDirectory}.`); const urlString = this.buildDownloadUrl(fileName); const isZipFile: boolean = path.extname(fileName) === ".zip"; - this._logger.appendLine(`${Constants.serviceDownloading} ${urlString}`); + this._logger.info(`${Constants.serviceDownloading} ${urlString}`); let pkg: IPackage = { installPath: installDirectory, url: urlString, @@ -156,11 +156,11 @@ export default class ServiceDownloadProvider { try { await this._downloadHelper.downloadFile(pkg.url, pkg, this._logger, this._statusView); - this._logger.logDebug(`Downloaded to ${pkg.tmpFile.name}...`); - this._logger.appendLine(" Done!"); + this._logger.debug(`Downloaded to ${pkg.tmpFile.name}...`); + this._logger.info(" Done!"); await this.decompressAndInstallPackage(pkg); } catch (err) { - this._logger.appendLine(`[ERROR] ${err}`); + this._logger.info(`[ERROR] ${err}`); throw err; } return true; @@ -192,7 +192,7 @@ export default class ServiceDownloadProvider { } private async decompressAndInstallPackage(pkg: IPackage): Promise { - this._logger.appendLine("Installing ..."); + this._logger.info("Installing ..."); this._statusView.installingService(); await this._decompressProvider.decompress(pkg, this._logger); this._statusView.serviceInstalled(); diff --git a/extensions/mssql/src/languageservice/serviceInstallerUtil.ts b/extensions/mssql/src/languageservice/serviceInstallerUtil.ts index 0527148d5b..99626e5d6f 100644 --- a/extensions/mssql/src/languageservice/serviceInstallerUtil.ts +++ b/extensions/mssql/src/languageservice/serviceInstallerUtil.ts @@ -10,7 +10,7 @@ import DecompressProvider from "./decompressProvider"; import DownloadHelper from "./downloadHelper"; import ServerProvider from "./server"; import { IStatusView } from "./interfaces"; -import { ILogger } from "../models/interfaces"; +import { ILogger } from "../models/logger"; import * as fs from "fs"; export class StubStatusView implements IStatusView { @@ -35,47 +35,40 @@ export class StubStatusView implements IStatusView { export class StubLogger implements ILogger { constructor(private _log: (msg: string) => void) {} - logDebug(message: string): void { + trace(message: string): void { this._log(message); } - verbose(msg: any, ..._vals: any[]): void { - this._log(msg); + debug(message: string): void { + this._log(message); } - warn(msg: any, ..._vals: any[]): void { - this._log(msg); + info(message: string): void { + this._log(message); } - error(msg: any, ..._vals: any[]): void { - this._log(msg); + warn(message: string): void { + this._log(message); } - piiSanitized( - _msg: any, - _objsToSanitize: { name: string; objOrArray: any | any[] }[], - _stringsToShorten: { name: string; value: string }[], - ..._vals: any[] - ): void { - // no-op + error(message: string): void { + this._log(message); } - increaseIndent(): void { + piiSanitized(): void { // no-op } - decreaseIndent(): void { + show(): void { // no-op } - append(message?: string): void { - this._log(message); - } - appendLine(message?: string): void { - this._log(message); + withPrefix(): ILogger { + return this; } - info(msg: any, ..._vals: any[]): void { - this._log(msg); + + dispose(): void { + // no-op } } @@ -97,11 +90,11 @@ let serverProvider = new ServerProvider(downloadProvider, statusView); * Cleans existing service install and reinstalls the service for the runtime. */ export async function cleanAndInstallService(runtime: Runtime): Promise { - logger.verbose(`Cleaning and installing service for runtime: ${runtime}`); + logger.debug(`Cleaning and installing service for runtime: ${runtime}`); const serviceInstallDirectoryRoot = getServiceInstallDirectoryRoot(); try { await fs.promises.rm(serviceInstallDirectoryRoot, { recursive: true, force: true }); - logger.verbose(`Deleted service install directory: ${serviceInstallDirectoryRoot}`); + logger.debug(`Deleted service install directory: ${serviceInstallDirectoryRoot}`); } catch (error) { logger.error(`Error deleting service install directory: ${error.message}`); throw error; @@ -113,7 +106,7 @@ export async function cleanAndInstallService(runtime: Runtime): Promise { logger.error(`Error installing service for runtime ${runtime}: ${error.message}`); throw error; } - logger.verbose(`Service installation complete for runtime: ${runtime}, path: ${path}`); + logger.debug(`Service installation complete for runtime: ${runtime}, path: ${path}`); } /* diff --git a/extensions/mssql/src/languageservice/serviceclient.ts b/extensions/mssql/src/languageservice/serviceclient.ts index ae723681c7..0eb1e25554 100644 --- a/extensions/mssql/src/languageservice/serviceclient.ts +++ b/extensions/mssql/src/languageservice/serviceclient.ts @@ -17,7 +17,7 @@ import { } from "vscode-languageclient"; import VscodeWrapper from "../controllers/vscodeWrapper"; import * as Utils from "../models/utils"; -import { Logger } from "../models/logger"; +import { ILogger, logger as baseLogger } from "../models/logger"; import * as Constants from "../constants/constants"; import ServerProvider from "./server"; import ServiceDownloadProvider from "./serviceDownloadProvider"; @@ -152,13 +152,13 @@ export default class SqlToolsServiceClient { return this._client.diagnostics; } - public get logger(): Logger { + public get logger(): ILogger { return this._logger; } constructor( private _server: ServerProvider, - private _logger: Logger, + private _logger: ILogger, private _statusView: StatusView, private _vscodeWrapper: VscodeWrapper, private _dotnetRuntimeProvider: DotnetRuntimeProvider, @@ -170,7 +170,7 @@ export default class SqlToolsServiceClient { let config = new ExtConfig(); let vscodeWrapper = new VscodeWrapper(); - let logger = Logger.create(vscodeWrapper.outputChannel, "SQL Tools Service"); + let logger = baseLogger.withPrefix("SQL Tools Service"); let serverStatusView = new ServerStatusView(); let downloadHelper = new DownloadHelper(); @@ -199,7 +199,7 @@ export default class SqlToolsServiceClient { // initialize the SQL Tools Service Client instance by launching // out-of-proc server through the LanguageClient public async initialize(context: vscode.ExtensionContext): Promise { - this._logger.verbose("Initializing SQL Tools Service Client for mssql extension"); + this._logger.debug("Initializing SQL Tools Service Client for mssql extension"); this._logPath = context.logUri.fsPath; const platformInfo = await PlatformInformation.getCurrent(); return this.initializeForPlatform(platformInfo, context); @@ -215,7 +215,7 @@ export default class SqlToolsServiceClient { throw new Error(unsupportedPlatformMessage); } - this._logger.verbose( + this._logger.debug( `Detected runtime: ${platformInfo.platform} ${platformInfo.architecture}`, ); @@ -260,7 +260,7 @@ export default class SqlToolsServiceClient { platformInfo.runtimeId, ); if (osSpecificServerPath) { - this._logger.verbose( + this._logger.debug( `Found OS-specific SQL Tools Service install folder: ${osSpecificServerPath}`, ); await launchServer(osSpecificServerPath, platformInfo.runtimeId); @@ -287,12 +287,12 @@ export default class SqlToolsServiceClient { : "portableDownloaded"; if (!portableServerPath) { this.showOutputChannelPreservingFocus(); - this._logger.verbose(`Could not find portable SQL Tools Service executable.`); + this._logger.debug(`Could not find portable SQL Tools Service executable.`); portableServerPath = await this._server.downloadAndGetServerInstallFolder( Runtime.Portable, ); } - this._logger.verbose( + this._logger.debug( `Found portable SQL Tools Service install folder: ${portableServerPath}`, ); await launchServer(portableServerPath, Runtime.Portable); @@ -370,7 +370,7 @@ export default class SqlToolsServiceClient { throw new Error("Service path is undefined."); } - this._logger.verbose( + this._logger.debug( `Attempting to launch SQL Tools Service from install folder: ${serverFolder} for runtime: ${runtime}`, ); @@ -380,9 +380,7 @@ export default class SqlToolsServiceClient { ServiceExecutable.MicrosoftSqlToolsServiceLayer, ); if (!sqlToolsServicePath) { - this.logger.logDebug( - "Sql Tools Service executable was not found in expected location.", - ); + this.logger.debug("Sql Tools Service executable was not found in expected location."); throw new Error("Sql Tools Service executable was not found in expected location."); } this.client = await this.createLanguageClient(sqlToolsServicePath); @@ -393,7 +391,7 @@ export default class SqlToolsServiceClient { ServiceExecutable.SqlToolsResourceProviderService, ); if (!resourceProviderServicePath) { - this.logger.logDebug( + this.logger.debug( "Resource Provider Service executable was not found in expected location.", ); throw new Error( @@ -442,7 +440,7 @@ export default class SqlToolsServiceClient { // volume manageable while preserving the diagnostic signal // for the notebook IntelliSense issue. if (count === 0 || scheme === "vscode-notebook-cell") { - this._logger.logDebug( + this._logger.debug( `Completion count=${count} scheme=${scheme} triggerKind=${context.triggerKind} uri=${document.uri.toString()}`, ); } @@ -494,7 +492,7 @@ export default class SqlToolsServiceClient { } })(); if (scheme === "vscode-notebook-cell" || scheme === "unknown") { - this._logger.verbose( + this._logger.debug( `LanguageServiceStatus scheme=${scheme} status=${event.status} ownerUri=${event.ownerUri}`, ); } @@ -507,7 +505,7 @@ export default class SqlToolsServiceClient { serviceRuntime: Runtime, platformInfo: PlatformInformation, ): void { - this._logger.verbose( + this._logger.debug( `Sending service launch telemetry: launchType=${launchType}, serviceRuntime=${serviceRuntime}, detectedRuntime=${platformInfo?.runtimeId}, platform=${platformInfo?.platform}, architecture=${platformInfo?.architecture}`, ); sendActionEvent(SERVICE_LAUNCH_TELEMETRY_VIEW, TelemetryActions.ServiceStarted, { diff --git a/extensions/mssql/src/models/connectionStore.ts b/extensions/mssql/src/models/connectionStore.ts index 4d745ea6b7..d0373bbf0c 100644 --- a/extensions/mssql/src/models/connectionStore.ts +++ b/extensions/mssql/src/models/connectionStore.ts @@ -22,7 +22,7 @@ import { ICredentialStore, Credential } from "../credentialstore/icredentialstor import { ConnectionConfig } from "../connectionconfig/connectionconfig"; import VscodeWrapper from "../controllers/vscodeWrapper"; import { IConnectionInfo } from "vscode-mssql"; -import { Logger } from "./logger"; +import { ILogger, logger } from "./logger"; import { Deferred } from "../protocol"; import { ConnectionMatcher, MatchScore } from "./utils"; import { sendActionEvent } from "../telemetry/telemetry"; @@ -44,7 +44,7 @@ export class ConnectionStore { constructor( private _context: vscode.ExtensionContext, private _credentialStore: ICredentialStore, - private _logger?: Logger, + private _logger?: ILogger, private _connectionConfig?: ConnectionConfig, private _vscodeWrapper?: VscodeWrapper, ) { @@ -53,7 +53,7 @@ export class ConnectionStore { } if (!this._logger) { - this._logger = Logger.create(this.vscodeWrapper.outputChannel, "ConnectionStore"); + this._logger = logger.withPrefix("ConnectionStore"); } if (!this._connectionConfig) { @@ -477,7 +477,9 @@ export class ConnectionStore { await this._credentialStore.deleteCredential(credentialId); } catch (err) { deleteCredentialSuccess = false; - this._logger.log(LocalizedConstants.deleteCredentialError, credentialId, err); + this._logger.trace( + LocalizedConstants.deleteCredentialError(credentialId, String(err)), + ); } } // Update the MRU list to be empty @@ -718,7 +720,7 @@ export class ConnectionStore { uniqueConnections.push(conn); } else { dupeCount++; - this._logger.verbose( + this._logger.debug( `Duplicate connection ID found: ${conn.id}. Ignoring duplicate connection.`, ); } @@ -742,7 +744,7 @@ export class ConnectionStore { logMessage += `; ${dupeCount} duplicate connections ignored`; } - this._logger.logDebug(logMessage); + this._logger.debug(logMessage); return connResults; } diff --git a/extensions/mssql/src/models/interfaces.ts b/extensions/mssql/src/models/interfaces.ts index 2d6a42e236..31ded00701 100644 --- a/extensions/mssql/src/models/interfaces.ts +++ b/extensions/mssql/src/models/interfaces.ts @@ -174,24 +174,6 @@ export interface IResultsConfig { resultsFontFamily: string; } -export interface ILogger { - logDebug(message: string): void; - verbose(msg: any, ...vals: any[]): void; - warn(msg: any, ...vals: any[]): void; - error(msg: any, ...vals: any[]): void; - piiSanitized( - msg: any, - objsToSanitize: { name: string; objOrArray: any | any[] }[], - stringsToShorten: { name: string; value: string }[], - ...vals: any[] - ): void; - increaseIndent(): void; - decreaseIndent(): void; - append(message?: string): void; - appendLine(message?: string): void; - info(msg: any, ...vals: any[]): void; -} - export interface IAzureSignInQuickPickItem extends vscode.QuickPickItem { command: string; } diff --git a/extensions/mssql/src/models/logger.ts b/extensions/mssql/src/models/logger.ts index f337df1f1a..7d46d9838c 100644 --- a/extensions/mssql/src/models/logger.ts +++ b/extensions/mssql/src/models/logger.ts @@ -3,180 +3,326 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { LogOutputChannel, OutputChannel } from "vscode"; +import * as vscode from "vscode"; import * as Constants from "../constants/constants"; -import { ILogger } from "./interfaces"; import * as Utils from "./utils"; -import { ILogger2, Logger2, logger2, sanitize, shorten } from "./logger2"; - -/** Logger levels, ordered from most critical to most verbose */ -export enum LogLevel { - Pii = 0, - Off = 1, - Critical = 2, - Error = 3, - Warning = 4, - Information = 5, - Verbose = 6, - All = 7, -} -/* - * Logger keeps the legacy API surface while delegating output to Logger2. - */ -export class Logger implements ILogger { - private _indentLevel: number = 0; - private _indentSize: number = 4; - private _logger2: ILogger2; - - constructor( - _writer: (message: string) => void, - _logLevel: LogLevel, - private _piiLogging: boolean, - prefix?: string, - ) { - this._logger2 = prefix ? logger2.withPrefix(prefix) : logger2; - } - - public static create(channel: OutputChannel, prefix?: string): Logger { - const logger = new Logger( - () => undefined, - LogLevel.All, - Utils.getConfigPiiLogging(), - prefix, - ); - logger._logger2 = logger.createLogger2(channel, prefix); - return logger; - } +export const loggerOutputChannelName = Constants.outputChannelName; +/** + * VS Code log-channel-style logger with support for MSSQL tracing and PII settings. + */ +export interface ILogger { /** - * Logs a message containing PII (when enabled). Provides the ability to sanitize or shorten values to hide information or reduce the amount logged. - * @param msg The initial message to log - * @param objsToSanitize Set of objects we want to sanitize - * @param stringsToShorten Set of strings to shorten - * @param vals Any other values to add on to the end of the log message + * Logs a message at the most verbose level. + * Visibility of the message is controlled by the VS Code log channel's configured log level. */ - public piiSanitized( - msg: any, - objsToSanitize: { name: string; objOrArray: any | any[] }[], + trace(message: string, ...args: unknown[]): void; + /** + * Logs a message at the debug level to the underlying VS Code log channel. + * Visibility of the message is controlled by the channel's configured log level. + */ + debug(message: string, ...args: unknown[]): void; + /** + * Logs a message at the information level to the underlying VS Code log channel. + * Visibility of the message is controlled by the channel's configured log level. + */ + info(message: string, ...args: unknown[]): void; + /** + * Logs a message at the warning level to the underlying VS Code log channel. + * Visibility of the message is controlled by the channel's configured log level. + */ + warn(message: string, ...args: unknown[]): void; + /** + * Logs a message at the error level to the underlying VS Code log channel. + * Visibility of the message is controlled by the channel's configured log level. + */ + error(message: string, ...args: unknown[]): void; + /** + * Logs a message containing sensitive values after applying the legacy MSSQL sanitization rules. + * Emission is gated by `mssql.piiLogging`, while visibility is controlled by the VS Code + * log channel's configured log level. + */ + piiSanitized( + msg: unknown, + objsToSanitize: { name: string; objOrArray: unknown | unknown[] }[], stringsToShorten: { name: string; value: string }[], - ...vals: any[] - ): void { - if (!this.piiLogging) { - return; - } + ...vals: unknown[] + ): void; + /** Reveals the underlying log channel in VS Code. */ + show(preserveFocus?: boolean): void; + /** Creates a lightweight logger view that prepends the given prefix to messages. */ + withPrefix(prefix: string): ILogger; + /** Disposes the owned channel, if this logger created one. */ + dispose(): void; +} - const sanitizedMessage = [ - msg, - ...objsToSanitize?.map((obj) => `${obj.name}=${sanitize(obj.objOrArray)}`), - ...stringsToShorten.map((str) => `${str.name}=${shorten(str.value)}`), - ].join(" "); +type LogMethod = "trace" | "debug" | "info" | "warn" | "error"; +type ChannelFactory = () => vscode.LogOutputChannel; - this._logger2.trace(this.applyIndent(`[PII] ${sanitizedMessage}`), ...vals); - } +interface LoggerChannelState { + ownsChannel: boolean; + cachedChannel?: vscode.LogOutputChannel; + createChannel: ChannelFactory; +} - /** - * Logs a message containing PII (when enabled). - * @param msg The initial message to log - * @param vals Any other values to add on to the end of the log message - */ - public pii(msg: any, ...vals: any[]): void { - if (!this.piiLogging) { - return; - } +let defaultChannel: vscode.LogOutputChannel | undefined; +const defaultChannelState: LoggerChannelState = { + createChannel: getDefaultChannel, + ownsChannel: false, +}; + +/** + * Returns the shared MSSQL log channel, creating it on first use. + */ +function getDefaultChannel(): vscode.LogOutputChannel { + defaultChannel ??= vscode.window.createOutputChannel(loggerOutputChannelName, { + log: true, + }); + return defaultChannel; +} - this._logger2.trace(this.applyIndent(`[PII] ${String(msg)}`), ...vals); +/** + * Ensures a string is normalized to a single line by replacing newlines with spaces. + */ +function normalizeSingleLine(text: string): string { + return text.replace(/[\r\n]+/g, " ").trim(); +} + +/** + * Converts arbitrary log values into a single-line string payload. + */ +function formatLogPart(value: unknown): string { + if (value instanceof Error) { + return normalizeSingleLine(value.stack ?? value.message); } - public set piiLogging(val: boolean) { - this._piiLogging = val; + if (typeof value === "string") { + return normalizeSingleLine(value); } - public get piiLogging(): boolean { - return this._piiLogging; + try { + const json = JSON.stringify(value); + return json === undefined ? String(value) : normalizeSingleLine(json); + } catch { + return normalizeSingleLine(String(value)); } +} + +/** + * Logger implementation backed by a VS Code `LogOutputChannel`. + */ +export class Logger implements ILogger { + private constructor( + private readonly _channelState: LoggerChannelState, + private readonly _prefix?: string, + ) {} /** - * Prints at the `verbose` level. - * If `mssql.logDebug` is enabled, prints the message to the developer console. - **/ - public logDebug(message: string): void { - Utils.logDebug(message); - this._logger2.debug(this.applyIndent(message)); + * Creates a logger backed by the shared MSSQL output channel. + */ + public static global(prefix?: string): Logger { + return new Logger(defaultChannelState, prefix); } - public critical(msg: any, ...vals: any[]): void { - this._logger2.error(this.applyIndent(String(msg)), ...vals); + /** + * Creates a logger backed by an existing log channel. + */ + public static forChannel(channel: vscode.LogOutputChannel, prefix?: string): Logger { + return new Logger( + { + createChannel: () => channel, + ownsChannel: false, + }, + prefix, + ); } - public error(msg: any, ...vals: any[]): void { - this._logger2.error(this.applyIndent(String(msg)), ...vals); + /** + * Creates a logger that owns a dedicated log channel with the given name. + */ + public static forChannelName(channelName: string, prefix?: string): Logger { + return new Logger( + { + createChannel: () => vscode.window.createOutputChannel(channelName, { log: true }), + ownsChannel: true, + }, + prefix, + ); } - public warn(msg: any, ...vals: any[]): void { - this._logger2.warn(this.applyIndent(String(msg)), ...vals); + /** @inheritdoc */ + public trace(message: string, ...args: unknown[]): void { + this.log("trace", message, ...args); } - public info(msg: any, ...vals: any[]): void { - this._logger2.info(this.applyIndent(String(msg)), ...vals); + /** @inheritdoc */ + public debug(message: string, ...args: unknown[]): void { + this.log("debug", message, ...args); } - public verbose(msg: any, ...vals: any[]): void { - this._logger2.debug(this.applyIndent(String(msg)), ...vals); + /** @inheritdoc */ + public info(message: string, ...args: unknown[]): void { + this.log("info", message, ...args); } - /** Outputs a message with priority "All" (most verbose) */ - public log(msg: any, ...vals: any[]): void { - this._logger2.trace(this.applyIndent(String(msg)), ...vals); + /** @inheritdoc */ + public warn(message: string, ...args: unknown[]): void { + this.log("warn", message, ...args); } - public increaseIndent(): void { - this._indentLevel += 1; + /** @inheritdoc */ + public error(message: string, ...args: unknown[]): void { + this.log("error", message, ...args); } - public decreaseIndent(): void { - if (this._indentLevel > 0) { - this._indentLevel -= 1; + /** @inheritdoc */ + public piiSanitized( + msg: unknown, + objsToSanitize: { name: string; objOrArray: unknown | unknown[] }[], + stringsToShorten: { name: string; value: string }[], + ...vals: unknown[] + ): void { + if (!Utils.getConfigPiiLogging()) { + return; } + + const sanitizedMessage = [ + formatLogPart(msg), + ...(objsToSanitize ?? []).map((obj) => `${obj.name}=${sanitize(obj.objOrArray)}`), + ...(stringsToShorten ?? []).map((str) => `${str.name}=${shorten(str.value)}`), + ] + .filter((part) => part.length > 0) + .join(" "); + + this.channel.trace(this.formatMessage(`[PII] ${sanitizedMessage}`, vals)); } - /** Prints a message directly, regardless of log level */ - public append(message?: string): void { - this._logger2.trace(this.applyIndent(message || "")); + /** @inheritdoc */ + public show(preserveFocus?: boolean): void { + this.channel.show(preserveFocus); } - /** Prints a message directly, regardless of log level */ - public appendLine(message?: string): void { - this._logger2.info(this.applyIndent(message || "")); + /** @inheritdoc */ + public withPrefix(prefix: string): Logger { + return new Logger(this._channelState, prefix); } - private applyIndent(message: string): string { - if (this._indentLevel <= 0 || message.length === 0) { - return message; + /** @inheritdoc */ + public dispose(): void { + if (this._channelState.ownsChannel && this._channelState.cachedChannel) { + this._channelState.cachedChannel.dispose(); + this._channelState.cachedChannel = undefined; } + } - return `${" ".repeat(this._indentLevel * this._indentSize)}${message}`; + private get channel(): vscode.LogOutputChannel { + this._channelState.cachedChannel ??= this._channelState.createChannel(); + return this._channelState.cachedChannel; } - private createLogger2(channel: OutputChannel, prefix?: string): ILogger2 { - if (channel.name === Constants.outputChannelName) { - return prefix ? logger2.withPrefix(prefix) : logger2; + private log(method: LogMethod, message: string, ...args: unknown[]): void { + const formatted = this.formatMessage(message, args); + + switch (method) { + case "trace": + this.channel.trace(formatted); + break; + case "debug": + this.channel.debug(formatted); + break; + case "info": + this.channel.info(formatted); + break; + case "warn": + this.channel.warn(formatted); + console.warn(formatted); + break; + case "error": + this.channel.error(formatted); + console.error(formatted); + break; } + } + + /** + * Formats a message and optional arguments into the final emitted log payload. + */ + private formatMessage(message: string, args: unknown[]): string { + const formattedArgs = args.map((arg) => formatLogPart(arg)).filter((arg) => arg.length > 0); + const payload = [message, ...formattedArgs].filter((part) => part.length > 0).join(" "); - const maybeLogChannel = channel as OutputChannel & - Partial>; - if ( - typeof maybeLogChannel.trace === "function" && - typeof maybeLogChannel.debug === "function" && - typeof maybeLogChannel.info === "function" && - typeof maybeLogChannel.warn === "function" && - typeof maybeLogChannel.error === "function" - ) { - return Logger2.forChannel(maybeLogChannel as LogOutputChannel, prefix); + if (!this._prefix) { + return payload; } - return Logger2.forChannelName(channel.name, prefix); + return payload.length > 0 ? `[${this._prefix}] ${payload}` : `[${this._prefix}]`; + } +} + +/** + * Shared MSSQL logger instance for callers that do not need a custom channel or prefix. + */ +export const logger: ILogger = Logger.global(); + +export default logger; + +/** + * Exported for unit tests to isolate the cached default channel. + */ +export function resetLoggerDefaultChannelForTest(): void { + defaultChannel?.dispose(); + defaultChannel = undefined; + defaultChannelState.cachedChannel = undefined; +} + +/** + * Sanitizes a given object for logging to the output window, removing/shortening any PII or unneeded values. + * @param objOrArray The object to sanitize for output logging + * @returns The stringified version of the sanitized object + */ +export function sanitize(objOrArray: any): string { + if (Array.isArray(objOrArray)) { + return JSON.stringify(objOrArray.map((o) => sanitizeImpl(o))); + } else { + return sanitizeImpl(objOrArray); + } +} + +function sanitizeImpl(obj: any): string { + obj = Object.assign({}, obj); + delete obj.domains; // very long and not really useful + // Shorten all tokens since we don't usually need the exact values and there's security concerns if they leaked. + shortenIfExists(obj, "token"); + shortenIfExists(obj, "refresh_token"); + shortenIfExists(obj, "access_token"); + shortenIfExists(obj, "code"); + shortenIfExists(obj, "id_token"); + return JSON.stringify(obj); +} + +/** + * Shortens the given string property on an object if it exists, otherwise does nothing. + * @param obj The object possibly containing the property + * @param property The name of the property to shorten - if it exists + */ +function shortenIfExists(obj: any, property: string): void { + if (obj[property]) { + obj[property] = shorten(obj[property]); } } -export { sanitize, shorten } from "./logger2"; +/** + * Shortens a given string. If it's longer than 6 characters it returns the first 3 characters + * followed by a ... followed by the last 3 characters. Returns the original string if 6 characters + * or less. + * @param str The string to shorten + * @returns Shortened string in the form 'xxx...xxx' + */ +export function shorten(str?: string): string | undefined { + // Don't shorten if adding the ... wouldn't make the string shorter. + if (!str || str.length < 10) { + return str; + } + return `${str.substr(0, 3)}...${str.slice(-3)}`; +} diff --git a/extensions/mssql/src/models/logger2.ts b/extensions/mssql/src/models/logger2.ts deleted file mode 100644 index 04add72667..0000000000 --- a/extensions/mssql/src/models/logger2.ts +++ /dev/null @@ -1,328 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import * as vscode from "vscode"; -import * as Constants from "../constants/constants"; -import * as Utils from "./utils"; - -export const logger2OutputChannelName = Constants.outputChannelName; - -/** - * VS Code log-channel-style logger with support for MSSQL tracing and PII settings. - */ -export interface ILogger2 { - /** - * Logs a message at the most verbose level. - * Visibility of the message is controlled by the VS Code log channel's configured log level. - */ - trace(message: string, ...args: unknown[]): void; - /** - * Logs a message at the debug level to the underlying VS Code log channel. - * Visibility of the message is controlled by the channel's configured log level. - */ - debug(message: string, ...args: unknown[]): void; - /** - * Logs a message at the information level to the underlying VS Code log channel. - * Visibility of the message is controlled by the channel's configured log level. - */ - info(message: string, ...args: unknown[]): void; - /** - * Logs a message at the warning level to the underlying VS Code log channel. - * Visibility of the message is controlled by the channel's configured log level. - */ - warn(message: string, ...args: unknown[]): void; - /** - * Logs a message at the error level to the underlying VS Code log channel. - * Visibility of the message is controlled by the channel's configured log level. - */ - error(message: string, ...args: unknown[]): void; - /** - * Logs a message containing sensitive values after applying the legacy MSSQL sanitization rules. - * Emission is gated by `mssql.piiLogging`, while visibility is controlled by the VS Code - * log channel's configured log level. - */ - piiSanitized( - msg: unknown, - objsToSanitize: { name: string; objOrArray: unknown | unknown[] }[], - stringsToShorten: { name: string; value: string }[], - ...vals: unknown[] - ): void; - /** Reveals the underlying log channel in VS Code. */ - show(preserveFocus?: boolean): void; - /** Creates a lightweight logger view that prepends the given prefix to messages. */ - withPrefix(prefix: string): ILogger2; - /** Disposes the owned channel, if this logger created one. */ - dispose(): void; -} - -type LogMethod = "trace" | "debug" | "info" | "warn" | "error"; -type ChannelFactory = () => vscode.LogOutputChannel; - -interface Logger2ChannelState { - ownsChannel: boolean; - cachedChannel?: vscode.LogOutputChannel; - createChannel: ChannelFactory; -} - -let defaultChannel: vscode.LogOutputChannel | undefined; -const defaultChannelState: Logger2ChannelState = { - createChannel: getDefaultChannel, - ownsChannel: false, -}; - -/** - * Returns the shared MSSQL log channel, creating it on first use. - */ -function getDefaultChannel(): vscode.LogOutputChannel { - defaultChannel ??= vscode.window.createOutputChannel(logger2OutputChannelName, { - log: true, - }); - return defaultChannel; -} - -/** - * Ensures a string is normalized to a single line by replacing newlines with spaces. - */ -function normalizeSingleLine(text: string): string { - return text.replace(/[\r\n]+/g, " ").trim(); -} - -/** - * Converts arbitrary log values into a single-line string payload. - */ -function formatLogPart(value: unknown): string { - if (value instanceof Error) { - return normalizeSingleLine(value.stack ?? value.message); - } - - if (typeof value === "string") { - return normalizeSingleLine(value); - } - - try { - const json = JSON.stringify(value); - return json === undefined ? String(value) : normalizeSingleLine(json); - } catch { - return normalizeSingleLine(String(value)); - } -} - -/** - * Logger implementation backed by a VS Code `LogOutputChannel`. - */ -export class Logger2 implements ILogger2 { - private constructor( - private readonly _channelState: Logger2ChannelState, - private readonly _prefix?: string, - ) {} - - /** - * Creates a logger backed by the shared MSSQL output channel. - */ - public static global(prefix?: string): Logger2 { - return new Logger2(defaultChannelState, prefix); - } - - /** - * Creates a logger backed by an existing log channel. - */ - public static forChannel(channel: vscode.LogOutputChannel, prefix?: string): Logger2 { - return new Logger2( - { - createChannel: () => channel, - ownsChannel: false, - }, - prefix, - ); - } - - /** - * Creates a logger that owns a dedicated log channel with the given name. - */ - public static forChannelName(channelName: string, prefix?: string): Logger2 { - return new Logger2( - { - createChannel: () => vscode.window.createOutputChannel(channelName, { log: true }), - ownsChannel: true, - }, - prefix, - ); - } - - /** @inheritdoc */ - public trace(message: string, ...args: unknown[]): void { - this.log("trace", message, ...args); - } - - /** @inheritdoc */ - public debug(message: string, ...args: unknown[]): void { - this.log("debug", message, ...args); - } - - /** @inheritdoc */ - public info(message: string, ...args: unknown[]): void { - this.log("info", message, ...args); - } - - /** @inheritdoc */ - public warn(message: string, ...args: unknown[]): void { - this.log("warn", message, ...args); - } - - /** @inheritdoc */ - public error(message: string, ...args: unknown[]): void { - this.log("error", message, ...args); - } - - /** @inheritdoc */ - public piiSanitized( - msg: unknown, - objsToSanitize: { name: string; objOrArray: unknown | unknown[] }[], - stringsToShorten: { name: string; value: string }[], - ...vals: unknown[] - ): void { - if (!Utils.getConfigPiiLogging()) { - return; - } - - const sanitizedMessage = [ - formatLogPart(msg), - ...(objsToSanitize ?? []).map((obj) => `${obj.name}=${sanitize(obj.objOrArray)}`), - ...(stringsToShorten ?? []).map((str) => `${str.name}=${shorten(str.value)}`), - ] - .filter((part) => part.length > 0) - .join(" "); - - this.channel.trace(this.formatMessage(`[PII] ${sanitizedMessage}`, vals)); - } - - /** @inheritdoc */ - public show(preserveFocus?: boolean): void { - this.channel.show(preserveFocus); - } - - /** @inheritdoc */ - public withPrefix(prefix: string): Logger2 { - return new Logger2(this._channelState, prefix); - } - - /** @inheritdoc */ - public dispose(): void { - if (this._channelState.ownsChannel && this._channelState.cachedChannel) { - this._channelState.cachedChannel.dispose(); - this._channelState.cachedChannel = undefined; - } - } - - private get channel(): vscode.LogOutputChannel { - this._channelState.cachedChannel ??= this._channelState.createChannel(); - return this._channelState.cachedChannel; - } - - private log(method: LogMethod, message: string, ...args: unknown[]): void { - const formatted = this.formatMessage(message, args); - - switch (method) { - case "trace": - this.channel.trace(formatted); - break; - case "debug": - this.channel.debug(formatted); - break; - case "info": - this.channel.info(formatted); - break; - case "warn": - this.channel.warn(formatted); - console.warn(formatted); - break; - case "error": - this.channel.error(formatted); - console.error(formatted); - break; - } - } - - /** - * Formats a message and optional arguments into the final emitted log payload. - */ - private formatMessage(message: string, args: unknown[]): string { - const formattedArgs = args.map((arg) => formatLogPart(arg)).filter((arg) => arg.length > 0); - const payload = [message, ...formattedArgs].filter((part) => part.length > 0).join(" "); - - if (!this._prefix) { - return payload; - } - - return payload.length > 0 ? `[${this._prefix}] ${payload}` : `[${this._prefix}]`; - } -} - -/** - * Shared MSSQL logger instance for callers that do not need a custom channel or prefix. - */ -export const logger2: ILogger2 = Logger2.global(); - -export default logger2; - -/** - * Exported for unit tests to isolate the cached default channel. - */ -export function resetLogger2DefaultChannelForTest(): void { - defaultChannel?.dispose(); - defaultChannel = undefined; - defaultChannelState.cachedChannel = undefined; -} - -/** - * Sanitizes a given object for logging to the output window, removing/shortening any PII or unneeded values. - * @param objOrArray The object to sanitize for output logging - * @returns The stringified version of the sanitized object - */ -export function sanitize(objOrArray: any): string { - if (Array.isArray(objOrArray)) { - return JSON.stringify(objOrArray.map((o) => sanitizeImpl(o))); - } else { - return sanitizeImpl(objOrArray); - } -} - -function sanitizeImpl(obj: any): string { - obj = Object.assign({}, obj); - delete obj.domains; // very long and not really useful - // Shorten all tokens since we don't usually need the exact values and there's security concerns if they leaked. - shortenIfExists(obj, "token"); - shortenIfExists(obj, "refresh_token"); - shortenIfExists(obj, "access_token"); - shortenIfExists(obj, "code"); - shortenIfExists(obj, "id_token"); - return JSON.stringify(obj); -} - -/** - * Shortens the given string property on an object if it exists, otherwise does nothing. - * @param obj The object possibly containing the property - * @param property The name of the property to shorten - if it exists - */ -function shortenIfExists(obj: any, property: string): void { - if (obj[property]) { - obj[property] = shorten(obj[property]); - } -} - -/** - * Shortens a given string. If it's longer than 6 characters it returns the first 3 characters - * followed by a ... followed by the last 3 characters. Returns the original string if 6 characters - * or less. - * @param str The string to shorten - * @returns Shortened string in the form 'xxx...xxx' - */ -export function shorten(str?: string): string | undefined { - // Don't shorten if adding the ... wouldn't make the string shorter. - if (!str || str.length < 10) { - return str; - } - return `${str.substr(0, 3)}...${str.slice(-3)}`; -} diff --git a/extensions/mssql/src/mssqlProtocolHandler.ts b/extensions/mssql/src/mssqlProtocolHandler.ts index f8080e1100..34581f91de 100644 --- a/extensions/mssql/src/mssqlProtocolHandler.ts +++ b/extensions/mssql/src/mssqlProtocolHandler.ts @@ -10,7 +10,7 @@ import SqlToolsServiceClient from "./languageservice/serviceclient"; import { CapabilitiesResult, GetCapabilitiesRequest } from "./models/contracts/connection"; import { IConnectionProfile } from "./models/interfaces"; import { AuthenticationType } from "./sharedInterfaces/connectionDialog"; -import { Logger } from "./models/logger"; +import { ILogger, logger } from "./models/logger"; import VscodeWrapper from "./controllers/vscodeWrapper"; import MainController from "./controllers/mainController"; import { cmdAddObjectExplorer } from "./constants/constants"; @@ -31,14 +31,14 @@ interface ConnectionOptionProperty { * Handles MSSQL protocol URIs. */ export class MssqlProtocolHandler { - private _logger: Logger; + private _logger: ILogger; constructor( vscodeWrapper: VscodeWrapper, private mainController: MainController, private client: SqlToolsServiceClient, ) { - this._logger = Logger.create(vscodeWrapper.outputChannel, "MssqlProtocolHandler"); + this._logger = logger.withPrefix("MssqlProtocolHandler"); } /** diff --git a/extensions/mssql/src/notebooks/notebookConnectionManager.ts b/extensions/mssql/src/notebooks/notebookConnectionManager.ts index 9baa8adf78..a09f9f2440 100644 --- a/extensions/mssql/src/notebooks/notebookConnectionManager.ts +++ b/extensions/mssql/src/notebooks/notebookConnectionManager.ts @@ -14,7 +14,7 @@ import { generateQueryUri } from "../models/utils"; import * as LocalizedConstants from "../constants/locConstants"; import { sendActionEvent, startActivity } from "../telemetry/telemetry"; import { TelemetryViews, TelemetryActions, ActivityStatus } from "../sharedInterfaces/telemetry"; -import { ILogger2 } from "../models/logger2"; +import { ILogger } from "../models/logger"; import { NotebookQueryExecutor, NotebookQueryResult } from "./notebookQueryExecutor"; /** @@ -38,7 +38,7 @@ export class NotebookConnectionManager implements vscode.Disposable { private connectionUri: string | undefined; private connectionInfo: IConnectionInfo | undefined; private connectionLabel: string = ""; - private log: ILogger2; + private log: ILogger; private readonly queryExecutor: NotebookQueryExecutor; /** @@ -65,7 +65,7 @@ export class NotebookConnectionManager implements vscode.Disposable { constructor( private connectionMgr: ConnectionManager, private connectionSharingService: ConnectionSharingService, - log: ILogger2, + log: ILogger, client?: SqlToolsServiceClient, notificationHandler?: QueryNotificationHandler, ) { diff --git a/extensions/mssql/src/notebooks/notebookQueryExecutor.ts b/extensions/mssql/src/notebooks/notebookQueryExecutor.ts index 03497b96d7..7f4168ed36 100644 --- a/extensions/mssql/src/notebooks/notebookQueryExecutor.ts +++ b/extensions/mssql/src/notebooks/notebookQueryExecutor.ts @@ -27,7 +27,7 @@ import { QueryDisposeRequest, QueryDisposeParams } from "../models/contracts/que import { QueryCancelRequest, QueryCancelParams } from "../models/contracts/queryCancel"; import { IDbColumn, IResultMessage } from "../models/interfaces"; import { Deferred } from "../protocol"; -import { ILogger2 } from "../models/logger2"; +import { ILogger } from "../models/logger"; export interface NotebookResultSetData { columnInfo: IDbColumn[]; @@ -69,7 +69,7 @@ export class NotebookQueryExecutor { constructor( private readonly client: SqlToolsServiceClient, private readonly notificationHandler: QueryNotificationHandler, - private readonly log?: ILogger2, + private readonly log?: ILogger, ) {} async execute( diff --git a/extensions/mssql/src/notebooks/sqlNotebookController.ts b/extensions/mssql/src/notebooks/sqlNotebookController.ts index ad64ba5984..a4c49ba5ca 100644 --- a/extensions/mssql/src/notebooks/sqlNotebookController.ts +++ b/extensions/mssql/src/notebooks/sqlNotebookController.ts @@ -12,7 +12,7 @@ import * as LocalizedConstants from "../constants/locConstants"; import ConnectionManager from "../controllers/connectionManager"; import { ConnectionSharingService } from "../connectionSharing/connectionSharingService"; import * as Utils from "../models/utils"; -import { ILogger2, Logger2 } from "../models/logger2"; +import { ILogger, Logger } from "../models/logger"; import { NotebookConnectionManager } from "./notebookConnectionManager"; import { NotebookCodeLensProvider } from "./notebookCodeLensProvider"; import { NotebookBatchResult } from "./notebookQueryExecutor"; @@ -68,7 +68,7 @@ export class SqlNotebookController implements vscode.Disposable { readonly connections = new Map(); private readonly codeLensProvider: NotebookCodeLensProvider; private readonly statusBarItem: vscode.StatusBarItem; - private readonly log: ILogger2; + private readonly log: ILogger; private readonly disposables: vscode.Disposable[] = []; private executionOrder = 0; // Track notebooks by their document object to handle URI changes on save @@ -85,10 +85,10 @@ export class SqlNotebookController implements vscode.Disposable { private readonly _connectionManagerFactory?: ( connectionMgr: ConnectionManager, connectionSharingService: ConnectionSharingService, - log: ILogger2, + log: ILogger, ) => NotebookConnectionManager, ) { - this.log = Logger2.forChannelName("MSSQL - Notebooks", "SqlNotebookController"); + this.log = Logger.forChannelName("MSSQL - Notebooks", "SqlNotebookController"); this.controller = vscode.notebooks.createNotebookController( "ms-mssql.sql-notebook-controller", diff --git a/extensions/mssql/src/objectExplorer/objectExplorerDragAndDropController.ts b/extensions/mssql/src/objectExplorer/objectExplorerDragAndDropController.ts index 595f67fdb8..995f933cb2 100644 --- a/extensions/mssql/src/objectExplorer/objectExplorerDragAndDropController.ts +++ b/extensions/mssql/src/objectExplorer/objectExplorerDragAndDropController.ts @@ -9,7 +9,7 @@ import { TreeNodeInfo } from "./nodes/treeNodeInfo"; import { ObjectExplorerUtils } from "./objectExplorerUtils"; import { ConnectionNode } from "./nodes/connectionNode"; import { ConnectionGroupNode } from "./nodes/connectionGroupNode"; -import { Logger } from "../models/logger"; +import { ILogger, logger } from "../models/logger"; import VscodeWrapper from "../controllers/vscodeWrapper"; import { getErrorMessage } from "../utils/utils"; import { ConnectionStore } from "../models/connectionStore"; @@ -33,13 +33,13 @@ export class ObjectExplorerDragAndDropController readonly dragMimeTypes = [OE_MIME_TYPE, TEXT_MIME_TYPE]; readonly dropMimeTypes = [OE_MIME_TYPE]; - private readonly _logger: Logger; + private readonly _logger: ILogger; constructor( vscodeWrapper: VscodeWrapper, private connectionStore: ConnectionStore, ) { - this._logger = Logger.create(vscodeWrapper.outputChannel, "DragAndDrop"); + this._logger = logger.withPrefix("DragAndDrop"); } public handleDrag( @@ -102,7 +102,7 @@ export class ObjectExplorerDragAndDropController }; } - this._logger.verbose( + this._logger.debug( `Dragged ${dragData.type} '${dragData.name}' (ID: ${dragData.id}) onto group '${targetInfo.label}' (ID: ${targetInfo.id})`, ); @@ -118,7 +118,7 @@ export class ObjectExplorerDragAndDropController ); if (group.id === targetInfo.id) { - this._logger.verbose("Cannot move group into itself; skipping."); + this._logger.debug("Cannot move group into itself; skipping."); return; } diff --git a/extensions/mssql/src/objectExplorer/objectExplorerService.ts b/extensions/mssql/src/objectExplorer/objectExplorerService.ts index 3e5cea962e..105feae894 100644 --- a/extensions/mssql/src/objectExplorer/objectExplorerService.ts +++ b/extensions/mssql/src/objectExplorer/objectExplorerService.ts @@ -46,7 +46,7 @@ import { GetSessionIdRequest, GetSessionIdResponse, } from "../models/contracts/objectExplorer/getSessionIdRequest"; -import { Logger } from "../models/logger"; +import { ILogger, logger } from "../models/logger"; import VscodeWrapper from "../controllers/vscodeWrapper"; import { restartSqlServerContainer } from "../deployment/sqlServerContainer"; import { ExpandErrorNode } from "./nodes/expandErrorNode"; @@ -69,7 +69,7 @@ export interface CreateSessionResult { export class ObjectExplorerService { private _client: SqlToolsServiceClient; - private _logger: Logger; + private _logger: ILogger; public initialized: Deferred = new Deferred(); /** @@ -85,7 +85,7 @@ export class ObjectExplorerService { const result = []; if (!this._connectionGroupNodes.has(ConnectionConfig.ROOT_GROUP_ID)) { - this._logger.verbose( + this._logger.debug( "Root server group is not defined. Cannot get root nodes for Object Explorer.", ); return []; @@ -125,7 +125,7 @@ export class ObjectExplorerService { this._client = this._connectionManager.client; - this._logger = Logger.create(this._vscodeWrapper.outputChannel, "ObjectExplorerService"); + this._logger = logger.withPrefix("ObjectExplorerService"); this._treeNodeToChildrenMap = new Map(); @@ -201,7 +201,7 @@ export class ObjectExplorerService { isRefresh: node.shouldRefresh.toString(), }, ); - this._logger.verbose(`Expanding node ${node.label} with session ID ${sessionId}`); + this._logger.debug(`Expanding node ${node.label} with session ID ${sessionId}`); try { const expandParams: ExpandParams = { sessionId: sessionId, @@ -213,13 +213,13 @@ export class ObjectExplorerService { let response: boolean; if (node.shouldRefresh) { - this._logger.verbose(`Refreshing node ${node.label} with session ID ${sessionId}`); + this._logger.debug(`Refreshing node ${node.label} with session ID ${sessionId}`); response = await this._connectionManager.client.sendRequest( RefreshRequest.type, expandParams, ); } else { - this._logger.verbose(`Expanding node ${node.label} with session ID ${sessionId}`); + this._logger.debug(`Expanding node ${node.label} with session ID ${sessionId}`); response = await this._connectionManager.client.sendRequest( ExpandRequest.type, expandParams, @@ -228,7 +228,7 @@ export class ObjectExplorerService { if (response) { const result = await expandResponse; - this._logger.verbose( + this._logger.debug( `Expand node response: ${JSON.stringify(result)} for sessionId ${sessionId}`, ); if (!result) { @@ -236,7 +236,7 @@ export class ObjectExplorerService { } if (result.nodes && !result.errorMessage) { - this._logger.verbose( + this._logger.debug( `Received ${result.nodes.length} children for node ${node.label} for sessionId ${sessionId}`, ); // successfully received children from SQL Tools Service @@ -376,7 +376,7 @@ export class ObjectExplorerService { serverGroups.length === 1 && serverGroups[0].id === ConnectionConfig.ROOT_GROUP_ID ) { - this._logger.verbose( + this._logger.debug( "No saved connections or groups found. Showing add connection node.", ); getConnectionActivity.end(ActivityStatus.Succeeded, undefined, { @@ -650,7 +650,7 @@ export class ObjectExplorerService { if (createSessionResponse) { const sessionCreationResult = await sessionCreatedResponse; if (sessionCreationResult.success) { - this._logger.verbose( + this._logger.debug( `Session created successfully with session ID ${sessionCreationResult.sessionId}`, ); this._pendingSessionCreations.delete(sessionIdResponse.sessionId); @@ -724,7 +724,7 @@ export class ObjectExplorerService { containerNode, this, ); - this._logger.verbose( + this._logger.debug( successfullyRunning ? `Failed to restart Docker container "${connectionProfile.containerName}".` : `Docker container "${connectionProfile.containerName}" has been restarted.`, @@ -994,7 +994,7 @@ export class ObjectExplorerService { private addConnectionNode(connectionNode: ConnectionNode): void { const oldNode = this._connectionNodes.get(connectionNode.connectionProfile.id); - this._logger.verbose( + this._logger.debug( `${oldNode ? "Updating" : "Adding"} connection node: ${connectionNode.label}`, ); @@ -1081,7 +1081,7 @@ export class ObjectExplorerService { const foundNode = this._connectionNodes.get(connectionProfile.id); if (!foundNode) { - this._logger.verbose( + this._logger.debug( `Connection node not found for profile with ID: ${connectionProfile.id}`, ); } diff --git a/extensions/mssql/src/profiler/profilerController.ts b/extensions/mssql/src/profiler/profilerController.ts index 23e1bba631..5a1efbaa38 100644 --- a/extensions/mssql/src/profiler/profilerController.ts +++ b/extensions/mssql/src/profiler/profilerController.ts @@ -16,7 +16,7 @@ import { SESSION_NAME_MAX_LENGTH } from "../sharedInterfaces/profiler"; import VscodeWrapper from "../controllers/vscodeWrapper"; import { getProfilerConfigService } from "./profilerConfigService"; import { ProfilerSessionTemplate } from "../models/contracts/profiler"; -import { Logger } from "../models/logger"; +import { ILogger, logger } from "../models/logger"; import { Profiler as LocProfiler } from "../constants/locConstants"; import * as Constants from "../constants/constants"; import { TreeNodeInfo } from "../objectExplorer/nodes/treeNodeInfo"; @@ -33,7 +33,7 @@ import { TelemetryViews, TelemetryActions } from "../sharedInterfaces/telemetry" * Handles command registration, connection management, and launching the profiler UI. */ export class ProfilerController { - private _logger: Logger; + private _logger: ILogger; private _webviewControllers: Map = new Map(); private _xelWebviewControllers: Map = new Map(); private _profilerUri: string | undefined; @@ -46,7 +46,7 @@ export class ProfilerController { private _vscodeWrapper: VscodeWrapper, private _sessionManager: ProfilerSessionManager, ) { - this._logger = Logger.create(this._vscodeWrapper.outputChannel, "Profiler"); + this._logger = logger.withPrefix("Profiler"); this.registerCommands(); } @@ -64,9 +64,7 @@ export class ProfilerController { connectionProfile: IConnectionProfile, databaseScopeFilter?: string, ): Promise { - this._logger.verbose( - `Launching profiler with connection to ${connectionProfile.server}...`, - ); + this._logger.debug(`Launching profiler with connection to ${connectionProfile.server}...`); try { // Determine if this is an Azure/Fabric server. @@ -75,7 +73,7 @@ export class ProfilerController { const isAzureOrFabric = serverInfo ? serverInfo.isCloud : isAzureSqlDbCompatible(getServerTypes(connectionProfile)); - this._logger.verbose( + this._logger.debug( serverInfo ? `Server info: engineEditionId=${serverInfo.engineEditionId}, isCloud=${serverInfo.isCloud}` : `Server types detected: ${getServerTypes(connectionProfile).join(", ")}`, @@ -86,7 +84,7 @@ export class ProfilerController { this._currentEngineType = isAzureOrFabric ? EngineType.AzureSQLDB : EngineType.Standalone; - this._logger.verbose(`Engine type set to: ${this._currentEngineType}`); + this._logger.debug(`Engine type set to: ${this._currentEngineType}`); // For Azure SQL and Fabric, we need to ensure a user database is selected let profileToUse = connectionProfile; @@ -100,7 +98,7 @@ export class ProfilerController { const updatedProfile = await this.ensureAzureDatabaseSelected(profileToUse); if (!updatedProfile) { // User cancelled database selection - this._logger.verbose("User cancelled database selection"); + this._logger.debug("User cancelled database selection"); return; } profileToUse = updatedProfile; @@ -119,7 +117,7 @@ export class ProfilerController { databaseScopeFilter = profileToUse.database; } profileToUse = { ...profileToUse, database: "" }; - this._logger.verbose( + this._logger.debug( `Cleared database from on-prem profile to ensure server-scoped session (filter: ${databaseScopeFilter})`, ); } @@ -127,18 +125,18 @@ export class ProfilerController { // Generate a unique URI for this profiler connection const profilerUri = `profiler://${uuid()}`; - this._logger.verbose(`Connecting to ${profileToUse.server} with URI: ${profilerUri}`); + this._logger.debug(`Connecting to ${profileToUse.server} with URI: ${profilerUri}`); // Connect using the connection manager with the provided profile const connected = await this._connectionManager.connect(profilerUri, profileToUse); if (!connected) { - this._logger.verbose("Connection failed"); + this._logger.debug("Connection failed"); vscode.window.showErrorMessage(LocProfiler.failedToConnect); return; } - this._logger.verbose(`Successfully connected to ${profileToUse.server}`); + this._logger.debug(`Successfully connected to ${profileToUse.server}`); // Store the engine type for this profiler URI this._profilerEngineTypes.set(profilerUri, this._currentEngineType); @@ -182,11 +180,11 @@ export class ProfilerController { ): Promise { // Check if a user database is already selected if (!isSystemDatabase(connectionProfile.database)) { - this._logger.verbose(`User database already selected: ${connectionProfile.database}`); + this._logger.debug(`User database already selected: ${connectionProfile.database}`); return connectionProfile; } - this._logger.verbose( + this._logger.debug( "No user database selected for Azure SQL, prompting for database selection", ); @@ -195,7 +193,7 @@ export class ProfilerController { try { const connected = await this._connectionManager.connect(tempUri, connectionProfile); if (!connected) { - this._logger.verbose("Failed to connect to get database list"); + this._logger.debug("Failed to connect to get database list"); vscode.window.showErrorMessage(LocProfiler.failedToConnect); return undefined; } @@ -207,7 +205,7 @@ export class ProfilerController { const userDatabases = databases.filter((db) => !isSystemDatabase(db)); if (userDatabases.length === 0) { - this._logger.verbose("No user databases found"); + this._logger.debug("No user databases found"); vscode.window.showWarningMessage(LocProfiler.noDatabasesFound); return undefined; } @@ -219,11 +217,11 @@ export class ProfilerController { }); if (!selectedDatabase) { - this._logger.verbose("User cancelled database selection"); + this._logger.debug("User cancelled database selection"); return undefined; } - this._logger.verbose(`User selected database: ${selectedDatabase}`); + this._logger.debug(`User selected database: ${selectedDatabase}`); // Create a new connection profile with the selected database const updatedProfile: IConnectionProfile = { @@ -235,7 +233,7 @@ export class ProfilerController { } finally { // Clean up the temporary connection await this._connectionManager.disconnect(tempUri).catch((err) => { - this._logger.verbose(`Error disconnecting temp connection: ${err}`); + this._logger.debug(`Error disconnecting temp connection: ${err}`); }); } } @@ -270,7 +268,7 @@ export class ProfilerController { // connectionProfile.database is often empty for Database nodes because they // inherit the parent Server node's connection profile unchanged. const databaseName = ObjectExplorerUtils.getDatabaseName(treeNodeInfo); - this._logger.verbose( + this._logger.debug( `Launching profiler from database node: ${databaseName}`, ); await this.launchProfilerWithConnection(connectionProfile, databaseName); @@ -298,7 +296,7 @@ export class ProfilerController { }), ); - this._logger.verbose("Profiler commands registered"); + this._logger.debug("Profiler commands registered"); } /** @@ -310,11 +308,11 @@ export class ProfilerController { sessionName: string, webviewController: ProfilerWebviewController, ): Promise { - this._logger.verbose(`Starting profiler session: ${sessionName}`); + this._logger.debug(`Starting profiler session: ${sessionName}`); const sessionId = uuid(); try { if (!this._profilerUri) { - this._logger.verbose("No profiler connection available"); + this._logger.debug("No profiler connection available"); vscode.window.showErrorMessage(LocProfiler.noConnectionAvailable); return; } @@ -322,7 +320,7 @@ export class ProfilerController { // Clear existing session and captured events from previous sessions webviewController.setCurrentSession(undefined); // Clear old session first webviewController.clearRows(); - this._logger.verbose("Cleared existing events from grid"); + this._logger.debug("Cleared existing events from grid"); // Create a ProfilerSession for the selected session const bufferCapacity = vscode.workspace @@ -337,7 +335,7 @@ export class ProfilerController { bufferCapacity: bufferCapacity, engineType: this._profilerEngineTypes.get(this._profilerUri!) ?? "SQLServer", }); - this._logger.verbose( + this._logger.debug( `Created ProfilerSession: id=${sessionId}, ownerUri=${this._profilerUri}`, ); @@ -346,7 +344,7 @@ export class ProfilerController { // Set up event handlers on the session session.onEventsReceived((events) => { - this._logger.verbose( + this._logger.debug( `Events received: ${events.length} events for session ${sessionId}`, ); webviewController.notifyNewEvents(events.length); @@ -354,7 +352,7 @@ export class ProfilerController { session.onEventsRemoved((events) => { const sequenceNumbers = events.map((e) => e.eventNumber).join(", "); - this._logger.verbose( + this._logger.debug( `Events removed from ring buffer: ${events.length} events (sequence #s: ${sequenceNumbers}) for session ${sessionId}`, ); webviewController.notifyRowsRemoved(events); @@ -372,7 +370,7 @@ export class ProfilerController { }); session.onSessionStopped((errorMessage) => { - this._logger.verbose(`Session ${sessionId} stopped notification received`); + this._logger.debug(`Session ${sessionId} stopped notification received`); if (errorMessage) { this._logger.error(`Session stopped with error: ${errorMessage}`); } @@ -393,7 +391,7 @@ export class ProfilerController { // Session is now running - update the webview state webviewController.setSessionState(SessionState.Running); webviewController.setSessionName(sessionName); - this._logger.verbose("Profiling session started"); + this._logger.debug("Profiling session started"); } catch (e) { this._logger.error(`Error starting profiler session: ${e}`); const errMsg = getErrorMessage(e); @@ -417,7 +415,7 @@ export class ProfilerController { */ private async handleCreateSession(webviewController: ProfilerWebviewController): Promise { if (!this._profilerUri) { - this._logger.verbose("No profiler connection available"); + this._logger.debug("No profiler connection available"); vscode.window.showErrorMessage(LocProfiler.noConnectionAvailable); return; } @@ -429,7 +427,7 @@ export class ProfilerController { const engineType = this._profilerEngineTypes.get(this._profilerUri) ?? EngineType.Standalone; const templates = configService.getTemplatesForEngine(engineType); - this._logger.verbose( + this._logger.debug( `Filtered templates for engine ${engineType}: ${templates.length} available`, ); @@ -452,11 +450,11 @@ export class ProfilerController { }); if (!selectedTemplate) { - this._logger.verbose("User cancelled template selection"); + this._logger.debug("User cancelled template selection"); return; } - this._logger.verbose(`Selected template: ${selectedTemplate.template.name}`); + this._logger.debug(`Selected template: ${selectedTemplate.template.name}`); // Step 2: Show session name input const sessionName = await vscode.window.showInputBox({ @@ -481,11 +479,11 @@ export class ProfilerController { }); if (!sessionName) { - this._logger.verbose("User cancelled session name input"); + this._logger.debug("User cancelled session name input"); return; } - this._logger.verbose(`Session name: ${sessionName}`); + this._logger.debug(`Session name: ${sessionName}`); // Step 3: Show spinner (set creating state) webviewController.setCreatingSession(true); @@ -497,7 +495,7 @@ export class ProfilerController { createStatement: selectedTemplate.template.createStatement, }; - this._logger.verbose( + this._logger.debug( `Creating XEvent session: ${sessionName} with template: ${template.name}`, ); @@ -513,7 +511,7 @@ export class ProfilerController { (params) => { clearTimeout(timeout); disposable.dispose(); - this._logger.verbose( + this._logger.debug( `Session created notification received: ${params.sessionName}`, ); resolve(); @@ -546,7 +544,7 @@ export class ProfilerController { vscode.window.showInformationMessage( LocProfiler.sessionCreatedSuccessfully(sessionName), ); - this._logger.verbose(`Session '${sessionName}' created successfully`); + this._logger.debug(`Session '${sessionName}' created successfully`); // Step 7: Auto-start the session await this.startSession(sessionName, webviewController); @@ -575,7 +573,7 @@ export class ProfilerController { // Step 1: Show template selection quick pick (filtered by engine type) const configService = getProfilerConfigService(); const templates = configService.getTemplatesForEngine(engineType); - this._logger.verbose( + this._logger.debug( `Filtered templates for engine ${engineType}: ${templates.length} available`, ); @@ -600,13 +598,13 @@ export class ProfilerController { }); if (!selectedTemplate) { - this._logger.verbose("User cancelled template selection"); + this._logger.debug("User cancelled template selection"); // Disconnect since user cancelled await this._connectionManager.disconnect(profilerUri); return; } - this._logger.verbose(`Selected template: ${selectedTemplate.template.name}`); + this._logger.debug(`Selected template: ${selectedTemplate.template.name}`); // Step 2: Show session name input (default to template name) const sessionName = await vscode.window.showInputBox({ @@ -631,18 +629,18 @@ export class ProfilerController { }); if (!sessionName) { - this._logger.verbose("User cancelled session name input"); + this._logger.debug("User cancelled session name input"); // Disconnect since user cancelled await this._connectionManager.disconnect(profilerUri); return; } - this._logger.verbose(`Session name: ${sessionName}`); + this._logger.debug(`Session name: ${sessionName}`); // Fetch available XEvent sessions from the server - this._logger.verbose("Fetching available XEvent sessions..."); + this._logger.debug("Fetching available XEvent sessions..."); const xeventSessions = await this._sessionManager.getXEventSessions(profilerUri); - this._logger.verbose(`Found ${xeventSessions.length} available XEvent sessions`); + this._logger.debug(`Found ${xeventSessions.length} available XEvent sessions`); // Convert to session objects for the webview const availableSessions = xeventSessions.map((name) => ({ @@ -679,7 +677,7 @@ export class ProfilerController { this._profilerEngineTypes.delete(webviewProfilerUri); // Disconnect the profiler connection to avoid lingering connections - this._logger.verbose(`Cleaning up profiler connection: ${webviewProfilerUri}`); + this._logger.debug(`Cleaning up profiler connection: ${webviewProfilerUri}`); this._connectionManager.disconnect(webviewProfilerUri).catch((err) => { this._logger.error(`Error disconnecting profiler connection: ${err}`); }); @@ -701,25 +699,25 @@ export class ProfilerController { const session = webviewController.currentSession; if (!session) { - this._logger.verbose("No active session to pause/resume for this webview"); + this._logger.debug("No active session to pause/resume for this webview"); return; } try { - this._logger.verbose( + this._logger.debug( `Current session state: ${session.state}, session.id: ${session.id}`, ); if (session.state === SessionState.Running) { - this._logger.verbose(`Pausing profiler session ${session.id}...`); + this._logger.debug(`Pausing profiler session ${session.id}...`); await this._sessionManager.pauseProfilingSession(session.id); webviewController.setSessionState(SessionState.Paused); - this._logger.verbose("Session paused"); + this._logger.debug("Session paused"); } else if (session.state === SessionState.Paused) { - this._logger.verbose(`Resuming profiler session ${session.id}...`); + this._logger.debug(`Resuming profiler session ${session.id}...`); await this._sessionManager.togglePauseProfilingSession(session.id); webviewController.setSessionState(SessionState.Running); - this._logger.verbose("Session resumed"); + this._logger.debug("Session resumed"); } else { - this._logger.verbose( + this._logger.debug( `Session in unexpected state: ${session.state}, cannot pause/resume`, ); } @@ -732,14 +730,14 @@ export class ProfilerController { const session = webviewController.currentSession; if (!session) { - this._logger.verbose("No active session to stop for this webview"); + this._logger.debug("No active session to stop for this webview"); return; } try { - this._logger.verbose(`Stopping profiler session ${session.id}...`); + this._logger.debug(`Stopping profiler session ${session.id}...`); await this._sessionManager.stopProfilingSession(session.id); webviewController.setSessionState(SessionState.Stopped); - this._logger.verbose("Session stopped"); + this._logger.debug("Session stopped"); // Telemetry: session stopped by user const durationMs = session.startedAt > 0 ? Date.now() - session.startedAt : 0; @@ -763,7 +761,7 @@ export class ProfilerController { } }, onViewChange: (viewId: string) => { - this._logger.verbose(`View changed to: ${viewId}`); + this._logger.debug(`View changed to: ${viewId}`); }, onExportToCsv: async (suggestedFileName: string): Promise => { return await this.getStreamForWriting(webviewController, suggestedFileName); @@ -777,7 +775,7 @@ export class ProfilerController { if (sessionExists) { // Session already exists - just start it - this._logger.verbose( + this._logger.debug( `Session '${sessionName}' already exists, starting without creating`, ); webviewController.setSelectedSession(sessionName); @@ -797,7 +795,7 @@ export class ProfilerController { createStatement: selectedTemplate.template.createStatement, }; - this._logger.verbose( + this._logger.debug( `Creating XEvent session: ${sessionName} with template: ${template.name}`, ); @@ -813,7 +811,7 @@ export class ProfilerController { (params) => { clearTimeout(timeout); disposable.dispose(); - this._logger.verbose( + this._logger.debug( `Session created notification received: ${params.sessionName}`, ); resolve(); @@ -839,7 +837,7 @@ export class ProfilerController { webviewController.setSelectedSession(sessionName); webviewController.setCreatingSession(false); - this._logger.verbose(`Session '${sessionName}' created successfully`); + this._logger.debug(`Session '${sessionName}' created successfully`); // Auto-start the session await this.startSession(sessionName, webviewController); @@ -860,7 +858,7 @@ export class ProfilerController { * Launches the profiler UI in read-only mode for the selected file. */ private async openXelFileCommand(): Promise { - this._logger.verbose("Opening XEL file picker..."); + this._logger.debug("Opening XEL file picker..."); const fileUri = await vscode.window.showOpenDialog({ canSelectFiles: true, @@ -873,7 +871,7 @@ export class ProfilerController { }); if (!fileUri || fileUri.length === 0) { - this._logger.verbose("User cancelled XEL file selection"); + this._logger.debug("User cancelled XEL file selection"); return; } @@ -888,7 +886,7 @@ export class ProfilerController { * @param filePath - Full path to the XEL file */ public async openXelFile(filePath: string): Promise { - this._logger.verbose(`Opening XEL file: ${filePath}`); + this._logger.debug(`Opening XEL file: ${filePath}`); // Validate file exists and is accessible const fileInfo = await this.validateXelFile(filePath); @@ -898,7 +896,7 @@ export class ProfilerController { // Check if we already have a webview for this file if (this._xelWebviewControllers.has(filePath)) { - this._logger.verbose(`Webview already exists for ${filePath}, focusing it`); + this._logger.debug(`Webview already exists for ${filePath}, focusing it`); const existingController = this._xelWebviewControllers.get(filePath)!; existingController.revealToForeground(); return; @@ -906,7 +904,7 @@ export class ProfilerController { // XEL file sessions do not require a database connection // The file is parsed locally and displayed in read-only mode - this._logger.verbose("Opening XEL file in read-only disconnected mode..."); + this._logger.debug("Opening XEL file in read-only disconnected mode..."); try { // Create the webview controller in read-only disconnected mode @@ -946,7 +944,7 @@ export class ProfilerController { LocProfiler.xelFileReadOnlyDisconnectedNotification(fileInfo.fileName), ); - this._logger.verbose( + this._logger.debug( `XEL file ${fileInfo.fileName} opened successfully in read-only mode`, ); } catch (e) { @@ -1019,29 +1017,29 @@ export class ProfilerController { // New Session - disabled in read-only disconnected mode onCreateSession: async () => { // No-op for read-only disconnected sessions - this._logger.verbose( + this._logger.debug( "Create session ignored for read-only disconnected XEL file session", ); }, // Start Session - disabled in read-only disconnected mode onStartSession: async () => { // No-op for read-only disconnected sessions - this._logger.verbose( + this._logger.debug( "Start session ignored for read-only disconnected XEL file session", ); }, // Pause/Resume - disabled for read-only file sessions onPauseResume: async () => { // No-op for read-only sessions - this._logger.verbose("Pause/Resume ignored for read-only XEL file session"); + this._logger.debug("Pause/Resume ignored for read-only XEL file session"); }, // Stop - disabled for read-only file sessions onStop: async () => { // No-op for read-only sessions - this._logger.verbose("Stop ignored for read-only XEL file session"); + this._logger.debug("Stop ignored for read-only XEL file session"); }, onViewChange: (viewId: string) => { - this._logger.verbose(`View changed to: ${viewId}`); + this._logger.debug(`View changed to: ${viewId}`); }, }); } @@ -1054,11 +1052,11 @@ export class ProfilerController { webviewController: ProfilerWebviewController, fileInfo: XelFileInfo, ): Promise { - this._logger.verbose(`Loading XEL file events for: ${fileInfo.filePath}`); + this._logger.debug(`Loading XEL file events for: ${fileInfo.filePath}`); // Generate a unique URI for this file-based session (not a real connection) const fileSessionUri = `profiler://xelfile/${uuid()}`; - this._logger.verbose(`Created file session URI: ${fileSessionUri}`); + this._logger.debug(`Created file session URI: ${fileSessionUri}`); // Create a ProfilerSession for the file const sessionId = uuid(); @@ -1071,7 +1069,7 @@ export class ProfilerController { readOnly: true, engineType: "SQLServer", }); - this._logger.verbose(`Created ProfilerSession: id=${sessionId}, type=File`); + this._logger.debug(`Created ProfilerSession: id=${sessionId}, type=File`); // Set up the webview controller with the session reference webviewController.setCurrentSession(session); @@ -1082,7 +1080,7 @@ export class ProfilerController { // Set up event handlers on the session session.onEventsReceived((events) => { - this._logger.verbose( + this._logger.debug( `Events received: ${events.length} events for XEL file session ${sessionId}`, ); webviewController.notifyNewEvents(events.length); @@ -1090,14 +1088,14 @@ export class ProfilerController { session.onEventsRemoved((events) => { const sequenceNumbers = events.map((e) => e.eventNumber).join(", "); - this._logger.verbose( + this._logger.debug( `Events removed from ring buffer: ${events.length} events (sequence #s: ${sequenceNumbers}) for XEL file session ${sessionId}`, ); webviewController.notifyRowsRemoved(events); }); session.onSessionStopped((errorMessage) => { - this._logger.verbose(`XEL file session ${sessionId} stopped notification received`); + this._logger.debug(`XEL file session ${sessionId} stopped notification received`); if (errorMessage) { this._logger.error(`XEL file session stopped with error: ${errorMessage}`); } @@ -1114,7 +1112,7 @@ export class ProfilerController { // since there's no live data to stream webviewController.setSessionState(SessionState.Stopped); - this._logger.verbose( + this._logger.debug( `XEL file ${fileInfo.fileName} loaded successfully in read-only mode`, ); } catch (e) { @@ -1171,7 +1169,7 @@ export class ProfilerController { if (!saveUri) { // User cancelled - this._logger.verbose("Export to CSV cancelled by user"); + this._logger.debug("Export to CSV cancelled by user"); return undefined; } @@ -1201,7 +1199,7 @@ export class ProfilerController { } }); - this._logger.verbose(`Profiler events exported to ${filePath}`); + this._logger.debug(`Profiler events exported to ${filePath}`); }); // Handle stream errors diff --git a/extensions/mssql/src/profiler/profilerSession.ts b/extensions/mssql/src/profiler/profilerSession.ts index e416212b4a..f9b9e27624 100644 --- a/extensions/mssql/src/profiler/profilerSession.ts +++ b/extensions/mssql/src/profiler/profilerSession.ts @@ -8,7 +8,7 @@ import { FilteredBuffer } from "./filteredBuffer"; import { EventRow, SessionType, SessionState, ViewTemplate } from "./profilerTypes"; import { ProfilerService } from "../services/profilerService"; import { ProfilingSessionType } from "../models/contracts/profiler"; -import { Logger } from "../models/logger"; +import { ILogger } from "../models/logger"; import { uuid } from "../utils/utils"; /** @@ -134,8 +134,8 @@ export class ProfilerSession { /** Counter for generating sequential event numbers when service doesn't provide them */ private _eventNumberCounter: number = 0; - /** Logger for diagnostic output */ - private readonly _logger: Logger | undefined; + /** ILogger for diagnostic output */ + private readonly _logger: ILogger | undefined; /** * Creates a new ProfilerSession. * @param options - Session configuration options @@ -145,7 +145,7 @@ export class ProfilerSession { constructor( options: ProfilerSessionOptions, profilerService: ProfilerService, - logger?: Logger, + logger?: ILogger, ) { this._logger = logger; this.id = options.id; diff --git a/extensions/mssql/src/schemaCompare/schemaCompareUtils.ts b/extensions/mssql/src/schemaCompare/schemaCompareUtils.ts index 557b2a5200..3fedecb0f0 100644 --- a/extensions/mssql/src/schemaCompare/schemaCompareUtils.ts +++ b/extensions/mssql/src/schemaCompare/schemaCompareUtils.ts @@ -15,7 +15,7 @@ import { TaskExecutionMode, } from "../sharedInterfaces/schemaCompare"; import * as locConstants from "../constants/locConstants"; -import { Logger } from "../models/logger"; +import { ILogger } from "../models/logger"; /** * A constant string representing the command to publish schema compare changes * for SQL database projects. @@ -174,7 +174,7 @@ export async function compare( * @param operationId - The ID of the schema comparison operation. * @param payload - The payload containing parameters for generating the script. * @param schemaCompareService - The service used to perform schema comparison operations. - * @param logger - Logger instance for diagnostic logging. + * @param logger - ILogger instance for diagnostic logging. * @returns A promise that resolves to the result status of the script generation operation. */ export async function generateScript( @@ -182,7 +182,7 @@ export async function generateScript( taskExecutionMode: TaskExecutionMode, payload: SchemaCompareReducers["generateScript"], schemaCompareService: mssql.ISchemaCompareService, - logger?: Logger, + logger?: ILogger, ): Promise { logger?.info( `[schemaCompareUtils] generateScript called - operationId: ${operationId}, taskExecutionMode: ${taskExecutionMode} - OperationId: ${operationId}`, @@ -190,7 +190,7 @@ export async function generateScript( logger?.info( `[schemaCompareUtils] Payload - hasTargetServerName: ${!!payload?.targetServerName}, hasTargetDatabaseName: ${!!payload?.targetDatabaseName} - OperationId: ${operationId}`, ); - logger?.verbose( + logger?.debug( `[schemaCompareUtils] Calling schemaCompareService.generateScript - OperationId: ${operationId}`, ); @@ -209,7 +209,7 @@ export async function generateScript( logger?.info( `[schemaCompareUtils] Result object type: ${typeof result}, keys: ${Object.keys(result).join(", ")} - OperationId: ${operationId}`, ); - logger?.verbose( + logger?.debug( `[schemaCompareUtils] Full result JSON: ${JSON.stringify(result)} - OperationId: ${operationId}`, ); } else { @@ -293,12 +293,12 @@ export async function includeExcludeNode( taskExecutionMode: TaskExecutionMode, payload: SchemaCompareReducers["includeExcludeNode"], schemaCompareService: mssql.ISchemaCompareService, - logger?: Logger, + logger?: ILogger, ): Promise { logger?.info( `[schemaCompareUtils] includeExcludeNode called - operationId: ${operationId}, includeRequest: ${payload.includeRequest}, diffEntry type: ${payload.diffEntry?.name}`, ); - logger?.verbose( + logger?.debug( `[schemaCompareUtils] Diff entry ID: ${payload.id}, taskExecutionMode: ${taskExecutionMode}`, ); @@ -344,12 +344,12 @@ export async function includeExcludeAllNodes( taskExecutionMode: TaskExecutionMode, payload: SchemaCompareReducers["includeExcludeAllNodes"], schemaCompareService: mssql.ISchemaCompareService, - logger?: Logger, + logger?: ILogger, ): Promise { logger?.info( `[schemaCompareUtils] includeExcludeAllNodes called - operationId: ${operationId}, includeRequest: ${payload.includeRequest}`, ); - logger?.verbose(`[schemaCompareUtils] taskExecutionMode: ${taskExecutionMode}`); + logger?.debug(`[schemaCompareUtils] taskExecutionMode: ${taskExecutionMode}`); const startTime = Date.now(); logger?.info(`[schemaCompareUtils] Calling schemaCompareService.includeExcludeAllNodes`); @@ -398,12 +398,12 @@ export async function includeExcludeAllNodes( export async function openScmp( filePath: string, schemaCompareService: mssql.ISchemaCompareService, - logger?: Logger, + logger?: ILogger, ): Promise { logger?.info( `[schemaCompareUtils] openScmp called with file path length: ${filePath?.length || 0}`, ); - logger?.verbose(`[schemaCompareUtils] Calling schemaCompareService.openScmp`); + logger?.debug(`[schemaCompareUtils] Calling schemaCompareService.openScmp`); const result = await schemaCompareService.openScmp(filePath); diff --git a/extensions/mssql/src/schemaCompare/schemaCompareWebViewController.ts b/extensions/mssql/src/schemaCompare/schemaCompareWebViewController.ts index e7e379423d..860f113c02 100644 --- a/extensions/mssql/src/schemaCompare/schemaCompareWebViewController.ts +++ b/extensions/mssql/src/schemaCompare/schemaCompareWebViewController.ts @@ -204,7 +204,7 @@ export class SchemaCompareWebViewController extends WebviewPanelController< runComparison: boolean, comparisonResult: mssql.SchemaCompareResult = undefined, ): Promise { - this.logger.info( + this.logger.debug( `Starting schema comparison with sourceContext type: ${sourceContext ? typeof sourceContext : "undefined"} - OperationId: ${this.operationId}`, ); @@ -228,7 +228,7 @@ export class SchemaCompareWebViewController extends WebviewPanelController< if (this.isTreeNodeInfoType(context)) { const node = context as TreeNodeInfo; if (node?.connectionProfile) { - this.logger.verbose( + this.logger.debug( `Using connection profile: ${node.connectionProfile.server} - OperationId: ${this.operationId}`, ); return await this.getEndpointInfoFromConnectionProfile( @@ -237,15 +237,15 @@ export class SchemaCompareWebViewController extends WebviewPanelController< ); } } else if (context && typeof context === "string" && context.endsWith(".dacpac")) { - this.logger.verbose(`Using dacpac: ${context} - OperationId: ${this.operationId}`); + this.logger.debug(`Using dacpac: ${context} - OperationId: ${this.operationId}`); return this.getEndpointInfoFromDacpac(context as string); } else if (context && typeof context === "string" && context.endsWith(".sqlproj")) { - this.logger.verbose(`Using project: ${context} - OperationId: ${this.operationId}`); + this.logger.debug(`Using project: ${context} - OperationId: ${this.operationId}`); return await this.getEndpointInfoFromProject(context as string); } else if (context && typeof context === "object") { return context as mssql.SchemaCompareEndpointInfo; } else { - this.logger.verbose(`No context provided - OperationId: ${this.operationId}`); + this.logger.debug(`No context provided - OperationId: ${this.operationId}`); return undefined; } } @@ -263,7 +263,7 @@ export class SchemaCompareWebViewController extends WebviewPanelController< runComparison: boolean = false, comparisonResult: mssql.SchemaCompareResult | undefined, ): Promise { - this.logger.info( + this.logger.debug( `Launching schema comparison with runComparison=${runComparison}, has source=${!!source}, has target=${!!target}, has comparisonResult=${!!comparisonResult} - OperationId: ${this.operationId}`, ); @@ -279,7 +279,7 @@ export class SchemaCompareWebViewController extends WebviewPanelController< // Trigger automatic comparison if requested if (runComparison && source && target) { - this.logger.info( + this.logger.debug( `Auto-starting schema comparison as runComparison=true - OperationId: ${this.operationId}`, ); @@ -363,7 +363,7 @@ export class SchemaCompareWebViewController extends WebviewPanelController< } private async getProjectScriptFiles(projectFilePath: string): Promise { - this.logger.verbose( + this.logger.debug( `Getting project script files for: ${projectFilePath} - OperationId: ${this.operationId}`, ); let scriptFiles: string[] = []; @@ -373,14 +373,14 @@ export class SchemaCompareWebViewController extends WebviewPanelController< SchemaCompareWebViewController.SQL_DATABASE_PROJECTS_EXTENSION_ID, ); if (databaseProjectsExtension) { - this.logger.verbose( + this.logger.debug( `SQL Database Projects extension found, activating... - OperationId: ${this.operationId}`, ); scriptFiles = await ( await databaseProjectsExtension.activate() ).getProjectScriptFiles(projectFilePath); - this.logger.verbose( + this.logger.debug( `Retrieved ${scriptFiles.length} script files from project - OperationId: ${this.operationId}`, ); } else { @@ -409,7 +409,7 @@ export class SchemaCompareWebViewController extends WebviewPanelController< } private async getDatabaseSchemaProvider(projectFilePath: string): Promise { - this.logger.verbose( + this.logger.debug( `Getting database schema provider for project: ${projectFilePath} - OperationId: ${this.operationId}`, ); let provider = ""; @@ -420,13 +420,13 @@ export class SchemaCompareWebViewController extends WebviewPanelController< ); if (databaseProjectsExtension) { - this.logger.verbose( + this.logger.debug( `SQL Database Projects extension found, activating... - OperationId: ${this.operationId}`, ); provider = await ( await databaseProjectsExtension.activate() ).getProjectDatabaseSchemaProvider(projectFilePath); - this.logger.verbose( + this.logger.debug( `Retrieved database schema provider: ${provider || "empty"} - OperationId: ${this.operationId}`, ); } else { @@ -464,7 +464,7 @@ export class SchemaCompareWebViewController extends WebviewPanelController< private registerRpcHandlers(): void { this.registerReducer("isSqlProjectExtensionInstalled", async (state) => { - this.logger.verbose( + this.logger.debug( `Checking if SQL Database Projects extension is installed - OperationId: ${this.operationId}`, ); @@ -483,7 +483,7 @@ export class SchemaCompareWebViewController extends WebviewPanelController< if (extension) { if (!extension.isActive) { - this.logger.verbose( + this.logger.debug( `SQL Database Projects extension found but not activated, activating... - OperationId: ${this.operationId}`, ); await extension.activate(); @@ -498,12 +498,12 @@ export class SchemaCompareWebViewController extends WebviewPanelController< isSqlProjectExtensionInstalled: "true", }); - this.logger.info( + this.logger.debug( `SQL Database Projects extension is installed and activated - OperationId: ${this.operationId}`, ); state.isSqlProjectExtensionInstalled = true; } else { - this.logger.info( + this.logger.debug( `SQL Database Projects extension is not installed - OperationId: ${this.operationId}`, ); @@ -521,11 +521,11 @@ export class SchemaCompareWebViewController extends WebviewPanelController< }); this.registerReducer("listActiveServers", (state) => { - this.logger.verbose(`Listing active SQL servers - OperationId: ${this.operationId}`); + this.logger.debug(`Listing active SQL servers - OperationId: ${this.operationId}`); const activeServers = this.getActiveServersList(); const serverCount = Object.keys(activeServers).length; - this.logger.info( + this.logger.debug( `Found ${serverCount} active SQL server connection(s) - OperationId: ${this.operationId}`, ); sendActionEvent(TelemetryViews.SchemaCompare, TelemetryActions.ListingActiveServers, { @@ -540,7 +540,7 @@ export class SchemaCompareWebViewController extends WebviewPanelController< }); this.registerReducer("listDatabasesForActiveServer", async (state, payload) => { - this.logger.info( + this.logger.debug( `Listing databases for server connection: ${payload.connectionUri} - OperationId: ${this.operationId}`, ); @@ -556,7 +556,7 @@ export class SchemaCompareWebViewController extends WebviewPanelController< let databases: string[] = []; try { databases = await this.connectionMgr.listDatabases(payload.connectionUri); - this.logger.info( + this.logger.debug( `Found ${databases.length} database(s) on server - OperationId: ${this.operationId}`, ); @@ -590,7 +590,7 @@ export class SchemaCompareWebViewController extends WebviewPanelController< }); this.registerReducer("openAddNewConnectionDialog", (state, payload) => { - this.logger.info( + this.logger.debug( `Opening new connection dialog for ${payload.endpointType} endpoint - OperationId: ${this.operationId}`, ); @@ -605,7 +605,7 @@ export class SchemaCompareWebViewController extends WebviewPanelController< state.waitingForNewConnection = true; state.pendingConnectionEndpointType = payload.endpointType; - this.logger.verbose( + this.logger.debug( `Executing command: ${cmdAddObjectExplorer} - OperationId: ${this.operationId}`, ); @@ -615,7 +615,7 @@ export class SchemaCompareWebViewController extends WebviewPanelController< }); this.registerReducer("selectFile", async (state, payload) => { - this.logger.info( + this.logger.debug( `Selecting ${payload.fileType} file for ${payload.endpointType} endpoint - OperationId: ${this.operationId}`, ); @@ -623,7 +623,7 @@ export class SchemaCompareWebViewController extends WebviewPanelController< if (payload.endpoint) { endpointFilePath = payload.endpoint.packageFilePath || payload.endpoint.projectFilePath; - this.logger.verbose( + this.logger.debug( `Using existing file path as starting point: ${endpointFilePath} - OperationId: ${this.operationId}`, ); } @@ -632,13 +632,13 @@ export class SchemaCompareWebViewController extends WebviewPanelController< Files: [payload.fileType], }; - this.logger.verbose( + this.logger.debug( `Opening file dialog with filters: ${JSON.stringify(filters)} - OperationId: ${this.operationId}`, ); const filePath = await showOpenDialogForDacpacOrSqlProj(endpointFilePath, filters); if (filePath) { - this.logger.info(`Selected file: ${filePath} - OperationId: ${this.operationId}`); + this.logger.debug(`Selected file: ${filePath} - OperationId: ${this.operationId}`); const updatedEndpointInfo = payload.fileType === "dacpac" @@ -649,7 +649,7 @@ export class SchemaCompareWebViewController extends WebviewPanelController< if (payload.fileType === "sqlproj") { if (payload.endpointType === "target") { - this.logger.verbose( + this.logger.debug( `Setting extract target to schemaObjectType for target project - OperationId: ${this.operationId}`, ); state.auxiliaryEndpointInfo.extractTarget = ExtractTarget.schemaObjectType; @@ -658,7 +658,7 @@ export class SchemaCompareWebViewController extends WebviewPanelController< this.updateState(state); } else { - this.logger.info( + this.logger.debug( `File selection canceled by user - OperationId: ${this.operationId}`, ); } @@ -667,25 +667,25 @@ export class SchemaCompareWebViewController extends WebviewPanelController< }); this.registerReducer("confirmSelectedSchema", async (state, payload) => { - this.logger.info( + this.logger.debug( `Confirming selected schema for ${payload.endpointType} endpoint - OperationId: ${this.operationId}`, ); if (payload.endpointType === "source") { - this.logger.info( + this.logger.debug( `Setting source endpoint info from auxiliary endpoint info - OperationId: ${this.operationId}`, ); state.sourceEndpointInfo = state.auxiliaryEndpointInfo; } else { if (state.auxiliaryEndpointInfo) { - this.logger.info( + this.logger.debug( `Setting target endpoint info from auxiliary endpoint info - OperationId: ${this.operationId}`, ); state.targetEndpointInfo = state.auxiliaryEndpointInfo; } if (state.targetEndpointInfo?.endpointType === SchemaCompareEndpointType.Project) { - this.logger.info( + this.logger.debug( `Setting target extract target to ${payload.folderStructure} - OperationId: ${this.operationId}`, ); state.targetEndpointInfo.extractTarget = this.mapExtractTargetEnum( @@ -694,7 +694,7 @@ export class SchemaCompareWebViewController extends WebviewPanelController< } } - this.logger.verbose( + this.logger.debug( `Clearing auxiliary endpoint info - OperationId: ${this.operationId}`, ); state.auxiliaryEndpointInfo = undefined; @@ -704,12 +704,12 @@ export class SchemaCompareWebViewController extends WebviewPanelController< }); this.registerReducer("confirmSelectedDatabase", (state, payload) => { - this.logger.info( + this.logger.debug( `Confirming selected database for ${payload.endpointType} endpoint: ${payload.databaseName} - OperationId: ${this.operationId}`, ); const connection = this.connectionMgr.activeConnections[payload.serverConnectionUri]; - this.logger.verbose( + this.logger.debug( `Using connection: ${payload.serverConnectionUri} - OperationId: ${this.operationId}`, ); @@ -718,7 +718,7 @@ export class SchemaCompareWebViewController extends WebviewPanelController< let user = connectionProfile.user; if (!user) { user = locConstants.SchemaCompare.defaultUserName; - this.logger.verbose( + this.logger.debug( `Using default user name: ${user} - OperationId: ${this.operationId}`, ); } @@ -739,10 +739,10 @@ export class SchemaCompareWebViewController extends WebviewPanelController< }; if (payload.endpointType === "source") { - this.logger.info(`Setting as source endpoint - OperationId: ${this.operationId}`); + this.logger.debug(`Setting as source endpoint - OperationId: ${this.operationId}`); state.sourceEndpointInfo = endpointInfo; } else { - this.logger.info(`Setting as target endpoint - OperationId: ${this.operationId}`); + this.logger.debug(`Setting as target endpoint - OperationId: ${this.operationId}`); state.targetEndpointInfo = endpointInfo; } @@ -752,11 +752,11 @@ export class SchemaCompareWebViewController extends WebviewPanelController< }); this.registerReducer("setIntermediarySchemaOptions", async (state) => { - this.logger.verbose( + this.logger.debug( `Setting intermediary schema options - OperationId: ${this.operationId}`, ); state.intermediaryOptionsResult = structuredClone(state.defaultDeploymentOptionsResult); - this.logger.info( + this.logger.debug( `Cloned deployment options for editing - OperationId: ${this.operationId}`, ); @@ -766,7 +766,7 @@ export class SchemaCompareWebViewController extends WebviewPanelController< }); this.registerReducer("intermediaryIncludeObjectTypesOptionsChanged", (state, payload) => { - this.logger.verbose( + this.logger.debug( `Updating object type inclusion option: ${payload.key} - OperationId: ${this.operationId}`, ); @@ -779,12 +779,12 @@ export class SchemaCompareWebViewController extends WebviewPanelController< const isFound = optionIndex !== -1; if (isFound) { - this.logger.info( + this.logger.debug( `Removing object type from exclusion list: ${payload.key} - OperationId: ${this.operationId}`, ); excludeObjectTypeOptions.splice(optionIndex, 1); } else { - this.logger.info( + this.logger.debug( `Adding object type to exclusion list: ${payload.key} - OperationId: ${this.operationId}`, ); excludeObjectTypeOptions.push(payload.key); @@ -796,7 +796,7 @@ export class SchemaCompareWebViewController extends WebviewPanelController< }); this.registerReducer("intermediaryIncludeObjectTypesBulkChanged", (state, payload) => { - this.logger.verbose( + this.logger.debug( `Bulk updating object type inclusion options: ${payload.keys.join(", ")} - OperationId: ${this.operationId}`, ); @@ -822,7 +822,7 @@ export class SchemaCompareWebViewController extends WebviewPanelController< } }); - this.logger.info( + this.logger.debug( `Bulk changed ${payload.keys.length} object types to ${payload.checked ? "included" : "excluded"} - OperationId: ${this.operationId}`, ); @@ -832,14 +832,14 @@ export class SchemaCompareWebViewController extends WebviewPanelController< }); this.registerReducer("confirmSchemaOptions", async (state, payload) => { - this.logger.info( + this.logger.debug( `Confirming schema comparison options - OperationId: ${this.operationId}`, ); state.defaultDeploymentOptionsResult.defaultDeploymentOptions = structuredClone( state.intermediaryOptionsResult.defaultDeploymentOptions, ); - this.logger.verbose( + this.logger.debug( `Applied intermediary options to default deployment options - OperationId: ${this.operationId}`, ); state.intermediaryOptionsResult = undefined; @@ -864,12 +864,12 @@ export class SchemaCompareWebViewController extends WebviewPanelController< }, ); - this.logger.verbose( + this.logger.debug( `Sent telemetry event for options changed - OperationId: ${this.operationId}`, ); if (payload.optionsChanged) { - this.logger.info( + this.logger.debug( `Options were changed, prompting user to run comparison again - OperationId: ${this.operationId}`, ); vscode.window @@ -881,7 +881,7 @@ export class SchemaCompareWebViewController extends WebviewPanelController< ) .then(async (result) => { if (result.title === locConstants.SchemaCompare.Yes) { - this.logger.info( + this.logger.debug( `User chose to run comparison with new options - OperationId: ${this.operationId}`, ); @@ -903,7 +903,7 @@ export class SchemaCompareWebViewController extends WebviewPanelController< message: "Comparison run with new options", }); } else { - this.logger.info( + this.logger.debug( `User chose not to run comparison with new options - OperationId: ${this.operationId}`, ); @@ -914,7 +914,7 @@ export class SchemaCompareWebViewController extends WebviewPanelController< } }); } else { - this.logger.info(`No options were changed - OperationId: ${this.operationId}`); + this.logger.debug(`No options were changed - OperationId: ${this.operationId}`); endActivity.end(ActivityStatus.Succeeded, { operationId: this.operationId, @@ -926,7 +926,7 @@ export class SchemaCompareWebViewController extends WebviewPanelController< }); this.registerReducer("intermediaryGeneralOptionsChanged", (state, payload) => { - this.logger.verbose( + this.logger.debug( `Changing general option: ${payload.key} - OperationId: ${this.operationId}`, ); @@ -935,7 +935,7 @@ export class SchemaCompareWebViewController extends WebviewPanelController< const oldValue = generalOptionsDictionary[payload.key].value; generalOptionsDictionary[payload.key].value = !oldValue; - this.logger.info( + this.logger.debug( `Changed option ${payload.key} from ${oldValue} to ${!oldValue} - OperationId: ${this.operationId}`, ); @@ -944,7 +944,7 @@ export class SchemaCompareWebViewController extends WebviewPanelController< }); this.registerReducer("intermediaryGeneralOptionsBulkChanged", (state, payload) => { - this.logger.verbose( + this.logger.debug( `Bulk changing general options: ${payload.keys.join(", ")} - OperationId: ${this.operationId}`, ); @@ -957,7 +957,7 @@ export class SchemaCompareWebViewController extends WebviewPanelController< } }); - this.logger.info( + this.logger.debug( `Bulk changed ${payload.keys.length} options to ${payload.checked} - OperationId: ${this.operationId}`, ); @@ -966,7 +966,7 @@ export class SchemaCompareWebViewController extends WebviewPanelController< }); this.registerReducer("switchEndpoints", async (state, payload) => { - this.logger.info( + this.logger.debug( `Switching source and target endpoints - OperationId: ${this.operationId}`, ); @@ -997,10 +997,10 @@ export class SchemaCompareWebViewController extends WebviewPanelController< const targetType = payload.newTargetEndpointInfo ? getSchemaCompareEndpointTypeString(payload.newTargetEndpointInfo.endpointType) : "None"; - this.logger.verbose( + this.logger.debug( `New source endpoint type: ${sourceType} - OperationId: ${this.operationId}`, ); - this.logger.verbose( + this.logger.debug( `New target endpoint type: ${targetType} - OperationId: ${this.operationId}`, ); @@ -1010,7 +1010,7 @@ export class SchemaCompareWebViewController extends WebviewPanelController< this.updateState(state); - this.logger.info(`Successfully switched endpoints - OperationId: ${this.operationId}`); + this.logger.debug(`Successfully switched endpoints - OperationId: ${this.operationId}`); endActivity.end(ActivityStatus.Succeeded, { elapsedTime: (Date.now() - startTime).toString(), operationId: this.operationId, @@ -1035,15 +1035,15 @@ export class SchemaCompareWebViewController extends WebviewPanelController< this.logger.info( `Generating script for schema changes with operation ID: ${this.operationId}`, ); - this.logger.info( + this.logger.debug( `Generate script reducer invoked with payload - hasTargetServerName: ${!!payload?.targetServerName}, hasTargetDatabaseName: ${!!payload?.targetDatabaseName} - OperationId: ${this.operationId}`, ); - this.logger.info( + this.logger.debug( `Current state - sourceEndpoint: ${state.sourceEndpointInfo?.endpointType || "undefined"}, targetEndpoint: ${state.targetEndpointInfo?.endpointType || "undefined"}, hasCompareResult: ${!!state.schemaCompareResult} - OperationId: ${this.operationId}`, ); if (state.schemaCompareResult) { - this.logger.info( + this.logger.debug( `Schema compare result has ${state.schemaCompareResult.differences?.length || 0} differences - OperationId: ${this.operationId}`, ); } @@ -1067,8 +1067,8 @@ export class SchemaCompareWebViewController extends WebviewPanelController< }, ); - this.logger.verbose(`Starting script generation - OperationId: ${this.operationId}`); - this.logger.verbose( + this.logger.debug(`Starting script generation - OperationId: ${this.operationId}`); + this.logger.debug( `Calling generateScript with TaskExecutionMode.script - OperationId: ${this.operationId}`, ); @@ -1080,15 +1080,15 @@ export class SchemaCompareWebViewController extends WebviewPanelController< this.logger, ); - this.logger.info( + this.logger.debug( `Generate script service call completed - success: ${result?.success}, hasErrorMessage: ${!!result?.errorMessage} - OperationId: ${this.operationId}`, ); if (result) { - this.logger.info( + this.logger.debug( `Generate script result object keys: ${Object.keys(result).join(", ")} - OperationId: ${this.operationId}`, ); - this.logger.info( + this.logger.debug( `Generate script result details: ${JSON.stringify(result)} - OperationId: ${this.operationId}`, ); } else { @@ -1127,7 +1127,7 @@ export class SchemaCompareWebViewController extends WebviewPanelController< this.logger.info( `Successfully generated script - OperationId: ${this.operationId}`, ); - this.logger.info( + this.logger.debug( `Script generation completed, updating state with result - OperationId: ${this.operationId}`, ); } @@ -1137,12 +1137,12 @@ export class SchemaCompareWebViewController extends WebviewPanelController< operationId: this.operationId, }); - this.logger.verbose( + this.logger.debug( `Setting state.generateScriptResultStatus with result - OperationId: ${this.operationId}`, ); state.generateScriptResultStatus = result; - this.logger.info( + this.logger.debug( `Generate script reducer completed, returning updated state - OperationId: ${this.operationId}`, ); return state; @@ -1150,7 +1150,7 @@ export class SchemaCompareWebViewController extends WebviewPanelController< this.registerReducer("publishChanges", async (state, payload) => { this.logger.info(`Publishing changes requested with operation ID: ${this.operationId}`); - this.logger.verbose( + this.logger.debug( `Target endpoint type: ${getSchemaCompareEndpointTypeString(state.targetEndpointInfo.endpointType)} - OperationId: ${this.operationId}`, ); @@ -1179,7 +1179,7 @@ export class SchemaCompareWebViewController extends WebviewPanelController< ); if (result !== yes) { - this.logger.info( + this.logger.debug( `User canceled publishing changes - OperationId: ${this.operationId}`, ); @@ -1222,7 +1222,7 @@ export class SchemaCompareWebViewController extends WebviewPanelController< }); } - this.logger.info( + this.logger.debug( `Starting publish operation to ${getSchemaCompareEndpointTypeString(state.targetEndpointInfo.endpointType)} - OperationId: ${this.operationId}`, ); @@ -1231,7 +1231,7 @@ export class SchemaCompareWebViewController extends WebviewPanelController< try { switch (state.targetEndpointInfo.endpointType) { case SchemaCompareEndpointType.Database: - this.logger.info( + this.logger.debug( `Publishing changes to database ${state.targetEndpointInfo.databaseName} - OperationId: ${this.operationId}`, ); @@ -1257,7 +1257,7 @@ export class SchemaCompareWebViewController extends WebviewPanelController< break; case SchemaCompareEndpointType.Project: - this.logger.info( + this.logger.debug( `Publishing changes to project ${state.targetEndpointInfo.projectFilePath} - OperationId: ${this.operationId}`, ); endActivity.update({ @@ -1432,7 +1432,7 @@ export class SchemaCompareWebViewController extends WebviewPanelController< this.registerReducer("publishProjectChanges", async (state, payload) => { this.logger.info(`Publishing project changes with operation ID: ${this.operationId}`); - this.logger.verbose( + this.logger.debug( `Target project path: ${payload.targetProjectPath} - OperationId: ${this.operationId}`, ); @@ -1455,7 +1455,7 @@ export class SchemaCompareWebViewController extends WebviewPanelController< ); if (result.success) { - this.logger.info( + this.logger.debug( `Successfully published project changes - OperationId: ${this.operationId}`, ); @@ -1504,7 +1504,7 @@ export class SchemaCompareWebViewController extends WebviewPanelController< }); this.registerReducer("resetOptions", async (state) => { - this.logger.info( + this.logger.debug( `Resetting schema compare options to defaults - OperationId: ${this.operationId}`, ); @@ -1520,7 +1520,7 @@ export class SchemaCompareWebViewController extends WebviewPanelController< ); state.intermediaryOptionsResult = structuredClone(state.defaultDeploymentOptionsResult); - this.logger.info(`Reset options to defaults - OperationId: ${this.operationId}`); + this.logger.debug(`Reset options to defaults - OperationId: ${this.operationId}`); endActivity.end(ActivityStatus.Succeeded, { elapsedTime: (Date.now() - startTime).toString(), @@ -1536,15 +1536,15 @@ export class SchemaCompareWebViewController extends WebviewPanelController< diffEntry.sourceValue ? diffEntry.sourceValue : diffEntry.targetValue, ); - this.logger.info( + this.logger.debug( `${payload.includeRequest ? "Including" : "Excluding"} node: ${diffEntryName} (ID: ${payload.id}) - OperationId: ${this.operationId}`, ); - this.logger.info( + this.logger.debug( `Diff entry type: ${payload.diffEntry.name}, update action: ${this.getSchemaUpdateActionString(payload.diffEntry.updateAction)} - OperationId: ${this.operationId}`, ); if (state.schemaCompareResult) { - this.logger.info( + this.logger.debug( `Total differences in state: ${state.schemaCompareResult.differences?.length || 0} - OperationId: ${this.operationId}`, ); } else { @@ -1569,7 +1569,7 @@ export class SchemaCompareWebViewController extends WebviewPanelController< }, ); - this.logger.verbose( + this.logger.debug( `Calling includeExcludeNode service - OperationId: ${this.operationId}`, ); const result = await includeExcludeNode( @@ -1580,17 +1580,17 @@ export class SchemaCompareWebViewController extends WebviewPanelController< this.logger, ); - this.logger.info( + this.logger.debug( `includeExcludeNode service returned - success: ${result?.success}, elapsed: ${Date.now() - startTime}ms - OperationId: ${this.operationId}`, ); if (result.success) { - this.logger.info( + this.logger.debug( `Successfully ${payload.includeRequest ? "included" : "excluded"} node with ${result.affectedDependencies?.length || 0} affected dependencies - OperationId: ${this.operationId}`, ); if (result.affectedDependencies && result.affectedDependencies.length > 0) { - this.logger.info( + this.logger.debug( `Affected dependencies count: ${result.affectedDependencies.length} - OperationId: ${this.operationId}`, ); } @@ -1606,13 +1606,13 @@ export class SchemaCompareWebViewController extends WebviewPanelController< state.schemaCompareIncludeExcludeResult = result; if (state.schemaCompareResult) { - this.logger.verbose( + this.logger.debug( `Updating node at index ${payload.id} - OperationId: ${this.operationId}`, ); state.schemaCompareResult.differences[payload.id].included = payload.includeRequest; - this.logger.verbose( + this.logger.debug( `Updating ${result.affectedDependencies?.length || 0} affected dependencies in the UI state - OperationId: ${this.operationId}`, ); @@ -1633,7 +1633,7 @@ export class SchemaCompareWebViewController extends WebviewPanelController< foundCount++; if (depIndex < 5) { // Log first 5 dependencies only - this.logger.verbose( + this.logger.debug( `Updated dependency ${depIndex + 1}/${result.affectedDependencies.length} at index ${index} to included=${payload.includeRequest} - OperationId: ${this.operationId}`, ); } @@ -1651,16 +1651,16 @@ export class SchemaCompareWebViewController extends WebviewPanelController< }); const updateElapsed = Date.now() - updateStartTime; - this.logger.info( + this.logger.debug( `Updated ${foundCount} dependencies, ${notFoundCount} not found, took ${updateElapsed}ms - OperationId: ${this.operationId}`, ); } - this.logger.verbose( + this.logger.debug( `Calling updateState to refresh UI - OperationId: ${this.operationId}`, ); this.updateState(state); - this.logger.info( + this.logger.debug( `includeExcludeNode completed successfully - OperationId: ${this.operationId}`, ); } else { @@ -1746,7 +1746,7 @@ export class SchemaCompareWebViewController extends WebviewPanelController< }); this.registerReducer("includeExcludeAllNodes", async (state, payload) => { - this.logger.info( + this.logger.debug( `${payload.includeRequest ? "Including" : "Excluding"} all nodes - OperationId: ${this.operationId}`, ); @@ -1754,7 +1754,7 @@ export class SchemaCompareWebViewController extends WebviewPanelController< const totalDiffs = state.schemaCompareResult.differences?.length || 0; const includedCount = state.schemaCompareResult.differences?.filter((d) => d.included).length || 0; - this.logger.info( + this.logger.debug( `Current state - Total differences: ${totalDiffs}, Currently included: ${includedCount} - OperationId: ${this.operationId}`, ); } else { @@ -1764,7 +1764,7 @@ export class SchemaCompareWebViewController extends WebviewPanelController< } state.isIncludeExcludeAllOperationInProgress = true; - this.logger.verbose( + this.logger.debug( `Set operation in progress flag, updating UI - OperationId: ${this.operationId}`, ); this.updateState(state); @@ -1785,7 +1785,7 @@ export class SchemaCompareWebViewController extends WebviewPanelController< ); try { - this.logger.info( + this.logger.debug( `Calling includeExcludeAllNodes service - OperationId: ${this.operationId}`, ); const result = await includeExcludeAllNodes( @@ -1797,7 +1797,7 @@ export class SchemaCompareWebViewController extends WebviewPanelController< ); const serviceElapsed = Date.now() - startTime; - this.logger.info( + this.logger.debug( `includeExcludeAllNodes service returned after ${serviceElapsed}ms - success: ${result?.success} - OperationId: ${this.operationId}`, ); @@ -1805,7 +1805,7 @@ export class SchemaCompareWebViewController extends WebviewPanelController< if (result.success) { const count = result.allIncludedOrExcludedDifferences?.length || 0; - this.logger.info( + this.logger.debug( `Successfully ${payload.includeRequest ? "included" : "excluded"} all nodes (${count} differences) - OperationId: ${this.operationId}`, ); @@ -1813,12 +1813,12 @@ export class SchemaCompareWebViewController extends WebviewPanelController< const includedAfter = result.allIncludedOrExcludedDifferences.filter( (d) => d.included, ).length; - this.logger.info( + this.logger.debug( `Result includes ${includedAfter} included differences out of ${count} total - OperationId: ${this.operationId}`, ); } - this.logger.verbose( + this.logger.debug( `Replacing state differences with result - OperationId: ${this.operationId}`, ); state.schemaCompareResult.differences = result.allIncludedOrExcludedDifferences; @@ -1836,7 +1836,7 @@ export class SchemaCompareWebViewController extends WebviewPanelController< excludedCount: excludedCount.toString(), }); - this.logger.info( + this.logger.debug( `includeExcludeAllNodes completed successfully - OperationId: ${this.operationId}`, ); } else { @@ -1890,7 +1890,7 @@ export class SchemaCompareWebViewController extends WebviewPanelController< this.state.isIncludeExcludeAllOperationInProgress = false; } - this.logger.verbose( + this.logger.debug( `Updating state after includeExcludeAllNodes operation - OperationId: ${this.operationId}`, ); this.updateState(state); @@ -1898,23 +1898,23 @@ export class SchemaCompareWebViewController extends WebviewPanelController< }); this.registerReducer("openScmp", async (state) => { - this.logger.info( + this.logger.debug( `Opening schema comparison (.scmp) file - OperationId: ${this.operationId}`, ); const selectedFilePath = await showOpenDialogForScmp(); if (!selectedFilePath) { - this.logger.info( + this.logger.debug( `File selection canceled by user - OperationId: ${this.operationId}`, ); return state; } - this.logger.info( + this.logger.debug( `Selected file path length: ${selectedFilePath?.length || 0} characters - OperationId: ${this.operationId}`, ); - this.logger.info( + this.logger.debug( `File extension: ${selectedFilePath?.split(".").pop() || "unknown"} - OperationId: ${this.operationId}`, ); @@ -1929,31 +1929,31 @@ export class SchemaCompareWebViewController extends WebviewPanelController< }, ); - this.logger.verbose( + this.logger.debug( `Calling openScmp service to open schema comparison file - OperationId: ${this.operationId}`, ); const result = await openScmp(selectedFilePath, this.schemaCompareService, this.logger); - this.logger.info( + this.logger.debug( `openScmp service call completed - success: ${result?.success}, hasErrorMessage: ${!!result?.errorMessage} - OperationId: ${this.operationId}`, ); if (result) { - this.logger.info( + this.logger.debug( `Result object keys: ${Object.keys(result).join(", ")} - OperationId: ${this.operationId}`, ); - this.logger.info( + this.logger.debug( `Has sourceEndpointInfo: ${!!result.sourceEndpointInfo}, Has targetEndpointInfo: ${!!result.targetEndpointInfo} - OperationId: ${this.operationId}`, ); if (result.sourceEndpointInfo) { - this.logger.info( + this.logger.debug( `Source endpoint type: ${getSchemaCompareEndpointTypeString(result.sourceEndpointInfo.endpointType)} - OperationId: ${this.operationId}`, ); } if (result.targetEndpointInfo) { - this.logger.info( + this.logger.debug( `Target endpoint type: ${getSchemaCompareEndpointTypeString(result.targetEndpointInfo.endpointType)} - OperationId: ${this.operationId}`, ); } @@ -1985,12 +1985,12 @@ export class SchemaCompareWebViewController extends WebviewPanelController< return state; } - this.logger.info( + this.logger.debug( `Successfully opened schema comparison file, constructing endpoint info - OperationId: ${this.operationId}`, ); // construct source endpoint info - this.logger.verbose( + this.logger.debug( `Constructing source endpoint info - OperationId: ${this.operationId}`, ); state.sourceEndpointInfo = await this.constructEndpointInfo( @@ -1998,12 +1998,12 @@ export class SchemaCompareWebViewController extends WebviewPanelController< "source", ); - this.logger.info( + this.logger.debug( `Source endpoint constructed - type: ${getSchemaCompareEndpointTypeString(state.sourceEndpointInfo?.endpointType)} - OperationId: ${this.operationId}`, ); // construct target endpoint info - this.logger.verbose( + this.logger.debug( `Constructing target endpoint info - OperationId: ${this.operationId}`, ); state.targetEndpointInfo = await this.constructEndpointInfo( @@ -2011,11 +2011,11 @@ export class SchemaCompareWebViewController extends WebviewPanelController< "target", ); - this.logger.info( + this.logger.debug( `Target endpoint constructed - type: ${getSchemaCompareEndpointTypeString(state.targetEndpointInfo?.endpointType)} - OperationId: ${this.operationId}`, ); - this.logger.verbose( + this.logger.debug( `Setting deployment options from loaded file - OperationId: ${this.operationId}`, ); state.defaultDeploymentOptionsResult.defaultDeploymentOptions = @@ -2024,7 +2024,7 @@ export class SchemaCompareWebViewController extends WebviewPanelController< // Update intermediaryOptionsResult to ensure UI reflects loaded options state.intermediaryOptionsResult = structuredClone(state.defaultDeploymentOptionsResult); - this.logger.info( + this.logger.debug( `Loading excluded elements - source: ${result.excludedSourceElements?.length || 0}, target: ${result.excludedTargetElements?.length || 0} - OperationId: ${this.operationId}`, ); state.scmpSourceExcludes = result.excludedSourceElements; @@ -2032,14 +2032,14 @@ export class SchemaCompareWebViewController extends WebviewPanelController< state.sourceTargetSwitched = result.originalTargetName !== state.targetEndpointInfo.databaseName; - this.logger.verbose( + this.logger.debug( `Source/Target switched: ${state.sourceTargetSwitched} - OperationId: ${this.operationId}`, ); // Reset the schema comparison result similarly to what happens in Azure Data Studio. state.schemaCompareResult = undefined; - this.logger.info( + this.logger.debug( `Successfully completed loading .scmp file - OperationId: ${this.operationId}`, ); @@ -2057,7 +2057,7 @@ export class SchemaCompareWebViewController extends WebviewPanelController< state.schemaCompareOpenScmpResult = result; this.updateState(state); - this.logger.info( + this.logger.debug( `openScmp reducer completed, state updated - OperationId: ${this.operationId}`, ); @@ -2072,13 +2072,13 @@ export class SchemaCompareWebViewController extends WebviewPanelController< const saveFilePath = await showSaveDialogForScmp(); if (!saveFilePath) { - this.logger.info( + this.logger.debug( `Save file operation canceled by user - OperationId: ${this.operationId}`, ); return state; } - this.logger.info( + this.logger.debug( `Saving schema comparison to: ${saveFilePath} - OperationId: ${this.operationId}`, ); @@ -2089,7 +2089,7 @@ export class SchemaCompareWebViewController extends WebviewPanelController< state.originalTargetExcludes, ); - this.logger.verbose( + this.logger.debug( `Prepared ${sourceExcludes.length} source excludes and ${targetExcludes.length} target excludes - OperationId: ${this.operationId}`, ); @@ -2110,7 +2110,7 @@ export class SchemaCompareWebViewController extends WebviewPanelController< }, ); - this.logger.verbose(`Calling saveScmp service - OperationId: ${this.operationId}`); + this.logger.debug(`Calling saveScmp service - OperationId: ${this.operationId}`); const result = await saveScmp( state.sourceEndpointInfo, state.targetEndpointInfo, @@ -2206,7 +2206,7 @@ export class SchemaCompareWebViewController extends WebviewPanelController< return state; } - this.logger.info( + this.logger.debug( `Successfully cancelled schema comparison operation - OperationId: ${this.operationId}`, ); endActivity.end(ActivityStatus.Succeeded, { @@ -2280,24 +2280,24 @@ export class SchemaCompareWebViewController extends WebviewPanelController< connectionUri: string, endpointType: "source" | "target", ): Promise { - this.logger.info( + this.logger.debug( `Auto-selecting new connection for ${endpointType} endpoint: ${connectionUri} - OperationId: ${this.operationId}`, ); try { // Get the list of databases for the new connection - this.logger.verbose( + this.logger.debug( `Retrieving databases for connection: ${connectionUri} - OperationId: ${this.operationId}`, ); const databases = await this.connectionMgr.listDatabases(connectionUri); - this.logger.verbose( + this.logger.debug( `Found ${databases.length} databases on server - OperationId: ${this.operationId}`, ); // If there are databases, select the first one if (databases.length > 0) { const databaseName = databases[0]; - this.logger.info( + this.logger.debug( `Auto-selecting database: ${databaseName} - OperationId: ${this.operationId}`, ); @@ -2306,13 +2306,13 @@ export class SchemaCompareWebViewController extends WebviewPanelController< const connectionProfile = connection?.credentials as IConnectionProfile; if (connectionProfile) { - this.logger.verbose( + this.logger.debug( `Creating endpoint info from connection profile: ${connectionProfile.server} - OperationId: ${this.operationId}`, ); let user = connectionProfile.user; if (!user) { user = locConstants.SchemaCompare.defaultUserName; - this.logger.verbose( + this.logger.debug( `Using default user name: ${user} - OperationId: ${this.operationId}`, ); } @@ -2335,12 +2335,12 @@ export class SchemaCompareWebViewController extends WebviewPanelController< }; if (endpointType === "source") { - this.logger.info( + this.logger.debug( `Setting connection as source endpoint - OperationId: ${this.operationId}`, ); this.state.sourceEndpointInfo = endpointInfo; } else { - this.logger.info( + this.logger.debug( `Setting connection as target endpoint - OperationId: ${this.operationId}`, ); this.state.targetEndpointInfo = endpointInfo; @@ -2364,7 +2364,7 @@ export class SchemaCompareWebViewController extends WebviewPanelController< ); } finally { // Reset the waiting state - this.logger.verbose(`Resetting waiting state - OperationId: ${this.operationId}`); + this.logger.debug(`Resetting waiting state - OperationId: ${this.operationId}`); this.state.waitingForNewConnection = false; this.state.pendingConnectionEndpointType = null; } @@ -2399,10 +2399,10 @@ export class SchemaCompareWebViewController extends WebviewPanelController< triggerSource?: string, ) { this.logger.info(`Starting schema comparison with operation ID: ${this.operationId}`); - this.logger.verbose( + this.logger.debug( `Source endpoint type: ${getSchemaCompareEndpointTypeString(payload.sourceEndpointInfo.endpointType)} - OperationId: ${this.operationId}`, ); - this.logger.verbose( + this.logger.debug( `Target endpoint type: ${getSchemaCompareEndpointTypeString(payload.targetEndpointInfo.endpointType)} - OperationId: ${this.operationId}`, ); @@ -2428,7 +2428,7 @@ export class SchemaCompareWebViewController extends WebviewPanelController< ); if (payload.sourceEndpointInfo.endpointType === SchemaCompareEndpointType.Project) { - this.logger.logDebug( + this.logger.debug( `Getting project script files for source: ${payload.sourceEndpointInfo.projectFilePath} - OperationId: ${this.operationId}`, ); payload.sourceEndpointInfo.targetScripts = await this.getProjectScriptFiles( @@ -2436,7 +2436,7 @@ export class SchemaCompareWebViewController extends WebviewPanelController< ); } if (payload.targetEndpointInfo.endpointType === SchemaCompareEndpointType.Project) { - this.logger.logDebug( + this.logger.debug( `Getting project script files for target: ${payload.targetEndpointInfo.projectFilePath} - OperationId: ${this.operationId}`, ); payload.targetEndpointInfo.targetScripts = await this.getProjectScriptFiles( @@ -2542,7 +2542,7 @@ export class SchemaCompareWebViewController extends WebviewPanelController< }); const finalDifferences = this.getAllObjectTypeDifferences(result); - this.logger.verbose( + this.logger.debug( `Filtered to ${finalDifferences.length} object type differences - OperationId: ${this.operationId}`, ); result.differences = finalDifferences; @@ -2557,7 +2557,7 @@ export class SchemaCompareWebViewController extends WebviewPanelController< endpoint: mssql.SchemaCompareEndpointInfo, caller: string, ): Promise { - this.logger.info( + this.logger.debug( `constructEndpointInfo called for ${caller} endpoint - OperationId: ${this.operationId}`, ); @@ -2566,7 +2566,7 @@ export class SchemaCompareWebViewController extends WebviewPanelController< `Endpoint is null or undefined for ${caller} - OperationId: ${this.operationId}`, ); } else { - this.logger.info( + this.logger.debug( `Endpoint type: ${getSchemaCompareEndpointTypeString(endpoint.endpointType)} (${endpoint.endpointType}) - OperationId: ${this.operationId}`, ); } @@ -2574,25 +2574,25 @@ export class SchemaCompareWebViewController extends WebviewPanelController< let ownerUri; let endpointInfo; if (endpoint && endpoint.endpointType === SchemaCompareEndpointType.Database) { - this.logger.info( + this.logger.debug( `Processing Database endpoint for ${caller} - OperationId: ${this.operationId}`, ); const connInfo = endpoint.connectionDetails.options as mssql.IConnectionInfo; - this.logger.verbose( + this.logger.debug( `Has connectionDetails: ${!!endpoint.connectionDetails}, Has options: ${!!endpoint.connectionDetails?.options} - OperationId: ${this.operationId}`, ); ownerUri = this.connectionMgr.getUriForScmpConnection(connInfo); - this.logger.verbose( + this.logger.debug( `Got owner URI from existing connection: ${!!ownerUri} - OperationId: ${this.operationId}`, ); let isConnected = ownerUri ? true : false; if (!ownerUri) { - this.logger.info( + this.logger.debug( `No existing connection found, creating new connection for ${caller} - OperationId: ${this.operationId}`, ); ownerUri = utils.generateQueryUri().toString(); @@ -2633,7 +2633,7 @@ export class SchemaCompareWebViewController extends WebviewPanelController< ); } - this.logger.info( + this.logger.debug( `Connection attempt result for ${caller}: ${isConnected} - OperationId: ${this.operationId}`, ); @@ -2645,7 +2645,7 @@ export class SchemaCompareWebViewController extends WebviewPanelController< delete this.connectionMgr.activeConnections[ownerUri]; } } else { - this.logger.info( + this.logger.debug( `Using existing connection for ${caller} - OperationId: ${this.operationId}`, ); } @@ -2653,12 +2653,12 @@ export class SchemaCompareWebViewController extends WebviewPanelController< const connection = this.connectionMgr.activeConnections[ownerUri]; const connectionProfile = connection?.credentials as IConnectionProfile; - this.logger.verbose( + this.logger.debug( `Has connection: ${!!connection}, Has connectionProfile: ${!!connectionProfile} - OperationId: ${this.operationId}`, ); if (isConnected && ownerUri && connectionProfile) { - this.logger.info( + this.logger.debug( `Successfully created Database endpoint info for ${caller} - OperationId: ${this.operationId}`, ); endpointInfo = { @@ -2697,10 +2697,10 @@ export class SchemaCompareWebViewController extends WebviewPanelController< }; } } else if (endpoint.endpointType === SchemaCompareEndpointType.Project) { - this.logger.info( + this.logger.debug( `Processing Project endpoint for ${caller} - OperationId: ${this.operationId}`, ); - this.logger.verbose( + this.logger.debug( `Project file path length: ${endpoint.projectFilePath?.length || 0} - OperationId: ${this.operationId}`, ); endpointInfo = { @@ -2716,14 +2716,14 @@ export class SchemaCompareWebViewController extends WebviewPanelController< dataSchemaProvider: endpoint.dataSchemaProvider, extractTarget: endpoint.extractTarget, }; - this.logger.info( + this.logger.debug( `Successfully created Project endpoint info for ${caller} - OperationId: ${this.operationId}`, ); } else { - this.logger.info( + this.logger.debug( `Processing Dacpac/other endpoint type for ${caller} - detected type: ${getSchemaCompareEndpointTypeString(endpoint.endpointType)} - OperationId: ${this.operationId}`, ); - this.logger.verbose( + this.logger.debug( `Package file path length: ${endpoint.packageFilePath?.length || 0} - OperationId: ${this.operationId}`, ); endpointInfo = { @@ -2738,19 +2738,19 @@ export class SchemaCompareWebViewController extends WebviewPanelController< packageFilePath: endpoint.packageFilePath, connectionDetails: undefined, }; - this.logger.info( + this.logger.debug( `Successfully created Dacpac endpoint info for ${caller} - OperationId: ${this.operationId}`, ); } - this.logger.info( + this.logger.debug( `constructEndpointInfo completed for ${caller} - final type: ${getSchemaCompareEndpointTypeString(endpointInfo.endpointType)} - OperationId: ${this.operationId}`, ); return endpointInfo; } private getAllObjectTypeDifferences(result: mssql.SchemaCompareResult): DiffEntry[] { - this.logger.verbose( + this.logger.debug( `Filtering differences from schema comparison result - OperationId: ${this.operationId}`, ); @@ -2764,7 +2764,7 @@ export class SchemaCompareWebViewController extends WebviewPanelController< return finalDifferences; } - this.logger.verbose( + this.logger.debug( `Processing ${differences.length} total differences - OperationId: ${this.operationId}`, ); @@ -2775,14 +2775,14 @@ export class SchemaCompareWebViewController extends WebviewPanelController< (difference.targetValue !== null && difference.targetValue.length > 0) ) { finalDifferences.push(difference); - this.logger.logDebug( + this.logger.debug( `Including difference: ${difference.name} with update action ${difference.updateAction} - OperationId: ${this.operationId}`, ); } } }); - this.logger.info( + this.logger.debug( `Found ${finalDifferences.length} object type differences out of ${differences.length} total differences - OperationId: ${this.operationId}`, ); return finalDifferences; diff --git a/extensions/mssql/src/schemaDesigner/schemaDesignerWebviewController.ts b/extensions/mssql/src/schemaDesigner/schemaDesignerWebviewController.ts index 1ec5c2613e..a9dcb8d3e7 100644 --- a/extensions/mssql/src/schemaDesigner/schemaDesignerWebviewController.ts +++ b/extensions/mssql/src/schemaDesigner/schemaDesignerWebviewController.ts @@ -27,10 +27,6 @@ import { getSchemaDesignerDefinitionOutput, SchemaDesignerDefinitionOutput, } from "../sharedInterfaces/schemaDesignerDefinitionOutput"; -import logger2 from "../models/logger2"; - -const logger = logger2.withPrefix("SchemaDesignerWebviewController"); - function isExpandCollapseButtonsEnabled(): boolean { return vscode.workspace .getConfiguration() @@ -693,7 +689,7 @@ export class SchemaDesignerWebviewController extends WebviewPanelController< return; } - logger.info("Progress", progress); + this.logger.info("Progress", progress); try { void this.sendNotification( @@ -710,7 +706,7 @@ export class SchemaDesignerWebviewController extends WebviewPanelController< return; } - logger.info("Message", message); + this.logger.info("Message", message); try { void this.sendNotification( diff --git a/extensions/mssql/src/scripting/scriptingService.ts b/extensions/mssql/src/scripting/scriptingService.ts index 5f2a3d3a68..99eec2e96b 100644 --- a/extensions/mssql/src/scripting/scriptingService.ts +++ b/extensions/mssql/src/scripting/scriptingService.ts @@ -28,7 +28,7 @@ import { Deferred } from "../protocol"; import { SqlOutputContentProvider } from "../models/sqlOutputContentProvider"; import { IConnectionProfile } from "../models/interfaces"; import StatusView from "../views/statusView"; -import { Logger } from "../models/logger"; +import { ILogger, logger } from "../models/logger"; import VscodeWrapper from "../controllers/vscodeWrapper"; import { UserSurvey } from "../nps/userSurvey"; @@ -44,11 +44,11 @@ export class ScriptingService { errorDetails: string; }> > = new Map(); - private _logger: Logger; + private _logger: ILogger; constructor( private _context: vscode.ExtensionContext, - private _vscodeWrapper: VscodeWrapper, + _vscodeWrapper: VscodeWrapper, private _connectionManager: ConnectionManager, private _sqlDocumentService: SqlDocumentService, private _sqlOutputContentProvider: SqlOutputContentProvider, @@ -56,7 +56,7 @@ export class ScriptingService { private _objectExplorerTree: vscode.TreeView, ) { this._client = this._connectionManager.client; - this._logger = Logger.create(this._vscodeWrapper.outputChannel, "ObjectExplorerService"); + this._logger = logger.withPrefix("ScriptingService"); this.initialize(); } diff --git a/extensions/mssql/src/searchDatabase/searchDatabaseWebViewController.ts b/extensions/mssql/src/searchDatabase/searchDatabaseWebViewController.ts index 0b98f1ca17..afc2af477f 100644 --- a/extensions/mssql/src/searchDatabase/searchDatabaseWebViewController.ts +++ b/extensions/mssql/src/searchDatabase/searchDatabaseWebViewController.ts @@ -171,7 +171,7 @@ export class SearchDatabaseWebViewController extends WebviewPanelController< } private logVerbose(message: string): void { - this.logger.verbose(`[${this._operationId}] ${message}`); + this.logger.debug(`[${this._operationId}] ${message}`); } /** diff --git a/extensions/mssql/src/services/dabService.ts b/extensions/mssql/src/services/dabService.ts index 729db9cfe8..977cae8552 100644 --- a/extensions/mssql/src/services/dabService.ts +++ b/extensions/mssql/src/services/dabService.ts @@ -293,7 +293,7 @@ export class DabService implements Dab.IDabService { encoding: "utf8", mode: 0o600, }); - dockerLogger.appendLine(`DAB config written to: ${configFilePath}`); + dockerLogger.info(`DAB config written to: ${configFilePath}`); return configFilePath; } @@ -314,9 +314,9 @@ export class DabService implements Dab.IDabService { await fs.promises.rmdir(configDir); } - dockerLogger.appendLine(`Cleaned up DAB config: ${configFilePath}`); + dockerLogger.info(`Cleaned up DAB config: ${configFilePath}`); } catch (e) { - dockerLogger.appendLine(`Failed to cleanup DAB config file: ${getErrorMessage(e)}`); + dockerLogger.warn(`Failed to cleanup DAB config file: ${getErrorMessage(e)}`); } } @@ -378,7 +378,7 @@ export class DabService implements Dab.IDabService { `${serverPropertyPrefix}${newServerValue}`, ); - dockerLogger.appendLine( + dockerLogger.info( `Transformed connection string server for DAB: ${serverValue} -> ${newServerValue}`, ); diff --git a/extensions/mssql/src/services/fileBrowserService.ts b/extensions/mssql/src/services/fileBrowserService.ts index 00f1430ed1..6ecd67f317 100644 --- a/extensions/mssql/src/services/fileBrowserService.ts +++ b/extensions/mssql/src/services/fileBrowserService.ts @@ -12,13 +12,13 @@ import { FileBrowserOpenNotification, FileBrowserOpenRequest, } from "../models/contracts/fileBrowser"; -import { Logger } from "../models/logger"; +import { ILogger, logger } from "../models/logger"; import { Deferred } from "../protocol"; import * as fb from "../sharedInterfaces/fileBrowser"; export class FileBrowserService { private _client: SqlToolsServiceClient; - private _logger: Logger; + private _logger: ILogger; fileBrowserState: fb.FileBrowserState; /** @@ -34,12 +34,9 @@ export class FileBrowserService { private _pendingFileBrowserExpands: Map> = new Map>(); - constructor( - private _vscodeWrapper: VscodeWrapper, - _client: SqlToolsServiceClient, - ) { + constructor(_vscodeWrapper: VscodeWrapper, _client: SqlToolsServiceClient) { this._client = _client; - this._logger = Logger.create(this._vscodeWrapper.outputChannel, "FileBrowserService"); + this._logger = logger.withPrefix("FileBrowserService"); this._client.onNotification(FileBrowserOpenNotification.type, (e) => this.handleFileBrowserOpenNotification(e), @@ -111,7 +108,7 @@ export class FileBrowserService { if (openFileBrowserResponse) { const fileBrowserResult = await fileBrowserOpenedResponse; if (fileBrowserResult.succeeded) { - this._logger.verbose( + this._logger.debug( `File browser opened successfully with owner uri ${fileBrowserResult.ownerUri}`, ); this._pendingFileBrowserOpens.delete(fileBrowserResult.ownerUri); @@ -167,7 +164,7 @@ export class FileBrowserService { if (expandFileBrowserResponse) { const fileBrowserResult = await fileBrowserExpandedResponse; if (fileBrowserResult.succeeded) { - this._logger.verbose( + this._logger.debug( `File browser expanded successfully with owner uri ${fileBrowserResult.ownerUri}`, ); this._pendingFileBrowserExpands.delete(fileBrowserResult.ownerUri); diff --git a/extensions/mssql/src/tableDesigner/tableDesignerWebviewController.ts b/extensions/mssql/src/tableDesigner/tableDesignerWebviewController.ts index db77e9ddd6..27137b8083 100644 --- a/extensions/mssql/src/tableDesigner/tableDesignerWebviewController.ts +++ b/extensions/mssql/src/tableDesigner/tableDesignerWebviewController.ts @@ -20,10 +20,8 @@ import { UserSurvey } from "../nps/userSurvey"; import { ObjectExplorerProvider } from "../objectExplorer/objectExplorerProvider"; import { getErrorMessage } from "../utils/utils"; import VscodeWrapper from "../controllers/vscodeWrapper"; -import logger2 from "../models/logger2"; const TABLE_DESIGNER_VIEW_ID = "tableDesigner"; -const logger = logger2.withPrefix("TableDesignerWebviewController"); export class TableDesignerWebviewController extends WebviewPanelController< designer.TableDesignerWebviewState, @@ -640,7 +638,7 @@ export class TableDesignerWebviewController extends WebviewPanelController< return; } - logger.info("Progress", progress); + this.logger.info("Progress", progress); this.appendOperationProgress(progress.operation, progress.message, progress.status); try { @@ -658,7 +656,7 @@ export class TableDesignerWebviewController extends WebviewPanelController< return; } - logger.info("Message", message); + this.logger.info("Message", message); this.appendOperationProgress(message.operation, message.message, message.messageType); try { diff --git a/extensions/mssql/src/tableExplorer/tableExplorerWebViewController.ts b/extensions/mssql/src/tableExplorer/tableExplorerWebViewController.ts index 4c153b33ca..e1bbfa3fd4 100644 --- a/extensions/mssql/src/tableExplorer/tableExplorerWebViewController.ts +++ b/extensions/mssql/src/tableExplorer/tableExplorerWebViewController.ts @@ -216,7 +216,7 @@ export class TableExplorerWebViewController extends WebviewPanelController< undefined, ); - this.logger.info( + this.logger.debug( `Table explorer initialized successfully - OperationId: ${this.operationId}`, ); endActivity.end(ActivityStatus.Succeeded, { @@ -317,7 +317,7 @@ export class TableExplorerWebViewController extends WebviewPanelController< const combinedScript = scriptResult.scripts?.join(os.EOL) || ""; state.updateScript = combinedScript; this.updateState(); - this.logger.info("Script regenerated successfully in real-time"); + this.logger.debug("Script regenerated successfully in real-time"); } catch (error) { this.logger.error(`Error regenerating script: ${error}`); } @@ -407,7 +407,7 @@ export class TableExplorerWebViewController extends WebviewPanelController< objectType, undefined, ); - this.logger.info("Restored original session after custom query failure"); + this.logger.debug("Restored original session after custom query failure"); return true; } catch (restoreError) { this.logger.error( @@ -449,7 +449,7 @@ export class TableExplorerWebViewController extends WebviewPanelController< state.originalCellValues?.clear(); // Clear cached original values since they're now outdated this.showRestorePromptAfterClose = false; - this.logger.info( + this.logger.debug( `Cleared new rows, deleted rows, failed cells, and original cell values cache after successful commit - OperationId: ${this.operationId}`, ); @@ -482,7 +482,7 @@ export class TableExplorerWebViewController extends WebviewPanelController< }); this.registerReducer("loadSubset", async (state, payload) => { - this.logger.info( + this.logger.debug( `Loading subset with rowCount: ${payload.rowCount} - OperationId: ${this.operationId}`, ); @@ -521,7 +521,7 @@ export class TableExplorerWebViewController extends WebviewPanelController< rowCount: backendRowsOnly.length + state.newRows.length, }; - this.logger.info( + this.logger.debug( `Loaded ${backendRowsOnly.length} committed rows from database, appended ${state.newRows.length} new uncommitted rows - OperationId: ${this.operationId}`, ); @@ -587,7 +587,7 @@ export class TableExplorerWebViewController extends WebviewPanelController< vscode.window.showInformationMessage( LocConstants.TableExplorer.rowCreatedSuccessfully, ); - this.logger.info( + this.logger.debug( `Created row with ID: ${result.newRowId} - OperationId: ${this.operationId}`, ); @@ -604,7 +604,7 @@ export class TableExplorerWebViewController extends WebviewPanelController< rowCount: state.resultSet.rowCount + 1, }; - this.logger.info( + this.logger.debug( `Added new row to result set, now has ${state.resultSet.rowCount} rows (${state.newRows.length} new)`, ); @@ -644,7 +644,7 @@ export class TableExplorerWebViewController extends WebviewPanelController< }); this.registerReducer("deleteRow", async (state, payload) => { - this.logger.info(`Deleting row: ${payload.rowId} - OperationId: ${this.operationId}`); + this.logger.debug(`Deleting row: ${payload.rowId} - OperationId: ${this.operationId}`); const startTime = Date.now(); const endActivity = startActivity( @@ -681,7 +681,7 @@ export class TableExplorerWebViewController extends WebviewPanelController< } }); keysToDelete.forEach((key) => state.originalCellValues?.delete(key)); - this.logger.info( + this.logger.debug( `Cleared ${keysToDelete.length} cached values for deleted row ${payload.rowId}`, ); } @@ -705,7 +705,7 @@ export class TableExplorerWebViewController extends WebviewPanelController< LocConstants.TableExplorer.rowDeletedSuccessfully, ); - this.logger.info( + this.logger.debug( `Removed newly created row ${payload.rowId} from UI (${state.newRows.length} new rows remaining)`, ); @@ -725,7 +725,7 @@ export class TableExplorerWebViewController extends WebviewPanelController< this.showRestorePromptAfterClose = true; - this.logger.info( + this.logger.debug( `Marked row ${payload.rowId} for deletion (${state.deletedRows.length} total deleted)`, ); } @@ -764,7 +764,7 @@ export class TableExplorerWebViewController extends WebviewPanelController< }); this.registerReducer("updateCell", async (state, payload) => { - this.logger.info( + this.logger.debug( `Updating cell: row ${payload.rowId}, column ${payload.columnId} - OperationId: ${this.operationId}`, ); @@ -797,9 +797,7 @@ export class TableExplorerWebViewController extends WebviewPanelController< isNull: originalCell.isNull, invariantCultureDisplayValue: originalCell.invariantCultureDisplayValue, }); - this.logger.verbose( - `Cached original value for cell ${cacheKey}: ${originalCell.displayValue}`, - ); + this.logger.trace(`Cached original value for cell ${cacheKey}`); } } @@ -835,13 +833,13 @@ export class TableExplorerWebViewController extends WebviewPanelController< this.updateState(); - this.logger.info( + this.logger.debug( `Updated cell in result set at row ${rowIndex}, column ${payload.columnId}`, ); } } - this.logger.info(`Cell updated successfully - OperationId: ${this.operationId}`); + this.logger.debug(`Cell updated successfully - OperationId: ${this.operationId}`); await this.regenerateScriptIfVisible(state); @@ -880,7 +878,7 @@ export class TableExplorerWebViewController extends WebviewPanelController< state.resultSet.subset[rowIndex].cells[payload.columnId] = failedCell; - this.logger.info( + this.logger.debug( `Updated cell in result set to show failed edit at row ${rowIndex}, column ${payload.columnId}`, ); } @@ -908,7 +906,7 @@ export class TableExplorerWebViewController extends WebviewPanelController< }); this.registerReducer("revertCell", async (state, payload) => { - this.logger.info( + this.logger.debug( `Reverting cell: row ${payload.rowId}, column ${payload.columnId} - OperationId: ${this.operationId}`, ); @@ -927,7 +925,7 @@ export class TableExplorerWebViewController extends WebviewPanelController< try { // Always call the service to revert to ensure backend state is properly cleaned up - this.logger.info(`Calling service to revert cell ${cacheKey}`); + this.logger.trace(`Calling service to revert cell ${cacheKey}`); const revertCellResult = await this._tableExplorerService.revertCell( state.ownerUri, payload.rowId, @@ -950,15 +948,13 @@ export class TableExplorerWebViewController extends WebviewPanelController< }; if (cachedOriginalValue) { - this.logger.info( - `Using cached original value for display: ${cachedOriginalValue.displayValue}`, - ); + this.logger.trace(`Using cached original value for cell ${cacheKey}`); } // Remove from cache after successful revert if (state.originalCellValues?.has(cacheKey)) { state.originalCellValues.delete(cacheKey); - this.logger.info( + this.logger.trace( `Removed cached value for cell ${cacheKey} after successful revert`, ); } @@ -997,14 +993,14 @@ export class TableExplorerWebViewController extends WebviewPanelController< subset: newSubset, }; - this.logger.info( + this.logger.debug( `Reverted cell in result set at row ${rowIndex}, column ${payload.columnId}`, ); this.updateState(); } } - this.logger.info(`Cell reverted successfully - OperationId: ${this.operationId}`); + this.logger.debug(`Cell reverted successfully - OperationId: ${this.operationId}`); await this.regenerateScriptIfVisible(state); @@ -1037,7 +1033,7 @@ export class TableExplorerWebViewController extends WebviewPanelController< }); this.registerReducer("revertRow", async (state, payload) => { - this.logger.info(`Reverting row: ${payload.rowId} - OperationId: ${this.operationId}`); + this.logger.debug(`Reverting row: ${payload.rowId} - OperationId: ${this.operationId}`); const startTime = Date.now(); const endActivity = startActivity( @@ -1075,7 +1071,7 @@ export class TableExplorerWebViewController extends WebviewPanelController< } }); keysToDelete.forEach((key) => state.originalCellValues?.delete(key)); - this.logger.info( + this.logger.debug( `Cleared ${keysToDelete.length} cached values for row ${payload.rowId}`, ); } @@ -1104,7 +1100,7 @@ export class TableExplorerWebViewController extends WebviewPanelController< this.updateState(); - this.logger.info( + this.logger.debug( `Reverted row at index ${rowIndex} with ${revertRowResult.row.cells.length} cells`, ); } @@ -1125,7 +1121,7 @@ export class TableExplorerWebViewController extends WebviewPanelController< this.updateState(); - this.logger.info( + this.logger.debug( `Removed newly created row ${payload.rowId} from UI after revert`, ); @@ -1135,7 +1131,7 @@ export class TableExplorerWebViewController extends WebviewPanelController< } } - this.logger.info(`Row reverted successfully - OperationId: ${this.operationId}`); + this.logger.debug(`Row reverted successfully - OperationId: ${this.operationId}`); await this.regenerateScriptIfVisible(state); @@ -1190,7 +1186,7 @@ export class TableExplorerWebViewController extends WebviewPanelController< // Combine script array into single string const combinedScript = scriptResult.scripts?.join(os.EOL) || ""; - this.logger.info( + this.logger.debug( `Script result received: ${scriptResult.scripts?.length} script(s), combined length: ${combinedScript.length} - OperationId: ${this.operationId}`, ); @@ -1199,11 +1195,11 @@ export class TableExplorerWebViewController extends WebviewPanelController< state.showScriptPane = true; state.sqlPaneMode = SqlPaneMode.ScriptChanges; - this.logger.info( + this.logger.trace( `State before updateState - updateScript length: ${state.updateScript?.length}, showScriptPane: ${state.showScriptPane}`, ); this.updateState(); - this.logger.info( + this.logger.trace( `State after updateState - this.state.updateScript length: ${this.state.updateScript?.length} - OperationId: ${this.operationId}`, ); @@ -1310,7 +1306,7 @@ export class TableExplorerWebViewController extends WebviewPanelController< this.registerReducer("toggleScriptPane", async (state) => { state.showScriptPane = !state.showScriptPane; - this.logger.info( + this.logger.debug( `Script pane toggled to: ${state.showScriptPane} - OperationId: ${this.operationId}`, ); @@ -1327,7 +1323,7 @@ export class TableExplorerWebViewController extends WebviewPanelController< this.registerReducer("setCurrentPage", async (state, payload) => { state.currentPage = payload.pageNumber; - this.logger.info(`Current page set to: ${payload.pageNumber}`); + this.logger.trace(`Current page set to: ${payload.pageNumber}`); return state; }); @@ -1405,7 +1401,7 @@ export class TableExplorerWebViewController extends WebviewPanelController< throw new Error(result.messages || "Serialization failed"); } } else { - this.logger.info("Save dialog cancelled by user"); + this.logger.debug("Save dialog cancelled by user"); } } catch (error) { this.logger.error( @@ -1432,7 +1428,7 @@ export class TableExplorerWebViewController extends WebviewPanelController< }); this.registerReducer("showTableQuery", async (state) => { - this.logger.info(`Showing table query pane - OperationId: ${this.operationId}`); + this.logger.debug(`Showing table query pane - OperationId: ${this.operationId}`); sendActionEvent(TelemetryViews.TableExplorer, TelemetryActions.ShowTableQuery, { operationId: this.operationId, @@ -1469,7 +1465,7 @@ export class TableExplorerWebViewController extends WebviewPanelController< // Validate input before tearing down the session if (!payload.queryString || !payload.queryString.trim()) { - this.logger.info("Empty query string provided, skipping custom query"); + this.logger.debug("Empty query string provided, skipping custom query"); endActivity.end(ActivityStatus.Succeeded, { elapsedTime: (Date.now() - startTime).toString(), operationId: this.operationId, @@ -1498,7 +1494,7 @@ export class TableExplorerWebViewController extends WebviewPanelController< } if (this.hasPendingChanges(state) && !(await this.promptDiscardPendingChanges())) { - this.logger.info("User cancelled custom query due to pending changes"); + this.logger.debug("User cancelled custom query due to pending changes"); endActivity.end(ActivityStatus.Succeeded, { elapsedTime: (Date.now() - startTime).toString(), operationId: this.operationId, @@ -1538,7 +1534,7 @@ export class TableExplorerWebViewController extends WebviewPanelController< state.currentRowCount = payload.rowCount; } - this.logger.info( + this.logger.debug( `Custom query session re-initialized successfully - OperationId: ${this.operationId}`, ); diff --git a/extensions/mssql/test/unit/azureHelpers.test.ts b/extensions/mssql/test/unit/azureHelpers.test.ts index 844f9ef94f..5357f7b757 100644 --- a/extensions/mssql/test/unit/azureHelpers.test.ts +++ b/extensions/mssql/test/unit/azureHelpers.test.ts @@ -9,7 +9,7 @@ import sinonChai from "sinon-chai"; import { AzureAccountService } from "../../src/services/azureAccountService"; import * as sinon from "sinon"; import * as azureHelpers from "../../src/connectionconfig/azureHelpers"; -import { Logger } from "../../src/models/logger"; +import { ILogger } from "../../src/models/logger"; import { IAccount } from "vscode-mssql"; import * as vscode from "vscode"; import * as armStorage from "@azure/arm-storage"; @@ -31,7 +31,7 @@ chai.use(sinonChai); suite("Azure Helpers", () => { let sandbox: sinon.SinonSandbox; let mockAzureAccountService: AzureAccountService; - let mockLogger: sinon.SinonStubbedInstance; + let mockLogger: sinon.SinonStubbedInstance; setup(() => { sandbox = sinon.createSandbox(); diff --git a/extensions/mssql/test/unit/connectionManager.test.ts b/extensions/mssql/test/unit/connectionManager.test.ts index eb191bc989..01561c9676 100644 --- a/extensions/mssql/test/unit/connectionManager.test.ts +++ b/extensions/mssql/test/unit/connectionManager.test.ts @@ -10,7 +10,7 @@ import * as chai from "chai"; import { expect } from "chai"; import { ConnectionDetails, IToken, IConnectionInfo } from "vscode-mssql"; import { ConnectionStore } from "../../src/models/connectionStore"; -import { Logger } from "../../src/models/logger"; +import { ILogger } from "../../src/models/logger"; import VscodeWrapper from "../../src/controllers/vscodeWrapper"; import ConnectionManager from "../../src/controllers/connectionManager"; import SqlToolsServerClient from "../../src/languageservice/serviceclient"; @@ -49,7 +49,7 @@ suite("ConnectionManager Tests", () => { let connectionManager: ConnectionManager; let mockContext: vscode.ExtensionContext; - let mockLogger: sinon.SinonStubbedInstance; + let mockLogger: sinon.SinonStubbedInstance; let mockCredentialStore: sinon.SinonStubbedInstance; let mockVscodeWrapper: sinon.SinonStubbedInstance; let mockConnectionStore: sinon.SinonStubbedInstance; diff --git a/extensions/mssql/test/unit/connectionStore.test.ts b/extensions/mssql/test/unit/connectionStore.test.ts index a35c1dfc11..9142ba072d 100644 --- a/extensions/mssql/test/unit/connectionStore.test.ts +++ b/extensions/mssql/test/unit/connectionStore.test.ts @@ -9,7 +9,7 @@ import * as vscode from "vscode"; import * as Constants from "../../src/constants/constants"; import { ConnectionStore } from "../../src/models/connectionStore"; import { CredentialStore } from "../../src/credentialstore/credentialstore"; -import { Logger } from "../../src/models/logger"; +import { ILogger } from "../../src/models/logger"; import { ConnectionConfig } from "../../src/connectionconfig/connectionconfig"; import VscodeWrapper from "../../src/controllers/vscodeWrapper"; import { @@ -27,7 +27,7 @@ suite("ConnectionStore Tests", () => { let connectionStore: ConnectionStore; let mockContext: vscode.ExtensionContext; - let mockLogger: sinon.SinonStubbedInstance; + let mockLogger: sinon.SinonStubbedInstance; let mockCredentialStore: sinon.SinonStubbedInstance; let mockConnectionConfig: sinon.SinonStubbedInstance; let mockVscodeWrapper: sinon.SinonStubbedInstance; diff --git a/extensions/mssql/test/unit/dotnetRuntimeProvider.test.ts b/extensions/mssql/test/unit/dotnetRuntimeProvider.test.ts index 46e4e78ba8..e077bd4748 100644 --- a/extensions/mssql/test/unit/dotnetRuntimeProvider.test.ts +++ b/extensions/mssql/test/unit/dotnetRuntimeProvider.test.ts @@ -11,7 +11,7 @@ import * as vscode from "vscode"; import * as fs from "fs/promises"; import DotnetRuntimeProvider from "../../src/languageservice/dotnetRuntimeProvider"; import * as Constants from "../../src/constants/constants"; -import { ILogger } from "../../src/models/interfaces"; +import { ILogger } from "../../src/models/logger"; import { ServiceClient } from "../../src/constants/locConstants"; import { stubILogger } from "./utils"; @@ -86,7 +86,7 @@ suite("DotnetRuntimeProvider tests", () => { expect(fsAccessStub).to.have.been.calledWith("/extension/dotnet"); expect(getExtensionStub).to.have.been.calledWith(Constants.dotnetRuntimeExtensionId); expect(activateExtensionStub).to.have.been.called; - expect(logger.verbose).to.have.been.calledWithMatch("Acquired .NET runtime via"); + expect(logger.debug).to.have.been.calledWithMatch("Acquired .NET runtime via"); }); test("should request the runtime version from the provided runtimeconfig", async () => { diff --git a/extensions/mssql/test/unit/download.test.ts b/extensions/mssql/test/unit/download.test.ts index 69efcfa16c..dd2a5df15d 100644 --- a/extensions/mssql/test/unit/download.test.ts +++ b/extensions/mssql/test/unit/download.test.ts @@ -13,7 +13,7 @@ import DecompressProvider from "../../src/languageservice/decompressProvider"; import ConfigUtils from "../../src/configurations/configUtils"; import { Runtime } from "../../src/models/platform"; import * as path from "path"; -import { Logger } from "../../src/models/logger"; +import { ILogger } from "../../src/models/logger"; import * as fs from "fs/promises"; import { expect } from "chai"; import { ServerStatusView } from "../../src/languageservice/serverStatus"; @@ -55,7 +55,7 @@ suite("ServiceDownloadProvider Tests", () => { let statusView: sinon.SinonStubbedInstance; let testDownloadHelper: sinon.SinonStubbedInstance; let testDecompressProvider: sinon.SinonStubbedInstance; - let testLogger: sinon.SinonStubbedInstance; + let testLogger: sinon.SinonStubbedInstance; setup(() => { sandbox = sinon.createSandbox(); @@ -224,8 +224,8 @@ suite("ServiceDownloadProvider Tests", () => { config.getSqlToolsConfigValue.withArgs("downloadFileNames").returns(fileNamesJson); config.getSqlToolsServiceDownloadUrl.returns(baseDownloadUrl); config.getSqlToolsPackageVersion.returns(version); - testLogger.append.returns(); - testLogger.appendLine.returns(); + testLogger.trace.returns(); + testLogger.info.returns(); testDecompressProvider.decompress.callsFake(() => { return fixture.decompressResult; diff --git a/extensions/mssql/test/unit/fabricProvisioningHelpers.test.ts b/extensions/mssql/test/unit/fabricProvisioningHelpers.test.ts index 564803b46e..cb1fa2c28b 100644 --- a/extensions/mssql/test/unit/fabricProvisioningHelpers.test.ts +++ b/extensions/mssql/test/unit/fabricProvisioningHelpers.test.ts @@ -15,14 +15,14 @@ import { createStubLogger, stubTelemetry } from "./utils"; import { FormItemOptions, FormItemType } from "../../src/sharedInterfaces/form"; import * as fp from "../../src/sharedInterfaces/fabricProvisioning"; import { Fabric } from "../../src/constants/locConstants"; -import { Logger } from "../../src/models/logger"; +import { ILogger } from "../../src/models/logger"; chai.use(sinonChai); suite("Fabric Provisioning logic", () => { let sandbox: sinon.SinonSandbox; let deploymentController: any; - let logger: sinon.SinonStubbedInstance; + let logger: sinon.SinonStubbedInstance; let sendActionEvent: sinon.SinonStub; let accountOptions = [{ label: "acct1", id: "account1" }]; let tenantOptions = [{ displayName: "tenant1", tenantId: "tenant1" }]; diff --git a/extensions/mssql/test/unit/httpClient.test.ts b/extensions/mssql/test/unit/httpClient.test.ts index 222157be56..8946df2948 100644 --- a/extensions/mssql/test/unit/httpClient.test.ts +++ b/extensions/mssql/test/unit/httpClient.test.ts @@ -13,7 +13,7 @@ import { PassThrough, Writable } from "stream"; import axios, { AxiosResponse } from "axios"; import * as LocalizedConstants from "../../src/constants/locConstants"; import { HttpClient, HttpDownloadError } from "../../src/http/httpClient"; -import { Logger } from "../../src/models/logger"; +import { ILogger } from "../../src/models/logger"; import { createStubLogger } from "./utils"; chai.use(sinonChai); @@ -21,7 +21,7 @@ chai.use(sinonChai); suite("HttpClient tests", () => { let sandbox: sinon.SinonSandbox; let httpClient: HttpClient; - let logger: sinon.SinonStubbedInstance; + let logger: sinon.SinonStubbedInstance; setup(() => { sandbox = sinon.createSandbox(); @@ -532,7 +532,7 @@ suite("HttpClient tests", () => { httpClient["setupConfigAndProxyForRequest"](requestUrl, token); - expect(logger.verbose).to.have.been.calledWith( + expect(logger.debug).to.have.been.calledWith( "Proxy endpoint found in environment variables or workspace configuration.", ); }); diff --git a/extensions/mssql/test/unit/logger2.test.ts b/extensions/mssql/test/unit/logger.test.ts similarity index 86% rename from extensions/mssql/test/unit/logger2.test.ts rename to extensions/mssql/test/unit/logger.test.ts index 1e9a2075ba..7fdc1275d2 100644 --- a/extensions/mssql/test/unit/logger2.test.ts +++ b/extensions/mssql/test/unit/logger.test.ts @@ -9,11 +9,11 @@ import * as chai from "chai"; import * as vscode from "vscode"; import { expect } from "chai"; import { - Logger2, - logger2, - logger2OutputChannelName, - resetLogger2DefaultChannelForTest, -} from "../../src/models/logger2"; + Logger, + logger, + loggerOutputChannelName, + resetLoggerDefaultChannelForTest, +} from "../../src/models/logger"; import * as Utils from "../../src/models/utils"; chai.use(sinonChai); @@ -48,17 +48,17 @@ function createChannelStub(): TestLogOutputChannel { } as unknown as TestLogOutputChannel; } -suite("Logger2 tests", () => { +suite("Logger tests", () => { let sandbox: sinon.SinonSandbox; setup(() => { sandbox = sinon.createSandbox(); - resetLogger2DefaultChannelForTest(); + resetLoggerDefaultChannelForTest(); }); teardown(() => { sandbox.restore(); - resetLogger2DefaultChannelForTest(); + resetLoggerDefaultChannelForTest(); }); test("global logger lazily creates and reuses the MSSQL log channel", () => { @@ -67,10 +67,10 @@ suite("Logger2 tests", () => { .stub(vscode.window, "createOutputChannel") .returns(channel); - logger2.info("first message"); - logger2.warn("second message"); + logger.info("first message"); + logger.warn("second message"); - expect(createOutputChannelStub).to.have.been.calledWithExactly(logger2OutputChannelName, { + expect(createOutputChannelStub).to.have.been.calledWithExactly(loggerOutputChannelName, { log: true, }); expect(channel.info).to.have.been.calledWithExactly("first message"); @@ -79,7 +79,7 @@ suite("Logger2 tests", () => { test("withPrefix prepends the prefix to all messages", () => { const channel = createChannelStub(); - const prefixedLogger = Logger2.forChannel(channel).withPrefix("SchemaCompare"); + const prefixedLogger = Logger.forChannel(channel).withPrefix("SchemaCompare"); prefixedLogger.debug("operation started", { id: 42 }); @@ -91,7 +91,7 @@ suite("Logger2 tests", () => { test("forChannel uses the provided channel without creating a new one", () => { const channel = createChannelStub(); const createOutputChannelStub = sandbox.stub(vscode.window, "createOutputChannel"); - const alternateLogger = Logger2.forChannel(channel, "Profiler"); + const alternateLogger = Logger.forChannel(channel, "Profiler"); alternateLogger.error("failed", new Error("boom")); @@ -108,7 +108,7 @@ suite("Logger2 tests", () => { const createOutputChannelStub = sandbox .stub(vscode.window, "createOutputChannel") .returns(channel); - const alternateLogger = Logger2.forChannelName("Custom Channel", "Custom"); + const alternateLogger = Logger.forChannelName("Custom Channel", "Custom"); alternateLogger.trace("hello"); alternateLogger.dispose(); @@ -122,7 +122,7 @@ suite("Logger2 tests", () => { test("show delegates to the underlying channel", () => { const channel = createChannelStub(); - const logger = Logger2.forChannel(channel); + const logger = Logger.forChannel(channel); logger.show(true); @@ -131,7 +131,7 @@ suite("Logger2 tests", () => { test("piiSanitized logs sanitized values when pii logging is enabled", () => { const channel = createChannelStub(); - const logger = Logger2.forChannel(channel, "Auth"); + const logger = Logger.forChannel(channel, "Auth"); sandbox.stub(Utils, "getConfigPiiLogging").returns(true); logger.piiSanitized( @@ -157,7 +157,7 @@ suite("Logger2 tests", () => { test("piiSanitized does not log when pii logging is disabled", () => { const channel = createChannelStub(); - const logger = Logger2.forChannel(channel); + const logger = Logger.forChannel(channel); sandbox.stub(Utils, "getConfigPiiLogging").returns(false); logger.piiSanitized("secret", [], []); diff --git a/extensions/mssql/test/unit/metadataService.test.ts b/extensions/mssql/test/unit/metadataService.test.ts index b905a40c14..07c627741d 100644 --- a/extensions/mssql/test/unit/metadataService.test.ts +++ b/extensions/mssql/test/unit/metadataService.test.ts @@ -27,7 +27,7 @@ import { TableMetadataResult, ViewMetadataResult, } from "../../src/sharedInterfaces/metadata"; -import { Logger } from "../../src/models/logger"; +import { ILogger } from "../../src/models/logger"; import { stubLoggerGetter } from "./utils"; chai.use(sinonChai); @@ -35,7 +35,7 @@ chai.use(sinonChai); suite("Metadata Service Tests", () => { let sandbox: sinon.SinonSandbox; let mockClient: sinon.SinonStubbedInstance; - let mockLogger: sinon.SinonStubbedInstance; + let mockLogger: sinon.SinonStubbedInstance; let metadataService: MetadataService; setup(() => { diff --git a/extensions/mssql/test/unit/msalAzureController.test.ts b/extensions/mssql/test/unit/msalAzureController.test.ts index 21352f3fb0..d6a4aa02c3 100644 --- a/extensions/mssql/test/unit/msalAzureController.test.ts +++ b/extensions/mssql/test/unit/msalAzureController.test.ts @@ -22,7 +22,7 @@ import { MsalCachePluginProvider } from "../../src/azure/msal/msalCachePlugin"; import { MsalAzureCodeGrant } from "../../src/azure/msal/msalAzureCodeGrant"; import { MsalAzureDeviceCode } from "../../src/azure/msal/msalAzureDeviceCode"; import VscodeWrapper from "../../src/controllers/vscodeWrapper"; -import { Logger } from "../../src/models/logger"; +import { ILogger } from "../../src/models/logger"; import { CloudAuthApplication, MsalAzureController, @@ -40,7 +40,7 @@ suite("CloudAuthApplication Tests", () => { let sandbox: sinon.SinonSandbox; let mockContext: vscode.ExtensionContext; let mockVscodeWrapper: sinon.SinonStubbedInstance; - let mockLogger: sinon.SinonStubbedInstance; + let mockLogger: sinon.SinonStubbedInstance; let mockCachePluginProvider: sinon.SinonStubbedInstance; let loggerCallback: ILoggerCallback; diff --git a/extensions/mssql/test/unit/notebooks/notebookConnectionManager.test.ts b/extensions/mssql/test/unit/notebooks/notebookConnectionManager.test.ts index 5e1463c385..b4235d0a79 100644 --- a/extensions/mssql/test/unit/notebooks/notebookConnectionManager.test.ts +++ b/extensions/mssql/test/unit/notebooks/notebookConnectionManager.test.ts @@ -12,7 +12,7 @@ import type { IConnectionInfo, ConnectionDetails } from "vscode-mssql"; chai.use(sinonChai); import { NotebookConnectionManager } from "../../../src/notebooks/notebookConnectionManager"; -import { ILogger2 } from "../../../src/models/logger2"; +import { ILogger } from "../../../src/models/logger"; import ConnectionManager from "../../../src/controllers/connectionManager"; import { ConnectionSharingService } from "../../../src/connectionSharing/connectionSharingService"; import { ConnectionStore } from "../../../src/models/connectionStore"; @@ -71,10 +71,10 @@ function makeConnectionInfo(overrides?: Partial): IConnectionIn } /** - * Build a stub ILogger2 with all required interface + * Build a stub ILogger with all required interface * members so the type checker is satisfied without `as any`. */ -function makeLogStub(sandbox: sinon.SinonSandbox): sinon.SinonStubbedInstance { +function makeLogStub(sandbox: sinon.SinonSandbox): sinon.SinonStubbedInstance { return { trace: sandbox.stub(), debug: sandbox.stub(), @@ -85,7 +85,7 @@ function makeLogStub(sandbox: sinon.SinonSandbox): sinon.SinonStubbedInstance; + } as sinon.SinonStubbedInstance; } suite("NotebookConnectionManager", () => { @@ -94,7 +94,7 @@ suite("NotebookConnectionManager", () => { let sharingService: sinon.SinonStubbedInstance; let mockClient: sinon.SinonStubbedInstance; let mockNotificationHandler: sinon.SinonStubbedInstance; - let log: sinon.SinonStubbedInstance; + let log: sinon.SinonStubbedInstance; let stubStore: sinon.SinonStubbedInstance; let stubUI: sinon.SinonStubbedInstance; let mgr: NotebookConnectionManager; diff --git a/extensions/mssql/test/unit/objectExplorerService.test.ts b/extensions/mssql/test/unit/objectExplorerService.test.ts index 9fb6c34611..12c964667b 100644 --- a/extensions/mssql/test/unit/objectExplorerService.test.ts +++ b/extensions/mssql/test/unit/objectExplorerService.test.ts @@ -15,7 +15,7 @@ import { expect } from "chai"; import VscodeWrapper from "../../src/controllers/vscodeWrapper"; import ConnectionManager, { SqlConnectionErrorType } from "../../src/controllers/connectionManager"; import SqlToolsServiceClient from "../../src/languageservice/serviceclient"; -import { Logger } from "../../src/models/logger"; +import { ILogger } from "../../src/models/logger"; import { ConnectionStore } from "../../src/models/connectionStore"; import { IConnectionProfile, @@ -205,7 +205,7 @@ suite("OE Service Tests", () => { let endStub: sinon.SinonStub; let endFailedStub: sinon.SinonStub; let startActivityStub: sinon.SinonStub; - let mockLogger: sinon.SinonStubbedInstance; + let mockLogger: sinon.SinonStubbedInstance; setup(() => { sandbox = sinon.createSandbox(); @@ -224,9 +224,7 @@ suite("OE Service Tests", () => { startTime: 0, update: sandbox.stub(), }); - // Mock the Logger.create static method mockLogger = stubLogger(sandbox); - mockLogger.verbose = sandbox.stub(); objectExplorerService = new ObjectExplorerService( mockVscodeWrapper, mockConnectionManager, @@ -322,8 +320,7 @@ suite("OE Service Tests", () => { ); // Verify logging - expect(mockLogger.verbose.called, "Logger should be called once for verbose").to.be - .true; + expect(mockLogger.debug.called, "ILogger should be called once for debug").to.be.true; // Verify the request was sent correctly expect(mockClient.sendRequest.calledOnce, "Send request should be called once").to.be @@ -684,7 +681,7 @@ suite("OE Service Tests", () => { suite("handleSessionCreationFailure", () => { let sandbox: sinon.SinonSandbox; - let mockLogger: sinon.SinonStubbedInstance; + let mockLogger: sinon.SinonStubbedInstance; let mockConnectionManager: sinon.SinonStubbedInstance; let mockVscodeWrapper: sinon.SinonStubbedInstance; let mockConnectionUI: sinon.SinonStubbedInstance; @@ -918,7 +915,7 @@ suite("OE Service Tests", () => { suite("handleSessionCreationSuccess", () => { let sandbox: sinon.SinonSandbox; - let mockLogger: sinon.SinonStubbedInstance; + let mockLogger: sinon.SinonStubbedInstance; let mockConnectionManager: sinon.SinonStubbedInstance; let mockVscodeWrapper: sinon.SinonStubbedInstance; let mockConnectionUI: sinon.SinonStubbedInstance; @@ -1189,7 +1186,7 @@ suite("OE Service Tests", () => { let mockActivity: ActivityObject; let mockClient: sinon.SinonStubbedInstance; let mockConnectionStore: sinon.SinonStubbedInstance; - let mockLogger: sinon.SinonStubbedInstance; + let mockLogger: sinon.SinonStubbedInstance; setup(() => { sandbox = sinon.createSandbox(); @@ -2200,7 +2197,7 @@ suite("OE Service Tests", () => { let mockFirewallService: sinon.SinonStubbedInstance; let mockWithProgress: sinon.SinonStub; - let mockLogger: sinon.SinonStubbedInstance; + let mockLogger: sinon.SinonStubbedInstance; let startActivityStub: sinon.SinonStub; let mockRefreshCallback: sinon.SinonStub; let endStub: sinon.SinonStub; @@ -2256,9 +2253,7 @@ suite("OE Service Tests", () => { }); mockRefreshCallback = sandbox.stub(); - // Mock the Logger.create static method mockLogger = stubLogger(sandbox); - mockLogger.verbose = sandbox.stub(); mockLogger.error = sandbox.stub(); objectExplorerService = new ObjectExplorerService( diff --git a/extensions/mssql/test/unit/objectManagementService.test.ts b/extensions/mssql/test/unit/objectManagementService.test.ts index c1a0642e2d..dacc3acb26 100644 --- a/extensions/mssql/test/unit/objectManagementService.test.ts +++ b/extensions/mssql/test/unit/objectManagementService.test.ts @@ -19,13 +19,13 @@ import { BackupConfigInfoRequest, } from "../../src/models/contracts/objectManagement"; import { RestoreParams } from "../../src/sharedInterfaces/restore"; -import { Logger } from "../../src/models/logger"; +import { ILogger } from "../../src/models/logger"; suite("ObjectManagementService Tests", () => { let sandbox: sinon.SinonSandbox; let objectManagementService: ObjectManagementService; let sqlToolsClientStub: sinon.SinonStubbedInstance; - let loggerStub: sinon.SinonStubbedInstance; // Add this + let loggerStub: sinon.SinonStubbedInstance; // Add this setup(() => { sandbox = sinon.createSandbox(); diff --git a/extensions/mssql/test/unit/scriptingService.test.ts b/extensions/mssql/test/unit/scriptingService.test.ts index 551d30c74d..31818381ca 100644 --- a/extensions/mssql/test/unit/scriptingService.test.ts +++ b/extensions/mssql/test/unit/scriptingService.test.ts @@ -29,7 +29,7 @@ import * as telemetry from "../../src/telemetry/telemetry"; import * as Constants from "../../src/constants/constants"; import * as LocalizedConstants from "../../src/constants/locConstants"; import { ActivityObject, ActivityStatus } from "../../src/sharedInterfaces/telemetry"; -import { Logger } from "../../src/models/logger"; +import { ILogger } from "../../src/models/logger"; import { stubLogger, stubExtensionContext, @@ -66,7 +66,7 @@ suite("Scripting Service", () => { let configurationGetStub: sinon.SinonStub; let registerCommandStub: sinon.SinonStub; let sendRequestStub: sinon.SinonStub; - let loggerStub: sinon.SinonStubbedInstance; + let loggerStub: sinon.SinonStubbedInstance; let objectExplorerTree: { selection: TreeNodeInfo[] }; let scriptingProgressHandler: ProgressHandler | undefined; let scriptingCompleteHandler: ProgressHandler | undefined; diff --git a/extensions/mssql/test/unit/serviceClient.test.ts b/extensions/mssql/test/unit/serviceClient.test.ts index 1ece5e40c3..4cabc8d890 100644 --- a/extensions/mssql/test/unit/serviceClient.test.ts +++ b/extensions/mssql/test/unit/serviceClient.test.ts @@ -13,7 +13,7 @@ import { ServiceClient as ServiceClientLoc } from "../../src/constants/locConsta import ServerProvider from "../../src/languageservice/server"; import SqlToolsServiceClient from "../../src/languageservice/serviceclient"; import DotnetRuntimeProvider from "../../src/languageservice/dotnetRuntimeProvider"; -import { Logger } from "../../src/models/logger"; +import { ILogger } from "../../src/models/logger"; import { PlatformInformation, Runtime } from "../../src/models/platform"; import StatusView from "../../src/views/statusView"; import * as LanguageServiceContracts from "../../src/models/contracts/languageService"; @@ -39,7 +39,7 @@ interface ILaunchAttempt { suite("Service Client tests", () => { let sandbox: sinon.SinonSandbox; let testServiceProvider: sinon.SinonStubbedInstance; - let logger: sinon.SinonStubbedInstance; + let logger: sinon.SinonStubbedInstance; let testStatusView: sinon.SinonStubbedInstance; let vscodeWrapper: sinon.SinonStubbedInstance; let dotnetRuntimeProvider: sinon.SinonStubbedInstance; diff --git a/extensions/mssql/test/unit/serviceInstallerUtils.test.ts b/extensions/mssql/test/unit/serviceInstallerUtils.test.ts index ae4bbafcfb..12a54af333 100644 --- a/extensions/mssql/test/unit/serviceInstallerUtils.test.ts +++ b/extensions/mssql/test/unit/serviceInstallerUtils.test.ts @@ -66,28 +66,18 @@ suite("Stub Logger tests", function (): void { sinon.restore(); }); - test("Test logdebug method", () => { - stubLogger.logDebug("test"); + test("Test debug method", () => { + stubLogger.debug("test"); expect(logStub, "Should print expected output to console").to.have.been.calledWith("test"); }); - test("Test increaseIndent method", () => { - stubLogger.increaseIndent(); - expect(logStub.notCalled, "Should not have printed anything to console").to.be.true; - }); - - test("Test decreaseIndent method", () => { - stubLogger.decreaseIndent(); - expect(logStub.notCalled, "Should not have printed anything to console").to.be.true; - }); - - test("Test append method", () => { - stubLogger.append("test"); + test("Test trace method", () => { + stubLogger.trace("test"); expect(logStub, "Should print expected output to console").to.have.been.calledWith("test"); }); - test("Test appendLine method", () => { - stubLogger.appendLine("test"); + test("Test info method", () => { + stubLogger.info("test"); expect(logStub, "Should print expected output to console").to.have.been.calledWith("test"); }); }); diff --git a/extensions/mssql/test/unit/tableExplorerService.test.ts b/extensions/mssql/test/unit/tableExplorerService.test.ts index f445bbc89c..20e6b57fd5 100644 --- a/extensions/mssql/test/unit/tableExplorerService.test.ts +++ b/extensions/mssql/test/unit/tableExplorerService.test.ts @@ -33,13 +33,13 @@ import { EditSubsetResult, EditUpdateCellResult, } from "../../src/sharedInterfaces/tableExplorer"; -import { Logger } from "../../src/models/logger"; +import { ILogger } from "../../src/models/logger"; import { stubLoggerGetter } from "./utils"; suite("TableExplorerService Tests", () => { let sandbox: sinon.SinonSandbox; let mockClient: sinon.SinonStubbedInstance; - let mockLogger: sinon.SinonStubbedInstance; + let mockLogger: sinon.SinonStubbedInstance; let tableExplorerService: TableExplorerService; setup(() => { diff --git a/extensions/mssql/test/unit/utils.ts b/extensions/mssql/test/unit/utils.ts index b0cc1873b7..a0b940ed4a 100644 --- a/extensions/mssql/test/unit/utils.ts +++ b/extensions/mssql/test/unit/utils.ts @@ -16,8 +16,7 @@ import { IPrompter } from "../../src/prompts/question"; import CodeAdapter from "../../src/prompts/adapter"; import { buildCapabilitiesResult } from "./mocks"; import { GetCapabilitiesRequest } from "../../src/models/contracts/connection"; -import { ILogger } from "../../src/models/interfaces"; -import { Logger } from "../../src/models/logger"; +import { ILogger, logger as baseLogger } from "../../src/models/logger"; import { PreviewFeature, previewService } from "../../src/previews/previewService"; // Stubs the telemetry code @@ -161,40 +160,46 @@ export function stubExtensionContext( return context; } -export function createStubLogger(sandbox?: sinon.SinonSandbox): sinon.SinonStubbedInstance { +export function createStubLogger( + sandbox?: sinon.SinonSandbox, +): sinon.SinonStubbedInstance { const stubber = sandbox || sinon; - return stubber.createStubInstance(Logger); + const logger = { + trace: stubber.stub(), + debug: stubber.stub(), + info: stubber.stub(), + warn: stubber.stub(), + error: stubber.stub(), + piiSanitized: stubber.stub(), + show: stubber.stub(), + withPrefix: stubber.stub(), + dispose: stubber.stub(), + } as sinon.SinonStubbedInstance; + logger.withPrefix.returns(logger); + return logger; } -export function stubLogger(sandbox?: sinon.SinonSandbox): sinon.SinonStubbedInstance { +export function stubLogger(sandbox?: sinon.SinonSandbox): sinon.SinonStubbedInstance { const stubber = sandbox || sinon; const logger = createStubLogger(sandbox); - stubber.stub(Logger, "create").returns(logger); + const withPrefix = baseLogger.withPrefix as unknown as sinon.SinonStub; + if (typeof withPrefix.restore === "function") { + withPrefix.returns(logger); + } else { + stubber.stub(baseLogger, "withPrefix").returns(logger); + } return logger; } export function stubILogger(sandbox?: sinon.SinonSandbox): sinon.SinonStubbedInstance { - const stubber = sandbox || sinon; - - return { - logDebug: stubber.stub(), - verbose: stubber.stub(), - warn: stubber.stub(), - error: stubber.stub(), - piiSanitized: stubber.stub(), - increaseIndent: stubber.stub(), - decreaseIndent: stubber.stub(), - append: stubber.stub(), - appendLine: stubber.stub(), - info: stubber.stub(), - } as sinon.SinonStubbedInstance; + return createStubLogger(sandbox); } -export function stubLoggerGetter( +export function stubLoggerGetter( sandbox: sinon.SinonSandbox, target: T, - logger: sinon.SinonStubbedInstance = createStubLogger(sandbox), -): sinon.SinonStubbedInstance { + logger: sinon.SinonStubbedInstance = createStubLogger(sandbox), +): sinon.SinonStubbedInstance { sandbox.stub(target, "logger").get(() => logger); return logger; }