Skip to content

Commit eca5b94

Browse files
committed
Add log file picker when viewing logs without active connection
1 parent 677eee4 commit eca5b94

File tree

2 files changed

+62
-19
lines changed

2 files changed

+62
-19
lines changed

src/commands.ts

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import {
55
type Workspace,
66
type WorkspaceAgent,
77
} from "coder/site/src/api/typesGenerated";
8+
import * as fs from "node:fs/promises";
9+
import * as path from "node:path";
810
import * as vscode from "vscode";
911

1012
import { createWorkspaceIdentifier, extractAgents } from "./api/api-helper";
@@ -225,7 +227,43 @@ export class Commands {
225227
* View the logs for the currently connected workspace.
226228
*/
227229
public async viewLogs(): Promise<void> {
228-
if (!this.workspaceLogPath) {
230+
if (this.workspaceLogPath) {
231+
// Return the connected deployment's log file.
232+
return this.openFile(this.workspaceLogPath);
233+
}
234+
235+
const logDir = vscode.workspace
236+
.getConfiguration()
237+
.get<string>("coder.proxyLogDirectory");
238+
if (logDir) {
239+
try {
240+
const files = await fs.readdir(logDir);
241+
// Sort explicitly since fs.readdir order is platform-dependent
242+
const logFiles = files
243+
.filter((f) => f.endsWith(".log"))
244+
.sort()
245+
.reverse();
246+
247+
if (logFiles.length === 0) {
248+
vscode.window.showInformationMessage(
249+
"No log files found in the configured log directory.",
250+
);
251+
return;
252+
}
253+
254+
const selected = await vscode.window.showQuickPick(logFiles, {
255+
title: "Select a log file to view",
256+
});
257+
258+
if (selected) {
259+
await this.openFile(path.join(logDir, selected));
260+
}
261+
} catch (error) {
262+
vscode.window.showErrorMessage(
263+
`Failed to read log directory: ${error instanceof Error ? error.message : String(error)}`,
264+
);
265+
}
266+
} else {
229267
vscode.window
230268
.showInformationMessage(
231269
"No logs available. Make sure to set coder.proxyLogDirectory to get logs.",
@@ -239,9 +277,11 @@ export class Commands {
239277
);
240278
}
241279
});
242-
return;
243280
}
244-
const uri = vscode.Uri.file(this.workspaceLogPath);
281+
}
282+
283+
private async openFile(path: string): Promise<void> {
284+
const uri = vscode.Uri.file(path);
245285
const doc = await vscode.workspace.openTextDocument(uri);
246286
await vscode.window.showTextDocument(doc);
247287
}

src/remote/sshProcess.ts

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ export class SshProcessMonitor implements vscode.Disposable {
257257
while (!this.disposed && this.currentPid === targetPid) {
258258
try {
259259
const logFiles = await fs.readdir(logDir);
260-
logFiles.reverse();
260+
logFiles.sort().reverse();
261261
const logFileName = logFiles.find(
262262
(file) =>
263263
file === `${targetPid}.log` || file.endsWith(`-${targetPid}.log`),
@@ -404,15 +404,11 @@ async function findRemoteSshLogPath(
404404
// Try extension-specific folder (for VS Code clones like Cursor, Windsurf)
405405
try {
406406
const extensionLogDir = path.join(logsParentDir, extensionId);
407-
// Node returns these directories sorted already!
408-
const files = await fs.readdir(extensionLogDir);
409-
files.reverse();
410-
411-
const remoteSsh = files.find((file) => file.includes("Remote - SSH"));
412-
if (remoteSsh) {
413-
return path.join(extensionLogDir, remoteSsh);
407+
const remoteSshLog = await findSshLogInDir(extensionLogDir);
408+
if (remoteSshLog) {
409+
return remoteSshLog;
414410
}
415-
// Folder exists but no Remote SSH log yet
411+
416412
logger.debug(
417413
`Extension log folder exists but no Remote SSH log found: ${extensionLogDir}`,
418414
);
@@ -421,18 +417,19 @@ async function findRemoteSshLogPath(
421417
}
422418

423419
try {
424-
// Node returns these directories sorted already!
425420
const dirs = await fs.readdir(logsParentDir);
426-
dirs.reverse();
427-
const outputDirs = dirs.filter((d) => d.startsWith("output_logging_"));
421+
const outputDirs = dirs
422+
.filter((d) => d.startsWith("output_logging_"))
423+
.sort()
424+
.reverse();
428425

429426
if (outputDirs.length > 0) {
430427
const outputPath = path.join(logsParentDir, outputDirs[0]);
431-
const files = await fs.readdir(outputPath);
432-
const remoteSSHLog = files.find((f) => f.includes("Remote - SSH"));
433-
if (remoteSSHLog) {
434-
return path.join(outputPath, remoteSSHLog);
428+
const remoteSshLog = await findSshLogInDir(outputPath);
429+
if (remoteSshLog) {
430+
return remoteSshLog;
435431
}
432+
436433
logger.debug(
437434
`Output logging folder exists but no Remote SSH log found: ${outputPath}`,
438435
);
@@ -445,3 +442,9 @@ async function findRemoteSshLogPath(
445442

446443
return undefined;
447444
}
445+
446+
async function findSshLogInDir(dirPath: string): Promise<string | undefined> {
447+
const files = await fs.readdir(dirPath);
448+
const remoteSshLog = files.find((f) => f.includes("Remote - SSH"));
449+
return remoteSshLog ? path.join(dirPath, remoteSshLog) : undefined;
450+
}

0 commit comments

Comments
 (0)