treewide: set up rustfmt and taplo with custom rules
Signed-off-by: NotAShelf <raf@notashelf.dev> Change-Id: I794f9152bb02e3dd91c9738369b94fc66a6a6964
This commit is contained in:
parent
a4a0b9135a
commit
ffae695240
27 changed files with 1851 additions and 1618 deletions
28
.rustfmt.toml
Normal file
28
.rustfmt.toml
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
# float_literal_trailing_zero = "Always" # TODO: Warning for some reason?
|
||||
condense_wildcard_suffixes = true
|
||||
doc_comment_code_block_width = 80
|
||||
edition = "2024" # Keep in sync with Cargo.toml.
|
||||
enum_discrim_align_threshold = 60
|
||||
force_explicit_abi = false
|
||||
force_multiline_blocks = true
|
||||
format_code_in_doc_comments = true
|
||||
format_macro_matchers = true
|
||||
format_strings = true
|
||||
group_imports = "StdExternalCrate"
|
||||
hex_literal_case = "Upper"
|
||||
imports_granularity = "Crate"
|
||||
imports_layout = "Vertical"
|
||||
inline_attribute_width = 60
|
||||
match_block_trailing_comma = true
|
||||
max_width = 80
|
||||
newline_style = "Unix"
|
||||
normalize_comments = true
|
||||
normalize_doc_attributes = true
|
||||
overflow_delimited_expr = true
|
||||
struct_field_align_threshold = 60
|
||||
tab_spaces = 2
|
||||
unstable_features = true
|
||||
use_field_init_shorthand = true
|
||||
use_try_shorthand = true
|
||||
wrap_comments = true
|
||||
|
||||
14
.taplo.toml
Normal file
14
.taplo.toml
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
[formatting]
|
||||
align_entries = true
|
||||
column_width = 100
|
||||
compact_arrays = false
|
||||
reorder_inline_tables = true
|
||||
reorder_keys = true
|
||||
|
||||
[[rule]]
|
||||
include = [ "**/Cargo.toml" ]
|
||||
keys = [ "package" ]
|
||||
|
||||
[rule.formatting]
|
||||
reorder_keys = false
|
||||
|
||||
30
Cargo.toml
30
Cargo.toml
|
|
@ -1,5 +1,4 @@
|
|||
[workspace]
|
||||
resolver = "3"
|
||||
members = [
|
||||
"crates/*",
|
||||
"scanners/scanner-system",
|
||||
|
|
@ -7,34 +6,35 @@ members = [
|
|||
"scanners/scanner-power",
|
||||
"scanners/scanner-proc",
|
||||
]
|
||||
resolver = "3"
|
||||
|
||||
[workspace.package]
|
||||
version = "0.1.0"
|
||||
authors = [ "NotAShelf <raf@notashelf.dev>" ]
|
||||
edition = "2021"
|
||||
license = "MPL-2.0"
|
||||
authors = ["NotAShelf <raf@notashelf.dev>"]
|
||||
version = "0.1.0"
|
||||
|
||||
[workspace.dependencies]
|
||||
pscand-core = { path = "./crates/pscand-core" }
|
||||
pscand-macros = { path = "./crates/pscand-macros" }
|
||||
|
||||
tokio = { version = "1.49.0", features = ["full"] }
|
||||
serde = { version = "1.0.228", features = ["derive"] }
|
||||
serde_json = "1.0.149"
|
||||
toml = "1.0.0"
|
||||
libloading = "0.9.0"
|
||||
chrono = { version = "0.4.43", features = ["serde"] }
|
||||
sysinfo = "0.38.2"
|
||||
log = "0.4.29"
|
||||
chrono = { features = [ "serde" ], version = "0.4.43" }
|
||||
clap = { features = [ "derive" ], version = "4.5.59" }
|
||||
dirs = "6.0.0"
|
||||
env_logger = "0.11.9"
|
||||
thiserror = "2.0.18"
|
||||
libloading = "0.9.0"
|
||||
log = "0.4.29"
|
||||
parking_lot = "0.12.5"
|
||||
ringbuf = "0.4.8"
|
||||
dirs = "6.0.0"
|
||||
clap = { version = "4.5.59", features = ["derive"] }
|
||||
serde = { features = [ "derive" ], version = "1.0.228" }
|
||||
serde_json = "1.0.149"
|
||||
sha2 = "0.10.9"
|
||||
sysinfo = "0.38.2"
|
||||
thiserror = "2.0.18"
|
||||
tokio = { features = [ "full" ], version = "1.49.0" }
|
||||
toml = "1.0.0"
|
||||
|
||||
[profile.release]
|
||||
codegen-units = 1
|
||||
lto = true
|
||||
opt-level = "z"
|
||||
codegen-units = 1
|
||||
|
|
|
|||
|
|
@ -1,14 +1,12 @@
|
|||
file_enabled = true
|
||||
journal_enabled = true
|
||||
log_dir = "/var/log/pscand"
|
||||
retention_days = 7
|
||||
ring_buffer_size = 60
|
||||
journal_enabled = true
|
||||
file_enabled = true
|
||||
|
||||
[scanner_dirs]
|
||||
# Directories to load scanner plugins from
|
||||
dirs = [
|
||||
"~/.local/share/pscand/scanners",
|
||||
]
|
||||
dirs = [ "~/.local/share/pscand/scanners" ]
|
||||
|
||||
[scanners.system]
|
||||
enabled = true
|
||||
|
|
|
|||
|
|
@ -10,20 +10,20 @@ name = "pscand"
|
|||
path = "src/main.rs"
|
||||
|
||||
[dependencies]
|
||||
chrono.workspace = true
|
||||
clap.workspace = true
|
||||
dirs.workspace = true
|
||||
env_logger.workspace = true
|
||||
libloading.workspace = true
|
||||
log.workspace = true
|
||||
parking_lot.workspace = true
|
||||
pscand-core.workspace = true
|
||||
pscand-macros.workspace = true
|
||||
tokio.workspace = true
|
||||
ringbuf.workspace = true
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
toml.workspace = true
|
||||
libloading.workspace = true
|
||||
chrono.workspace = true
|
||||
log.workspace = true
|
||||
env_logger.workspace = true
|
||||
thiserror.workspace = true
|
||||
parking_lot.workspace = true
|
||||
ringbuf.workspace = true
|
||||
dirs.workspace = true
|
||||
sysinfo.workspace = true
|
||||
clap.workspace = true
|
||||
sha2.workspace = true
|
||||
sysinfo.workspace = true
|
||||
thiserror.workspace = true
|
||||
tokio.workspace = true
|
||||
toml.workspace = true
|
||||
|
|
|
|||
|
|
@ -1,19 +1,45 @@
|
|||
#![allow(improper_ctypes_definitions)]
|
||||
|
||||
use std::{
|
||||
fs,
|
||||
io::Read,
|
||||
path::{
|
||||
Path,
|
||||
PathBuf,
|
||||
},
|
||||
sync::{
|
||||
atomic::{
|
||||
AtomicBool,
|
||||
Ordering,
|
||||
},
|
||||
Arc,
|
||||
},
|
||||
time::{
|
||||
Duration,
|
||||
Instant,
|
||||
SystemTime,
|
||||
UNIX_EPOCH,
|
||||
},
|
||||
};
|
||||
|
||||
use clap::Parser;
|
||||
use libloading::Library;
|
||||
use pscand_core::Config as CoreConfig;
|
||||
use pscand_core::logging::{LogLevel, RingBufferLogger};
|
||||
use pscand_core::scanner::Scanner;
|
||||
use sha2::{Digest, Sha256};
|
||||
use std::fs;
|
||||
use std::io::Read;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
|
||||
use tokio::sync::RwLock;
|
||||
use tokio::time::interval;
|
||||
use pscand_core::{
|
||||
logging::{
|
||||
LogLevel,
|
||||
RingBufferLogger,
|
||||
},
|
||||
scanner::Scanner,
|
||||
Config as CoreConfig,
|
||||
};
|
||||
use sha2::{
|
||||
Digest,
|
||||
Sha256,
|
||||
};
|
||||
use tokio::{
|
||||
sync::RwLock,
|
||||
time::interval,
|
||||
};
|
||||
|
||||
type ScannerCreator = pscand_core::ScannerCreatorFfi;
|
||||
|
||||
|
|
@ -334,7 +360,8 @@ async fn run_daemon(args: RunArgs) -> Result<(), Box<dyn std::error::Error>> {
|
|||
" 1. Scanner plugins are installed in one of the configured directories"
|
||||
);
|
||||
log::error!(
|
||||
" 2. Scanner directories are correctly set in config file or PSCAND_SCANNER_DIRS env var"
|
||||
" 2. Scanner directories are correctly set in config file or \
|
||||
PSCAND_SCANNER_DIRS env var"
|
||||
);
|
||||
log::error!(" 3. Scanners are not disabled in the configuration");
|
||||
logger.log(
|
||||
|
|
@ -664,7 +691,8 @@ async fn list_scanners() -> Result<(), Box<dyn std::error::Error>> {
|
|||
"\nDynamic scanners are loaded from $PSCAND_SCANNER_DIRS (colon-separated)"
|
||||
);
|
||||
println!(
|
||||
" Default fallback: ~/.local/share/pscand/scanners/ or ~/.config/pscand/scanners/"
|
||||
" Default fallback: ~/.local/share/pscand/scanners/ or \
|
||||
~/.config/pscand/scanners/"
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,17 +6,17 @@ license.workspace = true
|
|||
authors.workspace = true
|
||||
|
||||
[dependencies]
|
||||
tokio.workspace = true
|
||||
chrono.workspace = true
|
||||
dirs.workspace = true
|
||||
log.workspace = true
|
||||
parking_lot.workspace = true
|
||||
ringbuf.workspace = true
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
toml.workspace = true
|
||||
chrono.workspace = true
|
||||
log.workspace = true
|
||||
thiserror.workspace = true
|
||||
parking_lot.workspace = true
|
||||
dirs.workspace = true
|
||||
sysinfo.workspace = true
|
||||
ringbuf.workspace = true
|
||||
thiserror.workspace = true
|
||||
tokio.workspace = true
|
||||
toml.workspace = true
|
||||
|
||||
[lib]
|
||||
name = "pscand_core"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,15 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
path::{
|
||||
Path,
|
||||
PathBuf,
|
||||
},
|
||||
};
|
||||
|
||||
use serde::{
|
||||
Deserialize,
|
||||
Serialize,
|
||||
};
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
use std::collections::HashMap;
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
fs,
|
||||
path::PathBuf,
|
||||
};
|
||||
|
||||
pub struct PowerHelper;
|
||||
|
||||
|
|
@ -103,7 +105,8 @@ impl PowerHelper {
|
|||
Ok(None)
|
||||
}
|
||||
|
||||
pub fn power_supplies() -> std::io::Result<HashMap<String, HashMap<String, String>>> {
|
||||
pub fn power_supplies(
|
||||
) -> std::io::Result<HashMap<String, HashMap<String, String>>> {
|
||||
let mut supplies = HashMap::new();
|
||||
let power_supply_path = PathBuf::from("/sys/class/power_supply");
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
use std::collections::HashMap;
|
||||
use std::fs;
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
fs,
|
||||
};
|
||||
|
||||
pub struct ProcessHelper;
|
||||
|
||||
|
|
@ -25,14 +27,16 @@ impl ProcessHelper {
|
|||
}
|
||||
|
||||
let pid: u32 = match path.file_name() {
|
||||
Some(name) => match name.to_str() {
|
||||
Some(name) => {
|
||||
match name.to_str() {
|
||||
Some(s) => s.parse().ok(),
|
||||
None => None,
|
||||
}
|
||||
.ok_or(std::io::Error::new(
|
||||
std::io::ErrorKind::InvalidData,
|
||||
"invalid pid",
|
||||
))?,
|
||||
))?
|
||||
},
|
||||
None => continue,
|
||||
};
|
||||
|
||||
|
|
@ -88,10 +92,12 @@ impl ProcessHelper {
|
|||
}
|
||||
|
||||
pub fn zombie_processes() -> std::io::Result<Vec<ProcessInfo>> {
|
||||
Ok(Self::list_processes()?
|
||||
Ok(
|
||||
Self::list_processes()?
|
||||
.into_iter()
|
||||
.filter(|p| p.state.starts_with('Z'))
|
||||
.collect())
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn process_count() -> std::io::Result<HashMap<String, usize>> {
|
||||
|
|
@ -109,14 +115,16 @@ impl ProcessHelper {
|
|||
'R' => *counts.get_mut("running").unwrap() += 1,
|
||||
'S' | 'D' => *counts.get_mut("sleeping").unwrap() += 1,
|
||||
'Z' => *counts.get_mut("zombie").unwrap() += 1,
|
||||
_ => {}
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
|
||||
Ok(counts)
|
||||
}
|
||||
|
||||
pub fn top_memory_processes(count: usize) -> std::io::Result<Vec<ProcessInfo>> {
|
||||
pub fn top_memory_processes(
|
||||
count: usize,
|
||||
) -> std::io::Result<Vec<ProcessInfo>> {
|
||||
let mut processes = Self::list_processes()?;
|
||||
processes.sort_by(|a, b| b.memory_kb.cmp(&a.memory_kb));
|
||||
processes.truncate(count);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
use std::collections::HashMap;
|
||||
use std::fs;
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
fs,
|
||||
};
|
||||
|
||||
pub struct ResourceHelper;
|
||||
|
||||
|
|
@ -72,7 +74,8 @@ impl ResourceHelper {
|
|||
Ok(result)
|
||||
}
|
||||
|
||||
pub fn disk_stats() -> std::io::Result<HashMap<String, HashMap<String, u64>>> {
|
||||
pub fn disk_stats() -> std::io::Result<HashMap<String, HashMap<String, u64>>>
|
||||
{
|
||||
let content = fs::read_to_string("/proc/diskstats")?;
|
||||
let mut result = HashMap::new();
|
||||
|
||||
|
|
@ -81,7 +84,8 @@ impl ResourceHelper {
|
|||
if parts.len() >= 14 {
|
||||
let device = parts[2].to_string();
|
||||
let mut stats = HashMap::new();
|
||||
stats.insert("reads_completed".to_string(), parts[3].parse().unwrap_or(0));
|
||||
stats
|
||||
.insert("reads_completed".to_string(), parts[3].parse().unwrap_or(0));
|
||||
stats.insert("reads_merged".to_string(), parts[4].parse().unwrap_or(0));
|
||||
stats.insert("sectors_read".to_string(), parts[5].parse().unwrap_or(0));
|
||||
stats.insert("reads_ms".to_string(), parts[6].parse().unwrap_or(0));
|
||||
|
|
@ -89,8 +93,10 @@ impl ResourceHelper {
|
|||
"writes_completed".to_string(),
|
||||
parts[7].parse().unwrap_or(0),
|
||||
);
|
||||
stats.insert("writes_merged".to_string(), parts[8].parse().unwrap_or(0));
|
||||
stats.insert("sectors_written".to_string(), parts[9].parse().unwrap_or(0));
|
||||
stats
|
||||
.insert("writes_merged".to_string(), parts[8].parse().unwrap_or(0));
|
||||
stats
|
||||
.insert("sectors_written".to_string(), parts[9].parse().unwrap_or(0));
|
||||
stats.insert("writes_ms".to_string(), parts[10].parse().unwrap_or(0));
|
||||
result.insert(device, stats);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,11 @@
|
|||
use std::collections::HashMap;
|
||||
use std::fs;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
fs,
|
||||
path::{
|
||||
Path,
|
||||
PathBuf,
|
||||
},
|
||||
};
|
||||
|
||||
pub struct SensorHelper;
|
||||
|
||||
|
|
@ -21,7 +26,10 @@ impl SensorHelper {
|
|||
Ok(hwmons)
|
||||
}
|
||||
|
||||
pub fn read_hwmon_sensor(hwmon_path: &Path, sensor: &str) -> std::io::Result<Option<f64>> {
|
||||
pub fn read_hwmon_sensor(
|
||||
hwmon_path: &Path,
|
||||
sensor: &str,
|
||||
) -> std::io::Result<Option<f64>> {
|
||||
let sensor_path = hwmon_path.join(sensor);
|
||||
if sensor_path.exists() {
|
||||
let content = fs::read_to_string(sensor_path)?;
|
||||
|
|
@ -31,7 +39,9 @@ impl SensorHelper {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn hwmon_info(hwmon_path: &Path) -> std::io::Result<HashMap<String, String>> {
|
||||
pub fn hwmon_info(
|
||||
hwmon_path: &Path,
|
||||
) -> std::io::Result<HashMap<String, String>> {
|
||||
let mut info = HashMap::new();
|
||||
|
||||
let name_path = hwmon_path.join("name");
|
||||
|
|
@ -53,7 +63,10 @@ impl SensorHelper {
|
|||
.ok()
|
||||
.flatten()
|
||||
{
|
||||
info.insert(format!("temp_{}_celsius", id), format!("{}", t / 1000.0));
|
||||
info.insert(
|
||||
format!("temp_{}_celsius", id),
|
||||
format!("{}", t / 1000.0),
|
||||
);
|
||||
}
|
||||
}
|
||||
if filename.starts_with("fan") && filename.ends_with("_input") {
|
||||
|
|
@ -73,7 +86,8 @@ impl SensorHelper {
|
|||
.ok()
|
||||
.flatten()
|
||||
{
|
||||
info.insert(format!("voltage_{}_mv", id), format!("{}", v / 1000.0));
|
||||
info
|
||||
.insert(format!("voltage_{}_mv", id), format!("{}", v / 1000.0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -82,7 +96,8 @@ impl SensorHelper {
|
|||
Ok(info)
|
||||
}
|
||||
|
||||
pub fn all_sensors() -> std::io::Result<HashMap<String, HashMap<String, String>>> {
|
||||
pub fn all_sensors(
|
||||
) -> std::io::Result<HashMap<String, HashMap<String, String>>> {
|
||||
let mut all = HashMap::new();
|
||||
|
||||
for hwmon in Self::discover_hwmon()? {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
use std::fs;
|
||||
use std::time::Duration;
|
||||
use std::{
|
||||
fs,
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
pub struct SystemHelper;
|
||||
|
||||
|
|
@ -14,7 +16,8 @@ impl SystemHelper {
|
|||
}
|
||||
|
||||
pub fn boot_id() -> std::io::Result<String> {
|
||||
fs::read_to_string("/proc/sys/kernel/random/boot_id").map(|s| s.trim().to_string())
|
||||
fs::read_to_string("/proc/sys/kernel/random/boot_id")
|
||||
.map(|s| s.trim().to_string())
|
||||
}
|
||||
|
||||
pub fn load_average() -> std::io::Result<(f64, f64, f64)> {
|
||||
|
|
@ -36,10 +39,12 @@ impl SystemHelper {
|
|||
}
|
||||
|
||||
pub fn hostname() -> std::io::Result<String> {
|
||||
fs::read_to_string("/proc/sys/kernel/hostname").map(|s| s.trim().to_string())
|
||||
fs::read_to_string("/proc/sys/kernel/hostname")
|
||||
.map(|s| s.trim().to_string())
|
||||
}
|
||||
|
||||
pub fn kernel_version() -> std::io::Result<String> {
|
||||
fs::read_to_string("/proc/sys/kernel/osrelease").map(|s| s.trim().to_string())
|
||||
fs::read_to_string("/proc/sys/kernel/osrelease")
|
||||
.map(|s| s.trim().to_string())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,8 +4,17 @@ pub mod logging;
|
|||
pub mod scanner;
|
||||
|
||||
pub use config::Config;
|
||||
pub use logging::{DaemonLogEntry, LogLevel, RingBufferLogger};
|
||||
pub use logging::{
|
||||
DaemonLogEntry,
|
||||
LogLevel,
|
||||
RingBufferLogger,
|
||||
};
|
||||
pub use scanner::{
|
||||
get_scanner, register_scanner, MetricValue, Scanner, ScannerCreatorFfi, ScannerError,
|
||||
get_scanner,
|
||||
register_scanner,
|
||||
MetricValue,
|
||||
Scanner,
|
||||
ScannerCreatorFfi,
|
||||
ScannerError,
|
||||
};
|
||||
pub type Result<T> = std::result::Result<T, ScannerError>;
|
||||
|
|
|
|||
|
|
@ -1,19 +1,42 @@
|
|||
use chrono::{DateTime, Utc};
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
fs::{
|
||||
self,
|
||||
OpenOptions,
|
||||
},
|
||||
io::Write,
|
||||
path::{
|
||||
Path,
|
||||
PathBuf,
|
||||
},
|
||||
sync::{
|
||||
atomic::{
|
||||
AtomicU64,
|
||||
Ordering,
|
||||
},
|
||||
Arc,
|
||||
},
|
||||
time::Instant,
|
||||
};
|
||||
|
||||
use chrono::{
|
||||
DateTime,
|
||||
Utc,
|
||||
};
|
||||
use parking_lot::Mutex;
|
||||
use ringbuf::{
|
||||
storage::Heap,
|
||||
traits::*,
|
||||
wrap::caching::{CachingCons, CachingProd},
|
||||
wrap::caching::{
|
||||
CachingCons,
|
||||
CachingProd,
|
||||
},
|
||||
SharedRb,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use std::fs::{self, OpenOptions};
|
||||
use std::io::Write;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::atomic::{AtomicU64, Ordering};
|
||||
use std::sync::Arc;
|
||||
use std::time::Instant;
|
||||
use serde::{
|
||||
Deserialize,
|
||||
Serialize,
|
||||
};
|
||||
|
||||
use crate::scanner::MetricValue;
|
||||
|
||||
|
|
@ -70,7 +93,11 @@ pub struct DaemonLogEntry {
|
|||
}
|
||||
|
||||
impl DaemonLogEntry {
|
||||
pub fn new(source: impl Into<String>, event: impl Into<String>, message: String) -> Self {
|
||||
pub fn new(
|
||||
source: impl Into<String>,
|
||||
event: impl Into<String>,
|
||||
message: String,
|
||||
) -> Self {
|
||||
Self {
|
||||
timestamp: Utc::now(),
|
||||
level: LogLevel::Info,
|
||||
|
|
@ -91,7 +118,10 @@ impl DaemonLogEntry {
|
|||
}
|
||||
|
||||
impl LogEntry {
|
||||
pub fn new(scanner: impl Into<String>, metrics: HashMap<String, MetricValue>) -> Self {
|
||||
pub fn new(
|
||||
scanner: impl Into<String>,
|
||||
metrics: HashMap<String, MetricValue>,
|
||||
) -> Self {
|
||||
Self {
|
||||
timestamp: Utc::now(),
|
||||
scanner: scanner.into(),
|
||||
|
|
@ -124,7 +154,8 @@ impl LogEntry {
|
|||
}
|
||||
|
||||
pub fn to_json(&self) -> String {
|
||||
serde_json::to_string(self).unwrap_or_else(|e| format!("{{\"error\":\"{}\"}}", e))
|
||||
serde_json::to_string(self)
|
||||
.unwrap_or_else(|e| format!("{{\"error\":\"{}\"}}", e))
|
||||
}
|
||||
|
||||
pub fn to_journal(&self) -> String {
|
||||
|
|
@ -211,7 +242,13 @@ impl RingBufferLogger {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn log(&self, level: LogLevel, source: &str, event: &str, message: String) {
|
||||
pub fn log(
|
||||
&self,
|
||||
level: LogLevel,
|
||||
source: &str,
|
||||
event: &str,
|
||||
message: String,
|
||||
) {
|
||||
let entry = DaemonLogEntry {
|
||||
timestamp: Utc::now(),
|
||||
level,
|
||||
|
|
@ -256,19 +293,23 @@ impl RingBufferLogger {
|
|||
use std::os::unix::net::UnixDatagram;
|
||||
|
||||
let journal_msg = format!(
|
||||
"PRIORITY={}\nSYSLOG_IDENTIFIER=pscand\nPSCAND_SCANNER={}\nMESSAGE={}\n",
|
||||
"PRIORITY={}\nSYSLOG_IDENTIFIER=pscand\nPSCAND_SCANNER={}\nMESSAGE={}\\
|
||||
n",
|
||||
priority, scanner, msg
|
||||
);
|
||||
|
||||
if let Ok(sock) = UnixDatagram::unbound() {
|
||||
let _ = sock.send_to(journal_msg.as_bytes(), "/run/systemd/journal/socket");
|
||||
let _ =
|
||||
sock.send_to(journal_msg.as_bytes(), "/run/systemd/journal/socket");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn write_to_file(&self, entry: &LogEntry) {
|
||||
if let Some(ref path) = self.file_path {
|
||||
if let Ok(mut file) = OpenOptions::new().create(true).append(true).open(path) {
|
||||
if let Ok(mut file) =
|
||||
OpenOptions::new().create(true).append(true).open(path)
|
||||
{
|
||||
let _ = writeln!(file, "{}", entry.to_json());
|
||||
}
|
||||
}
|
||||
|
|
@ -292,19 +333,23 @@ impl RingBufferLogger {
|
|||
use std::os::unix::net::UnixDatagram;
|
||||
|
||||
let journal_msg = format!(
|
||||
"PRIORITY={}\nSYSLOG_IDENTIFIER=pscand\nPSCAND_SOURCE={}\nPSCAND_EVENT={}\nMESSAGE={}\n",
|
||||
"PRIORITY={}\nSYSLOG_IDENTIFIER=pscand\nPSCAND_SOURCE={}\\
|
||||
nPSCAND_EVENT={}\nMESSAGE={}\n",
|
||||
priority, source, event, msg
|
||||
);
|
||||
|
||||
if let Ok(sock) = UnixDatagram::unbound() {
|
||||
let _ = sock.send_to(journal_msg.as_bytes(), "/run/systemd/journal/socket");
|
||||
let _ =
|
||||
sock.send_to(journal_msg.as_bytes(), "/run/systemd/journal/socket");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn write_daemon_to_file(&self, entry: &DaemonLogEntry) {
|
||||
if let Some(ref path) = self.file_path {
|
||||
if let Ok(mut file) = OpenOptions::new().create(true).append(true).open(path) {
|
||||
if let Ok(mut file) =
|
||||
OpenOptions::new().create(true).append(true).open(path)
|
||||
{
|
||||
let _ = writeln!(file, "{}", entry.to_json());
|
||||
}
|
||||
}
|
||||
|
|
@ -384,10 +429,16 @@ impl RuntimeMonitor {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn record_collection(&self, scanner: &str, time_ms: u64, error: Option<&str>) {
|
||||
pub fn record_collection(
|
||||
&self,
|
||||
scanner: &str,
|
||||
time_ms: u64,
|
||||
error: Option<&str>,
|
||||
) {
|
||||
self.total_collections.fetch_add(1, Ordering::Relaxed);
|
||||
self.last_collection_time.store(time_ms, Ordering::Relaxed);
|
||||
self.collection_time_sum
|
||||
self
|
||||
.collection_time_sum
|
||||
.fetch_add(time_ms, Ordering::Relaxed);
|
||||
|
||||
let mut collections = self.scanner_collections.lock();
|
||||
|
|
@ -463,16 +514,13 @@ impl RuntimeMonitor {
|
|||
0.0
|
||||
};
|
||||
|
||||
scanner_stats.insert(
|
||||
name.clone(),
|
||||
ScannerStats {
|
||||
scanner_stats.insert(name.clone(), ScannerStats {
|
||||
collections: coll_count,
|
||||
errors: err_count,
|
||||
last_error: last_err,
|
||||
last_collection_time_ms: last_t,
|
||||
avg_collection_time_ms: avg_t,
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
RuntimeStats {
|
||||
|
|
@ -543,8 +591,12 @@ impl CrashDetector {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn new_with_interval(state_dir: PathBuf, heartbeat_interval_secs: u64) -> Self {
|
||||
let heartbeat = Heartbeat::new(state_dir.join("heartbeat"), heartbeat_interval_secs);
|
||||
pub fn new_with_interval(
|
||||
state_dir: PathBuf,
|
||||
heartbeat_interval_secs: u64,
|
||||
) -> Self {
|
||||
let heartbeat =
|
||||
Heartbeat::new(state_dir.join("heartbeat"), heartbeat_interval_secs);
|
||||
let state_file = state_dir.join("state");
|
||||
Self {
|
||||
heartbeat,
|
||||
|
|
|
|||
|
|
@ -1,23 +1,35 @@
|
|||
use std::collections::HashMap;
|
||||
use std::os::raw::c_void;
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
use std::sync::LazyLock;
|
||||
use std::sync::Mutex;
|
||||
use std::time::Duration;
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
os::raw::c_void,
|
||||
sync::{
|
||||
atomic::{
|
||||
AtomicUsize,
|
||||
Ordering,
|
||||
},
|
||||
LazyLock,
|
||||
Mutex,
|
||||
},
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde::{
|
||||
Deserialize,
|
||||
Serialize,
|
||||
};
|
||||
use thiserror::Error;
|
||||
|
||||
pub type ScannerBox = Box<dyn Scanner>;
|
||||
pub type ScannerResult = Result<ScannerBox>;
|
||||
pub type ScannerMetrics = HashMap<String, MetricValue>;
|
||||
pub type ScannerCollectionResult = Result<ScannerMetrics>;
|
||||
pub type ScannerCollectFn = Box<dyn Fn() -> ScannerCollectionResult + Send + Sync>;
|
||||
pub type ScannerInitFnMut = Mutex<Box<dyn FnMut(&toml::Value) -> Result<()> + Send>>;
|
||||
pub type ScannerCollectFn =
|
||||
Box<dyn Fn() -> ScannerCollectionResult + Send + Sync>;
|
||||
pub type ScannerInitFnMut =
|
||||
Mutex<Box<dyn FnMut(&toml::Value) -> Result<()> + Send>>;
|
||||
pub type ScannerCleanupFnMut = Mutex<Box<dyn FnMut() -> Result<()> + Send>>;
|
||||
pub type ScannerCreatorFfi = unsafe extern "C" fn() -> *mut c_void;
|
||||
pub type ScannerInitFn = unsafe extern "C" fn() -> *mut c_void;
|
||||
pub type ScannerDropFn = unsafe extern "C" fn(*mut c_void);
|
||||
pub type ScannerCreatorFfi = unsafe extern fn() -> *mut c_void;
|
||||
pub type ScannerInitFn = unsafe extern fn() -> *mut c_void;
|
||||
pub type ScannerDropFn = unsafe extern fn(*mut c_void);
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum ScannerError {
|
||||
|
|
|
|||
|
|
@ -11,4 +11,4 @@ proc-macro = true
|
|||
[dependencies]
|
||||
proc-macro2 = "1"
|
||||
quote = "1"
|
||||
syn = { version = "2", features = ["full"] }
|
||||
syn = { features = [ "full" ], version = "2" }
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
use proc_macro::TokenStream;
|
||||
use quote::quote;
|
||||
use syn::{parse_macro_input, ItemFn};
|
||||
use syn::{
|
||||
parse_macro_input,
|
||||
ItemFn,
|
||||
};
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn scanner(name: TokenStream, input: TokenStream) -> TokenStream {
|
||||
|
|
|
|||
|
|
@ -10,6 +10,6 @@ pscand-core.workspace = true
|
|||
toml.workspace = true
|
||||
|
||||
[lib]
|
||||
crate-type = [ "cdylib" ]
|
||||
name = "scanner_power"
|
||||
path = "src/lib.rs"
|
||||
crate-type = ["cdylib"]
|
||||
|
|
|
|||
|
|
@ -1,12 +1,20 @@
|
|||
use pscand_core::helpers::PowerHelper;
|
||||
use pscand_core::scanner::{MetricValue, Scanner};
|
||||
use std::collections::HashMap;
|
||||
use std::time::Duration;
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use pscand_core::{
|
||||
helpers::PowerHelper,
|
||||
scanner::{
|
||||
MetricValue,
|
||||
Scanner,
|
||||
},
|
||||
};
|
||||
|
||||
struct PowerScanner;
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn pscand_scanner() -> *mut std::os::raw::c_void {
|
||||
pub extern fn pscand_scanner() -> *mut std::os::raw::c_void {
|
||||
Box::into_raw(Box::new(PowerScanner)) as *mut std::os::raw::c_void
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,6 @@ pscand-core.workspace = true
|
|||
toml.workspace = true
|
||||
|
||||
[lib]
|
||||
crate-type = [ "cdylib" ]
|
||||
name = "scanner_proc"
|
||||
path = "src/lib.rs"
|
||||
crate-type = ["cdylib"]
|
||||
|
|
|
|||
|
|
@ -1,12 +1,20 @@
|
|||
use pscand_core::helpers::ProcessHelper;
|
||||
use pscand_core::scanner::{MetricValue, Scanner};
|
||||
use std::collections::HashMap;
|
||||
use std::time::Duration;
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use pscand_core::{
|
||||
helpers::ProcessHelper,
|
||||
scanner::{
|
||||
MetricValue,
|
||||
Scanner,
|
||||
},
|
||||
};
|
||||
|
||||
struct ProcScanner;
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn pscand_scanner() -> *mut std::os::raw::c_void {
|
||||
pub extern fn pscand_scanner() -> *mut std::os::raw::c_void {
|
||||
Box::into_raw(Box::new(ProcScanner)) as *mut std::os::raw::c_void
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,6 @@ pscand-core.workspace = true
|
|||
toml.workspace = true
|
||||
|
||||
[lib]
|
||||
crate-type = [ "cdylib" ]
|
||||
name = "scanner_sensor"
|
||||
path = "src/lib.rs"
|
||||
crate-type = ["cdylib"]
|
||||
|
|
|
|||
|
|
@ -1,13 +1,21 @@
|
|||
use pscand_core::helpers::SensorHelper;
|
||||
use pscand_core::scanner::{MetricValue, Scanner};
|
||||
use pscand_core::Result;
|
||||
use std::collections::HashMap;
|
||||
use std::time::Duration;
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use pscand_core::{
|
||||
helpers::SensorHelper,
|
||||
scanner::{
|
||||
MetricValue,
|
||||
Scanner,
|
||||
},
|
||||
Result,
|
||||
};
|
||||
|
||||
struct SensorScanner;
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn pscand_scanner() -> *mut std::os::raw::c_void {
|
||||
pub extern fn pscand_scanner() -> *mut std::os::raw::c_void {
|
||||
Box::into_raw(Box::new(SensorScanner)) as *mut std::os::raw::c_void
|
||||
}
|
||||
|
||||
|
|
@ -41,7 +49,8 @@ impl Scanner for SensorScanner {
|
|||
for (key, value) in values {
|
||||
if key.starts_with("temp_") && key.ends_with("_celsius") {
|
||||
if let Ok(v) = value.parse::<f64>() {
|
||||
metrics.insert(format!("{}_{}", hwmon, key), MetricValue::from_f64(v));
|
||||
metrics
|
||||
.insert(format!("{}_{}", hwmon, key), MetricValue::from_f64(v));
|
||||
temp_count += 1;
|
||||
if temp_count <= 3 {
|
||||
metrics.insert(
|
||||
|
|
@ -53,17 +62,21 @@ impl Scanner for SensorScanner {
|
|||
}
|
||||
if key.starts_with("fan_") && key.ends_with("_rpm") {
|
||||
if let Ok(v) = value.parse::<f64>() {
|
||||
metrics.insert(format!("{}_{}", hwmon, key), MetricValue::from_f64(v));
|
||||
metrics
|
||||
.insert(format!("{}_{}", hwmon, key), MetricValue::from_f64(v));
|
||||
fan_count += 1;
|
||||
if fan_count <= 2 {
|
||||
metrics
|
||||
.insert(format!("fan_{}", fan_count), MetricValue::from_f64(v));
|
||||
metrics.insert(
|
||||
format!("fan_{}", fan_count),
|
||||
MetricValue::from_f64(v),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
if key.starts_with("voltage_") {
|
||||
if let Ok(v) = value.parse::<f64>() {
|
||||
metrics.insert(format!("{}_{}", hwmon, key), MetricValue::from_f64(v));
|
||||
metrics
|
||||
.insert(format!("{}_{}", hwmon, key), MetricValue::from_f64(v));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,6 @@ pscand-core.workspace = true
|
|||
toml.workspace = true
|
||||
|
||||
[lib]
|
||||
crate-type = [ "cdylib" ]
|
||||
name = "scanner_system"
|
||||
path = "src/lib.rs"
|
||||
crate-type = ["cdylib"]
|
||||
|
|
|
|||
|
|
@ -1,8 +1,19 @@
|
|||
use pscand_core::helpers::{ResourceHelper, SystemHelper};
|
||||
use pscand_core::scanner::{MetricValue, Scanner};
|
||||
use pscand_core::Result;
|
||||
use std::collections::HashMap;
|
||||
use std::time::Duration;
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use pscand_core::{
|
||||
helpers::{
|
||||
ResourceHelper,
|
||||
SystemHelper,
|
||||
},
|
||||
scanner::{
|
||||
MetricValue,
|
||||
Scanner,
|
||||
},
|
||||
Result,
|
||||
};
|
||||
|
||||
#[derive(Default)]
|
||||
struct SystemScanner {
|
||||
|
|
@ -10,7 +21,7 @@ struct SystemScanner {
|
|||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn pscand_scanner() -> *mut std::os::raw::c_void {
|
||||
pub extern fn pscand_scanner() -> *mut std::os::raw::c_void {
|
||||
Box::into_raw(Box::new(SystemScanner::default())) as *mut std::os::raw::c_void
|
||||
}
|
||||
|
||||
|
|
@ -45,7 +56,8 @@ impl Scanner for SystemScanner {
|
|||
|
||||
if let Ok(cpu) = ResourceHelper::cpu_usage() {
|
||||
if let Some(total) = cpu.get("total_usage_percent") {
|
||||
metrics.insert("cpu_percent".to_string(), MetricValue::from_f64(*total));
|
||||
metrics
|
||||
.insert("cpu_percent".to_string(), MetricValue::from_f64(*total));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -62,7 +74,9 @@ impl Scanner for SystemScanner {
|
|||
MetricValue::Integer(*available as i64),
|
||||
);
|
||||
}
|
||||
if let (Some(used), Some(total)) = (mem.get("MemAvailable"), mem.get("MemTotal")) {
|
||||
if let (Some(used), Some(total)) =
|
||||
(mem.get("MemAvailable"), mem.get("MemTotal"))
|
||||
{
|
||||
let used_mem = total.saturating_sub(*used);
|
||||
metrics.insert(
|
||||
"mem_used_bytes".to_string(),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue