Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Introduction

socktop is a TUI-first remote system monitor built with Rust. Two components:

  • socktop (TUI Client) - A terminal-based user interface for viewing system metrics
  • socktop_agent - A lightweight background service that collects and serves system metrics over WebSocket

Features

  • TUI built with ratatui, Catppuccin Frappe theme
  • CPU: overall sparkline + per-core bars, accurate per-process CPU% (normalized 0-100%)
  • Memory/Swap gauges
  • Disks: per-device usage
  • Network: per-interface throughput with sparklines
  • Temperatures: CPU (optional)
  • Process list: fuzzy search, sortable by CPU% or memory, scrollable
  • Process details: command line, working directory, per-thread CPU, journal entries
  • Kill local processes from the TUI (Terminate / Force kill, with confirmation)
  • Optional GPU metrics
  • Compact layout for small terminal windows (automatic, or pinned with --compact)
  • Remote monitoring via WebSocket (JSON over WS)
  • Optional WSS (TLS): agent auto-generates self-signed cert on first run, client pins cert via –tls-ca/-t
  • Optional auth token
  • Connection profiles for quick access to saved hosts
  • Built-in demo mode (–demo)

Architecture

socktop uses a client-server architecture:

┌─────────────────┐         WebSocket          ┌──────────────────┐
│                 │ ◄────────────────────────► │                  │
│  socktop (TUI)  │    (with TLS optional)     │  socktop-agent   │
│     Client      │                            │   (Background)   │
│                 │                            │                  │
└─────────────────┘                            └──────────────────┘
        │                                               │
        │                                               │
        ▼                                               ▼
  User Terminal                                  System Metrics
  Local or Remote                                (sysinfo crate)

The agent runs on each system you want to monitor, collecting metrics using the sysinfo crate. The client connects to one or more agents to display real-time system information.

Quick Demo

socktop --demo

Spins up a temporary local agent on port 3231 and connects to it. Stops automatically when you quit.

Use Cases

  • Remote server monitoring
  • Homelab / Raspberry Pi cluster monitoring
  • Development / testing resource usage
  • Custom dashboards via socktop_connector library

Project Status

socktop is actively maintained and used in production environments. The project follows semantic versioning and maintains backward compatibility within major versions.

  • Current Version: 1.60.x — see GitHub Releases for release notes
  • Supported Platforms: Linux (amd64, arm64, armhf, riscv64), Windows, macOS (client) — see Platform Notes
  • License: MIT

Wire changes between versions are additive: mixed client/agent versions keep working during rollouts.

Community and Support

Next Steps

See Quick Start for installation.

Quick Start

Installation Methods

socktop can be installed via APT (Debian/Ubuntu), Cargo, or built from source.

Debian/Ubuntu installation:

# Add the repository's GPG signing key
curl -fsSL https://jasonwitty.github.io/socktop/KEY.gpg | \
    sudo gpg --dearmor -o /usr/share/keyrings/socktop-archive-keyring.gpg

# Add the APT repository
echo "deb [signed-by=/usr/share/keyrings/socktop-archive-keyring.gpg] https://jasonwitty.github.io/socktop stable main" | \
    sudo tee /etc/apt/sources.list.d/socktop.list

# Update the package list
sudo apt update

# Install socktop and the agent
sudo apt install socktop socktop-agent

# Enable the agent service
sudo systemctl enable --now socktop-agent

Then connect to it: socktop ws://localhost:3000/ws — or to any remote agent by hostname.

Option 2: Cargo Installation

Install from crates.io:

# Install GPU support libraries (see Prerequisites for other distros)
sudo apt install libdrm-dev libdrm-amdgpu1

# Install the TUI client
cargo install socktop

# Install the agent
cargo install socktop_agent

# Run the agent manually or set up as a service (see Agent Service Setup)
socktop_agent

Demo Mode

Test socktop without setting up an agent:

# If you have socktop installed
socktop --demo

# Or just run socktop with no arguments and select 'demo' from the interactive menu
socktop

This spins up a temporary local agent on port 3231, connects to it, and stops when you quit (Ctrl-C or q).

Usage

# Quick demo (no agent setup needed)
socktop --demo

# Connect to an agent (local or remote) — note the /ws path
socktop ws://localhost:3000/ws
socktop ws://hostname:3000/ws

# Or run socktop with no arguments to pick a saved profile interactively
socktop

The TUI displays system metrics in real-time.

Interactive Profile Selection

If you run socktop with no arguments, you’ll see an interactive menu:

Select profile:
  1. prod
  2. dev-server
  3. demo
Enter number (or blank to abort): 
  • Choose a numbered profile to connect to a saved server
  • Select demo to launch demo mode (always available)
  • Press Enter on blank to abort

Monitoring Remote Systems

To monitor a remote system:

  1. Install the agent on the target system (using APT or Cargo)
  2. Start the agent on the remote system:
    # Via systemd (APT install)
    sudo systemctl start socktop-agent
    
    # Or manually
    socktop_agent
    
  3. Connect from your client:
    socktop ws://remote-hostname:3000/ws
    

Save frequently used connections as profiles. See Connection Profiles.

Prerequisites

Supported Operating Systems

  • Debian 10+
  • Ubuntu 20.04+
  • Arch Linux (latest)
  • Fedora 35+
  • Raspberry Pi OS
  • Other Linux distributions with kernel 4.15+
  • Windows 10+ (binaries available in build artifacts)
  • macOS (client; the agent runs but is primarily targeted at Linux)

See Platform Notes for platform-specific details.

Supported Architectures

  • amd64 (x86_64)
  • arm64 (aarch64) - Raspberry Pi 4, AWS Graviton
  • armhf (ARMv7) - Raspberry Pi 3
  • riscv64 (experimental)

Software Dependencies

GPU support requires additional libraries (x86_64 and aarch64 only):

Debian/Ubuntu/Raspberry Pi OS:

sudo apt update
sudo apt install libdrm-dev libdrm-amdgpu1

Fedora:

sudo dnf install libdrm-devel libdrm-amdgpu

On ARMv7 (32-bit) and RISC-V, GPU support is not available — build the agent with --no-default-features:

cargo build --release -p socktop_agent --no-default-features

For Cargo Installation

1. Rust Toolchain

A current stable Rust toolchain is required (the crates use the 2024 edition, so Rust 1.85+).

# Install Rust via rustup (recommended)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

# Verify installation
rustc --version
cargo --version

# Update if needed
rustup update

2. Build Dependencies

Debian/Ubuntu:

sudo apt install build-essential pkg-config libssl-dev libdrm-dev libdrm-amdgpu1

Fedora:

sudo dnf install gcc pkg-config openssl-devel libdrm-devel libdrm-amdgpu

Arch Linux:

sudo pacman -S base-devel openssl libdrm

Install via Cargo

Installing socktop via Cargo gives you access to the latest version and works on any Linux distribution with Rust installed.

Prerequisites

