Architecture Overview
VSCode‑Logger is a Visual Studio Code extension designed to stream logs from embedded Linux devices over SSH, providing filtering, highlighting, bookmarking, and search. Alongside log viewing, it provides device grouping, a Device Manager settings UI, one-off SSH commands, interactive SSH terminals, a dual-pane SFTP explorer, and optional external or embedded browser actions for device URLs.
This codebase overview is organized in terms of architecture, maintainability, security, performance, and UI implementation and security. It covers the extension host code (TypeScript) and the Webview clients (JavaScript/CSS).
Design Principles
This project was designed around the following principles:
Documentation and configuration
Security-conscious design
Modular architecture
Robust asynchronous logic
User experience considerations
Testing practice
Linting, type-checking, formatting and spelling
Extensibility and configuration
Strengths
Clear modular structure: Components such as
logSession(split into authentication, host-key verification, fingerprint persistence, connection orchestration, and reconnection helpers), thelogPanelhost (split into lifecycle, HTML composition, messaging and persistence helpers),sftpExplorer,sshCommandRunner,sshTerminal,deviceManagerPanel, and the device tree/sidebar layers are well separated.Good use of VS Code APIs: Webview panels and views, tree data providers, pseudoterminals, secret storage, configuration scopes, workspace state, and file system APIs are used consistently.
Consistent TypeScript typings across devices, groups, bastion settings, SSH commands, log-panel messages, and SFTP operations.
Centralized configuration resolution: Defaults for ports, log commands, SSH terminals, SFTP explorer, browser actions, shared SSH commands, groups, and max log lines are normalized in one place before downstream components consume them.
Clear trust and validation gates: Log streaming, one-off SSH commands, SSH terminals, SFTP access, and browser actions all refuse to run in untrusted workspaces and validate key device inputs before use.
Secret handling: Passwords and passphrases are pulled from VS Code Secret Storage with migration from legacy settings, prompts, and controlled reuse across workspaces.
Connection hygiene: SSH features support host-key verification with SHA-256 fingerprints, secondary-host fallback, bastion tunnelling, and explicit disposal of SSH clients and channels.
Webview safety: The log viewer, devices view, Device Manager, and SFTP explorer all use nonce-backed CSPs and message passing, while log rendering uses text-safe insertion instead of raw HTML.
Performance Overview
Strengths
Efficient streaming pipeline: The log session buffers partial chunks until full lines are available, so the Webview receives complete entries instead of fragmented text.
Incremental rendering: The log viewer appends entries in batches and avoids rebuilding the full DOM for every new line.
Bounded memory usage: The log panel enforces
embeddedLogger.maxLinesPerTabto prevent unbounded in-memory and DOM growth for long-running sessions.Deferred heavy work: Activation registers views and commands but does not start network activity until the user opens a log panel, terminal, SFTP explorer, or browser action.
Targeted refresh behavior: Sidebar/device updates and SFTP preset updates send focused payloads rather than forcing full extension reloads.
Maintainability Overview
Strengths
Clear separation between backend and frontend: VS Code API and SSH logic live in
src/, while DOM/state handling lives inmedia/.Focused helper modules:
configuration.ts,passwordManager.ts,hostEndpoints.ts,logPanel/*, andlogSession/*keep cross-cutting concerns isolated.Schema-aware configuration editing: The Device Manager validates imported JSON and normalizes devices, groups, defaults, SSH commands, bastion settings, and SFTP presets before saving.
Good organization and naming conventions: The current module layout makes it easy to extend a specific area without loading unrelated concerns into
extension.ts.Automated checks are part of the workflow: The repository includes compile, lint, docs, unit, integration, and e2e test scripts.
UI/UX Overview
Strengths
Devices view supports multiple workflows: Devices can be grouped into collapsible sections, color coded, and exposed with context actions for logs, SSH, SFTP, and browser actions.
Log viewer is feature rich without mixing host logic into the Webview: Live logs and imported files share filtering, highlights, presets, search, bookmarks, exports, reconnect controls, and auto-save.
Device Manager improves discoverability: Users can edit defaults, groups, devices, SSH commands, fingerprints, and SFTP presets from a structured table UI instead of only editing raw JSON.
SFTP explorer is integrated into the same device model: It reuses device credentials, host-key expectations, presets, and terminal actions, which makes navigation consistent across features.
Responsive layout and theme integration: The Webviews use VS Code theme variables and preserve a native-feeling workflow inside the editor.
Security Overview
The VSCode-Logger extension interacts with remote systems over SSH and writes selected data to local files. It supports live log streaming, SFTP file operations, one-off commands, SSH terminals, and optional device URL launching. Because it handles credentials, host-key verification, and remote command execution, security is a core part of the design.
Strengths
Workspace trust enforcement and input validation: SSH-capable features refuse to run in untrusted workspaces and validate device host, username, port, and related settings before use.
Secure credential storage: Secrets are stored in VS Code Secret Storage after prompting users, keeping interactive credentials off disk by default. The extension uses the VS Code Secrets API for storing passwords and passphrases securely. Secrets are scoped per workspace with metadata prompts before reuse, reducing accidental credential leakage.
Webview security and XSS prevention: Webview UIs render log lines using
textContentrather thaninnerHTML. Log lines are inserted as text nodes, preventing HTML injection from streamed content. Webview CSPs block external scripts and restrict styles to bundled extension assets. A restrictive Content-Security-Policy disallows remote scripts and limits styles to extension resources, reducing XSS risk.Connection robustness: Auto-reconnect logic includes visible status updates and timers.
SSH integrity and tunnelling: Log streaming uses host key verification with captured fingerprints, and bastion tunnelling preserves fingerprint checks when present.
Controlled file and config operations: Exports, auto-save, local log opening, and imported settings all flow through validated extension-host code paths.
Workspace trust and configuration validation
Workspace trust gating. Log streaming, one-off SSH commands, SSH terminals, SFTP explorer access, and browser-opening actions all check
vscode.workspace.isTrustedbefore they run.Device configuration validation. SSH entry points validate core fields such as
host,username, andportbefore attempting a connection. The Device Manager also validates imported defaults, groups, devices, SSH commands, bastion blocks, and SFTP preset arrays before saving them.Sanitization of commands.
sanitizeCommandrejects control characters and newlines in one-off commands. The log session applies the same kind of validation tologCommand, and SSH-terminal command execution rejects multiline payloads as well.
Secure SSH handling
Host-key verification and fingerprint capture. SSH connections use SHA-256 host-key verification. When a configured fingerprint is present for the primary, secondary, or bastion endpoint, the connection is rejected on mismatch. When an endpoint has no saved fingerprint, the extension can persist the first successful fingerprint back into configuration for later connections.
Authentication management. Passwords, passphrases, and private keys are resolved on the extension host through
PasswordManagerand authentication helpers. Device and bastion secrets are stored separately, and reuse across workspaces is mediated with metadata and user confirmation.Session lifecycle management. Log sessions, terminal sessions, command-runner connections, SFTP clients, tunnels, and auto-save streams are all explicitly disposed when panels close or operations end. Errors are surfaced back to the UI instead of being silently ignored.
Bastion and endpoint support. Connection helpers support optional bastion tunnelling and secondary-host fallback so remote features can follow the same trusted endpoint model instead of each feature reimplementing its own connection rules.
Webview security
Content‑Security‑Policy (CSP). The webviews for both the log panel and sidebar set a strict CSP:
default-src 'none',script-src 'nonce‑…'andstyle-srclimited to the extension’s own origin. No external scripts or inline scripts are allowed. The script tag includes a random nonce generated withgetNonce()to prevent injection attacks.Safe HTML rendering. Log lines and user‑supplied highlight keys are inserted into the DOM using
createTextNodeor by settingtextContent. Highlight markers are built by splitting text and wrapping matches in<span>elements, never viainnerHTML. This design avoids cross‑site scripting (XSS) even when log lines contain HTML or markup.User interaction isolation. The sidebar view uses a nonce‑restricted script and a strict CSP. Inputs for highlight keywords are treated purely as text and not executed, and highlight colours come from a fixed palette, preventing CSS injection.
Logging and file operations
Controlled file access. When exporting logs or starting auto‑save, the extension prompts the user via
showSaveDialogto pick a destination file. It writes logs using VS Code’sworkspace.fs.writeFileor Node’sfs.createWriteStream, and errors are reported to the webview.Line limit enforcement. The log panel enforces
embeddedLogger.maxLinesPerTab(100000 by default) to keep long-running sessions bounded in memory and in the DOM.State persistence with sanitization. Presets, highlights, and SFTP path presets are stored only after normalization or sanitization, which reduces bad state carrying forward across sessions.
Keeping dependencies up-to-date
The extension depends on the ssh2 library. To ensure that this dependency is regularly updated to receive security patches, the dependency-bot is enabled in the repository. Also for every compilation, by default it is run npm audit to show the developer any new known vulnerability that needs to be fixed.
Code Overview
This document explains how the VSCode-Logger extension streams logs from embedded Linux devices into Visual Studio Code. It covers the activation lifecycle, major components, data flows between the extension host and the Webviews, and key configuration and security considerations.
Activation and configuration
Activation trigger: The extension activates when VS Code loads the workspace or when a contributed view or command is invoked.
Configuration resolution: Devices come from
embeddedLogger.devices, groups come fromembeddedLogger.groups, and device defaults are enriched fromembeddedLogger.defaultPort,embeddedLogger.defaultLogCommand,embeddedLogger.defaultEnableSshTerminal,embeddedLogger.defaultEnableSftpExplorer,embeddedLogger.defaultEnableWebBrowser,embeddedLogger.defaultEnableEmbeddedWebBrowser,embeddedLogger.defaultSshCommands, andembeddedLogger.maxLinesPerTab.Per-device overrides: Device fields such as
showDefaultSshCommands,enableSshTerminal,enableSftpExplorer, browser flags, SFTP presets, secondary hosts, colors, and bastion settings override or extend those defaults.Legacy migration: During activation, legacy plaintext passwords and passphrases are migrated into VS Code Secret Storage, and legacy workspace-state SFTP presets are migrated into
embeddedLogger.deviceswhen possible.View and command registration: Activation registers the tree view, the devices Webview, Device Manager commands, local-log opening, SSH command and terminal handlers, SFTP explorer handlers, browser actions, and
embeddedLogger.openDeviceso selecting a device opens or reuses its log panel.
Major components
Configuration helpers (
src/configuration.ts): Centralize reading extension settings, applying defaults, resolving groups, sanitizing SFTP presets, merging shared SSH commands, and surfacing the max-lines limit.Device tree (
src/deviceTree.ts): Supplies the Activity Bar tree view, including collapsible groups and per-device color icons.Sidebar view (
src/sidebarView.ts+media/sidebarView.*): Renders the devices Webview with grouped cards and quick actions for logs, SSH commands, SSH terminal, SFTP explorer, and browser actions.Device Manager (
src/deviceManagerPanel.ts+media/deviceManager.*): Provides a table-style configuration editor for defaults, groups, devices, import/export, JSON editing, and password cleanup.Password manager (
src/passwordManager.ts): Encapsulates storage, retrieval, migration, reuse, and cleanup of device and bastion passwords or private-key passphrases.Log panel host (
src/logPanel/):logPanel.tscreates a Webview panel per remote or local log source, injects assets viahtml.ts, validates inbound Webview messages withmessageParser.ts, persists presets and highlights throughstateStore.ts, and manages auto-save streams throughautoSaveManager.ts. It owns aLogSessionfor remote devices.LogSessionpipeline (src/logSession/):logSession.tsorchestrates streaming usingauthenticationProvider.ts(secrets and key loading),connectionManager.ts(SSH clients, channels, stream lifecycle),hostKeyVerifier.tsandfingerprintPersistence.ts(verification and capture), andreconnectionController.ts(retry strategy).SSH helpers (
src/sshCommandRunner.ts,src/sshTerminal.ts): Execute one-off SSH commands from the devices view or spawn an interactive SSH terminal using the same validation and authentication pipeline as log streaming.SFTP explorer (
src/sftpExplorer.ts+media/sftpExplorer.*): Hosts the dual-pane file explorer, transfers, permissions editing, quick search, path presets, and integrated terminal or run actions while reusing device authentication and bastion support.Webview clients (
media/loggerPanel/,media/loggerPanel.css): TheloggerPanel.jsentrypoint composesstate.js,rendering.js, andmessaging.jsto parse severity, apply filters and highlights, manage bookmarks and presets, enforce the max-lines cap, and render the terminal-like UI for both remote and local logs.
Data and control flow
graph TD
A[Extension activation] --> B[getEmbeddedLoggerConfiguration + groups]
B --> C[Register views, Device Manager, and commands]
C --> D[Devices tree + Devices Webview]
C --> R[Device Manager]
R -- Save/import configuration --> B
D -- Open device logs --> E[Create LogPanel]
D -- Run SSH command --> M[SshCommandRunner executes via ssh2]
D -- Open SSH terminal --> N[Create terminal using SshTerminalSession]
D -- Open SFTP explorer --> S[SftpExplorerPanel]
C -- Open local log file --> Q[Create local LogPanel]
E --> F["Start LogSession for remote devices"]
F --> G[Fetch credentials from Secret Storage or prompt]
G --> H[Resolve endpoint, verify host key, connect via ssh2]
H --> I[Run logCommand]
I --> J[Stream stdout/stderr data]
J --> K[Parse lines, levels, highlights, bookmarks in loggerPanel.js]
K --> L[Apply filters, presets, max-line cap, and formatting]
L --> O[Render log entries and statuses in Webview]
O -- Export/preset/bookmark requests --> P[Extension persists workspace state or writes file]
S --> T[Browse files, transfer data, save presets]
Q --> O
F -- Status updates --> O
High-level design and data flow
The extension follows a configuration -> device selection -> credential resolution -> connection -> stream or remote action -> Webview pipeline. The extension host owns SSH operations and file access, while Webviews render UI state and request actions through message passing. Each class has a narrowly scoped role to keep concerns separated:
configurationresolves user settings, groups, defaults, shared SSH commands, SFTP presets, and max log limits into normalized devices.passwordManagermediates secret storage and prompts, ensuring credentials are not persisted in Webviews or kept in plaintext settings.logSessionowns the SSH client lifecycle for streaming logs, endpoint rotation, host-key validation, fingerprint persistence, and reconnect behavior.logPanelbridges the extension host and the log-viewer Webview for both remote devices and local files, wiring callbacks for presets, exports, auto-save, bookmarks, and highlights.deviceTreeandsidebarViewexpose configured devices and their actions in tree and Webview form.deviceManagerPanelprovides schema-aware editing, import/export, and save flows for the current configuration model.sshCommandRunnerexecutes sanitized one-off commands with the same credential and endpoint model used elsewhere.sshTerminalprovides an interactive pseudoterminal session with the same authentication and host-key guarantees.sftpExplorerprovides a dual-pane file workflow built on the same device identity, secret handling, and bastion support.Webview clients (
loggerPanel.js,sidebarView.js,deviceManager.js,sftpExplorer.js) manage UI state and issue explicitpostMessagerequests back to the extension host.
Data flow: device configuration to Webview rendering
sequenceDiagram
participant User
participant VSCode as VS Code Settings
participant Config as configuration.ts
participant DeviceViews as deviceTree.ts / sidebarView.ts
participant LogPanel as logPanel.ts
participant Session as logSession.ts
participant Secrets as passwordManager.ts
participant SSH as ssh2 Client
participant Webview as loggerPanel.js
User->>VSCode: Configure embeddedLogger.groups / embeddedLogger.devices
VSCode-->>Config: Provide settings with defaults
Config-->>DeviceViews: Normalized groups and devices
User->>DeviceViews: Select device (open panel)
DeviceViews->>LogPanel: Request panel for device
LogPanel->>Session: Start log session
Session->>Secrets: Retrieve credentials (prompt or secret store)
Secrets-->>Session: Password/passphrase/private key
Session->>SSH: Connect (endpoint resolution + host-key verification)
SSH-->>Session: Secure channel ready
Session->>SSH: Execute logCommand
SSH-->>Session: Stream stdout/stderr chunks
Session-->>LogPanel: Emit complete log lines + statuses
LogPanel-->>Webview: postMessage lines, statuses, presets, highlights
Webview-->>User: Rendered logs, filters, highlights, bookmarks
Log streaming sequence (status + reconnection aware)
sequenceDiagram
participant User
participant Panel as LogPanel
participant Session as LogSession
participant Secrets as PasswordManager
participant SSH as ssh2 Client
participant Webview as loggerPanel.js
User->>Panel: Open device panel
Panel->>Session: create(device)
Session->>Secrets: getSecret(device)
Secrets-->>Session: credentials or prompt result
Session->>SSH: connect(host, port, auth, hostVerifier)
SSH-->>Session: ready or error
Session-->>Panel: onStatus("connecting"/"streaming")
Panel-->>Webview: postMessage(status)
Session->>SSH: exec(logCommand)
SSH-->>Session: data chunks
Session-->>Panel: onData(lines)
Panel-->>Webview: postMessage(logEntries)
alt disconnect/error
Session-->>Panel: onError(reason)
Panel-->>Webview: postMessage(error)
Session-->>Session: schedule reconnect with backoff
end
User->>Panel: Close panel
Panel->>Session: dispose()
Session->>SSH: end()
SSH command execution sequence
sequenceDiagram
participant User
participant Sidebar as SidebarView (Webview)
participant Extension as extension.ts
participant Runner as SshCommandRunner
participant Secrets as PasswordManager
participant SSH as ssh2 Client
User->>Sidebar: Click configured command
Sidebar-->>Extension: postMessage(runCommand)
Extension->>Runner: run(device, command)
Runner->>Secrets: getSecret(device)
Secrets-->>Runner: credentials
Runner->>SSH: connect(host, port, auth, hostVerifier)
SSH-->>Runner: ready
Runner->>SSH: exec(sanitizedCommand)
SSH-->>Runner: stdout/stderr
Runner-->>Extension: resolved output/errors
Extension-->>User: showInformationMessage / showErrorMessage
SSH connection flow (primary/secondary hosts, bastion, and secret retrieval)
flowchart LR
A[Device config] -->|defaults applied| B[Normalized device]
B --> C{Bastion configured?}
C -- Yes --> D["Build bastion client config (host, port, username, fingerprint)"]
D --> E[Retrieve bastion secret via PasswordManager]
E --> F[Open SSH tunnel to bastion]
F --> G[Forward connection to target host/port]
C -- No --> H[Direct target client config]
B --> H
H --> I[Resolve primary or secondary endpoint]
I --> J[Retrieve target secret via PasswordManager]
J --> K[Connect ssh2 client with hostVerifier]
K --> L{Connection established?}
L -- Yes --> M[Run logCommand or device command]
L -- No --> N[Surface error and retry/backoff]
M --> O[Stream stdout/stderr]
O --> P[Emit status/data to logPanel]
P --> Q["Render in Webview (loggerPanel.js)"]
Lifecycle details
Panel creation: Each remote device or imported local log file opens in its own log Webview panel. Existing panels are reactivated instead of duplicated when the same source is selected again.
Session management:
LogSessiontracks connection lifecycle events such as connecting, streaming, disconnecting, reconnect countdowns, and errors. SSH resources are disposed when panels close or the extension deactivates.Back-pressure handling: Incoming data is buffered until complete lines are available so log entries are not split mid-line.
Presets, filters, highlights, and bookmarks: Presets and highlights are stored per log target in workspace state keyed by device ID or local source ID. Filtering, search state, bookmark navigation, and highlight rendering live in the Webview state so the UI restores cleanly.
Exports, auto-save, and local files: The Webview requests exports only for currently visible lines. The extension host handles save dialogs, file writes, local-file refresh, and source-file open requests.
Configuration changes: When
embeddedLoggersettings change, the devices tree and devices Webview refresh with updated devices, groups, defaults, and commands. Active log panels continue using their existing session until reopened or reconnected.Security boundaries: Secrets stay in secret storage or transient prompts, SSH and file operations stay in extension-host code, and Webviews remain limited to rendering and explicit message passing.
Extending the Current Design
For the current architecture, these are the safest extension points:
add new device fields in
src/deviceTree.tsand normalize them insrc/configuration.tsadd new Device Manager controls in
src/deviceManagerPanel.tsandmedia/deviceManager.*add new Devices view actions in
src/sidebarView.tsandmedia/sidebarView.jsadd new log-panel backend behavior in
src/logPanel/logPanel.tsadd new log-panel UI behavior in
media/loggerPanel.*add new SSH connection behavior inside
src/logSession/extend SFTP behavior in
src/sftpExplorer.ts
Keep extension-host logic in src/ and DOM/state logic in media/. That separation is still the clearest architectural boundary in the current codebase.