Skip to content

chore: add additional logging around resource and memory useage #465

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 22 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
4617974
feat: create memory logger
brettkolodny Apr 1, 2025
e5ae295
fix: format
brettkolodny Apr 1, 2025
1e56a3f
feat: log information regarding network updates
brettkolodny Apr 1, 2025
f201d1a
chore: improve logging for findSSHProcessID
brettkolodny Apr 1, 2025
d7c650b
chore: add memory logging to WorkspacesProvider
brettkolodny Apr 1, 2025
f3bcbca
chore: add logging to inbox
brettkolodny Apr 1, 2025
5ebc004
chore: improve logging around extension starting and stopping
brettkolodny Apr 1, 2025
854ca01
chore: add logging around workspace fetching and refetching logic
brettkolodny Apr 1, 2025
8974e8b
fix: resolve lint warnings
brettkolodny Apr 1, 2025
9b440dc
chore: remove non-useful avgload information
brettkolodny Apr 2, 2025
1eed376
chore: remove unneeded type annotations
brettkolodny Apr 4, 2025
d6fb26c
fix: add radix to number parse
brettkolodny Apr 4, 2025
2c09de6
chore: rename loop attempts variable
brettkolodny Apr 4, 2025
3c3f452
chore: remove unneeded try-catch
brettkolodny Apr 4, 2025
44106ee
chore: remove unneeded comment
brettkolodny Apr 4, 2025
9659dd8
fix: remove unneeded try catch
brettkolodny Apr 4, 2025
86de75d
fix: move interval to class level and clear on dispose
brettkolodny Apr 4, 2025
5fbc7a7
chore: remove unneeded comment
brettkolodny Apr 4, 2025
b839ad5
Merge branch 'main' into brett-429/add-debuggin-to-the-plugin
brettkolodny Apr 4, 2025
c8e45da
fix: fix lint warnings
brettkolodny Apr 4, 2025
90172e6
chore: update version
brettkolodny Apr 4, 2025
0d04fba
fix: properly set version
brettkolodny Apr 4, 2025
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
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"displayName": "Coder",
"description": "Open any workspace with a single click.",
"repository": "https://github.com/coder/vscode-coder",
"version": "1.7.0",
"version": "1.7.0-debug.1",
"engines": {
"vscode": "^1.73.0"
},
Expand Down
40 changes: 40 additions & 0 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,27 @@ import { makeCoderSdk, needToken } from "./api"
import { errToStr } from "./api-helper"
import { Commands } from "./commands"
import { CertificateError, getErrorDetail } from "./error"
import { getMemoryLogger } from "./memoryLogger"
import { Remote } from "./remote"
import { Storage } from "./storage"
import { toSafeHost } from "./util"
import { WorkspaceQuery, WorkspaceProvider } from "./workspacesProvider"

export async function activate(ctx: vscode.ExtensionContext): Promise<void> {
// Initialize the memory logger right when the extension starts.
const logger = getMemoryLogger()
await logger.initLogFile(ctx.globalStorageUri.fsPath)

// Log initial memory usage and activation
logger.info("CODER extension activating")
logger.logMemoryUsage("EXTENSION_ACTIVATE")

// Register disposal of the logger when the extension deactivates
ctx.subscriptions.push({ dispose: () => logger.dispose() })

// Log extension mode
logger.info(`Extension mode: ${extensionModeToString(ctx.extensionMode)}`)

// The Remote SSH extension's proposed APIs are used to override the SSH host
// name in VS Code itself. It's visually unappealing having a lengthy name!
//
Expand All @@ -25,9 +40,13 @@ export async function activate(ctx: vscode.ExtensionContext): Promise<void> {
vscode.extensions.getExtension("codeium.windsurf-remote-openssh") ||
vscode.extensions.getExtension("ms-vscode-remote.remote-ssh")
if (!remoteSSHExtension) {
logger.error("Remote SSH extension not found, cannot activate Coder extension")
vscode.window.showErrorMessage("Remote SSH extension not found, cannot activate Coder extension")
throw new Error("Remote SSH extension not found")
}

logger.info(`Found Remote SSH extension: ${remoteSSHExtension.id}`)

// eslint-disable-next-line @typescript-eslint/no-explicit-any
const vscodeProposed: typeof vscode = (module as any)._load(
"vscode",
Expand Down Expand Up @@ -281,4 +300,25 @@ export async function activate(ctx: vscode.ExtensionContext): Promise<void> {
}
}
}

logger.info("Coder extension activation complete")
}

function extensionModeToString(mode: vscode.ExtensionMode): string {
switch (mode) {
case vscode.ExtensionMode.Development:
return "Development"
case vscode.ExtensionMode.Production:
return "Production"
case vscode.ExtensionMode.Test:
return "Test"
default:
return `Unknown (${mode})`
}
}

export function deactivate(): void {
const logger = getMemoryLogger()
logger.info("Coder extension deactivating")
logger.logMemoryUsage("EXTENSION_DEACTIVATE")
}
52 changes: 51 additions & 1 deletion src/inbox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import * as vscode from "vscode"
import { WebSocket } from "ws"
import { coderSessionTokenHeader } from "./api"
import { errToStr } from "./api-helper"
import { getMemoryLogger } from "./memoryLogger"
import { type Storage } from "./storage"

// These are the template IDs of our notifications.
Expand All @@ -17,9 +18,17 @@ export class Inbox implements vscode.Disposable {
readonly #storage: Storage
#disposed = false
#socket: WebSocket
#messageCount = 0
#workspaceId: string
#memoryInterval: NodeJS.Timeout

constructor(workspace: Workspace, httpAgent: ProxyAgent, restClient: Api, storage: Storage) {
const logger = getMemoryLogger()
Comment on lines 25 to +26
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it might be better to refactor this class to take a single init object. That way, we can dependency-inject the logger, and also make it easier to add new parameters down the line. Moving the logger directly to the constructor parameters would give us a five-argument function, which feels a bit unwieldy

this.#storage = storage
this.#workspaceId = workspace.id

logger.trackResourceCreated("InboxWebSocket", workspace.id)
logger.info(`Creating inbox for workspace: ${workspace.owner_name}/${workspace.name} (${workspace.id})`)

const baseUrlRaw = restClient.getAxiosInstance().defaults.baseURL
if (!baseUrlRaw) {
Expand All @@ -38,6 +47,8 @@ export class Inbox implements vscode.Disposable {
const socketProto = baseUrl.protocol === "https:" ? "wss:" : "ws:"
const socketUrl = `${socketProto}//${baseUrl.host}/api/v2/notifications/inbox/watch?format=plaintext&templates=${watchTemplatesParam}&targets=${watchTargetsParam}`

logger.debug(`Connecting to inbox WebSocket at: ${socketUrl}`)

const token = restClient.getAxiosInstance().defaults.headers.common[coderSessionTokenHeader] as string | undefined
this.#socket = new WebSocket(new URL(socketUrl), {
agent: httpAgent,
Expand All @@ -50,35 +61,74 @@ export class Inbox implements vscode.Disposable {
})

this.#socket.on("open", () => {
logger.info(`Inbox WebSocket connection opened for workspace: ${workspace.id}`)
this.#storage.writeToCoderOutputChannel("Listening to Coder Inbox")
})

this.#socket.on("error", (error) => {
logger.error(`Inbox WebSocket error for workspace: ${workspace.id}`, error)
this.notifyError(error)
this.dispose()
})

this.#socket.on("close", (code, reason) => {
logger.info(`Inbox WebSocket closed for workspace: ${workspace.id}, code: ${code}, reason: ${reason || "none"}`)
if (!this.#disposed) {
this.dispose()
}
})

this.#socket.on("message", (data) => {
this.#messageCount++

// Log periodic message stats
if (this.#messageCount % 10 === 0) {
logger.info(`Inbox received ${this.#messageCount} messages for workspace: ${workspace.id}`)
logger.logMemoryUsage("INBOX_WEBSOCKET")
}
Comment on lines +84 to +88
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want a little more granularity here? The current setup means that we have to wait for the first 10 messages before we log anything. I don't know how quickly the messages are coming in, but I'm worried we'll never log anything. Wondering if we could have something more logarithmic, where maybe we could have:

  • First message
  • First five messages
  • Every 10 messages after that


try {
const inboxMessage = JSON.parse(data.toString()) as GetInboxNotificationResponse

logger.debug(`Inbox notification received: ${inboxMessage.notification.title}`)
vscode.window.showInformationMessage(inboxMessage.notification.title)
} catch (error) {
logger.error(`Error processing inbox message for workspace: ${workspace.id}`, error)
this.notifyError(error)
}
})

// Log memory stats periodically
this.#memoryInterval = setInterval(
() => {
if (!this.#disposed) {
logger.logMemoryUsage("INBOX_PERIODIC")
} else {
clearInterval(this.#memoryInterval)
}
},
5 * 60 * 1000,
) // Every 5 minutes
}

dispose() {
const logger = getMemoryLogger()

if (!this.#disposed) {
logger.info(`Disposing inbox for workspace: ${this.#workspaceId} after ${this.#messageCount} messages`)
this.#storage.writeToCoderOutputChannel("No longer listening to Coder Inbox")
this.#socket.close()
this.#disposed = true
logger.trackResourceDisposed("InboxWebSocket", this.#workspaceId)
}

clearInterval(this.#memoryInterval)
}

private notifyError(error: unknown) {
const logger = getMemoryLogger()
const message = errToStr(error, "Got empty error while monitoring Coder Inbox")

logger.error(`Inbox error for workspace: ${this.#workspaceId}`, error)
this.#storage.writeToCoderOutputChannel(message)
}
}
Loading
Loading