Before installing via Cargo, ensure you have:

  • Current stable Rust (1.85+, 2024 edition) - Install via rustup
  • Build dependencies - See Prerequisites for details
  • GPU support libraries (x86_64/aarch64):
    # Debian/Ubuntu
    sudo apt install libdrm-dev libdrm-amdgpu1
    # Fedora
    sudo dnf install libdrm-devel libdrm-amdgpu
    

Installation

Installing the TUI Client

cargo install socktop

This will download, compile, and install the socktop binary to ~/.cargo/bin/. Make sure this directory is in your PATH.

Installing the Agent

cargo install socktop_agent

This installs the socktop_agent binary to ~/.cargo/bin/.

cargo install socktop socktop_agent

Verify Installation

Check that the binaries are installed correctly:

# Check socktop client
socktop --version

# Check socktop agent
socktop_agent --version

You should see output like:

socktop 1.60.1

First Run

Start the Agent

Start the agent in a separate terminal or background process:

# Run in foreground (for testing)
socktop_agent

# Run in background
socktop_agent &

# Or on a custom port
socktop_agent --port 3000

Connect with the Client

In another terminal, connect to the agent:

socktop ws://localhost:3000/ws

Or just try demo mode (starts and stops its own local agent):

socktop --demo

Configuration

The agent is configured with a small set of flags (--port/-p, --enableSSL) and environment variables (SOCKTOP_TOKEN, SOCKTOP_AGENT_GPU=0, …). The client connects by URL or saved profile:

# Remote connection
socktop ws://192.168.1.100:3000/ws

# Secure connection with a pinned certificate
socktop --tls-ca /path/to/cert.pem wss://secure-host:8443/ws

# Using a connection profile
socktop -P my-server

See Configuration for the complete reference and Connection Profiles for profiles.

System-wide agent (Linux)

# If you installed with cargo, binaries are in ~/.cargo/bin
sudo install -o root -g root -m 0755 "$HOME/.cargo/bin/socktop_agent" /usr/local/bin/socktop_agent

# Install and enable the systemd service (example unit in docs/)
sudo install -o root -g root -m 0644 docs/socktop-agent.service /etc/systemd/system/socktop-agent.service
sudo systemctl daemon-reload
sudo systemctl enable --now socktop-agent

Install via APT

The easiest way to install socktop on Debian and Ubuntu systems is through the official APT repository.

Supported Systems

The APT repository supports:

  • Debian 10+ (Buster and newer)
  • Ubuntu 20.04+ (Focal and newer)
  • Raspberry Pi OS (Debian-based)
  • Other Debian derivatives

Supported Architectures

  • amd64 (x86_64)
  • arm64 (aarch64)
  • armhf (ARMv7)
  • riscv64 (experimental)

Installation

Step 1: Add GPG Signing Key

First, add the repository’s GPG signing key to verify package authenticity:

curl -fsSL https://jasonwitty.github.io/socktop/KEY.gpg | \
    sudo gpg --dearmor -o /usr/share/keyrings/socktop-archive-keyring.gpg

This ensures that packages are cryptographically verified before installation.

Step 2: Add APT Repository

Add the socktop repository to your system’s sources list:

echo "deb [signed-by=/usr/share/keyrings/socktop-archive-keyring.gpg] https://jasonwitty.github.io/socktop stable main" | \
    sudo tee /etc/apt/sources.list.d/socktop.list

Step 3: Update Package Lists

Refresh your package cache to include the new repository:

sudo apt update

Step 4: Install Packages

Install socktop and the agent:

# Install both client and agent
sudo apt install socktop socktop-agent

# Or install individually
sudo apt install socktop        # TUI client only
sudo apt install socktop-agent  # Agent only

Automatic Service Setup

The APT package automatically configures the agent as a systemd service, but it’s not enabled by default.

Enable and Start the Agent

# Enable the service to start at boot
sudo systemctl enable socktop-agent

# Start the service now
sudo systemctl start socktop-agent

# Or do both in one command
sudo systemctl enable --now socktop-agent

Check Service Status

# View service status
sudo systemctl status socktop-agent

# View service logs
sudo journalctl -u socktop-agent -f

# View recent logs
sudo journalctl -u socktop-agent -n 50

Control the Service

# Stop the service
sudo systemctl stop socktop-agent

# Restart the service
sudo systemctl restart socktop-agent

# Disable auto-start
sudo systemctl disable socktop-agent

Agent Service Setup

APT Installation

If you installed via APT, the service is already configured:

sudo systemctl enable --now socktop-agent

Cargo Installation

System-wide agent setup:

# If you installed with cargo, binaries are in ~/.cargo/bin
sudo install -o root -g root -m 0755 "$HOME/.cargo/bin/socktop_agent" /usr/local/bin/socktop_agent

# Install and enable the systemd service (example unit in docs/)
sudo install -o root -g root -m 0644 docs/socktop-agent.service /etc/systemd/system/socktop-agent.service
sudo systemctl daemon-reload
sudo systemctl enable --now socktop-agent

Enable SSL

# Stop service
sudo systemctl stop socktop-agent

# Edit service to append SSL option and port
sudo nano /etc/systemd/system/socktop-agent.service

# Change ExecStart line to:
# ExecStart=/usr/local/bin/socktop_agent --enableSSL --port 8443

# Reload
sudo systemctl daemon-reload

# Restart
sudo systemctl start socktop-agent

# Check logs for certificate location
sudo journalctl -u socktop-agent -f

# Example output:
# Aug 22 22:25:26 rpi-master socktop_agent[2913998]: socktop_agent: generated self-signed TLS certificate at /var/lib/socktop/.config/socktop_agent/tls/cert.pem

Configuration

Agent configuration via command-line flags or environment variables:

Port:

  • Flag: --port 8080 or -p 8080
  • Env: SOCKTOP_PORT=8080

TLS (self-signed):

  • Enable: --enableSSL
  • Default TLS port: 8443 (override with --port/-p)
  • Certificate/Key location (created on first TLS run):
    • Linux (XDG): $XDG_CONFIG_HOME/socktop_agent/tls/{cert.pem,key.pem} (defaults to ~/.config)
    • The agent prints these paths on creation
    • Note: when running as the packaged service, the service user’s home is /var/lib/socktop, so certs land under /var/lib/socktop/.config/socktop_agent/tls/

Auth token (optional): SOCKTOP_TOKEN=changeme

Disable GPU metrics: SOCKTOP_AGENT_GPU=0

Disable CPU temperature: SOCKTOP_AGENT_TEMP=0

See Configuration for the complete reference, including tuning variables.

Journal Access (Process Details)

The process-details view can show recent journal entries for a process. The agent reads them with journalctl, so it needs permission to read the system journal. If it can’t, the TUI shows a journal-access notice instead of entries (rather than a misleading “no entries”).

The packaged service runs as the socktop user. To grant journal access:

sudo usermod -aG systemd-journal socktop
sudo systemctl restart socktop-agent

An agent run ad hoc as your own user can typically only read your user journal; run it as a service (or as a user in the systemd-journal group) to see entries for system services.

Managing the Service

Basic Commands

# Start the service
sudo systemctl start socktop-agent

# Stop the service
sudo systemctl stop socktop-agent

# Restart the service
sudo systemctl restart socktop-agent

# Reload configuration (if supported)
sudo systemctl reload socktop-agent

# View service status
sudo systemctl status socktop-agent

# Enable auto-start on boot
sudo systemctl enable socktop-agent

# Disable auto-start on boot
sudo systemctl disable socktop-agent

# Enable and start in one command
sudo systemctl enable --now socktop-agent

Logs

# Follow live logs
sudo journalctl -u socktop-agent -f

# View recent logs
sudo journalctl -u socktop-agent -n 50

Status

# Check status
sudo systemctl status socktop-agent --no-pager

# Is the service running?
sudo systemctl is-active socktop-agent

Updating

See Upgrading.

Upgrading

This guide covers upgrading socktop and socktop_agent to newer versions.

Upgrade Order

Mixed versions keep working during rollouts (wire changes are additive), but two things set the order:

  • Upgrade clients first where you use TLS. Versions before 1.60 did not actually enforce certificate pinning — any server certificate was accepted. The fix is client-side.
  • Upgrade agent and client together on machines where you use the process kill feature — older agents keep reporting dead processes, so killed rows would linger on screen.

Upgrading via APT

Standard Upgrade

The easiest method - upgrade through normal system updates:

# Update package lists
sudo apt update

# Upgrade socktop packages
sudo apt upgrade socktop socktop-agent

# Or upgrade entire system
sudo apt upgrade

The service will automatically restart after the upgrade.

Verify Upgrade

# Check new versions
socktop --version
socktop_agent --version

# Check service status
sudo systemctl status socktop-agent

Tip: if socktop --version still shows the old version after upgrading, an older copy in ~/.cargo/bin may be shadowing the new one on your PATH. Check with type -a socktop and remove the stale copy (then hash -r in bash). Also note a long-running agent keeps serving its old behavior until restarted — restart the service after any upgrade.

Upgrading via Cargo

Update from crates.io

# Update client
cargo install socktop --force

# Update agent
# on the server running the agent
cargo install socktop_agent --force
sudo systemctl stop socktop-agent
sudo install -o root -g root -m 0755 "$HOME/.cargo/bin/socktop_agent" /usr/local/bin/socktop_agent
# if you changed the unit file:
# sudo install -o root -g root -m 0644 docs/socktop-agent.service /etc/systemd/system/socktop-agent.service
# sudo systemctl daemon-reload
sudo systemctl start socktop-agent
sudo systemctl status socktop-agent --no-pager
# logs:
# journalctl -u socktop-agent -f

Platform Notes

Linux

Fully supported — agent and client, amd64 and arm64. This is the primary platform.

Raspberry Pi

  • 64-bit (Raspberry Pi OS 64-bit, Ubuntu): aarch64-unknown-linux-gnu — full support including the APT packages.
  • 32-bit (ARMv7): armv7-unknown-linux-gnueabihf — supported, but GPU metrics are not available; when building from source, build the agent with --no-default-features.

Kernel tip: update to kernel 6.6 or newer if you can. The agent uses considerably less CPU on newer kernels — on a Pi 4 under continuous polling, roughly 0.8 of a core before 6.6 versus 0.2 after (idle usage is 0 either way).

Windows

  • Client and agent build with stable Rust and the MSVC toolchain (install Visual Studio Build Tools).
  • Prebuilt .exe binaries for both are available in the build artifacts under GitHub Actions.
  • CPU temperature may be unavailable.

macOS

  • The client works well — build or cargo install as on Linux.
  • The agent runs fine for local use and debugging, but it is primarily targeted at Linux; running it as a launchd service is not documented.

RISC-V (experimental)

  • riscv64 builds from source; install your distribution’s protobuf-compiler package first.
  • No GPU support — build the agent with --no-default-features.

Cross-Compiling

To build agent binaries for Raspberry Pi or other ARM devices from a faster machine, see the cross-compilation guide (Linux, macOS, or Windows hosts).

General Usage

Starting socktop

Demo Mode

Try socktop without any setup:

# Launch demo mode
socktop --demo

Starts a temporary local agent on port 3231, connects to it, and monitors your local system. The agent stops when you quit (you’ll see “Stopped demo agent on port 3231”). Demo mode needs the socktop_agent binary on your PATH; if it’s missing, socktop explains how to install it.

Interactive Mode

Run socktop with no arguments to see an interactive profile menu (if you have saved profiles):

Select profile:
  1. prod
  2. dev-server
  3. demo
Enter number (or blank to abort):

Select a number to connect, or choose demo (always available). Press Enter on blank to abort.

Monitor a Remote System

Connect to a remote agent by specifying the WebSocket URL (note the /ws path):

socktop ws://hostname:3000/ws
socktop ws://192.168.1.100:3000/ws
socktop --tls-ca /path/to/cert.pem wss://secure-host:8443/ws  # With TLS

Using Connection Profiles

For frequently monitored systems, use profiles:

# Use a saved profile
socktop -P production-server
socktop --profile rpi-cluster-01

Running socktop with no arguments lists your saved profiles interactively. See Connection Profiles.

Finding Processes

Press / to enter filter mode:

Filter: pyth_

This shows only processes matching “pyth” (fuzzy, case-insensitive). Press Esc to cancel or Enter to apply; c clears an applied filter.

Select a process with ↑/↓ and press Enter to open the details view (command line, working directory, per-thread CPU, journal entries, and more).

Killing a Process

With a process selected in the list (or from inside Process Details), press t to terminate it. A confirmation dialog offers two actions, btop-style:

  • Terminate - sends SIGTERM, letting the process shut down cleanly
  • Force kill - sends SIGKILL

Things to know:

  • Local agents only. The signal is sent by the socktop client itself, with its own privileges — it is never sent over the wire. When you’re connected to a remote agent, the option doesn’t appear, and an agent can never be instructed to kill anything remotely.
  • Your privileges apply. You can only kill processes your user could kill from the shell.
  • PID-reuse guard. If the PID has been recycled to a different process between confirmation and signal time, nothing is sent.
  • Killed rows leave the list once the process actually exits.
  • Requires agent and client 1.60 or newer together on the machine where you use it — older agents keep reporting dead processes, so killed rows would linger on screen.

Compact Layout

On small terminal windows, socktop automatically switches to a compact layout: the Disks pane is dropped, Memory/Swap sit side by side, and GPU collapses to a single line — keeping the CPU graph and per-core bars visible. Pass --compact to pin this layout regardless of window size.

Command Line Options

socktop [--tls-ca CERT_PEM|-t CERT_PEM] [--verify-hostname] [--profile NAME|-P NAME]
        [--save] [--demo] [--compact] [--metrics-interval-ms N]
        [--processes-interval-ms N] [ws://HOST:PORT/ws]

See Configuration for the full option reference, and Keyboard and Mouse Controls for all key bindings.

Examples

# Connect with custom intervals
socktop --metrics-interval-ms 750 --processes-interval-ms 3000 ws://server:3000/ws

# Connect with an authentication token (query parameter, quoted)
socktop "ws://server:3000/ws?token=mySecretToken"

# Connect with TLS, pinning the agent's certificate
socktop --tls-ca /path/to/cert.pem wss://server:8443/ws

# Connect with TLS and strict hostname verification
socktop --tls-ca /path/to/cert.pem --verify-hostname wss://server:8443/ws

# Pin the compact layout
socktop --compact -P rpi-cluster-01

Connection Profiles

Connection profiles allow you to save frequently used agent connections for quick access.

What are Connection Profiles?

Instead of typing the full WebSocket URL every time:

socktop ws://production-server.example.com:3000/ws

You can save it as a profile and use:

socktop -P production

Profile Configuration File

Profiles are stored in ~/.config/socktop/profiles.json (or $XDG_CONFIG_HOME/socktop/profiles.json).

Basic Profile Format

{
  "profiles": {
    "production": {
      "url": "ws://production-server:3000/ws"
    },
    "dev": {
      "url": "ws://dev-server:3000/ws"
    },
    "rpi": {
      "url": "ws://192.168.1.100:3000/ws"
    }
  },
  "version": 0
}

Profile with Authentication

{
  "profiles": {
    "secure-server": {
      "url": "wss://secure.example.com:3000/ws?token=your-secret-token-here"
    }
  },
  "version": 0
}

Note: Tokens are passed as query parameters in the URL.

Profile with TLS Configuration

{
  "profiles": {
    "tls-server": {
      "url": "wss://tls-server.example.com:8443/ws",
      "tls_ca": "/path/to/cert.pem"
    }
  },
  "version": 0
}

Profile with All Options

{
  "profiles": {
    "full-config": {
      "url": "wss://example.com:8443/ws?token=secret-token",
      "tls_ca": "/etc/socktop/cert.pem",
      "metrics_interval_ms": 750,
      "processes_interval_ms": 3000
    }
  },
  "version": 0
}

Note: Custom intervals are optional. Values below 100ms (metrics) or 200ms (processes) are clamped.

Creating Profiles

Method 1: Manual Creation

Create or edit the profiles file:

mkdir -p ~/.config/socktop
nano ~/.config/socktop/profiles.json

Add your profiles:

{
  "profiles": {
    "homelab": {
      "url": "ws://192.168.1.50:3000/ws"
    },
    "cloud-server": {
      "url": "wss://cloud.example.com:8443/ws?token=abc123xyz",
      "tls_ca": "/home/user/.config/socktop/cloud-cert.pem"
    }
  },
  "version": 0
}

Method 2: Automatic Profile Creation

When you specify a new --profile/-P name with a URL (and optional --tls-ca), it’s saved automatically:

# First connection creates and saves the profile
socktop --profile prod ws://prod-host:3000/ws

# With TLS pinning
socktop --profile prod-tls --tls-ca /path/to/cert.pem wss://prod-host:8443/ws

# With custom intervals
socktop --profile fast --metrics-interval-ms 250 --processes-interval-ms 1000 ws://host:3000/ws

To overwrite an existing profile without prompt, use --save:

socktop --profile prod --save ws://new-host:3000/ws

Using Profiles

Basic Usage

# Use a saved profile
socktop -P production
socktop --profile homelab

Keyboard and Mouse Controls

Keyboard

Global

  • Quit: q or Esc
  • About: a
  • Help: h

Processes

  • / - Start fuzzy search
  • c - Clear search filter
  • ↑/↓ - Navigate
  • Enter - Open details
  • t - Terminate selected process (local agents only; opens a Terminate / Force kill confirmation — see Killing a Process)
  • x - Clear selection

Search (after /)

  • Type - Enter query (fuzzy match)
  • ↑/↓ - Navigate results
  • Esc - Cancel
  • Enter - Apply filter

CPU Per-Core

  • ←/→ - Scroll cores
  • PgUp/PgDn - Page up/down
  • Home/End - Jump to first/last

Process Details

  • x - Close
  • p - Navigate to parent
  • t - Terminate this process (local agents only)
  • j/k - Scroll threads ↓/↑
  • d/u - Scroll threads (10 lines)
  • [ / ] - Scroll journal
  • Esc/Enter - Close
  • Tab/→ - Next button
  • Shift+Tab/← - Previous button
  • Enter - Confirm
  • Esc - Cancel

Mouse (Processes pane)

  • Click “CPU %” to sort by CPU descending
  • Click “Mem” to sort by memory descending
  • Mouse wheel: scroll
  • Drag scrollbar: scroll
  • Arrow/PageUp/PageDown/Home/End: scroll

Configuration

This page is the complete reference for configuring the socktop client and agent. Every option listed here exists in the current release — if an option isn’t listed, it isn’t supported.

Client Configuration

Command-Line Options

socktop [--tls-ca CERT_PEM|-t CERT_PEM] [--verify-hostname] [--profile NAME|-P NAME]
        [--save] [--demo] [--compact] [--metrics-interval-ms N]
        [--processes-interval-ms N] [ws://HOST:PORT/ws]
OptionDescription
--tls-ca <FILE>, -t <FILE>Pin the agent’s TLS certificate (PEM). Auto-upgrades ws:// to wss://. See TLS Configuration
--verify-hostnameEnable strict hostname/SAN verification instead of certificate pinning
--profile <NAME>, -P <NAME>Use (or create) a saved connection profile
--saveOverwrite an existing profile without the interactive prompt
--demoSpin up a temporary local agent and connect to it
--compactPin the compact layout (normally auto-selected when the window is small)
--metrics-interval-ms <N>Fast metrics polling interval (default: 500, clamped to ≥ 100)
--processes-interval-ms <N>Process list polling interval (default: 2000, clamped to ≥ 200)

Note: there is no --token client flag. Authentication tokens are passed in the URL as a query parameter: socktop "ws://HOST:3000/ws?token=changeme". See Authentication Token.

Configuration Files

The client stores connection profiles in:

  • $XDG_CONFIG_HOME/socktop/profiles.json
  • ~/.config/socktop/profiles.json when XDG_CONFIG_HOME is not set

See Connection Profiles for the file format.

Agent Configuration

The agent is configured with a small set of command-line flags and environment variables. There is no configuration file.

Command-Line Flags

FlagDescription
--port <PORT>, -p <PORT>Port to listen on (default: 3000, or 8443 with TLS)
--enableSSLEnable TLS with an auto-generated self-signed certificate
--version, -VPrint version and exit

The agent always binds to 0.0.0.0 (all interfaces). To restrict access, use a firewall or an authentication token.

Environment Variables

Core settings:

VariableDescription
SOCKTOP_PORTPort to listen on (same as --port)
SOCKTOP_ENABLE_SSLSet to 1 to enable TLS (same as --enableSSL)
SOCKTOP_TOKENRequire this authentication token from clients
SOCKTOP_AGENT_GPUSet to 0 to disable GPU metrics collection
SOCKTOP_AGENT_TEMPSet to 0 to disable CPU temperature collection
SOCKTOP_AGENT_EXTRA_SANSComma-separated extra IPs/DNS names to include in the auto-generated TLS certificate

Tuning (defaults are sensible; change only if you have a reason):

VariableDefaultDescription
SOCKTOP_WORKER_THREADS2Tokio worker threads (1–16). The agent is I/O-bound; 2 is enough for typical use
SOCKTOP_AGENT_METRICS_TTL_MS250How long a collected metrics snapshot is served from cache
SOCKTOP_AGENT_DISKS_TTL_MS1000Disk snapshot cache lifetime
SOCKTOP_AGENT_PROCESSES_TTL_MS1500Process list cache lifetime (Linux)
SOCKTOP_AGENT_NAME_CACHE_CLEANUP_THRESHOLD1000Process-name cache sweep threshold (non-Linux)

The TTL caches mean multiple clients polling the same agent share collection work instead of multiplying it.

Configuring the systemd Service

The service unit (installed by the APT package at /etc/systemd/system/ or from docs/socktop-agent.service) sets options on the ExecStart line and via Environment= entries. To change them without editing the packaged unit, use a drop-in:

sudo systemctl edit socktop-agent
[Service]
Environment=SOCKTOP_TOKEN=changeme
Environment=SOCKTOP_AGENT_GPU=0

Then:

sudo systemctl daemon-reload
sudo systemctl restart socktop-agent

To change the port or enable TLS, override ExecStart (it must be cleared first in a drop-in):

[Service]
ExecStart=
ExecStart=/usr/bin/socktop_agent --enableSSL --port 8443

See Agent Service Setup for the full service walkthrough.

Authentication Token

The agent can require a shared token from connecting clients. Without the correct token, the WebSocket connection is rejected.

  • Access control - only clients that know the token can connect
  • Defense in depth - combine with TLS so the token isn’t sent in cleartext over untrusted networks

Agent: Setting the Token

The token is configured with the SOCKTOP_TOKEN environment variable. (There is no --token command-line flag.)

Running Manually

SOCKTOP_TOKEN=changeme socktop_agent --port 3000

Running as a systemd Service

Add the environment variable with a drop-in (works for both APT and manual installs):

sudo systemctl edit socktop-agent
[Service]
Environment=SOCKTOP_TOKEN=changeme
sudo systemctl daemon-reload
sudo systemctl restart socktop-agent

Alternatively, uncomment the # Environment=SOCKTOP_TOKEN=changeme line that ships in the packaged unit file.

Client: Sending the Token

The client passes the token as a token query parameter in the WebSocket URL. Quote the URL so your shell doesn’t interpret the ?:

socktop "ws://server:3000/ws?token=changeme"

# With TLS
socktop --tls-ca /path/to/cert.pem "wss://server:8443/ws?token=changeme"

Warning: the client’s -t flag is short for --tls-ca (a certificate path), not for the token.

In a Connection Profile

Store the token as part of the profile URL (~/.config/socktop/profiles.json):

{
  "profiles": {
    "secure-server": {
      "url": "ws://server.example.com:3000/ws?token=changeme"
    }
  },
  "version": 0
}

Then connect:

socktop -P secure-server

Note: the profiles file then contains the token in plaintext — keep its permissions restrictive.

Generating a Strong Token

openssl rand -base64 32

Recommendations

  • On untrusted networks, always combine the token with TLS; over plain ws:// the token is visible to anyone who can capture traffic.
  • Rotate the token by updating SOCKTOP_TOKEN on the agent, restarting the service, and updating client profiles.

TLS Configuration

Secure your socktop agent connections with TLS/SSL encryption.

How Verification Works

The client supports two modes:

  • Certificate pinning (default). The certificate the agent presents must be byte-identical to one of the certificates in the PEM file you pass with --tls-ca/-t. Nothing else is accepted — not other certificates chained to the same CA, not renewed certificates. The pinned PEM may contain multiple certificates (useful during rotation: ship old + new together). Expiry is irrelevant for pinned connections. This mode is designed for the agent’s self-signed certificates on home networks.
  • Hostname verification (--verify-hostname). Standard WebPKI validation against the certificate as a root, including hostname/SAN checking.

Upgrade note: client versions before 1.60 did not enforce pinning — with --verify-hostname off, any server certificate was silently accepted. If you use TLS, make sure your clients are 1.60 or newer.

Enable TLS (Auto-Generated Certificate)

The agent automatically generates a self-signed certificate on first run when you enable TLS:

# The agent will auto-generate cert and key on first TLS run
socktop_agent --enableSSL --port 8443

The certificate is stored at:

  • Linux (XDG): $XDG_CONFIG_HOME/socktop_agent/tls/cert.pem (defaults to ~/.config/socktop_agent/tls/)
  • The agent prints the certificate location on first run
  • The private key (key.pem) is created with mode 0600; agents also tighten permissions on existing keys at startup

Example output:

socktop_agent: generated self-signed TLS certificate at /home/user/.config/socktop_agent/tls/cert.pem

Optional: Custom SANs (Subject Alternative Names)

To include additional IPs or hostnames in the auto-generated certificate:

SOCKTOP_AGENT_EXTRA_SANS="192.168.1.101,myhost.internal" socktop_agent --enableSSL --port 8443

This prevents NotValidForName errors when connecting via IPs not in the default SAN list.

Systemd Service with TLS

Edit /etc/systemd/system/socktop-agent.service:

[Service]
ExecStart=/usr/local/bin/socktop_agent --enableSSL --port 8443

Reload and restart:

sudo systemctl daemon-reload
sudo systemctl restart socktop-agent

# Check logs for certificate location
sudo journalctl -u socktop-agent -f

Connect with Client

Copy the auto-generated certificate from the agent to your client machine:

# Copy certificate from agent host
scp user@agent-host:~/.config/socktop_agent/tls/cert.pem ~/socktop-agent-cert.pem

Connect with certificate pinning:

# Connect with TLS and pin the server certificate
socktop --tls-ca ~/socktop-agent-cert.pem wss://hostname:8443/ws

# Short form
socktop -t ~/socktop-agent-cert.pem wss://hostname:8443/ws

Notes:

  • Providing --tls-ca/-t automatically upgrades ws:// to wss:// if you forget the protocol.
  • Copy only cert.pem to clients — never the private key (key.pem); it stays on the agent.
  • You can monitor multiple agents by passing a different --tls-ca per invocation, or better, saving one profile per host.

Certificate Expiry and Rotation

The auto-generated certificate is valid for ~397 days. Pinned clients don’t check expiry, but --verify-hostname clients do, and the agent won’t regenerate an expired certificate on its own. To rotate:

# On the agent host (adjust path if XDG_CONFIG_HOME is set, or
# /var/lib/socktop/.config/socktop_agent/tls/ for the packaged service)
rm ~/.config/socktop_agent/tls/cert.pem ~/.config/socktop_agent/tls/key.pem
sudo systemctl restart socktop-agent   # if running under systemd

The agent generates a fresh pair on the next TLS start. Distribute the new cert.pem to clients. For a seamless rollover, append the new cert to the clients’ pinned PEM first (both are accepted), then remove the old one after the agent switches.

Example Profiles with TLS

Profiles store the pinned certificate path alongside the URL (~/.config/socktop/profiles.json):

{
  "profiles": {
    "local": {
      "url": "ws://127.0.0.1:3000/ws"
    },
    "rpi-master": {
      "url": "wss://rpi-master:8443/ws",
      "tls_ca": "/home/user/.config/socktop/rpi-master.pem",
      "metrics_interval_ms": 1000,
      "processes_interval_ms": 5000
    },
    "rpi-worker-1": {
      "url": "wss://192.168.1.102:8443/ws",
      "tls_ca": "/home/user/.config/socktop/rpi-worker-1.pem",
      "metrics_interval_ms": 1000,
      "processes_interval_ms": 5000
    }
  },
  "version": 0
}

Then connect with socktop -P rpi-master. See Connection Profiles.

Monitor Multiple Hosts with tmux

Use tmux to show multiple socktop instances in a single terminal.

monitoring 4 Raspberry Pis using Tmux

Prerequisites

Install tmux:

# Ubuntu/Debian
sudo apt-get install tmux

Two panes (left/right)

This creates a session named “socktop”, splits it horizontally, and starts two socktops.

tmux new-session -d -s socktop 'socktop ws://HOST1:3000/ws' \; \
  split-window -h 'socktop ws://HOST2:3000/ws' \; \
  select-layout even-horizontal \; \
  attach

Four panes (2x2 grid)

This creates a 2x2 grid with one socktop per pane.

tmux new-session -d -s socktop 'socktop ws://HOST1:3000/ws' \; \
  split-window -h 'socktop ws://HOST2:3000/ws' \; \
  select-pane -t 0 \; split-window -v 'socktop ws://HOST3:3000/ws' \; \
  select-pane -t 1 \; split-window -v 'socktop ws://HOST4:3000/ws' \; \
  select-layout tiled \; \
  attach

Tips

  • Replace HOST1..HOST4 (and ports) with your targets
  • Reattach later: tmux attach -t socktop

Key bindings (defaults)

  • Split left/right: Ctrl-b %
  • Split top/bottom: Ctrl-b "
  • Move between panes: Ctrl-b + Arrow keys
  • Show pane numbers: Ctrl-b q
  • Close a pane: Ctrl-b x
  • Detach from session: Ctrl-b d

More Info

For detailed tmux documentation, see the tmux GitHub.

Monitor Multiple Hosts with Zellij

Use Zellij to monitor multiple socktop instances in a single terminal.

Installation

cargo install zellij

Example Layout

Create socktop-layout.kdl:

layout {
  pane split_direction="vertical" {
    pane command="socktop" {
      args "-P" "rpi-master"
    }
    pane command="socktop" {
      args "-P" "rpi-worker-1"
    }
  }
  pane split_direction="vertical" {
    pane command="socktop" {
      args "-P" "rpi-worker-2"
    }
    pane command="socktop" {
      args "-P" "rpi-worker-3"
    }
  }
}

Run it:

zellij --layout socktop-layout.kdl

Saved Layouts

Layouts placed in ~/.config/zellij/layouts/ can be launched by name:

cp socktop-layout.kdl ~/.config/zellij/layouts/socktop-monitoring.kdl
zellij --layout socktop-monitoring

The pane commands reference connection profiles by name (-P rpi-master), so create the profiles first.

More Info

For detailed Zellij documentation, see Zellij.

WebSocket API Integration

Integrate with the socktop agent’s WebSocket API to build custom monitoring tools. If you’re writing Rust, prefer the socktop_connector library, which wraps all of this.

WebSocket Endpoint

ws://HOST:PORT/ws         # Without TLS
wss://HOST:PORT/ws        # With TLS

With authentication token (if configured):

ws://HOST:PORT/ws?token=YOUR_TOKEN
wss://HOST:PORT/ws?token=YOUR_TOKEN

The agent also serves GET /healthz over plain HTTP, returning 200 OK — useful for liveness probes.

Request Types

Requests are plain text WebSocket messages (not JSON). The agent replies with one message per request:

RequestResponse
get_metricsJSON — fast-changing metrics (CPU, memory, network, GPU)
get_disksJSON — array of disk/partition entries
get_processesBinary — protobuf process list, gzip-compressed above ~768 bytes
get_process_metrics:<PID>JSON — detailed metrics for one process
get_journal_entries:<PID>JSON — recent journal entries for one process

Unknown messages are ignored. The agent is fully request-driven: it collects nothing until you ask, and short TTL caches (metrics 250 ms, disks 1 s, processes 1.5 s) mean multiple clients share collection work.

Response Formats

get_metrics (JSON)

{
  "sampled_at_ms": 1755900000000,
  "cpu_total": 12.4,
  "cpu_per_core": [11.2, 15.7],
  "mem_total": 33554432,
  "mem_used": 18321408,
  "swap_total": 0,
  "swap_used": 0,
  "hostname": "myserver",
  "cpu_temp_c": 42.5,
  "disks": [],
  "networks": [{"name":"eth0","received":12345678,"transmitted":87654321}],
  "top_processes": [],
  "gpus": [{"name":"NVIDIA GeForce RTX 5080","utilization_gpu_pct":56,"mem_used_bytes":1073741824,"mem_total_bytes":8589934592}]
}

Notes:

  • sampled_at_ms (added in 1.60) is the epoch-milliseconds timestamp of when the snapshot was actually collected on the agent. Because responses can be served from the TTL cache, compute rates (e.g. network KB/s) from deltas of sampled_at_ms, not from your own receive times.
  • disks and top_processes are always empty here — request them separately with get_disks / get_processes.
  • cpu_temp_c is null when no sensor is available; gpus is null when there is no GPU (or GPU collection is disabled).
  • received/transmitted are cumulative byte counters since agent start.

get_disks (JSON)

[
  {"name":"nvme0n1","total":512000000000,"available":320000000000,"temperature":38.5,"is_partition":false},
  {"name":"nvme0n1p2","total":511000000000,"available":320000000000,"temperature":null,"is_partition":true}
]

is_partition distinguishes partitions from whole disks (exact on Linux via /sys/block).

get_processes (Protocol Buffers)

Returned as a binary WebSocket message. If the encoded payload exceeds ~768 bytes (nearly always), it is gzip-compressed. Schema:

syntax = "proto3";
package socktop;

message Processes {
  uint64 process_count = 1;   // total processes in the system
  repeated Process rows = 2;  // all processes (sorting is client-side)
}

message Process {
  uint32 pid = 1;
  string name = 2;
  float cpu_usage = 3;        // 0..100
  uint64 mem_bytes = 4;       // RSS bytes
}

To decode: check for the gzip magic bytes (0x1f 0x8b), decompress if present, then parse with any protobuf library.

get_process_metrics:<PID> and get_journal_entries:<PID> (JSON)

Added for the process-details view: per-process detail (command line, executable, working directory, per-thread CPU times in microseconds, and more) and recent journal entries. Journal entries carry both a display timestamp (RFC 3339 UTC) and a numeric timestamp_us (epoch microseconds, added in 1.60); the response’s notice field, when present, explains empty results caused by journal access restrictions rather than absence of logs. These responses are cached per PID for 250 ms / 1 s respectively.

Example: JavaScript/Node.js

const WebSocket = require('ws');

const ws = new WebSocket('ws://localhost:3000/ws');

ws.on('open', () => {
  console.log('Connected to socktop_agent');

  // Requests are plain text messages
  setInterval(() => ws.send('get_metrics'), 1000);
  setInterval(() => ws.send('get_processes'), 3000);
});

ws.on('message', (data, isBinary) => {
  if (isBinary) {
    // get_processes reply: gzip'd protobuf (see schema above)
    console.log('Binary process list, length:', data.length);
  } else {
    const metrics = JSON.parse(data.toString());
    console.log(`CPU: ${metrics.cpu_total}%`);
  }
});

Example: Python

import json
import asyncio
import websockets

async def monitor_system():
    uri = "ws://localhost:3000/ws"
    async with websockets.connect(uri) as websocket:
        print("Connected to socktop_agent")

        while True:
            await websocket.send("get_metrics")   # plain text request
            response = await websocket.recv()

            if isinstance(response, str):
                data = json.loads(response)
                print(f"CPU: {data['cpu_total']}%, "
                      f"Memory: {data['mem_used']/data['mem_total']*100:.1f}%")
            else:
                print(f"Binary response, length: {len(response)}")

            await asyncio.sleep(1)

asyncio.run(monitor_system())
  • Metrics: ≥ 500 ms
  • Processes: ≥ 2000 ms
  • Disks: ≥ 5000 ms

Polling faster than the agent’s TTL caches (250 ms / 1.5 s / 1 s) just returns cached snapshots.

Error Handling

Send each request and await its reply before sending the next of the same kind — replies carry no request ID and are matched by order. Wrap requests in a timeout and treat a timeout as a dead connection: reconnect rather than continuing on a stream that may now be misaligned.

function connect() {
  const ws = new WebSocket('ws://localhost:3000/ws');

  ws.on('open', () => {
    // Start polling
  });

  ws.on('close', () => {
    console.log('Connection lost, reconnecting...');
    setTimeout(connect, 1000);
  });
}

connect();

Compatibility

Wire changes are additive: new fields (like sampled_at_ms and timestamp_us) appear alongside old ones, so integrations built against older agents keep working against newer ones and vice versa.

Socktop Connector Library

The socktop_connector library provides a high-level interface for connecting to socktop agents programmatically.

Overview

The connector library allows you to:

  • Build custom monitoring tools - Create your own dashboards and UIs
  • Integrate with existing systems - Add socktop metrics to your applications
  • Automate monitoring - Script-based system checks and alerts
  • WASM support - Use in browser-based applications

Installation

Add to your Cargo.toml:

[dependencies]
socktop_connector = "1.60"
tokio = { version = "1", features = ["full"] }

Quick Start

Basic Connection

use socktop_connector::{connect_to_socktop_agent, AgentRequest, AgentResponse};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Connect to agent
    let mut connector = connect_to_socktop_agent("ws://localhost:3000/ws").await?;
    
    // Request metrics
    if let Ok(AgentResponse::Metrics(metrics)) = connector.request(AgentRequest::Metrics).await {
        println!("Hostname: {}", metrics.hostname);
        println!("CPU Usage: {:.1}%", metrics.cpu_total);
        println!("Memory: {:.1} GB / {:.1} GB",
                 metrics.mem_used as f64 / 1_000_000_000.0,
                 metrics.mem_total as f64 / 1_000_000_000.0);
    }
    
    Ok(())
}

With TLS

use socktop_connector::connect_to_socktop_agent_with_tls;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let connector = connect_to_socktop_agent_with_tls(
        "wss://secure-host:8443/ws",
        "/path/to/cert.pem",
        false  // verify_hostname: false = pin the certificate (default socktop behavior)
    ).await?;
    
    // Use connector...
    
    Ok(())
}

Request Types

The connector supports several request types:

Metrics Request

Get comprehensive system metrics:

use socktop_connector::{AgentRequest, AgentResponse};

match connector.request(AgentRequest::Metrics).await {
    Ok(AgentResponse::Metrics(metrics)) => {
        println!("CPU Total: {:.1}%", metrics.cpu_total);
        
        // Per-core usage
        for (i, usage) in metrics.cpu_per_core.iter().enumerate() {
            println!("Core {}: {:.1}%", i, usage);
        }
        
        // CPU temperature
        if let Some(temp) = metrics.cpu_temp_c {
            println!("CPU Temperature: {:.1}°C", temp);
        }
        
        // Memory
        println!("Memory Used: {} bytes", metrics.mem_used);
        println!("Memory Total: {} bytes", metrics.mem_total);
        
        // Swap
        println!("Swap Used: {} bytes", metrics.swap_used);
        println!("Swap Total: {} bytes", metrics.swap_total);
        
        // Network interfaces
        for net in &metrics.networks {
            println!("Interface {}: ↓{} ↑{}", 
                     net.name, net.received, net.transmitted);
        }
        
        // GPU information
        if let Some(gpus) = &metrics.gpus {
            for gpu in gpus {
                if let Some(name) = &gpu.name {
                    println!("GPU: {}", name);
                    println!("  Utilization: {:.1}%", gpu.utilization.unwrap_or(0.0));
                    if let Some(temp) = gpu.temp {
                        println!("  Temperature: {:.1}°C", temp);
                    }
                }
            }
        }
    }
    Err(e) => eprintln!("Error: {}", e),
    _ => unreachable!(),
}

Process Request

Get process information:

match connector.request(AgentRequest::Processes).await {
    Ok(AgentResponse::Processes(processes)) => {
        println!("Total processes: {}", processes.process_count);
        
        for proc in &processes.top_processes {
            println!("PID {}: {} - CPU: {:.1}%, Mem: {} MB",
                     proc.pid,
                     proc.name,
                     proc.cpu_usage,
                     proc.mem_bytes / 1_000_000);
        }
    }
    Err(e) => eprintln!("Error: {}", e),
    _ => unreachable!(),
}

Disk Request

Get disk information:

match connector.request(AgentRequest::Disks).await {
    Ok(AgentResponse::Disks(disks)) => {
        for disk in disks {
            let used = disk.total - disk.available;
            let used_gb = used as f64 / 1_000_000_000.0;
            let total_gb = disk.total as f64 / 1_000_000_000.0;
            let percent = (used as f64 / disk.total as f64) * 100.0;
            
            println!("Disk {}: {:.1} GB / {:.1} GB ({:.1}%)",
                     disk.name, used_gb, total_gb, percent);
        }
    }
    Err(e) => eprintln!("Error: {}", e),
    _ => unreachable!(),
}

Continuous Monitoring

Monitor metrics in a loop:

use tokio::time::{sleep, Duration};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut connector = connect_to_socktop_agent("ws://localhost:3000/ws").await?;
    
    loop {
        match connector.request(AgentRequest::Metrics).await {
            Ok(AgentResponse::Metrics(metrics)) => {
                println!("CPU: {:.1}%, Memory: {:.1}%",
                    metrics.cpu_total,
                    (metrics.mem_used as f64 / metrics.mem_total as f64) * 100.0
                );
            }
            Err(e) => {
                eprintln!("Connection error: {}", e);
                break;
            }
            _ => unreachable!(),
        }
        
        sleep(Duration::from_secs(2)).await;
    }
    
    Ok(())
}

