From 040d620917e4e8fceb3d89a10ea4925dd663a683 Mon Sep 17 00:00:00 2001 From: NotAShelf Date: Thu, 19 Feb 2026 00:56:43 +0300 Subject: [PATCH] docs: document project motivation, usage and scanner development Signed-off-by: NotAShelf Change-Id: Ic762bb0d4b2fa619907a9e4f94278b5f6a6a6964 --- docs/README.md | 210 +++++++++++++++++++++++++++++++++++++++++++++++ docs/SCANNERS.md | 60 ++++++++++++++ 2 files changed, 270 insertions(+) create mode 100644 docs/README.md create mode 100644 docs/SCANNERS.md diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..a4c4785 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,210 @@ +# pscand + +A pluggable system condition monitoring daemon for Linux systems. + +## Overview + +`pscand` (Pluggable System Condition Monitoring Daemon) is a lightweight, +extensible monitoring daemon that collects system metrics through dynamically +loadable scanner plugins. Built with Rust and designed for systemd-based Linux +distributions, it provides real-time monitoring of system resources with minimal +overhead. + +### Motivation + +Sometime after updating to Linux 6.18, my system has started rebooting randomly. +While at first I've assumed this is some kind of hard failure, I have then +noticed that in the system's eyes the shutdown is _entirely graceful_. This lead +me to believe this is some hardware issue, where a certain anomaly prompts the +motherboard to poweroff. To understand what kind of an anomaly is triggering the +reboots, I've created `pscand`. + +It is a pluggable system daemon that collects system metrics through custom +scanner plugins that you load, and provides insight into your system. + +### Features + +- **Modular Architecture**: Scanner plugins are dynamically loaded as shared + libraries (`.so` files) +- **Configurable**: TOML-based configuration with per-scanner settings +- **Plugin System**: Easy to extend with custom scanners +- **Systemd Integration**: Native journal logging and service support +- **Runtime Metrics**: Built-in collection statistics and health monitoring + +## Included Scanners + + + +| Scanner | Description | Metrics Collected | +| ---------------- | -------------------------- | ---------------------------------------------- | +| `scanner-system` | System resource monitoring | CPU, memory, disk, network, load averages | +| `scanner-sensor` | Hardware sensor readings | Temperatures, fan speeds, voltages (via hwmon) | +| `scanner-power` | Power management | Battery status, power supply state | +| `scanner-proc` | Process monitoring | Process states, zombie detection | + + + +## Quick Start + +### Installation + +#### From Source + +```bash +# Clone the repository +$ git clone https://git.frzn.dev/NotAShelf/pscand +$ cd pscand + +# Build the project +$ cargo build --release + +# Install binaries (adjust paths as needed for your system) +$ install -Dm755 target/release/pscand ~/.local/bin/pscand +$ install -Dm644 config/pscand.toml ~/.config/pscand/pscand.toml +``` + +### Systemd Service + +Create `/etc/systemd/system/pscand.service`: + +```ini +[Unit] +Description=Pluggable System Condition Monitoring Daemon +After=network.target + +[Service] +Type=simple +ExecStart=%h/.local/bin/pscand run +Restart=on-failure +RestartSec=5 + +[Install] +WantedBy=multi-user.target +``` + +Then enable and start: + +```bash +sudo systemctl daemon-reload +sudo systemctl enable --now pscand +``` + +### Installing via Nix + +Keep in mind that the **recommended** way of installing pscand is through Nix. A +Nix package is provided, and is designed to work without additional +configuration on first run. To get the daemon functionality, you must use the +NixOS module. + +#### Run directly with `nix run` + +```bash +nix run git+https://git.frzn.dev/NotAShelf/pscand +``` + +#### NixOS Module + +The flake provides a NixOS module at `nixosModules.default`: + +```nix +{ inputs, config, pkgs, ...}: let + + pscandPkg = inputs.pscand.packages.${pkgs.hostPlatform.system}.default; +in { + imports = [inputs.pscand.nixosModules.default]; + services.pscand = { + enable = true; + package = pscandPkg; # or your custom package + }; +} +``` + +This will: + +- Install the `pscand` binary and scanner plugins +- Create and enable a Systemd service +- Configure scanner library paths automatically + +## Usage + +```bash +# Run the daemon with default configuration +pscand run + +# Run with debug logging +pscand run --debug + +# List available built-in scanners +pscand list +``` + +## Configuration + +Configuration is stored in `/etc/pscand/pscand.toml`: + +```toml +[daemon] +log_level = "info" +scanner_dirs = ["/usr/lib/pscand/scanners"] + +[scanners.system] +enabled = true +interval = 5000 # milliseconds + +[scanners.sensor] +enabled = true +interval = 10000 +``` + +### Scanner Directories + +Scanner directories can be configured via: + +1. Config file: `scanner_dirs` array +2. Environment variable: `PSCAND_SCANNER_DIRS` (colon-separated paths) + +Default search paths: + +- `$LIB_PSCAND/scanners` +- `~/.local/share/pscand/scanners` +- `./pscand/scanners` + +## Development + +### Prerequisites + +- Rust 1.90+ (stable toolchain) +- Cargo +- Linux system with systemd + +### Building + +```bash +# Build entire workspace +cargo build + +# Build release (optimized) +cargo build --release + +# Run tests +cargo test + +# Check formatting +cargo fmt --check + +# Run clippy +cargo clippy -- -D warnings +``` + +## Contributing + +Contributions are welcome! Please ensure your code: + +- Follows the existing code style (run `cargo fmt`) +- Passes clippy lints (`cargo clippy -- -D warnings`) +- Includes appropriate tests where applicable +- Maintains backward compatibility for existing scanners + +## License + +This project is licensed under the [Mozilla Public License 2.0](LICENSE). diff --git a/docs/SCANNERS.md b/docs/SCANNERS.md new file mode 100644 index 0000000..27471c3 --- /dev/null +++ b/docs/SCANNERS.md @@ -0,0 +1,60 @@ +# Creating a Custom Scanner + +pscand comes with four scanners built-in, but you may easily create your own +scanners for future extensibility. The process is simple. + +1. Create your own crate +2. Implement the `Scanner` trait +3. Build, and place it into a scanner directory + +See below: + +## Creating your scanner crate + +```toml +# scanners/scanner-custom/Cargo.toml +[package] +name = "scanner-custom" +version = "0.1.0" +edition = "2021" + +[lib] +crate-type = ["cdylib"] + +[dependencies] +pscand-core = { workspace = true } +``` + +## Implementing the `Scanner` trait + +```rust +use pscand_core::scanner::Scanner; +use pscand_macros::scanner; + +pub struct CustomScanner; + +impl Scanner for CustomScanner { + fn name(&self) -> &str { + "custom" + } + + fn collect(&self) -> Result> { + // Collect your metrics + Ok(serde_json::json!({ + "value": 42 + })) + } +} + +#[scanner] +static SCANNER: CustomScanner = CustomScanner; +``` + +## Building and installing + +```bash +cargo build --release +# Install to a directory in PSCAND_SCANNER_DIRS (e.g., ~/.local/share/pscand/scanners) +install -Dm755 target/release/libscanner_custom.so \ + ~/.local/share/pscand/scanners/scanner-custom.so +```