Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
273 changes: 263 additions & 10 deletions readme.md
Original file line number Diff line number Diff line change
@@ -1,30 +1,283 @@
# UniProc

UniProc is a terminal-first process monitor built with Rust and Ratatui. It monitors one process safely by PID or exact name, with a responsive dashboard and script-friendly exports.
UniProc is a terminal-first process resource monitor built with Rust, Ratatui, Crossterm, and sysinfo. It monitors one running process by PID or exact process name, displays an interactive TUI dashboard, and can export captured samples as CSV or pretty JSON for scripts, reports, and investigations.

## Why UniProc

Use UniProc when you want a lightweight, focused view of one process instead of a full-system monitor. It is useful for watching local services, CLI tools, development servers, stress tests, and short profiling sessions where you care about CPU, memory, disk I/O, and network activity over time.

## Features

- Live CPU, resident memory, disk I/O, and history charts
- System-wide network traffic shown alongside the selected process (per-process network I/O is not portable)
- Pause, clear-history, and quit controls
- Exact process-name lookup that refuses ambiguous matches
- Bounded in-memory history and reliable terminal cleanup
- CSV and pretty JSON export with byte-accurate fields
- Interactive Ratatui dashboard with CPU, resident memory, disk I/O, network, and history views
- Safe target selection by PID or exact process name
- Ambiguous process-name protection, with a prompt to select a PID when multiple processes match
- Pause, clear-history, and quit controls in the dashboard
- Bounded in-memory history for long-running TUI sessions
- CSV export for spreadsheet and shell workflows
- Pretty JSON export for automation and downstream tooling
- Byte-accurate raw fields in export files
- Reliable terminal cleanup when leaving the alternate screen

## Status

UniProc is early but usable. The command-line interface and export fields are intentionally small and stable for the current release, but the project is still pre-1.0, so future versions may refine the dashboard and output formats.

## Platform Support

UniProc is built on cross-platform Rust libraries and should work on common Unix-like systems and Windows.

Current support notes:

- macOS: expected to work
- Linux: expected to work
- Windows: not tested yet, but it should ideally work because the underlying libraries support Windows

Some metric values are platform dependent. In particular, disk I/O comes from process refresh data exposed by `sysinfo`, and network traffic is reported system-wide because portable per-process network I/O is not available through the current implementation.

## Requirements

- Rust toolchain with Cargo
- A terminal that supports alternate-screen TUI applications
- Permission to inspect the target process

The crate uses Rust edition `2024`, so use a recent stable Rust toolchain.

## Installation

From the repository root:

## Use
```bash
cargo build --release
```

The optimized binary will be created at:

```bash
target/release/uniproc
```

You can also run directly during development:

```bash
cargo run -- --pid 1234
cargo run -- --name my-service --interval 500
```

## Quick Start

Monitor a process by PID:

```bash
cargo run -- --pid 1234
```

Monitor a process by exact name:

```bash
cargo run -- --name my-service
```

Sample more frequently:

```bash
cargo run -- --pid 1234 --interval 500
```

Capture CSV for a fixed duration:

```bash
cargo run -- --pid 1234 --duration 60 --csv metrics.csv
```

Capture JSON for a fixed duration:

```bash
cargo run -- --pid 1234 --duration 60 --json metrics.json
```

Use `p` or `Space` to pause the dashboard, `c` to clear its history, and `q` or `Esc` to quit. Export modes require `--duration` so they always finish predictably.
## CLI Reference

```text
uniproc --pid <PID> [OPTIONS]
uniproc --name <NAME> [OPTIONS]
```

Exactly one target is required:

| Option | Description |
| --- | --- |
| `--pid <PID>` | Monitor the process with this process ID. |
| `--name <NAME>` | Monitor a process by exact process name. If multiple processes match, UniProc exits and prints the matching PIDs so you can choose one explicitly. |

General options:

| Option | Default | Description |
| --- | --- | --- |
| `--interval <MS>` | `1000` | Sampling interval in milliseconds. Must be at least `1`. |
| `--duration <SECONDS>` | none | Stop collection after this many seconds. Required when using `--csv` or `--json`. |
| `--csv <PATH>` | none | Write captured samples as CSV instead of starting the interactive dashboard. |
| `--json <PATH>` | none | Write captured samples as pretty JSON instead of starting the interactive dashboard. |
| `--help` | none | Print command help. |
| `--version` | none | Print the UniProc version. |

Export modes require `--duration` so the command has a defined end. Without `--csv` or `--json`, UniProc starts the interactive dashboard.

## Dashboard Controls

