Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 43 additions & 3 deletions src/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -225,7 +227,43 @@ export class Commands {
* View the logs for the currently connected workspace.
*/
public async viewLogs(): Promise<void> {
if (!this.workspaceLogPath) {
if (this.workspaceLogPath) {
// Return the connected deployment's log file.
return this.openFile(this.workspaceLogPath);
}

const logDir = vscode.workspace
.getConfiguration()
.get<string>("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.",
Expand All @@ -239,9 +277,11 @@ export class Commands {
);
}
});
return;
}
const uri = vscode.Uri.file(this.workspaceLogPath);
}

private async openFile(path: string): Promise<void> {
const uri = vscode.Uri.file(path);
const doc = await vscode.workspace.openTextDocument(uri);
await vscode.window.showTextDocument(doc);
}
Expand Down
35 changes: 19 additions & 16 deletions src/remote/sshProcess.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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`),
Expand Down Expand Up @@ -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}`,
);
Expand All @@ -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}`,
);
Expand All @@ -445,3 +442,9 @@ async function findRemoteSshLogPath(

return undefined;
}

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