A ground-up Rust rewrite of the popular Vitals GNOME Shell extension -- rebuilt as a native GTK4/Adwaita desktop app, D-Bus daemon, and optional shell extension.
Features • Performance • Installation • Usage • Configuration • Contributing
|
Comprehensive Monitoring
|
Modern Architecture
|
|
Production Ready
|
Built for Performance
|
Real benchmarks measured on the same machine (AMD Ryzen, 28 GiB RAM, Fedora 45, kernel 7.0). Reproduce with
cargo run --release --example benchmark.
| 4.8x | 2x | 13% | 0 |
|---|---|---|---|
| Less Memory 15.4 MiB vs 73.9 MiB RSS |
Faster Formatting 0.105 us vs 0.203 us/call |
Faster P99 Latency 26.9 ms vs 31.0 ms |
GC Pauses Ownership model, no runtime |
The Rust daemon uses 15.4 MiB RSS while collecting all 10 sensor categories. The GJS extension consumes 35-74 MiB for its JavaScript runtime alone, before accounting for GNOME Shell overhead.
| vitals-rs | Vitals (GJS) | Delta | |
|---|---|---|---|
| RSS (idle, after first poll) | 15.4 MiB | 73.9 MiB | 4.8x less |
| RSS (runtime baseline) | 15.4 MiB | 34.7 MiB | 2.3x less |
100 consecutive polls reading temperature, voltage, fan, memory, CPU, system, network, and storage from /proc and /sys:
| vitals-rs | Vitals (GJS) | |
|---|---|---|
| Average | 17.7 ms | 18.3 ms |
| Median | 17.1 ms | 17.6 ms |
| P99 | 26.9 ms | 31.0 ms |
| Max | 30.9 ms | 36.1 ms |
| Readings/poll | 71 | -- |
Both are I/O-bound (kernel VFS reads), but Rust is consistently faster at the tail -- zero GC pauses mean no surprise latency spikes. The Rust numbers include full parsing and computation; the GJS numbers measure raw file reads only.
50,000 sensor values formatted (temperature, percent, hertz, memory, watt with unit scaling):
| vitals-rs | Vitals (GJS) | Delta | |
|---|---|---|---|
| Total | 5.2 ms | 10.2 ms | 2.0x faster |
| Per call | 0.105 us | 0.203 us | 1.9x faster |
| vitals-rs | Vitals (GJS) | |
|---|---|---|
| Type safety | Compile-time | Runtime |
| Concurrency | Native threads | Single-threaded |
| GC pauses | None | Periodic |
| Unit tests | 105 | 0 |
| Memory safety | Ownership model | Manual |
| Error handling | Result / Option |
Exceptions |
+------------------+
| vitals-core | Pure Rust library
| | No GTK dependencies
| Sensors, Config |
| Format, History |
+--------+---------+
|
+------------+------------+
| |
+--------v--------+ +---------v--------+
| vitals-app | | vitals-daemon |
| | | |
| GTK4/Adwaita | | D-Bus Service |
| Desktop App | | Headless Mode |
+-----------------+ +--------+---------+
|
+--------v--------+
| extension.js |
| |
| GNOME Shell |
| Panel Client |
+-----------------+
| Crate | Description |
|---|---|
| vitals-core | Sensor discovery and polling, hwmon parsing, TOML config, value formatting, time-series history with JSON persistence. Zero GUI dependencies. |
| vitals-app | GTK4/libadwaita desktop UI with collapsible sensor groups, hot sensors bar, Cairo history graphs, and a full preferences dialog. |
| vitals-daemon | Headless D-Bus service (com.corecoding.Vitals.Sensors) built on zbus. Polls sensors on a timer and serves readings to any D-Bus client. |
| extension.js | Thin GNOME Shell extension (~215 lines). Connects to the daemon over D-Bus, renders sensor values in the top panel. Zero file I/O. |
The SensorProvider trait is the central abstraction. Each sensor category implements discover() for one-time hardware enumeration and query(dwell) for periodic polling. A SensorManager coordinates all enabled providers based on the loaded AppConfig.
Fedora / RHEL
sudo dnf install gtk4-devel libadwaita-devel gettext-devel meson ninja-build cargoUbuntu / Debian
sudo apt install libgtk-4-dev libadwaita-1-dev gettext meson ninja-build cargoArch Linux
sudo pacman -S gtk4 libadwaita gettext meson ninja cargogit clone https://github.com/NicksLameCode/vitals-rs.git
cd vitals-rs
cargo build --workspace --releaseBinaries are placed in target/release/vitals-app and target/release/vitals-daemon.
meson setup builddir --prefix=/usr
ninja -C builddir
sudo ninja -C builddir installInstalls binaries, desktop file, D-Bus service, GSettings schema, icons, and translations.
A manifest is included at build-aux/flatpak/com.corecoding.Vitals.json targeting GNOME 47:
flatpak-builder --user --install builddir build-aux/flatpak/com.corecoding.Vitals.jsonvitals-appOr launch Vitals from your application menu after system install.
vitals-daemonQuery it from the command line:
# Get all sensor readings
busctl --user call com.corecoding.Vitals /com/corecoding/Vitals \
com.corecoding.Vitals.Sensors GetReadings
# Get time-series history for a sensor
busctl --user call com.corecoding.Vitals /com/corecoding/Vitals \
com.corecoding.Vitals.Sensors GetTimeSeries s "_memory_usage_"The optional GNOME Shell extension (supporting versions 45-50) requires the daemon to be running:
# Install the extension
mkdir -p ~/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com
cp extension/* ~/.local/share/gnome-shell/extensions/Vitals@CoreCoding.com/
# Start the daemon
vitals-daemon &
# Restart GNOME Shell (X11) or re-login (Wayland)| Category | Source | What it monitors |
|---|---|---|
| Temperature | /sys/class/hwmon/*/temp*_input |
CPU package, per-core, GPU, chipset, NVMe, wireless adapter |
| Voltage | /sys/class/hwmon/*/in*_input |
CPU Vcore, DIMM, 3.3V / 5V / 12V rails |
| Fan | /sys/class/hwmon/*/fan*_input |
RPM for each detected fan |
| Memory | /proc/meminfo |
Usage %, allocated, free, cached, swap usage and totals |
| Processor | /proc/stat, cpufreq, /proc/cpuinfo |
Per-core usage %, avg/min/max frequency, vendor, cache |
| System | /proc/loadavg, /proc/uptime |
Load averages, uptime, open files, threads, kernel version |
| Network | /sys/class/net/*/statistics/ |
Per-interface TX/RX speeds, WiFi quality, public IP |
| Storage | /proc/diskstats, statvfs |
Disk usage, read/write rates, ZFS ARC stats |
| Battery | /sys/class/power_supply/BAT*/uevent |
Charge %, state, voltage, power, time remaining, cycles |
| GPU | nvidia-smi or /sys/class/drm/card*/ |
Utilization, temperature, VRAM, power, clocks, PCIe link |
Config lives at ~/.config/vitals/config.toml. Created automatically on first preferences save.
Full configuration reference
[general]
update_time = 5 # Seconds between polls (1-60)
use_higher_precision = false # Extra decimal digit
alphabetize = true # Sort sensors alphabetically
hide_zeros = false # Hide sensors reporting zero
fixed_widths = true # Prevent UI jitter
hide_icons = false # Hide icons in panel
menu_centered = false # Center dropdown menu
icon_style = 0 # 0 = Original, 1 = GNOME
monitor_cmd = "gnome-system-monitor"
[temperature]
show = true
unit = 0 # 0 = Celsius, 1 = Fahrenheit
[voltage]
show = true
[fan]
show = true
[memory]
show = true
measurement = 1 # 0 = binary (GiB), 1 = decimal (GB)
[processor]
show = true
include_static_info = false
[system]
show = true
[network]
show = true
include_public_ip = true
speed_format = 0 # 0 = bytes/s, 1 = bits/s
[storage]
show = true
path = "/"
measurement = 1 # 0 = binary (GiB), 1 = decimal (GB)
[battery]
show = false
slot = 0 # 0 = BAT0, 1 = BAT1, ... 7 = macsmc-battery
[gpu]
show = false
include_static_info = false
[history]
show_graphs = true
duration_seconds = 3600 # 1 hour of history
hot_sensors = [
"_memory_usage_",
"_system_load_1m_",
"__network-rx_max__",
]git clone https://github.com/NicksLameCode/vitals-rs.git
cd vitals-rs
cargo build --workspace # Build all crates
cargo test --workspace # Run 105 tests
cargo run -p vitals-app # Launch the GTK4 app
cargo run -p vitals-daemon # Start the D-Bus daemon
cargo run --release --example benchmark # Run benchmarkscargo fmt --all
cargo clippy --workspace -- -D warnings- Create
crates/vitals-core/src/sensors/your_sensor.rs - Implement the
SensorProvidertrait (discover()+query()) - Add a config section in
config.rswith ashowfield - Register in
SensorManager::new()insensors/mod.rs - Write tests with sample data strings
See existing providers for patterns. All parsing functions accept &str input for deterministic testing.
vitals-rs/
Cargo.toml Workspace root
meson.build System install
crates/
vitals-core/ Sensor library (no GTK)
src/
sensors/ 10 sensor providers
gpu/ NVIDIA + AMD + DRM
config.rs TOML configuration
format.rs Value formatting
history.rs Time-series storage
hwmon.rs Hardware monitor discovery
examples/
benchmark.rs Performance benchmarks
vitals-app/ GTK4/Adwaita desktop app
src/widgets/ UI components
vitals-daemon/ D-Bus service
extension/ GNOME Shell extension
data/ Desktop file, icons, schemas
po/ 20 translations
build-aux/flatpak/ Flatpak manifest
vitals-rs ships with 20 translations: Arabic, Belarusian, Catalan, Chinese (Simplified), Czech, Dutch, Finnish, French, German, Italian, Burmese, Occitan, Polish, Portuguese, Portuguese (Brazilian), Russian, Slovak, Turkish, and Ukrainian.
To add a new language:
- Copy
po/vitals.pottopo/<lang>.po - Translate with Poedit or any text editor
- Add your language code to
po/LINGUAS - Submit a pull request
See CONTRIBUTING.md for detailed guidelines.
vitals-rs is a Rust rewrite of Vitals by corecoding -- a widely-used GNOME Shell extension that has been providing system monitoring to the Linux desktop for years. This project brings the same monitoring capabilities to a standalone native application with improved performance and reliability.
Licensed under the BSD-3-Clause License.