| Key | Action |
| --- | --- |
| `p` | Pause or resume sampling. |
| `Space` | Pause or resume sampling. |
| `c` | Clear the in-memory dashboard history. |
| `q` | Quit and return collected samples to the caller. |
| `Esc` | Quit and return collected samples to the caller. |
Comment on lines +97 to +132

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

fd -t f -e rs -0 | xargs -0 -r rg -n -C 5 \
  'Parser|pid|name|interval|duration|csv|json|KeyCode|Esc|Space|clear|pause'

Repository: imsudiproy/uniproc

Length of output: 24675


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

printf '%s\n' '--- README CLI section ---'
sed -n '90,140p' readme.md

printf '%s\n' '--- main.rs ---'
cat -n src/main.rs

printf '%s\n' '--- monitor.rs ---'
cat -n src/core/monitor.rs

printf '%s\n' '--- TUI event loop ---'
sed -n '65,130p' src/output/tui.rs

printf '%s\n' '--- export writers ---'
cat -n src/output/csv.rs
cat -n src/output/json.rs

Repository: imsudiproy/uniproc

Length of output: 12495


🌐 Web query:

clap Rust ArgGroup required args multiple default behavior

💡 Result:

In the Rust clap library, an ArgGroup allows you to group multiple arguments together to define specific validation rules [1][2]. The behavior of a required ArgGroup is determined by the interaction between the.required and.multiple settings [3][2]. Default Behavior and Settings: 1..multiple(false) (Default): By default, multiple is set to false [3][4]. When combined with.required(true), this enforces that one and only one argument from the group must be present at runtime [3][2]. Providing more than one argument from the group will result in an error [3][2]. 2..multiple(true): When set to true, this allows more than one argument from the group to be used [3][4]. When combined with.required(true), this enforces that at least one argument from the group must be present, but allows for multiple arguments to be used simultaneously [3][2]. Important Considerations: - Required Groups: When an ArgGroup is marked as required, at least one argument from that group must be present at runtime [2]. If all arguments in the group have default values, the group may behave as if it is always present, which can sometimes lead to issues if requirements are not met or conflicts arise [5][6]. - Conflicting Rules: Setting a group as required is subject to other argument rules; conflicting arguments or overrides can take precedence over the required status [7][2]. - Interaction with Defaults: Be aware that if arguments within a group have default values assigned, it may trigger validation errors regarding the group's requirements, as clap interprets the presence of default values as the argument being "used" [5][6]. By using.multiple(true) in conjunction with.required(true), you change the restriction from "exactly one" to "at least one," providing flexibility when multiple related flags should be accepted together [3][2].

Citations:


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

printf '%s\n' '--- README metrics section ---'
sed -n '135,190p' readme.md

printf '%s\n' '--- ProcessInfo fields ---'
sed -n '1,35p' src/datasources/cpu_mem.rs

printf '%s\n' '--- CSV header and row fields ---'
sed -n '6,28p' src/output/csv.rs

Repository: imsudiproy/uniproc

Length of output: 4339


Align the documented CSV header with the emitted schema. The README uses system_network_received_bytes and system_network_transmitted_bytes, but the output fields are network_received_bytes and network_transmitted_bytes. Update the CSV example to match the generated header.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@readme.md` around lines 97 - 132, Update the README CSV example’s header to
use network_received_bytes and network_transmitted_bytes instead of the
system_network_* names, matching the fields emitted by the CSV output schema.


## Metrics

UniProc currently collects these fields for each sample:

| Field | Unit | Notes |
| --- | --- | --- |
| `timestamp_ms` | milliseconds | Unix timestamp in milliseconds. |
| `pid` | process ID | Target process ID. |
| `name` | string | Process name reported by the operating system. |
| `cpu_percent` | percent | CPU usage reported by `sysinfo`. |
| `memory_bytes` | bytes | Resident memory for the process. |
| `system_memory_bytes` | bytes | Total system memory at sample time. |
| `virtual_memory_bytes` | bytes | Virtual memory for the process. |
| `disk_read_bytes` | bytes | Bytes read since the preceding process refresh, platform dependent. |
| `disk_written_bytes` | bytes | Bytes written since the preceding process refresh, platform dependent. |
| `network_received_bytes` | bytes | System-wide network bytes received since the preceding refresh. |
| `network_transmitted_bytes` | bytes | System-wide network bytes transmitted since the preceding refresh. |
Comment on lines +147 to +150

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

fd -t f -e rs -0 | xargs -0 -r rg -n -C 6 \
  'disk_read_bytes|disk_written_bytes|network_received_bytes|network_transmitted_bytes|read_bytes|written_bytes|refresh|delta|File::create|OpenOptions'

Repository: imsudiproy/uniproc

Length of output: 10046


Correct the network metric descriptions.

disk_read_bytes and disk_written_bytes are refresh deltas. The network fields sum cumulative interface counters, so they are not deltas since the preceding refresh. Update the README or compute network deltas before export. File::create truncates existing output files as documented.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@readme.md` around lines 147 - 150, Update the README descriptions for
network_received_bytes and network_transmitted_bytes to state that they
represent cumulative system-wide interface counters, not bytes received or
transmitted since the preceding refresh; leave the disk metric descriptions
unchanged.