Advanced Usage

Custom Configuration

ConnectorConfig uses a builder pattern:

use socktop_connector::{ConnectorConfig, SocktopConnector};

let config = ConnectorConfig::new("wss://server:8443/ws?token=secret-token")
    .with_tls_ca("/path/to/cert.pem")
    .with_hostname_verification(false);

let mut connector = SocktopConnector::new(config);
connector.connect().await?;

An authentication token is passed as a token query parameter in the URL (there is no separate token field).

Error Handling

ConnectorError variants carry structured context:

use socktop_connector::{AgentRequest, ConnectorError, Result, connect_to_socktop_agent};

async fn monitor() -> Result<()> {
    let mut connector = connect_to_socktop_agent("ws://server:3000/ws").await?;

    match connector.request(AgentRequest::Metrics).await {
        Ok(_response) => {
            // Handle response
            Ok(())
        }
        Err(e @ ConnectorError::ConnectionClosed { .. }) => {
            eprintln!("Connection closed, attempting reconnect...");
            Err(e)
        }
        Err(e) => {
            eprintln!("Error: {}", e);
            Err(e)
        }
    }
}

WASM Support

The connector supports WebAssembly for browser usage:

[dependencies]
socktop_connector = { version = "1.60", default-features = false, features = ["wasm"] }
use socktop_connector::connect_to_socktop_agent;
use wasm_bindgen::prelude::*;

