diff --git a/extensions/mssql/package.json b/extensions/mssql/package.json index fa1ea0b42e..4d112d7b61 100644 --- a/extensions/mssql/package.json +++ b/extensions/mssql/package.json @@ -115,6 +115,11 @@ { "command": "mssql.clearSearchServerResult", "title": "%title.clearSearchServerResult%" + }, + { + "command": "mssql.showLogFile", + "category": "MSSQL", + "title": "%title.showLogFile%" } ], "outputChannels": [ @@ -943,4 +948,4 @@ ] } } -} \ No newline at end of file +} diff --git a/extensions/mssql/package.nls.json b/extensions/mssql/package.nls.json index defbbcb58a..b16aaad4e2 100644 --- a/extensions/mssql/package.nls.json +++ b/extensions/mssql/package.nls.json @@ -33,6 +33,8 @@ "title.endpoints": "Service Endpoints", "title.books": "Notebooks", + "title.showLogFile": "Show Log File", + "mssql.configuration.title": "MSSQL configuration", "mssql.query.displayBitAsNumber": "Should BIT columns be displayed as numbers (1 or 0)? If false, BIT columns will be displayed as 'true' or 'false'", "mssql.format.alignColumnDefinitionsInColumns": "Should column definitions be aligned?", diff --git a/extensions/mssql/src/credentialstore/credentialstore.ts b/extensions/mssql/src/credentialstore/credentialstore.ts index eecdf7332f..f8f4a243a6 100644 --- a/extensions/mssql/src/credentialstore/credentialstore.ts +++ b/extensions/mssql/src/credentialstore/credentialstore.ts @@ -70,7 +70,7 @@ export class CredentialStore { private _client: SqlOpsDataClient; private _config: IConfig; - constructor(baseConfig: IConfig) { + constructor(private logPath: string, baseConfig: IConfig) { if (baseConfig) { this._config = JSON.parse(JSON.stringify(baseConfig)); this._config.executableFiles = ['MicrosoftSqlToolsCredentials.exe', 'MicrosoftSqlToolsCredentials']; @@ -97,7 +97,7 @@ export class CredentialStore { } private generateServerOptions(executablePath: string): ServerOptions { - let launchArgs = Utils.getCommonLaunchArgsAndCleanupOldLogFiles('credentialstore', executablePath); + let launchArgs = Utils.getCommonLaunchArgsAndCleanupOldLogFiles(this.logPath, 'credentialstore.log', executablePath); return { command: executablePath, args: launchArgs, transport: TransportKind.stdio }; } } diff --git a/extensions/mssql/src/main.ts b/extensions/mssql/src/main.ts index 5f222c904a..5a22eca95d 100644 --- a/extensions/mssql/src/main.ts +++ b/extensions/mssql/src/main.ts @@ -53,13 +53,17 @@ export async function activate(context: vscode.ExtensionContext): Promise { const installationComplete = Date.now(); - let serverOptions = generateServerOptions(e); + let serverOptions = generateServerOptions(context.logPath, e); languageClient = new SqlOpsDataClient(Constants.serviceName, serverOptions, clientOptions); const processStart = Date.now(); languageClient.onReady().then(() => { @@ -118,6 +122,8 @@ export async function activate(context: vscode.ExtensionContext): Promise languageClient.stop() }); + registerLogCommand(context); + registerServiceEndpoints(context); // Get book contributions - in the future this will be integrated with the Books/Notebook widget to show as a dashboard widget const bookContributionProvider = getBookExtensionContributions(context); @@ -141,6 +147,19 @@ export async function activate(context: vscode.ExtensionContext): Promise { + const choice = await vscode.window.showQuickPick(logFiles); + if (choice) { + const document = await vscode.workspace.openTextDocument(vscode.Uri.file(path.join(context.logPath, choice))); + if (document) { + vscode.window.showTextDocument(document); + } + } + })); +} + function getClientOptions(): ClientOptions { return { documentSelector: ['sql'], @@ -287,8 +306,8 @@ async function handleOpenClusterStatusNotebookTask(profile: azdata.IConnectionPr }); } } -function generateServerOptions(executablePath: string): ServerOptions { - let launchArgs = Utils.getCommonLaunchArgsAndCleanupOldLogFiles('sqltools', executablePath); +function generateServerOptions(logPath: string, executablePath: string): ServerOptions { + let launchArgs = Utils.getCommonLaunchArgsAndCleanupOldLogFiles(logPath, 'sqltools.log', executablePath); return { command: executablePath, args: launchArgs, transport: TransportKind.stdio }; } diff --git a/extensions/mssql/src/resourceProvider/resourceProvider.ts b/extensions/mssql/src/resourceProvider/resourceProvider.ts index 09e439aac1..70d90de906 100644 --- a/extensions/mssql/src/resourceProvider/resourceProvider.ts +++ b/extensions/mssql/src/resourceProvider/resourceProvider.ts @@ -75,7 +75,7 @@ export class AzureResourceProvider { private _client: SqlOpsDataClient; private _config: IConfig; - constructor(baseConfig: IConfig) { + constructor(private logPath: string, baseConfig: IConfig) { if (baseConfig) { this._config = JSON.parse(JSON.stringify(baseConfig)); this._config.executableFiles = ['SqlToolsResourceProviderService.exe', 'SqlToolsResourceProviderService']; @@ -102,7 +102,7 @@ export class AzureResourceProvider { } private generateServerOptions(executablePath: string): ServerOptions { - let launchArgs = Utils.getCommonLaunchArgsAndCleanupOldLogFiles('resourceprovider', executablePath); + let launchArgs = Utils.getCommonLaunchArgsAndCleanupOldLogFiles(this.logPath, 'resourceprovider.log', executablePath); return { command: executablePath, args: launchArgs, transport: TransportKind.stdio }; } } diff --git a/extensions/mssql/src/utils.ts b/extensions/mssql/src/utils.ts index ff27d414e9..b22ca4edf0 100644 --- a/extensions/mssql/src/utils.ts +++ b/extensions/mssql/src/utils.ts @@ -11,6 +11,7 @@ import * as os from 'os'; import * as findRemoveSync from 'find-remove'; import * as constants from './constants'; import * as fs from 'fs'; +import { promisify } from 'util'; const configTracingLevel = 'tracingLevel'; const configLogRetentionMinutes = 'logRetentionMinutes'; @@ -30,6 +31,17 @@ export function getAppDataPath() { } } +export namespace pfs { + + export function exists(path: string): Promise { + return promisify(fs.exists)(path); + } + + export function mkdir(path: string, mode?: number): Promise { + return promisify(fs.mkdir)(path, mode); + } +} + /** * Get a file name that is not already used in the target directory * @param filePath source notebook file name @@ -57,8 +69,8 @@ export function copyFile(source: string, target: string): void { fs.copyFileSync(source, target); } -export function removeOldLogFiles(prefix: string): JSON { - return findRemoveSync(getDefaultLogDir(), { prefix: `${prefix}_`, age: { seconds: getConfigLogRetentionSeconds() }, limit: getConfigLogFilesRemovalLimit() }); +export function removeOldLogFiles(logPath: string, prefix: string): JSON { + return findRemoveSync(logPath, { age: { seconds: getConfigLogRetentionSeconds() }, limit: getConfigLogFilesRemovalLimit() }); } export function getConfiguration(config: string = extensionConfigSectionName): vscode.WorkspaceConfiguration { @@ -95,24 +107,20 @@ export function getConfigTracingLevel(): string { } } -export function getDefaultLogDir(): string { - return path.join(process.env['ADS_LOGS'], '..', '..', 'mssql'); +export function getLogFileName(prefix: string, pid: number): string { + return `${prefix}_${pid}.log`; } -export function getDefaultLogFile(prefix: string, pid: number): string { - return path.join(getDefaultLogDir(), `${prefix}_${pid}.log`); -} - -export function getCommonLaunchArgsAndCleanupOldLogFiles(prefix: string, executablePath: string): string[] { +export function getCommonLaunchArgsAndCleanupOldLogFiles(logPath: string, fileName: string, executablePath: string): string[] { let launchArgs = []; launchArgs.push('--log-file'); - let logFile = getDefaultLogFile(prefix, process.pid); + let logFile = path.join(logPath, fileName); launchArgs.push(logFile); console.log(`logFile for ${path.basename(executablePath)} is ${logFile}`); console.log(`This process (ui Extenstion Host) is pid: ${process.pid}`); // Delete old log files - let deletedLogFiles = removeOldLogFiles(prefix); + let deletedLogFiles = removeOldLogFiles(logPath, fileName); console.log(`Old log files deletion report: ${JSON.stringify(deletedLogFiles)}`); launchArgs.push('--tracing-level'); launchArgs.push(getConfigTracingLevel()); diff --git a/src/vs/workbench/contrib/logs/common/logConstants.ts b/src/vs/workbench/contrib/logs/common/logConstants.ts index 5d47b47fc4..2fe47ed000 100644 --- a/src/vs/workbench/contrib/logs/common/logConstants.ts +++ b/src/vs/workbench/contrib/logs/common/logConstants.ts @@ -8,5 +8,3 @@ export const sharedLogChannelId = 'sharedLog'; export const rendererLogChannelId = 'rendererLog'; export const extHostLogChannelId = 'extHostLog'; export const telemetryLogChannelId = 'telemetryLog'; -// {{SQL CARBON EDIT}} -export const sqlToolsLogChannellId = 'sqlToolsLog'; diff --git a/src/vs/workbench/contrib/logs/electron-browser/logs.contribution.ts b/src/vs/workbench/contrib/logs/electron-browser/logs.contribution.ts index ee4bc84db4..92b66a1344 100644 --- a/src/vs/workbench/contrib/logs/electron-browser/logs.contribution.ts +++ b/src/vs/workbench/contrib/logs/electron-browser/logs.contribution.ts @@ -32,12 +32,6 @@ class LogOutputChannels extends Disposable implements IWorkbenchContribution { this.registerLogChannel(Constants.sharedLogChannelId, nls.localize('sharedLog', "Shared"), URI.file(join(environmentService.logsPath, `sharedprocess.log`))); this.registerLogChannel(Constants.rendererLogChannelId, nls.localize('rendererLog', "Window"), URI.file(join(environmentService.logsPath, `renderer${environmentService.configuration.windowId}.log`))); - // {{SQL CARBON EDIT}} @anthonydresser 05/19/19 investigate, this should be in the extension - let toolsServiceLogFile: string = join(environmentService.logsPath, '..', '..', 'mssql', `sqltools_${Date.now()}.log`); - console.log(`SqlTools Log file is: ${toolsServiceLogFile}`); - this.registerLogChannel(Constants.sqlToolsLogChannellId, nls.localize('sqlToolsLog', "Log (SqlTools)"), URI.file(toolsServiceLogFile)); - // {{SQL CARBON EDIT}} - End - const registerTelemetryChannel = (level: LogLevel) => { if (level === LogLevel.Trace && !Registry.as(OutputExt.OutputChannels).getChannel(Constants.telemetryLogChannelId)) { this.registerLogChannel(Constants.telemetryLogChannelId, nls.localize('telemetryLog', "Telemetry"), URI.file(join(environmentService.logsPath, `telemetry.log`))); @@ -71,4 +65,4 @@ class LogOutputChannels extends Disposable implements IWorkbenchContribution { } -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(LogOutputChannels, LifecyclePhase.Restored); \ No newline at end of file +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(LogOutputChannels, LifecyclePhase.Restored);