diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index d3cd8ff..6f8acc7 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -9,6 +9,7 @@ - [Install via APT](./installation/apt.md) - [Agent Service Setup](./installation/agent-service.md) - [Upgrading](./installation/upgrading.md) + - [Platform Notes](./installation/platform-notes.md) - [Usage]() - [General Usage](./usage/general.md) @@ -24,4 +25,6 @@ - [Monitor Multiple Hosts with tmux](./advanced/tmux.md) - [Monitor Multiple Hosts with Zellij](./advanced/zellij.md) - [Agent Direct Integration](./advanced/agent-integration.md) - - [Socktop Connector Library](./advanced/connector.md) \ No newline at end of file + - [Socktop Connector Library](./advanced/connector.md) + +[Known Issues](./known-issues.md) \ No newline at end of file diff --git a/docs/src/advanced/agent-integration.md b/docs/src/advanced/agent-integration.md index 28ac5fa..3691e88 100644 --- a/docs/src/advanced/agent-integration.md +++ b/docs/src/advanced/agent-integration.md @@ -1,6 +1,6 @@ # WebSocket API Integration -Integrate with the socktop agent's WebSocket API to build custom monitoring tools. +Integrate with the socktop agent's WebSocket API to build custom monitoring tools. If you're writing Rust, prefer the [socktop_connector library](./connector.md), which wraps all of this. ## WebSocket Endpoint @@ -15,22 +15,29 @@ 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 -Send JSON messages to request specific metrics: +Requests are **plain text WebSocket messages** (not JSON). The agent replies with one message per request: -```json -{"type": "metrics"} // Fast-changing metrics (CPU, memory, network) -{"type": "disks"} // Disk information -{"type": "processes"} // Process list (returns protobuf) -``` +| Request | Response | +|---|---| +| `get_metrics` | JSON — fast-changing metrics (CPU, memory, network, GPU) | +| `get_disks` | JSON — array of disk/partition entries | +| `get_processes` | Binary — protobuf process list, gzip-compressed above ~768 bytes | +| `get_process_metrics:` | JSON — detailed metrics for one process | +| `get_journal_entries:` | 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 -### Metrics (JSON) +### `get_metrics` (JSON) ```json { + "sampled_at_ms": 1755900000000, "cpu_total": 12.4, "cpu_per_core": [11.2, 15.7], "mem_total": 33554432, @@ -39,40 +46,58 @@ Send JSON messages to request specific metrics: "swap_used": 0, "hostname": "myserver", "cpu_temp_c": 42.5, + "disks": [], "networks": [{"name":"eth0","received":12345678,"transmitted":87654321}], - "gpus": [{"name":"nvidia-0","usage":56.7,"memory_total":8589934592,"memory_used":1073741824,"temp_c":65.0}] + "top_processes": [], + "gpus": [{"name":"NVIDIA GeForce RTX 5080","utilization_gpu_pct":56,"mem_used_bytes":1073741824,"mem_total_bytes":8589934592}] } ``` -### Disks (JSON) +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) ```json [ - {"name":"nvme0n1p2","total":512000000000,"available":320000000000}, - {"name":"sda1","total":1000000000000,"available":750000000000} + {"name":"nvme0n1","total":512000000000,"available":320000000000,"temperature":38.5,"is_partition":false}, + {"name":"nvme0n1p2","total":511000000000,"available":320000000000,"temperature":null,"is_partition":true} ] ``` -### Processes (Protocol Buffers) +`is_partition` distinguishes partitions from whole disks (exact on Linux via `/sys/block`). -Processes are returned in protobuf format, optionally gzip-compressed. Schema: +### `get_processes` (Protocol Buffers) + +Returned as a binary WebSocket message. If the encoded payload exceeds ~768 bytes (nearly always), it is gzip-compressed. Schema: ```protobuf 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; - uint64 mem_bytes = 4; -} - -message ProcessList { - uint32 process_count = 1; - repeated Process processes = 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:` and `get_journal_entries:` (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 ```javascript @@ -80,36 +105,23 @@ const WebSocket = require('ws'); const ws = new WebSocket('ws://localhost:3000/ws'); -ws.on('open', function open() { +ws.on('open', () => { console.log('Connected to socktop_agent'); - - // Request metrics - ws.send(JSON.stringify({type: 'metrics'})); - - // Poll every second - setInterval(() => { - ws.send(JSON.stringify({type: 'metrics'})); - }, 1000); - - // Request processes every 3 seconds - setInterval(() => { - ws.send(JSON.stringify({type: 'processes'})); - }, 3000); + + // Requests are plain text messages + setInterval(() => ws.send('get_metrics'), 1000); + setInterval(() => ws.send('get_processes'), 3000); }); -ws.on('message', function incoming(data) { - try { - const jsonData = JSON.parse(data); - console.log('Received JSON data:', jsonData); - } catch (e) { - console.log('Received binary data (protobuf), length:', data.length); - // Process binary protobuf data with protobufjs +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}%`); } }); - -ws.on('close', function close() { - console.log('Disconnected from socktop_agent'); -}); ``` ## Example: Python @@ -123,23 +135,18 @@ async def monitor_system(): uri = "ws://localhost:3000/ws" async with websockets.connect(uri) as websocket: print("Connected to socktop_agent") - - # Request initial metrics - await websocket.send(json.dumps({"type": "metrics"})) - + while True: - # Request metrics - await websocket.send(json.dumps({"type": "metrics"})) - - # Receive response + await websocket.send("get_metrics") # plain text request response = await websocket.recv() - - try: + + if isinstance(response, str): data = json.loads(response) - print(f"CPU: {data['cpu_total']}%, Memory: {data['mem_used']/data['mem_total']*100:.1f}%") - except json.JSONDecodeError: - print(f"Received binary data, length: {len(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()) @@ -147,31 +154,24 @@ asyncio.run(monitor_system()) ## Recommended Intervals -- Metrics: ≥ 500ms -- Processes: ≥ 2000ms -- Disks: ≥ 5000ms +- Metrics: ≥ 500 ms +- Processes: ≥ 2000 ms +- Disks: ≥ 5000 ms -## Handling Protocol Buffers - -For processing binary process data: - -1. Check if response starts with gzip magic bytes (`0x1f, 0x8b`) -2. Decompress if necessary -3. Parse with protobuf library using the schema above +Polling faster than the agent's TTL caches (250 ms / 1.5 s / 1 s) just returns cached snapshots. ## Error Handling -Implement reconnection logic with exponential backoff: +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. ```javascript function connect() { const ws = new WebSocket('ws://localhost:3000/ws'); - + ws.on('open', () => { - console.log('Connected'); // Start polling }); - + ws.on('close', () => { console.log('Connection lost, reconnecting...'); setTimeout(connect, 1000); @@ -181,6 +181,6 @@ function connect() { connect(); ``` -## More Info +## Compatibility -For detailed implementation, see the [socktop_agent README](https://github.com/jasonwitty/socktop/tree/master/socktop_agent). \ No newline at end of file +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. diff --git a/docs/src/advanced/connector.md b/docs/src/advanced/connector.md index 623c51a..9cc727d 100644 --- a/docs/src/advanced/connector.md +++ b/docs/src/advanced/connector.md @@ -17,7 +17,7 @@ Add to your `Cargo.toml`: ```toml [dependencies] -socktop_connector = "1.50" +socktop_connector = "1.60" tokio = { version = "1", features = ["full"] } ``` @@ -54,9 +54,9 @@ use socktop_connector::connect_to_socktop_agent_with_tls; #[tokio::main] async fn main() -> Result<(), Box> { let connector = connect_to_socktop_agent_with_tls( - "wss://secure-host:3000/ws", - "/path/to/ca.pem", - false // Enable hostname verification + "wss://secure-host:8443/ws", + "/path/to/cert.pem", + false // verify_hostname: false = pin the certificate (default socktop behavior) ).await?; // Use connector... @@ -203,35 +203,39 @@ async fn main() -> Result<(), Box> { ### Custom Configuration +`ConnectorConfig` uses a builder pattern: + ```rust use socktop_connector::{ConnectorConfig, SocktopConnector}; -let config = ConnectorConfig { - url: "ws://server:3000/ws".to_string(), - token: Some("secret-token".to_string()), - ca_cert_path: Some("/path/to/ca.pem".to_string()), - verify_tls: true, -}; +let config = ConnectorConfig::new("wss://server:8443/ws?token=secret-token") + .with_tls_ca("/path/to/cert.pem") + .with_hostname_verification(false); -let connector = SocktopConnector::connect_with_config(config).await?; +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: + ```rust -use socktop_connector::{ConnectorError, Result}; +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) => { + Ok(_response) => { // Handle response Ok(()) } - Err(ConnectorError::ConnectionClosed) => { + Err(e @ ConnectorError::ConnectionClosed { .. }) => { eprintln!("Connection closed, attempting reconnect..."); - Err(ConnectorError::ConnectionClosed) + Err(e) } Err(e) => { eprintln!("Error: {}", e); @@ -247,7 +251,7 @@ The connector supports WebAssembly for browser usage: ```toml [dependencies] -socktop_connector = { version = "1.50", features = ["wasm"] } +socktop_connector = { version = "1.60", default-features = false, features = ["wasm"] } ``` ```rust @@ -356,12 +360,12 @@ async fn check_alerts(mut connector: SocktopConnector) -> Result<(), Box { - eprintln!("Connection failed: {}", e); + Err(ConnectorError::ConnectionFailed { source }) => { + eprintln!("Connection failed: {}", source); // Retry logic here } - Err(ConnectorError::InvalidUrl) => { - eprintln!("Invalid URL format"); + Err(ConnectorError::InvalidUrl { url, .. }) => { + eprintln!("Invalid URL: {}", url); } Err(e) => eprintln!("Other error: {}", e), Ok(conn) => { /* Success */ } @@ -400,25 +404,15 @@ match connect_to_socktop_agent(url).await { ### TLS Errors -```rust -// Disable TLS verification for testing (not recommended) -use socktop_connector::{ConnectorConfig, SocktopConnector}; - -let config = ConnectorConfig { - url: "wss://server:3000/ws".to_string(), - verify_tls: false, - ..Default::default() -}; -``` +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](../security/tls.md). Hostname verification is off by default (`with_hostname_verification(false)`), which pins the certificate rather than skipping checks. ## Examples Repository -More examples available in the socktop repository: +Working examples in the socktop repository: -- `examples/simple_monitor.rs` - Basic monitoring -- `examples/multi_server.rs` - Monitor multiple servers -- `examples/alert_system.rs` - Threshold-based alerts -- `examples/wasm_demo/` - Browser-based monitoring +- [`examples/wasm_example.rs`](https://github.com/jasonwitty/socktop/blob/master/examples/wasm_example.rs) - Connector usage from WASM +- [`socktop_wasm_test/`](https://github.com/jasonwitty/socktop/tree/master/socktop_wasm_test) - Browser-based test harness for the wasm feature +- [`socktop/`](https://github.com/jasonwitty/socktop/tree/master/socktop) - The TUI itself is the reference consumer of the connector ## API Reference @@ -429,9 +423,4 @@ Full API documentation: [docs.rs/socktop_connector](https://docs.rs/socktop_conn - [Agent Direct Integration](./agent-integration.md) - Embed agent in your app - [General Usage](../usage/general.md) - Using the TUI client - [Configuration](../usage/configuration.md) - Configuration options - - - - - \ No newline at end of file diff --git a/docs/src/advanced/zellij.md b/docs/src/advanced/zellij.md index bc94ae9..87041fc 100644 --- a/docs/src/advanced/zellij.md +++ b/docs/src/advanced/zellij.md @@ -39,34 +39,17 @@ Run it: zellij --layout socktop-layout.kdl ``` +## Saved Layouts + +Layouts placed in `~/.config/zellij/layouts/` can be launched by name: + +```bash +cp socktop-layout.kdl ~/.config/zellij/layouts/socktop-monitoring.kdl +zellij --layout socktop-monitoring +``` + +The pane commands reference [connection profiles](../usage/connection-profiles.md) by name (`-P rpi-master`), so create the profiles first. + ## More Info For detailed Zellij documentation, see [Zellij](https://zellij.dev/). - -Create `~/.config/zellij/layouts/socktop-monitoring.kdl`: - -```kdl -layout { - pane_template name="socktop_pane" { - command "socktop" - args "-P" "{profile}" - } - - pane split_direction="vertical" { - pane split_direction="horizontal" { - socktop_pane profile="production-web" - socktop_pane profile="production-db" - } - pane split_direction="horizontal" { - socktop_pane profile="staging-web" - socktop_pane profile="staging-db" - } - } -} -``` - -### Use the Layout - -```bash -zellij --layout socktop-monitoring -``` diff --git a/docs/src/installation/agent-service.md b/docs/src/installation/agent-service.md index 5fce1b0..338cd2d 100644 --- a/docs/src/installation/agent-service.md +++ b/docs/src/installation/agent-service.md @@ -53,7 +53,6 @@ Agent configuration via command-line flags or environment variables: Port: - Flag: `--port 8080` or `-p 8080` -- Positional: `socktop_agent 8080` - Env: `SOCKTOP_PORT=8080` TLS (self-signed): @@ -62,7 +61,7 @@ TLS (self-signed): - 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` @@ -70,6 +69,21 @@ Disable GPU metrics: `SOCKTOP_AGENT_GPU=0` Disable CPU temperature: `SOCKTOP_AGENT_TEMP=0` +See [Configuration](../usage/configuration.md) 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: + +```bash +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 @@ -122,17 +136,4 @@ sudo systemctl is-active socktop-agent ## Updating -```bash -# 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 -``` - -Tip: If only the binary changed, restart is enough. If the unit file changed, run `sudo systemctl daemon-reload`. -``` +See [Upgrading](./upgrading.md). diff --git a/docs/src/installation/cargo.md b/docs/src/installation/cargo.md index 02db844..99173fc 100644 --- a/docs/src/installation/cargo.md +++ b/docs/src/installation/cargo.md @@ -6,11 +6,14 @@ Installing socktop via Cargo gives you access to the latest version and works on Before installing via Cargo, ensure you have: -- **Rust 1.70 or newer** - Install via [rustup](https://rustup.rs/) +- **Current stable Rust** (1.85+, 2024 edition) - Install via [rustup](https://rustup.rs/) - **Build dependencies** - See [Prerequisites](./prerequisites.md) for details -- **GPU support libraries** - Required on all systems: +- **GPU support libraries** (x86_64/aarch64): ```bash + # Debian/Ubuntu sudo apt install libdrm-dev libdrm-amdgpu1 + # Fedora + sudo dnf install libdrm-devel libdrm-amdgpu ``` ## Installation @@ -26,7 +29,7 @@ This will download, compile, and install the `socktop` binary to `~/.cargo/bin/` ### Installing the Agent ```bash -cargo install socktop-agent +cargo install socktop_agent ``` This installs the `socktop_agent` binary to `~/.cargo/bin/`. @@ -34,7 +37,7 @@ This installs the `socktop_agent` binary to `~/.cargo/bin/`. ### Installing Both (Recommended) ```bash -cargo install socktop socktop-agent +cargo install socktop socktop_agent ``` ## Verify Installation @@ -51,7 +54,7 @@ socktop_agent --version You should see output like: ``` -socktop 1.50.2 +socktop 1.60.1 ``` ## First Run @@ -67,8 +70,8 @@ socktop_agent # Run in background socktop_agent & -# Or with custom options -socktop_agent --port 3000 --host 0.0.0.0 +# Or on a custom port +socktop_agent --port 3000 ``` ### Connect with the Client @@ -76,54 +79,31 @@ socktop_agent --port 3000 --host 0.0.0.0 In another terminal, connect to the agent: ```bash -# Monitor local system -socktop +socktop ws://localhost:3000/ws +``` -# Or explicitly specify the WebSocket URL -socktop ws://localhost:3000 +Or just try demo mode (starts and stops its own local agent): + +```bash +socktop --demo ``` ## Configuration -### Agent Configuration - -The agent accepts the following command-line arguments: +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: ```bash -socktop_agent --help -``` - -Common options: -- `--port ` - Port to listen on (default: 3000) -- `--host ` - Host/IP to bind to (default: 0.0.0.0) -- `--token ` - Authentication token (optional) -- `--tls-cert ` - TLS certificate path (optional) -- `--tls-key ` - TLS private key path (optional) - -Example with custom configuration: -```bash -socktop_agent --port 8080 --token mySecretToken123 -``` - -### Client Configuration - -The client can connect using various methods: - -```bash -# Local connection -socktop - # Remote connection -socktop ws://192.168.1.100:3000 +socktop ws://192.168.1.100:3000/ws -# Secure connection with TLS -socktop wss://secure-host:3000 +# 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](../usage/configuration.md) for details on setting up profiles. +See [Configuration](../usage/configuration.md) for the complete reference and [Connection Profiles](../usage/connection-profiles.md) for profiles. ## System-wide agent (Linux) diff --git a/docs/src/installation/platform-notes.md b/docs/src/installation/platform-notes.md new file mode 100644 index 0000000..b225184 --- /dev/null +++ b/docs/src/installation/platform-notes.md @@ -0,0 +1,32 @@ +# 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](https://github.com/jasonwitty/socktop/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](https://github.com/jasonwitty/socktop/blob/master/docs/cross-compiling.md) (Linux, macOS, or Windows hosts). diff --git a/docs/src/installation/prerequisites.md b/docs/src/installation/prerequisites.md index e75399f..eba6caf 100644 --- a/docs/src/installation/prerequisites.md +++ b/docs/src/installation/prerequisites.md @@ -8,7 +8,10 @@ - **Fedora** 35+ - **Raspberry Pi OS** - Other Linux distributions with kernel 4.15+ -- Windows 10+ (Binaries available in build artifacts) +- Windows 10+ (binaries available in build artifacts) +- macOS (client; the agent runs but is primarily targeted at Linux) + +See [Platform Notes](./platform-notes.md) for platform-specific details. #### Supported Architectures @@ -19,18 +22,30 @@ ## Software Dependencies -GPU support requires additional libraries: +GPU support requires additional libraries (x86_64 and aarch64 only): +**Debian/Ubuntu/Raspberry Pi OS:** ```bash sudo apt update sudo apt install libdrm-dev libdrm-amdgpu1 ``` +**Fedora:** +```bash +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`: + +```bash +cargo build --release -p socktop_agent --no-default-features +``` + ### For Cargo Installation #### 1. Rust Toolchain -Rust 1.70+ required. +A current stable Rust toolchain is required (the crates use the 2024 edition, so Rust 1.85+). ```bash # Install Rust via rustup (recommended) @@ -53,10 +68,10 @@ sudo apt install build-essential pkg-config libssl-dev libdrm-dev libdrm-amdgpu1 **Fedora:** ```bash -sudo dnf install gcc pkg-config openssl-devel +sudo dnf install gcc pkg-config openssl-devel libdrm-devel libdrm-amdgpu ``` **Arch Linux:** ```bash -sudo pacman -S base-devel openssl +sudo pacman -S base-devel openssl libdrm ``` diff --git a/docs/src/installation/quick-start.md b/docs/src/installation/quick-start.md index 8dfd161..ddc91fe 100644 --- a/docs/src/installation/quick-start.md +++ b/docs/src/installation/quick-start.md @@ -27,21 +27,21 @@ sudo apt install socktop socktop-agent sudo systemctl enable --now socktop-agent ``` -Run `socktop` to monitor your local system or connect to remote agents. +Then connect to it: `socktop ws://localhost:3000/ws` — or to any remote agent by hostname. ## Option 2: Cargo Installation Install from crates.io: ```bash -# Install GPU support libraries (required) +# 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 +cargo install socktop_agent # Run the agent manually or set up as a service (see Agent Service Setup) socktop_agent @@ -67,11 +67,12 @@ This spins up a temporary local agent on port 3231, connects to it, and stops wh # Quick demo (no agent setup needed) socktop --demo -# Monitor your local system (requires agent running) -socktop - -# Or connect to a remote agent +# 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. diff --git a/docs/src/installation/upgrading.md b/docs/src/installation/upgrading.md index 23a9eb9..c27dd40 100644 --- a/docs/src/installation/upgrading.md +++ b/docs/src/installation/upgrading.md @@ -1,6 +1,13 @@ # Upgrading -This guide covers upgrading socktop and socktop-agent to newer versions. +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](../usage/general.md#killing-a-process)** — older agents keep reporting dead processes, so killed rows would linger on screen. ## Upgrading via APT @@ -30,6 +37,9 @@ 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 diff --git a/docs/src/introduction.md b/docs/src/introduction.md index 529fd1e..05b6670 100644 --- a/docs/src/introduction.md +++ b/docs/src/introduction.md @@ -1,11 +1,11 @@ # Introduction -![socktop logo](https://raw.githubusercontent.com/jasonwitty/socktop/master/docs/socktop_demo.apng) +![socktop demo](https://raw.githubusercontent.com/jasonwitty/socktop/master/docs/socktop_demo_1_60.apng) **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 +- **socktop_agent** - A lightweight background service that collects and serves system metrics over WebSocket ## Features @@ -15,8 +15,11 @@ - Disks: per-device usage - Network: per-interface throughput with sparklines - Temperatures: CPU (optional) -- Top processes (top 50): sortable by CPU% or memory, scrollable +- 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 @@ -62,19 +65,21 @@ Spins up a temporary local agent on port 3231 and connects to it. Stops automati socktop is actively maintained and used in production environments. The project follows semantic versioning and maintains backward compatibility within major versions. -- **Current Version**: 1.50.x -- **Minimum Rust Version**: 1.70+ -- **Supported Platforms**: Linux (amd64, arm64, armhf, riscv64) +- **Current Version**: 1.60.x — see [GitHub Releases](https://github.com/jasonwitty/socktop/releases) for release notes +- **Supported Platforms**: Linux (amd64, arm64, armhf, riscv64), Windows, macOS (client) — see [Platform Notes](./installation/platform-notes.md) - **License**: MIT +Wire changes between versions are additive: mixed client/agent versions keep working during rollouts. + ## Community and Support - **GitHub Repository**: [https://github.com/jasonwitty/socktop](https://github.com/jasonwitty/socktop) +- **Release Notes**: [GitHub Releases](https://github.com/jasonwitty/socktop/releases) - **Issue Tracker**: Report bugs and request features on GitHub - **crates.io**: - [socktop](https://crates.io/crates/socktop) - TUI client - - [socktop-agent](https://crates.io/crates/socktop-agent) - Background agent - - [socktop-connector](https://crates.io/crates/socktop-connector) - Library for integrations + - [socktop_agent](https://crates.io/crates/socktop_agent) - Background agent + - [socktop_connector](https://crates.io/crates/socktop_connector) - Library for integrations - **APT Repository**: [https://jasonwitty.github.io/socktop/](https://jasonwitty.github.io/socktop/) ## Next Steps diff --git a/docs/src/known-issues.md b/docs/src/known-issues.md new file mode 100644 index 0000000..3ba39fd --- /dev/null +++ b/docs/src/known-issues.md @@ -0,0 +1,15 @@ +# Known Issues + +Current limitations worth knowing about. See the [issue tracker](https://github.com/jasonwitty/socktop/issues) for the live list. + +## Process kill inside containers + +The kill feature only offers itself when the agent is local (see [Killing a Process](./usage/general.md#killing-a-process)). A client running inside a container with **host networking but its own PID namespace** can pass that local-agent check even though its PID view differs from the host's. The PID-reuse guard (the process name must still match at signal time) limits the blast radius, but avoid using the kill feature from inside such containers. + +## Switching between agents of different versions mid-session + +When socktop detects an old agent without the per-process endpoints, it remembers that the details view is unsupported. If you then reconnect the same session to a *different, older* agent, that detection may not reset correctly. Restart socktop when hopping between agents that are generations apart. + +## Zellij plugin example + +The in-repo `zellij_socktop_plugin` example does not currently compile and is pending a rework. This does not affect [monitoring multiple hosts with Zellij](./advanced/zellij.md), which just runs the normal client in panes. diff --git a/docs/src/security/tls.md b/docs/src/security/tls.md index c34bd8e..c8b81e4 100644 --- a/docs/src/security/tls.md +++ b/docs/src/security/tls.md @@ -1,6 +1,16 @@ # 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: @@ -13,6 +23,7 @@ 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:** ``` @@ -67,19 +78,30 @@ socktop --tls-ca ~/socktop-agent-cert.pem wss://hostname:8443/ws socktop -t ~/socktop-agent-cert.pem wss://hostname:8443/ws ``` -**Note:** Providing `--tls-ca/-t` automatically upgrades `ws://` to `wss://` if you forget the protocol. +**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](../usage/connection-profiles.md) per host. -### Example Profile with SSL +### 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: ```bash -socktop wss://server:3000 +# 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 ``` -Profile: +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`): ```json -File: /home/jasonw/.config/socktop/profiles.json { "profiles": { "local": { @@ -87,30 +109,19 @@ File: /home/jasonw/.config/socktop/profiles.json }, "rpi-master": { "url": "wss://rpi-master:8443/ws", - "tls_ca": "/home/jasonw/.config/socktop/rpi-master.pem", + "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/jasonw/.config/socktop/rpi-worker-1.pem", - "metrics_interval_ms": 1000, - "processes_interval_ms": 5000 - }, - "rpi-worker-2": { - "url": "ws://192.168.1.103:8443/ws", - "tls_ca": "/home/jasonw/.config/socktop/rpi-worker-2.pem", - "metrics_interval_ms": 1000, - "processes_interval_ms": 5000 - }, - "rpi-worker-3": { - "url": "ws://192.168.1.104:8443/ws", - "tls_ca": "/home/jasonw/.config/socktop/rpi-worker-3.pem", + "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](../usage/connection-profiles.md). diff --git a/docs/src/security/token.md b/docs/src/security/token.md index e021a9e..8a1ff7e 100644 --- a/docs/src/security/token.md +++ b/docs/src/security/token.md @@ -1,56 +1,31 @@ # Authentication Token -This guide covers token-based authentication for securing socktop agent connections. +The agent can require a shared token from connecting clients. Without the correct token, the WebSocket connection is rejected. -- **Access Control** - Only authorized clients can connect -- **Security** - Prevent unauthorized monitoring of your systems -- **Auditability** - Track which tokens are in use -- **Flexibility** - Revoke and rotate tokens as needed +- **Access control** - only clients that know the token can connect +- **Defense in depth** - combine with [TLS](./tls.md) so the token isn't sent in cleartext over untrusted networks -## Configuring Token Authentication +## Agent: Setting the Token -### Agent Configuration +The token is configured with the `SOCKTOP_TOKEN` environment variable. (There is no `--token` command-line flag.) -#### APT Installation - -Edit `/etc/default/socktop-agent`: +### Running Manually ```bash -sudo nano /etc/default/socktop-agent +SOCKTOP_TOKEN=changeme socktop_agent --port 3000 ``` -Add your token: +### Running as a systemd Service -```bash -# Authentication token -TOKEN=7KJ9m3LnP4qR8sT2vW5xY6zA1bC3dE4fG7hI9jK0lM8= -``` - -Restart the service: - -```bash -sudo systemctl restart socktop-agent -``` - -#### Cargo Installation - -Start the agent with the token: - -```bash -socktop_agent --token "7KJ9m3LnP4qR8sT2vW5xY6zA1bC3dE4fG7hI9jK0lM8=" -``` - -Or with systemd service: +Add the environment variable with a drop-in (works for both APT and manual installs): ```bash sudo systemctl edit socktop-agent ``` -Add environment variable: - ```ini [Service] -Environment="TOKEN=7KJ9m3LnP4qR8sT2vW5xY6zA1bC3dE4fG7hI9jK0lM8=" +Environment=SOCKTOP_TOKEN=changeme ``` ```bash @@ -58,24 +33,30 @@ sudo systemctl daemon-reload sudo systemctl restart socktop-agent ``` -### Client Configuration +Alternatively, uncomment the `# Environment=SOCKTOP_TOKEN=changeme` line that ships in the packaged unit file. -#### Command Line +## 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 `?`: ```bash -# Pass token via command line -socktop ws://server:3000 -t "7KJ9m3LnP4qR8sT2vW5xY6zA1bC3dE4fG7hI9jK0lM8=" +socktop "ws://server:3000/ws?token=changeme" + +# With TLS +socktop --tls-ca /path/to/cert.pem "wss://server:8443/ws?token=changeme" ``` -#### Connection Profile +**Warning:** the client's `-t` flag is short for `--tls-ca` (a certificate path), not for the token. -Add token to profile (`~/.config/socktop/profiles.json`): +### In a Connection Profile + +Store the token as part of the profile URL (`~/.config/socktop/profiles.json`): ```json { "profiles": { "secure-server": { - "url": "ws://server.example.com:3000/ws?token=7KJ9m3LnP4qR8sT2vW5xY6zA1bC3dE4fG7hI9jK0lM8=" + "url": "ws://server.example.com:3000/ws?token=changeme" } }, "version": 0 @@ -88,12 +69,15 @@ Then connect: socktop -P secure-server ``` -#### Environment Variable +**Note:** the profiles file then contains the token in plaintext — keep its permissions restrictive. + +## Generating a Strong Token ```bash -# Set token in environment -export SOCKTOP_TOKEN="7KJ9m3LnP4qR8sT2vW5xY6zA1bC3dE4fG7hI9jK0lM8=" - -# Connect without specifying token -socktop ws://server:3000 +openssl rand -base64 32 ``` + +## Recommendations + +- On untrusted networks, always combine the token with [TLS](./tls.md); 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. diff --git a/docs/src/usage/configuration.md b/docs/src/usage/configuration.md index 61f99aa..0795101 100644 --- a/docs/src/usage/configuration.md +++ b/docs/src/usage/configuration.md @@ -1,115 +1,105 @@ # Configuration -This guide covers all configuration options for socktop client and agent. +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 -### Configuration File Location - -By default, socktop looks for configuration in: - -- **Linux**: `~/.config/socktop/` -- **Custom**: Set `XDG_CONFIG_HOME` environment variable - ### Command-Line Options -```bash -socktop_agent --help - -OPTIONS: - --port Port to listen on [default: 3000] - --host Host/IP to bind to [default: 0.0.0.0] - --token Authentication token (optional) - --tls-cert TLS certificate path (optional) - --tls-key TLS private key path (optional) - --log-level Log level: error, warn, info, debug, trace - --cache-duration Metrics cache duration in milliseconds [default: 1000] - --max-processes Maximum processes to report [default: 100] - --enable-journald Enable journald log collection - --journald-lines Number of journal lines to keep [default: 1000] +``` +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] ``` -### Configuration File (APT Installation) +| Option | Description | +|---|---| +| `--tls-ca `, `-t ` | Pin the agent's TLS certificate (PEM). Auto-upgrades `ws://` to `wss://`. See [TLS Configuration](../security/tls.md) | +| `--verify-hostname` | Enable strict hostname/SAN verification instead of certificate pinning | +| `--profile `, `-P ` | Use (or create) a saved connection profile | +| `--save` | Overwrite an existing profile without the interactive prompt | +| `--demo` | Spin up a temporary local agent and connect to it | +| `--compact` | Pin the compact layout (normally auto-selected when the window is small) | +| `--metrics-interval-ms ` | Fast metrics polling interval (default: 500, clamped to ≥ 100) | +| `--processes-interval-ms ` | Process list polling interval (default: 2000, clamped to ≥ 200) | -Edit `/etc/default/socktop-agent`: +**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](../security/token.md). + +### 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](./connection-profiles.md) 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 + +| Flag | Description | +|---|---| +| `--port `, `-p ` | Port to listen on (default: 3000, or 8443 with TLS) | +| `--enableSSL` | Enable TLS with an auto-generated self-signed certificate | +| `--version`, `-V` | Print version and exit | + +The agent always binds to `0.0.0.0` (all interfaces). To restrict access, use a firewall or an [authentication token](../security/token.md). + +### Environment Variables + +Core settings: + +| Variable | Description | +|---|---| +| `SOCKTOP_PORT` | Port to listen on (same as `--port`) | +| `SOCKTOP_ENABLE_SSL` | Set to `1` to enable TLS (same as `--enableSSL`) | +| `SOCKTOP_TOKEN` | Require this authentication token from clients | +| `SOCKTOP_AGENT_GPU` | Set to `0` to disable GPU metrics collection | +| `SOCKTOP_AGENT_TEMP` | Set to `0` to disable CPU temperature collection | +| `SOCKTOP_AGENT_EXTRA_SANS` | Comma-separated extra IPs/DNS names to include in the auto-generated TLS certificate | + +Tuning (defaults are sensible; change only if you have a reason): + +| Variable | Default | Description | +|---|---|---| +| `SOCKTOP_WORKER_THREADS` | 2 | Tokio worker threads (1–16). The agent is I/O-bound; 2 is enough for typical use | +| `SOCKTOP_AGENT_METRICS_TTL_MS` | 250 | How long a collected metrics snapshot is served from cache | +| `SOCKTOP_AGENT_DISKS_TTL_MS` | 1000 | Disk snapshot cache lifetime | +| `SOCKTOP_AGENT_PROCESSES_TTL_MS` | 1500 | Process list cache lifetime (Linux) | +| `SOCKTOP_AGENT_NAME_CACHE_CLEANUP_THRESHOLD` | 1000 | Process-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: ```bash -# Port configuration -PORT=3000 - -# Bind address (0.0.0.0 for all interfaces, 127.0.0.1 for local only) -HOST=0.0.0.0 - -# Authentication token -# Uncomment and set for token-based auth -# TOKEN=your-secret-token-here - -# TLS configuration -# Uncomment to enable TLS -# TLS_CERT=/etc/socktop/cert.pem -# TLS_KEY=/etc/socktop/key.pem - -# Log level (error, warn, info, debug, trace) -LOG_LEVEL=info - -# Cache duration (milliseconds) -CACHE_DURATION=1000 - -# Maximum processes to report -MAX_PROCESSES=100 - -# Enable journald collection -ENABLE_JOURNALD=false - -# Additional options -# OPTIONS="--some-option --another-option" +sudo systemctl edit socktop-agent ``` -After editing, restart the service: +```ini +[Service] +Environment=SOCKTOP_TOKEN=changeme +Environment=SOCKTOP_AGENT_GPU=0 +``` + +Then: ```bash +sudo systemctl daemon-reload sudo systemctl restart socktop-agent ``` -### Environment Variables (debugging) +To change the port or enable TLS, override `ExecStart` (it must be cleared first in a drop-in): -Override settings with environment variables: - -```bash -# Refresh rate -export SOCKTOP_REFRESH_RATE=2000 - -# Default profile -export SOCKTOP_DEFAULT_PROFILE=production - -# Config directory -export SOCKTOP_CONFIG_DIR=~/.config/socktop - -# Disable TLS verification (not recommended) -export SOCKTOP_NO_VERIFY_TLS=1 - -# Authentication token -export SOCKTOP_TOKEN=your-secret-token +```ini +[Service] +ExecStart= +ExecStart=/usr/bin/socktop_agent --enableSSL --port 8443 ``` -### Agent Environment Variables (debugging) - -```bash -# Port -export SOCKTOP_AGENT_PORT=3000 - -# Host -export SOCKTOP_AGENT_HOST=0.0.0.0 - -# Token -export SOCKTOP_AGENT_TOKEN=secret - -# TLS cert path -export SOCKTOP_AGENT_TLS_CERT=/path/to/cert.pem - -# TLS key path -export SOCKTOP_AGENT_TLS_KEY=/path/to/key.pem - -# Log level -export SOCKTOP_AGENT_LOG_LEVEL=info -``` +See [Agent Service Setup](../installation/agent-service.md) for the full service walkthrough. diff --git a/docs/src/usage/connection-profiles.md b/docs/src/usage/connection-profiles.md index 2759414..1021fb3 100644 --- a/docs/src/usage/connection-profiles.md +++ b/docs/src/usage/connection-profiles.md @@ -7,7 +7,7 @@ Connection profiles allow you to save frequently used agent connections for quic Instead of typing the full WebSocket URL every time: ```bash -socktop ws://production-server.example.com:3000 +socktop ws://production-server.example.com:3000/ws ``` You can save it as a profile and use: diff --git a/docs/src/usage/general.md b/docs/src/usage/general.md index a045f34..e31e667 100644 --- a/docs/src/usage/general.md +++ b/docs/src/usage/general.md @@ -11,7 +11,7 @@ Try socktop without any setup: 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"). +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 @@ -27,14 +27,14 @@ Enter number (or blank to abort): Select a number to connect, or choose `demo` (always available). Press Enter on blank to abort. -### Monitor Remote System +### Monitor a Remote System -Connect to a remote agent by specifying the WebSocket URL: +Connect to a remote agent by specifying the WebSocket URL (note the `/ws` path): ```bash socktop ws://hostname:3000/ws socktop ws://192.168.1.100:3000/ws -socktop wss://secure-host:8443/ws # With TLS +socktop --tls-ca /path/to/cert.pem wss://secure-host:8443/ws # With TLS ``` ### Using Connection Profiles @@ -44,29 +44,12 @@ For frequently monitored systems, use profiles: ```bash # Use a saved profile socktop -P production-server -socktop -P rpi-cluster-01 - -# List available profiles -socktop --list-profiles +socktop --profile rpi-cluster-01 ``` -See [Connection Profiles](./connection-profiles.md). +Running `socktop` with no arguments lists your saved profiles interactively. See [Connection Profiles](./connection-profiles.md). -## Keyboard and Mouse - -### Keyboard - -- Quit: `q` or `Esc` - -### 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 - -### Filtering Processes +## Finding Processes Press `/` to enter filter mode: @@ -74,42 +57,54 @@ Press `/` to enter filter mode: Filter: pyth_ ``` -This will show only processes matching "pyth" (case-insensitive). Press `ESC` to clear filter. +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 -### Client Options - -```bash -socktop [OPTIONS] [URL] - -OPTIONS: - -P, --profile Use a connection profile - -t, --token Authentication token - --tls-ca CA certificate for TLS verification - --verify-hostname Enable strict hostname verification for TLS - --metrics-interval-ms Fast metrics polling interval (default: 500) - --processes-interval-ms Process list polling interval (default: 2000) - --list-profiles List available connection profiles - -h, --help Show help information - -V, --version Show version information - -ARGUMENTS: - [URL] WebSocket URL (e.g., ws://host:3000) ``` +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](./configuration.md) for the full option reference, and [Keyboard and Mouse Controls](./keyboard-mouse.md) for all key bindings. ### Examples ```bash # Connect with custom intervals -socktop ws://server:3000 --metrics-interval-ms 750 --processes-interval-ms 3000 +socktop --metrics-interval-ms 750 --processes-interval-ms 3000 ws://server:3000/ws -# Connect with authentication token -socktop ws://server:3000 -t mySecretToken +# Connect with an authentication token (query parameter, quoted) +socktop "ws://server:3000/ws?token=mySecretToken" -# Connect with TLS and custom CA -socktop wss://server:3000 --tls-ca /path/to/ca.pem +# Connect with TLS, pinning the agent's certificate +socktop --tls-ca /path/to/cert.pem wss://server:8443/ws -# Connect with TLS and hostname verification -socktop wss://server:3000 --tls-ca /path/to/ca.pem --verify-hostname +# 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 ``` diff --git a/docs/src/usage/keyboard-mouse.md b/docs/src/usage/keyboard-mouse.md index 42a0069..6e368f0 100644 --- a/docs/src/usage/keyboard-mouse.md +++ b/docs/src/usage/keyboard-mouse.md @@ -12,6 +12,7 @@ - `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](./general.md#killing-a-process)) - `x` - Clear selection ### Search (after /) @@ -28,6 +29,7 @@ ### 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