#[wasm_bindgen]
pub async fn monitor_system(url: String) -> Result<JsValue, JsValue> {
    let mut connector = connect_to_socktop_agent(&url)
        .await
        .map_err(|e| JsValue::from_str(&e.to_string()))?;
    
    match connector.request(AgentRequest::Metrics).await {
        Ok(AgentResponse::Metrics(metrics)) => {
            Ok(JsValue::from_str(&format!("CPU: {:.1}%", metrics.cpu_total)))
        }
        Err(e) => Err(JsValue::from_str(&e.to_string())),
        _ => Err(JsValue::from_str("Unexpected response")),
    }
}

Building Custom Applications

Example: Simple Dashboard

use socktop_connector::*;
use tokio::time::{interval, Duration};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let servers = vec![
        ("web", "ws://web.example.com:3000/ws"),
        ("db", "ws://db.example.com:3000/ws"),
        ("cache", "ws://cache.example.com:3000/ws"),
    ];
    
    let mut connectors = Vec::new();
    for (name, url) in servers {
        match connect_to_socktop_agent(url).await {
            Ok(conn) => connectors.push((name, conn)),
            Err(e) => eprintln!("Failed to connect to {}: {}", name, e),
        }
    }
    
    let mut tick = interval(Duration::from_secs(2));
    
    loop {
        tick.tick().await;
        
        for (name, connector) in &mut connectors {
            if let Ok(AgentResponse::Metrics(m)) = connector.request(AgentRequest::Metrics).await {
                println!("[{}] CPU: {:.1}%, Mem: {:.1}%",
                    name,
                    m.cpu_total,
                    (m.mem_used as f64 / m.mem_total as f64) * 100.0
                );
            }
        }
        
        println!("---");
    }
}

Example: Alert System

use socktop_connector::*;

async fn check_alerts(mut connector: SocktopConnector) -> Result<(), Box<dyn std::error::Error>> {
    match connector.request(AgentRequest::Metrics).await {
        Ok(AgentResponse::Metrics(metrics)) => {
            // CPU alert
            if metrics.cpu_total > 90.0 {
                eprintln!("ALERT: CPU usage at {:.1}%", metrics.cpu_total);
            }
            
            // Memory alert
            let mem_percent = (metrics.mem_used as f64 / metrics.mem_total as f64) * 100.0;
            if mem_percent > 90.0 {
                eprintln!("ALERT: Memory usage at {:.1}%", mem_percent);
            }
            
            // Disk alert
            if let Ok(AgentResponse::Disks(disks)) = connector.request(AgentRequest::Disks).await {
                for disk in disks {
                    let used_percent = ((disk.total - disk.available) as f64 / disk.total as f64) * 100.0;
                    if used_percent > 90.0 {
                        eprintln!("ALERT: Disk {} at {:.1}%", disk.name, used_percent);
                    }
                }
            }
        }
        Err(e) => eprintln!("Error fetching metrics: {}", e),
        _ => {}
    }
    
    Ok(())
}

Data Types

Key types provided by the library:

  • Metrics - System metrics (CPU, memory, network, GPU, etc.)
  • DetailedProcessInfo - Per-process detail (command, threads, …)
  • DiskInfo - Disk usage information
  • NetworkInfo - Network interface statistics
  • GpuInfo - GPU metrics
  • JournalEntry - Systemd journal entries
  • AgentRequest - Request types (Metrics, Disks, Processes, ProcessMetrics { pid }, JournalEntries { pid })
  • AgentResponse - Response types

See the crate documentation for complete API reference.

Performance Considerations

The connector is lightweight and efficient:

  • Protocol Buffers - Efficient binary serialization
  • Gzip compression - Reduced bandwidth usage
  • Async I/O - Non-blocking operations
  • Connection reuse - Single WebSocket for multiple requests

Typical resource usage:

  • Memory: ~1-5 MB per connection
  • CPU: < 0.1% during idle
  • Bandwidth: ~1-5 KB per metrics request

Troubleshooting

Connection Errors

match connect_to_socktop_agent(url).await {
    Err(ConnectorError::ConnectionFailed { source }) => {
        eprintln!("Connection failed: {}", source);
        // Retry logic here
    }
    Err(ConnectorError::InvalidUrl { url, .. }) => {
        eprintln!("Invalid URL: {}", url);
    }
    Err(e) => eprintln!("Other error: {}", e),
    Ok(conn) => { /* Success */ }
}

TLS Errors

A TlsError or CertificateError usually means the pinned certificate doesn’t match what the agent presented (or the PEM path is wrong). Re-copy cert.pem from the agent — see TLS Configuration. Hostname verification is off by default (with_hostname_verification(false)), which pins the certificate rather than skipping checks.

Examples Repository

Working examples in the socktop repository:

API Reference

Full API documentation: docs.rs/socktop_connector

Next Steps