diff --git a/package.json b/package.json index 48f9dbd8..8ffdb57c 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "coder-remote", "publisher": "coder", - "displayName": "Coder Remote", + "displayName": "Coder", "description": "Open any workspace with a single click.", "repository": "https://github.com/coder/vscode-coder", "version": "0.1.25", @@ -168,6 +168,12 @@ "title": "Coder: Refresh Workspace", "icon": "$(refresh)", "when": "coder.authenticated" + }, + { + "command": "coder.viewLogs", + "title": "Coder: View Logs", + "icon": "$(list-unordered)", + "when": "coder.authenticated" } ], "menus": { diff --git a/src/commands.ts b/src/commands.ts index 774768c5..c099a34f 100644 --- a/src/commands.ts +++ b/src/commands.ts @@ -115,6 +115,17 @@ export class Commands { } } + // viewLogs opens the workspace logs. + public async viewLogs(): Promise { + if (!this.storage.workspaceLogPath) { + vscode.window.showInformationMessage("No logs available.", this.storage.workspaceLogPath || "") + return + } + const uri = vscode.Uri.file(this.storage.workspaceLogPath) + const doc = await vscode.workspace.openTextDocument(uri) + await vscode.window.showTextDocument(doc) + } + public async logout(): Promise { await this.storage.setURL(undefined) await this.storage.setSessionToken(undefined) diff --git a/src/extension.ts b/src/extension.ts index 34188082..1bb82b84 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -157,6 +157,7 @@ export async function activate(ctx: vscode.ExtensionContext): Promise { myWorkspacesProvider.fetchAndRefresh() allWorkspacesProvider.fetchAndRefresh() }) + vscode.commands.registerCommand("coder.viewLogs", commands.viewLogs.bind(commands)) // Since the "onResolveRemoteAuthority:ssh-remote" activation event exists // in package.json we're able to perform actions before the authority is diff --git a/src/remote.ts b/src/remote.ts index 3e072dd9..fb0a4e7b 100644 --- a/src/remote.ts +++ b/src/remote.ts @@ -76,6 +76,10 @@ export class Remote { await this.closeRemote() return } + // CLI versions before 2.3.3 don't support the --log-dir flag! + // If this check didn't exist, VS Code connections would fail on + // older versions because of an unknown CLI argument. + const hasCoderLogs = (parsedVersion?.compare("2.3.3") || 0) >= 0 || parsedVersion?.prerelease[0] === "devel" // Find the workspace from the URI scheme provided! try { @@ -426,7 +430,7 @@ export class Remote { // // If we didn't write to the SSH config file, connecting would fail with // "Host not found". - await this.updateSSHConfig(authorityParts[1]) + await this.updateSSHConfig(authorityParts[1], hasCoderLogs) this.findSSHProcessID().then((pid) => { if (!pid) { @@ -434,6 +438,7 @@ export class Remote { return } disposables.push(this.showNetworkUpdates(pid)) + this.storage.workspaceLogPath = path.join(this.storage.getLogPath(), `${pid}.log`) }) // Register the label formatter again because SSH overrides it! @@ -456,7 +461,7 @@ export class Remote { // updateSSHConfig updates the SSH configuration with a wildcard that handles // all Coder entries. - private async updateSSHConfig(hostName: string) { + private async updateSSHConfig(hostName: string, hasCoderLogs = false) { let deploymentSSHConfig = defaultSSHConfigResponse try { const deploymentConfig = await getDeploymentSSHConfig() @@ -542,12 +547,16 @@ export class Remote { if (typeof headerCommand === "string" && headerCommand.trim().length > 0) { headerArg = ` --header-command ${escape(headerCommand)}` } - + let logArg = "" + if (hasCoderLogs) { + await fs.mkdir(this.storage.getLogPath(), { recursive: true }) + logArg = ` --log-dir ${escape(this.storage.getLogPath())}` + } const sshValues: SSHValues = { Host: `${Remote.Prefix}*`, ProxyCommand: `${escape(binaryPath)}${headerArg} vscodessh --network-info-dir ${escape( this.storage.getNetworkInfoPath(), - )} --session-token-file ${escape(this.storage.getSessionTokenPath())} --url-file ${escape( + )}${logArg} --session-token-file ${escape(this.storage.getSessionTokenPath())} --url-file ${escape( this.storage.getURLPath(), )} %h`, ConnectTimeout: "0", diff --git a/src/storage.ts b/src/storage.ts index 8506464f..fa173cdd 100644 --- a/src/storage.ts +++ b/src/storage.ts @@ -15,6 +15,7 @@ import { getHeaderCommand, getHeaders } from "./headers" export class Storage { public workspace?: Workspace + public workspaceLogPath?: string constructor( private readonly output: vscode.OutputChannel, @@ -279,6 +280,12 @@ export class Storage { return path.join(this.globalStorageUri.fsPath, "net") } + // getLogPath returns the path where log data from the Coder + // agent is stored. + public getLogPath(): string { + return path.join(this.globalStorageUri.fsPath, "log") + } + public getUserSettingsPath(): string { return path.join(this.globalStorageUri.fsPath, "..", "..", "..", "User", "settings.json") }