From eca5b947ca2acf47be2e2d56d6a366b587ecf23c Mon Sep 17 00:00:00 2001 From: Ehab Younes Date: Wed, 10 Dec 2025 16:00:20 +0300 Subject: [PATCH] Add log file picker when viewing logs without active connection --- src/commands.ts | 46 +++++++++++++++++++++++++++++++++++++--- src/remote/sshProcess.ts | 35 ++++++++++++++++-------------- 2 files changed, 62 insertions(+), 19 deletions(-) diff --git a/src/commands.ts b/src/commands.ts index 9bb2ed54..c04317a1 100644 --- a/src/commands.ts +++ b/src/commands.ts @@ -5,6 +5,8 @@ import { type Workspace, type WorkspaceAgent, } from "coder/site/src/api/typesGenerated"; +import * as fs from "node:fs/promises"; +import * as path from "node:path"; import * as vscode from "vscode"; import { createWorkspaceIdentifier, extractAgents } from "./api/api-helper"; @@ -225,7 +227,43 @@ export class Commands { * View the logs for the currently connected workspace. */ public async viewLogs(): Promise { - if (!this.workspaceLogPath) { + if (this.workspaceLogPath) { + // Return the connected deployment's log file. + return this.openFile(this.workspaceLogPath); + } + + const logDir = vscode.workspace + .getConfiguration() + .get("coder.proxyLogDirectory"); + if (logDir) { + try { + const files = await fs.readdir(logDir); + // Sort explicitly since fs.readdir order is platform-dependent + const logFiles = files + .filter((f) => f.endsWith(".log")) + .sort() + .reverse(); + + if (logFiles.length === 0) { + vscode.window.showInformationMessage( + "No log files found in the configured log directory.", + ); + return; + } + + const selected = await vscode.window.showQuickPick(logFiles, { + title: "Select a log file to view", + }); + + if (selected) { + await this.openFile(path.join(logDir, selected)); + } + } catch (error) { + vscode.window.showErrorMessage( + `Failed to read log directory: ${error instanceof Error ? error.message : String(error)}`, + ); + } + } else { vscode.window .showInformationMessage( "No logs available. Make sure to set coder.proxyLogDirectory to get logs.", @@ -239,9 +277,11 @@ export class Commands { ); } }); - return; } - const uri = vscode.Uri.file(this.workspaceLogPath); + } + + private async openFile(path: string): Promise { + const uri = vscode.Uri.file(path); const doc = await vscode.workspace.openTextDocument(uri); await vscode.window.showTextDocument(doc); } diff --git a/src/remote/sshProcess.ts b/src/remote/sshProcess.ts index e86cf154..248e071f 100644 --- a/src/remote/sshProcess.ts +++ b/src/remote/sshProcess.ts @@ -257,7 +257,7 @@ export class SshProcessMonitor implements vscode.Disposable { while (!this.disposed && this.currentPid === targetPid) { try { const logFiles = await fs.readdir(logDir); - logFiles.reverse(); + logFiles.sort().reverse(); const logFileName = logFiles.find( (file) => file === `${targetPid}.log` || file.endsWith(`-${targetPid}.log`), @@ -404,15 +404,11 @@ async function findRemoteSshLogPath( // Try extension-specific folder (for VS Code clones like Cursor, Windsurf) try { const extensionLogDir = path.join(logsParentDir, extensionId); - // Node returns these directories sorted already! - const files = await fs.readdir(extensionLogDir); - files.reverse(); - - const remoteSsh = files.find((file) => file.includes("Remote - SSH")); - if (remoteSsh) { - return path.join(extensionLogDir, remoteSsh); + const remoteSshLog = await findSshLogInDir(extensionLogDir); + if (remoteSshLog) { + return remoteSshLog; } - // Folder exists but no Remote SSH log yet + logger.debug( `Extension log folder exists but no Remote SSH log found: ${extensionLogDir}`, ); @@ -421,18 +417,19 @@ async function findRemoteSshLogPath( } try { - // Node returns these directories sorted already! const dirs = await fs.readdir(logsParentDir); - dirs.reverse(); - const outputDirs = dirs.filter((d) => d.startsWith("output_logging_")); + const outputDirs = dirs + .filter((d) => d.startsWith("output_logging_")) + .sort() + .reverse(); if (outputDirs.length > 0) { const outputPath = path.join(logsParentDir, outputDirs[0]); - const files = await fs.readdir(outputPath); - const remoteSSHLog = files.find((f) => f.includes("Remote - SSH")); - if (remoteSSHLog) { - return path.join(outputPath, remoteSSHLog); + const remoteSshLog = await findSshLogInDir(outputPath); + if (remoteSshLog) { + return remoteSshLog; } + logger.debug( `Output logging folder exists but no Remote SSH log found: ${outputPath}`, ); @@ -445,3 +442,9 @@ async function findRemoteSshLogPath( return undefined; } + +async function findSshLogInDir(dirPath: string): Promise { + const files = await fs.readdir(dirPath); + const remoteSshLog = files.find((f) => f.includes("Remote - SSH")); + return remoteSshLog ? path.join(dirPath, remoteSshLog) : undefined; +}