The dashboard formats byte values for readability. Export files keep raw byte values.

## CSV Output

CSV export writes a header row followed by one row per sample:

```text
timestamp_ms,pid,name,cpu_percent,memory_bytes,system_memory_bytes,virtual_memory_bytes,disk_read_bytes,disk_written_bytes,system_network_received_bytes,system_network_transmitted_bytes
Comment on lines +147 to +159

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

fd -t f -e rs -0 | xargs -0 -r rg -n -C 6 \
  'network_received_bytes|network_transmitted_bytes|system_network_received_bytes|system_network_transmitted_bytes|serialize|write_record'

Repository: imsudiproy/uniproc

Length of output: 5098


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

printf '%s\n' '--- README schema and related sections ---'
sed -n '125,205p' readme.md

printf '%s\n' '--- Output modules and tests ---'
fd -t f | rg '(^|/)(csv|json|output|readme|test|tests)' | sort
rg -n -C 5 'serde_json|to_string|write\(|CSV|csv|network_received_bytes|network_transmitted_bytes' src tests 2>/dev/null || true

Repository: imsudiproy/uniproc

Length of output: 13577


Use the canonical network field names in the CSV header.

The CSV serializer writes network_received_bytes and network_transmitted_bytes, but its header declares system_network_received_bytes and system_network_transmitted_bytes. Update the header and add an output-schema test.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@readme.md` around lines 147 - 159, Update the CSV header documentation and
serializer to use the canonical network field names network_received_bytes and
network_transmitted_bytes instead of the system_network_* variants, and add an
output-schema test covering the header and corresponding row columns.

```

Example:

```bash
cargo run -- --pid 1234 --duration 30 --csv metrics.csv
```

## JSON Output

JSON export writes a pretty-printed array of sample objects.

Example:

```bash
cargo run -- --pid 1234 --duration 30 --json metrics.json
```

Example shape:

```json
[
{
"timestamp_ms": 1760000000000,
"pid": 1234,
"name": "my-service",
"cpu_percent": 12.5,
"memory_bytes": 104857600,
"system_memory_bytes": 17179869184,
"virtual_memory_bytes": 4294967296,
"disk_read_bytes": 4096,
"disk_written_bytes": 8192,
"network_received_bytes": 2048,
"network_transmitted_bytes": 1024
}
]
```

## Behavior and Limitations

- UniProc monitors one process per run.
- `--name` uses exact process-name matching, not substring matching.
- If the process exits while monitoring, UniProc exits with an error.
- Dashboard history is bounded to avoid unbounded memory growth.
- Export collection sleeps for the configured interval between samples.
- Disk I/O values are platform dependent.
- Network values are system-wide deltas, not per-process network usage.
- Export paths are overwritten if the target file already exists.

## Troubleshooting

`process with PID <pid> was not found`

The PID does not exist or the process exited before UniProc could start sampling.

`no running process exactly named "<name>"`

The process name did not match exactly. Check the process name shown by your operating system and try again.

`"<name>" matches multiple processes`

More than one process has the same exact name. Re-run UniProc with `--pid` and one of the PIDs printed in the error message.

`--duration is required with --csv or --json`

Export mode needs a fixed end time. Add `--duration <SECONDS>`.

Terminal display looks broken after exit

UniProc attempts to restore the terminal on exit. If the terminal is still in a bad state after an unexpected interruption, run:

```bash
reset
```

## Development

Run tests:

```bash
cargo test
```

Check formatting:

```bash
cargo fmt --check
```

Build the release binary:

```bash
cargo build --release
```

Run the dashboard against the current shell or another known process:

```bash
cargo run -- --pid 1234
```

Optional local stress-test setup on Debian or Ubuntu:

```bash
sudo apt install -y stress
stress --cpu 1 --timeout 250
```

## Project Structure

```text
src/main.rs CLI parsing and top-level command flow
src/core/monitor.rs Target resolution and sample collection loop
src/datasources/cpu_mem.rs Process sampling through sysinfo
src/output/tui.rs Interactive Ratatui dashboard
src/output/csv.rs CSV writer
src/output/json.rs JSON writer
tests/ Integration tests
doc/help.md Extra development notes
```

## License

See `LICENSE`.
Loading