mirror of
https://codeberg.org/icewind/palantir.git
synced 2026-06-03 10:14:09 +02:00
prepare for windows impl
This commit is contained in:
parent
f363cac81d
commit
d12b70d11e
16 changed files with 550 additions and 279 deletions
119
Cargo.lock
generated
119
Cargo.lock
generated
|
|
@ -165,6 +165,12 @@ dependencies = [
|
|||
"tracing-error",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation-sys"
|
||||
version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
|
||||
|
||||
[[package]]
|
||||
name = "cpufeatures"
|
||||
version = "0.2.7"
|
||||
|
|
@ -174,6 +180,49 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-channel"
|
||||
version = "0.5.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-deque"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crossbeam-epoch",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-epoch"
|
||||
version = "0.9.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"cfg-if",
|
||||
"crossbeam-utils",
|
||||
"memoffset 0.8.0",
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crypto-common"
|
||||
version = "0.1.6"
|
||||
|
|
@ -280,6 +329,12 @@ version = "0.15.7"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b"
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91"
|
||||
|
||||
[[package]]
|
||||
name = "encoding_rs"
|
||||
version = "0.8.32"
|
||||
|
|
@ -699,6 +754,15 @@ dependencies = [
|
|||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mime"
|
||||
version = "0.3.17"
|
||||
|
|
@ -773,7 +837,7 @@ dependencies = [
|
|||
"cc",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"memoffset",
|
||||
"memoffset 0.6.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -788,6 +852,15 @@ dependencies = [
|
|||
"static_assertions",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ntapi"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e8a3895c6391c39d7fe7ebc444a87eb2991b2a0bc718fdabd071eec617fc68e4"
|
||||
dependencies = [
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nu-ansi-term"
|
||||
version = "0.46.0"
|
||||
|
|
@ -877,6 +950,7 @@ dependencies = [
|
|||
"once_cell",
|
||||
"regex",
|
||||
"sysconf",
|
||||
"sysinfo",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"tracing",
|
||||
|
|
@ -976,6 +1050,28 @@ dependencies = [
|
|||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rayon"
|
||||
version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b"
|
||||
dependencies = [
|
||||
"either",
|
||||
"rayon-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rayon-core"
|
||||
version = "1.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d"
|
||||
dependencies = [
|
||||
"crossbeam-channel",
|
||||
"crossbeam-deque",
|
||||
"crossbeam-utils",
|
||||
"num_cpus",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.8.1"
|
||||
|
|
@ -1018,6 +1114,12 @@ version = "1.0.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294"
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.160"
|
||||
|
|
@ -1186,6 +1288,21 @@ dependencies = [
|
|||
"winapi 0.2.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sysinfo"
|
||||
version = "0.29.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "02f1dc6930a439cc5d154221b5387d153f8183529b07c19aca24ea31e0a167e1"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
"ntapi",
|
||||
"once_cell",
|
||||
"rayon",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.40"
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ nvml-wrapper = "0.8.0"
|
|||
if-addrs = "0.7.0"
|
||||
sysconf = "0.3.4"
|
||||
thiserror = "1.0.40"
|
||||
sysinfo = { version = "0.29.0", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
iai = "0.1.1"
|
||||
|
|
|
|||
69
flake.lock
generated
69
flake.lock
generated
|
|
@ -1,5 +1,23 @@
|
|||
{
|
||||
"nodes": {
|
||||
"flake-utils": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1681202837,
|
||||
"narHash": "sha256-H+Rh19JDwRtpVPAWp64F+rlEtxUWBAQW28eAi3SRSzg=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "cfacdce06f30d2b68473a46042957675eebb3401",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"naersk": {
|
||||
"inputs": {
|
||||
"nixpkgs": "nixpkgs"
|
||||
|
|
@ -33,14 +51,16 @@
|
|||
},
|
||||
"nixpkgs_2": {
|
||||
"locked": {
|
||||
"lastModified": 1682669017,
|
||||
"narHash": "sha256-Vi+p4y3wnl0/4gcwTdmCO398kKlDaUrNROtf3GOD2NY=",
|
||||
"path": "/nix/store/wm2cdd01f8jqbxpw817nv5j3sw6p93g8-source",
|
||||
"rev": "7449971a3ecf857b4a554cf79b1d9dcc1a4647d8",
|
||||
"type": "path"
|
||||
"lastModified": 1684280442,
|
||||
"narHash": "sha256-nC1/kfh6tpMQSLQalbNTNnireIlxvLLugrjZdasNh+I=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "6c591e7adc514090a77209f56c9d0c551ab8530d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"id": "nixpkgs",
|
||||
"ref": "nixos-22.11",
|
||||
"type": "indirect"
|
||||
}
|
||||
},
|
||||
|
|
@ -48,9 +68,31 @@
|
|||
"inputs": {
|
||||
"naersk": "naersk",
|
||||
"nixpkgs": "nixpkgs_2",
|
||||
"rust-overlay": "rust-overlay",
|
||||
"utils": "utils"
|
||||
}
|
||||
},
|
||||
"rust-overlay": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils",
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1684290028,
|
||||
"narHash": "sha256-IWWfoF5aU8wzxJ6ixuW+3KRlppYvmhUP5v6owWiXJMQ=",
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"rev": "ded1f327ff2bdf0eb4bbb945865441ac636c423e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
|
|
@ -66,9 +108,24 @@
|
|||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems_2": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"utils": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
"systems": "systems_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1681202837,
|
||||
|
|
|
|||
33
flake.nix
33
flake.nix
|
|
@ -1,7 +1,10 @@
|
|||
{
|
||||
inputs = {
|
||||
nixpkgs.url = "nixpkgs/nixos-22.11";
|
||||
utils.url = "github:numtide/flake-utils";
|
||||
naersk.url = "github:nix-community/naersk";
|
||||
rust-overlay.url = "github:oxalica/rust-overlay";
|
||||
rust-overlay.inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
|
||||
outputs = {
|
||||
|
|
@ -9,9 +12,24 @@
|
|||
nixpkgs,
|
||||
utils,
|
||||
naersk,
|
||||
rust-overlay,
|
||||
}:
|
||||
utils.lib.eachDefaultSystem (system: let
|
||||
pkgs = nixpkgs.legacyPackages."${system}";
|
||||
overlays = [ (import rust-overlay) ];
|
||||
pkgs = import nixpkgs {
|
||||
inherit system overlays;
|
||||
};
|
||||
|
||||
pkgs-cross-mingw = import nixpkgs {
|
||||
crossSystem = {
|
||||
config = "x86_64-w64-mingw32";
|
||||
};
|
||||
inherit system overlays;
|
||||
};
|
||||
mingw_w64_cc = pkgs-cross-mingw.stdenv.cc;
|
||||
mingw_w64 = pkgs-cross-mingw.windows.mingw_w64;
|
||||
windows = pkgs-cross-mingw.windows;
|
||||
|
||||
naersk-lib = naersk.lib."${system}";
|
||||
in rec {
|
||||
# `nix build`
|
||||
|
|
@ -34,7 +52,18 @@
|
|||
|
||||
# `nix develop`
|
||||
devShell = pkgs.mkShell {
|
||||
nativeBuildInputs = with pkgs; [cargo bacon];
|
||||
nativeBuildInputs = with pkgs; [
|
||||
(rust-bin.stable.latest.default.override {
|
||||
targets = [ "x86_64-pc-windows-gnu" ];
|
||||
})
|
||||
bacon
|
||||
mingw_w64_cc
|
||||
];
|
||||
depsBuildBuild = [ pkgs.wine64 ];
|
||||
# buildInputs = [ windows.pthreads ];
|
||||
|
||||
CARGO_TARGET_X86_64_PC_WINDOWS_GNU_LINKER = "${mingw_w64_cc.targetPrefix}cc";
|
||||
CARGO_TARGET_X86_64_PC_WINDOWS_GNU_RUNNER = "wine64";
|
||||
};
|
||||
})
|
||||
// {
|
||||
|
|
|
|||
131
src/data.rs
Normal file
131
src/data.rs
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
use crate::SensorData;
|
||||
use std::array::IntoIter;
|
||||
use std::fmt::Write;
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct Temperatures {
|
||||
pub cpu: f32,
|
||||
pub gpu: f32,
|
||||
}
|
||||
|
||||
impl IntoIterator for Temperatures {
|
||||
type Item = (&'static str, f32);
|
||||
type IntoIter = IntoIter<Self::Item, 2>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
[("cpu", self.cpu), ("gpu", self.gpu)].into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl SensorData for Temperatures {
|
||||
fn write<W: Write>(&self, mut w: W, hostname: &str) {
|
||||
for (label, temp) in self.clone() {
|
||||
if temp != 0.0 {
|
||||
writeln!(
|
||||
&mut w,
|
||||
"temperature{{host=\"{}\", sensor=\"{}\"}} {:.1}",
|
||||
hostname, label, temp
|
||||
)
|
||||
.ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct Memory {
|
||||
pub total: u64,
|
||||
pub free: u64,
|
||||
pub available: u64,
|
||||
}
|
||||
|
||||
impl SensorData for Memory {
|
||||
fn write<W: Write>(&self, mut w: W, hostname: &str) {
|
||||
writeln!(
|
||||
&mut w,
|
||||
"memory_total{{host=\"{}\"}} {}",
|
||||
hostname, self.total
|
||||
)
|
||||
.ok();
|
||||
writeln!(
|
||||
&mut w,
|
||||
"memory_available{{host=\"{}\"}} {}",
|
||||
hostname, self.available
|
||||
)
|
||||
.ok();
|
||||
writeln!(&mut w, "memory_free{{host=\"{}\"}} {}", hostname, self.free).ok();
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct GpuMemory {
|
||||
pub total: u64,
|
||||
pub free: u64,
|
||||
}
|
||||
|
||||
impl SensorData for GpuMemory {
|
||||
fn write<W: Write>(&self, mut w: W, hostname: &str) {
|
||||
writeln!(
|
||||
&mut w,
|
||||
"gpu_memory_total{{host=\"{}\"}} {}",
|
||||
hostname, self.total
|
||||
)
|
||||
.ok();
|
||||
writeln!(
|
||||
&mut w,
|
||||
"gpu_memory_free{{host=\"{}\"}} {}",
|
||||
hostname, self.free
|
||||
)
|
||||
.ok();
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CpuTime(pub f32);
|
||||
|
||||
impl SensorData for CpuTime {
|
||||
fn write<W: Write>(&self, mut w: W, hostname: &str) {
|
||||
writeln!(w, "cpu_time{{host=\"{}\"}} {:.3}", hostname, self.0).ok();
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct NetStats {
|
||||
pub interface: String,
|
||||
pub bytes_sent: u64,
|
||||
pub bytes_received: u64,
|
||||
}
|
||||
|
||||
impl SensorData for NetStats {
|
||||
fn write<W: Write>(&self, mut w: W, hostname: &str) {
|
||||
if self.bytes_received > 0 || self.bytes_sent > 0 {
|
||||
writeln!(
|
||||
&mut w,
|
||||
"net_sent{{host=\"{}\", network=\"{}\"}} {}",
|
||||
hostname, self.interface, self.bytes_sent
|
||||
)
|
||||
.ok();
|
||||
writeln!(
|
||||
&mut w,
|
||||
"net_received{{host=\"{}\", network=\"{}\"}} {}",
|
||||
hostname, self.interface, self.bytes_received
|
||||
)
|
||||
.ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct GpuUsage {
|
||||
pub system: &'static str,
|
||||
pub usage: u32,
|
||||
}
|
||||
|
||||
impl GpuUsage {
|
||||
pub fn write<W: Write>(&self, mut w: W, hostname: &str) {
|
||||
writeln!(
|
||||
&mut w,
|
||||
r#"gpu_usage{{host="{}", system="{}"}} {:.3}"#,
|
||||
hostname, self.system, self.usage,
|
||||
)
|
||||
.ok();
|
||||
}
|
||||
}
|
||||
129
src/lib.rs
129
src/lib.rs
|
|
@ -1,27 +1,28 @@
|
|||
pub mod disk;
|
||||
pub mod docker;
|
||||
pub mod gpu;
|
||||
pub mod hwmon;
|
||||
pub mod power;
|
||||
pub mod sensors;
|
||||
|
||||
use crate::disk::zfs::pools;
|
||||
use crate::disk::*;
|
||||
use crate::sensors::*;
|
||||
use std::ffi::NulError;
|
||||
use std::fmt::Write;
|
||||
use std::io;
|
||||
use std::num::{ParseFloatError, ParseIntError};
|
||||
use std::str::Utf8Error;
|
||||
use std::sync::Mutex;
|
||||
use sysconf::SysconfError;
|
||||
use std::string::FromUtf8Error;
|
||||
|
||||
pub mod data;
|
||||
pub mod docker;
|
||||
|
||||
#[cfg(not(feature = "sysinfo"))]
|
||||
mod linux;
|
||||
#[cfg(feature = "sysinfo")]
|
||||
mod sys;
|
||||
|
||||
#[cfg(not(feature = "sysinfo"))]
|
||||
pub use linux::{get_metrics, Sensors};
|
||||
#[cfg(feature = "sysinfo")]
|
||||
pub use sys::{get_metrics, Sensors};
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum Error {
|
||||
#[error(transparent)]
|
||||
Io(#[from] io::Error),
|
||||
#[error("Unsupported sysconf")]
|
||||
Sysconf(SysconfError),
|
||||
Io(#[from] std::io::Error),
|
||||
#[error("{0}")]
|
||||
Other(String),
|
||||
#[error("Non UTF8 hostname")]
|
||||
InvalidHostName,
|
||||
#[error(transparent)]
|
||||
|
|
@ -36,98 +37,14 @@ pub enum Error {
|
|||
StatVfs,
|
||||
}
|
||||
|
||||
impl From<SysconfError> for Error {
|
||||
fn from(value: SysconfError) -> Self {
|
||||
Error::Sysconf(value)
|
||||
impl From<FromUtf8Error> for Error {
|
||||
fn from(err: FromUtf8Error) -> Self {
|
||||
Self::InvalidStringData(err.utf8_error())
|
||||
}
|
||||
}
|
||||
|
||||
pub type Result<T, E = Error> = std::result::Result<T, E>;
|
||||
|
||||
pub struct Sensors {
|
||||
pub hostname: String,
|
||||
cpu: Mutex<CpuTimeSource>,
|
||||
temp: Mutex<TemperatureSource>,
|
||||
net: Mutex<NetworkSource>,
|
||||
mem: Mutex<MemorySource>,
|
||||
disk_stats: Mutex<DiskStatSource>,
|
||||
disk_usage: Mutex<DiskUsageSource>,
|
||||
}
|
||||
|
||||
impl Sensors {
|
||||
pub fn new() -> Result<Sensors> {
|
||||
Ok(Sensors {
|
||||
hostname: hostname()?,
|
||||
cpu: Mutex::new(CpuTimeSource::new()?),
|
||||
temp: Mutex::new(TemperatureSource::new()?),
|
||||
net: Mutex::new(NetworkSource::new()?),
|
||||
mem: Mutex::new(MemorySource::new()?),
|
||||
disk_stats: Mutex::new(DiskStatSource::new()?),
|
||||
disk_usage: Mutex::new(DiskUsageSource::new()?),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_metrics(sensors: &Sensors) -> Result<String> {
|
||||
let hostname = &sensors.hostname;
|
||||
let mut disk_source = sensors.disk_stats.lock().unwrap();
|
||||
let mut disk_usage_source = sensors.disk_usage.lock().unwrap();
|
||||
let disks = disk_source.read()?;
|
||||
let disk_usage = disk_usage_source.read()?;
|
||||
let cpu = sensors.cpu.lock().unwrap().read()?;
|
||||
let memory = sensors.mem.lock().unwrap().read()?;
|
||||
let temperatures = sensors.temp.lock().unwrap().read()?;
|
||||
let mut net = sensors.net.lock().unwrap();
|
||||
let networks = net.read()?;
|
||||
let pools = pools();
|
||||
let mut result = String::with_capacity(256);
|
||||
|
||||
cpu.write(&mut result, &hostname);
|
||||
memory.write(&mut result, &hostname);
|
||||
|
||||
for pool in pools {
|
||||
writeln!(
|
||||
&mut result,
|
||||
"zfs_pool_size{{host=\"{}\", pool=\"{}\"}} {}",
|
||||
hostname, pool.name, pool.size
|
||||
)
|
||||
.ok();
|
||||
writeln!(
|
||||
&mut result,
|
||||
"zfs_pool_free{{host=\"{}\", pool=\"{}\"}} {}",
|
||||
hostname, pool.name, pool.free
|
||||
)
|
||||
.ok();
|
||||
}
|
||||
for network in networks {
|
||||
if let Ok(network) = network {
|
||||
network.write(&mut result, &hostname);
|
||||
}
|
||||
}
|
||||
for disk in disks {
|
||||
if let Ok(disk) = disk {
|
||||
disk.write(&mut result, hostname);
|
||||
}
|
||||
}
|
||||
|
||||
for disk in disk_usage {
|
||||
if let Ok(disk) = disk {
|
||||
disk.write(&mut result, hostname);
|
||||
}
|
||||
}
|
||||
for (label, temp) in temperatures {
|
||||
if temp != 0.0 {
|
||||
writeln!(
|
||||
&mut result,
|
||||
"temperature{{host=\"{}\", sensor=\"{}\"}} {:.1}",
|
||||
hostname, label, temp
|
||||
)
|
||||
.ok();
|
||||
}
|
||||
}
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
pub trait SensorData {
|
||||
/// Write sensor data in prometheus compatible format
|
||||
fn write<W: Write>(&self, w: W, hostname: &str);
|
||||
|
|
@ -147,3 +64,9 @@ pub trait MultiSensorSource {
|
|||
|
||||
fn read(&mut self) -> Result<Self::Iter<'_>>;
|
||||
}
|
||||
|
||||
pub fn hostname() -> Result<String> {
|
||||
hostname::get()?
|
||||
.into_string()
|
||||
.map_err(|_| Error::InvalidHostName)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use crate::disk::DiskUsage;
|
||||
use color_eyre::Result;
|
||||
use crate::linux::disk::DiskUsage;
|
||||
use crate::Result;
|
||||
use std::fmt::Write;
|
||||
use std::fs::read_to_string;
|
||||
use std::process::Command;
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
use crate::hwmon::FileSource;
|
||||
use crate::sensors::Memory;
|
||||
use std::fmt::Write;
|
||||
use crate::data::{GpuMemory, GpuUsage};
|
||||
use crate::linux::hwmon::FileSource;
|
||||
use std::fs::read_to_string;
|
||||
use std::str::FromStr;
|
||||
use std::sync::atomic::{AtomicU64, Ordering};
|
||||
|
|
@ -10,61 +9,23 @@ use std::time::{Duration, Instant};
|
|||
|
||||
pub mod nvidia;
|
||||
|
||||
pub fn gpu_metrics<W: Write>(mut out: W, hostname: &str) {
|
||||
if let Some(memory) = memory() {
|
||||
writeln!(
|
||||
&mut out,
|
||||
"gpu_memory_total{{host=\"{}\"}} {}",
|
||||
hostname, memory.total
|
||||
)
|
||||
.ok();
|
||||
writeln!(
|
||||
&mut out,
|
||||
"gpu_memory_free{{host=\"{}\"}} {}",
|
||||
hostname, memory.free
|
||||
)
|
||||
.ok();
|
||||
}
|
||||
|
||||
for usage in utilization() {
|
||||
usage.write(&mut out, hostname);
|
||||
}
|
||||
}
|
||||
|
||||
fn read_num<T: FromStr>(path: &str) -> Option<T> {
|
||||
read_to_string(path).ok()?.trim().parse().ok()
|
||||
}
|
||||
|
||||
pub fn memory() -> Option<Memory> {
|
||||
pub fn memory() -> Option<GpuMemory> {
|
||||
if let Some(nv_mem) = nvidia::memory() {
|
||||
return Some(nv_mem);
|
||||
}
|
||||
// 1 gpu should be enough for everyone
|
||||
let used = read_num::<u64>("/sys/class/drm/card0/device/mem_info_vram_used")?;
|
||||
let total = read_num("/sys/class/drm/card0/device/mem_info_vram_total")?;
|
||||
Some(Memory {
|
||||
Some(GpuMemory {
|
||||
total,
|
||||
free: total - used,
|
||||
available: total - used,
|
||||
})
|
||||
}
|
||||
|
||||
pub struct GpuUsage {
|
||||
pub system: &'static str,
|
||||
pub usage: u32,
|
||||
}
|
||||
|
||||
impl GpuUsage {
|
||||
pub fn write<W: Write>(&self, mut w: W, hostname: &str) {
|
||||
writeln!(
|
||||
&mut w,
|
||||
r#"gpu_usage{{host="{}", system="{}"}} {:.3}"#,
|
||||
hostname, self.system, self.usage,
|
||||
)
|
||||
.ok();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn utilization() -> impl Iterator<Item = GpuUsage> {
|
||||
let nv_usage = nvidia::utilization();
|
||||
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
use crate::gpu::GpuUsage;
|
||||
use crate::sensors::Memory;
|
||||
use crate::data::{GpuMemory, GpuUsage};
|
||||
use nvml_wrapper::enum_wrappers::device::TemperatureSensor;
|
||||
use nvml_wrapper::{Device, Nvml};
|
||||
use once_cell::sync::Lazy;
|
||||
|
|
@ -22,12 +21,11 @@ pub fn power() -> Option<u64> {
|
|||
.map(|mj| mj * 1_000)
|
||||
}
|
||||
|
||||
pub fn memory() -> Option<Memory> {
|
||||
pub fn memory() -> Option<GpuMemory> {
|
||||
let mem = device()?.memory_info().ok()?;
|
||||
Some(Memory {
|
||||
Some(GpuMemory {
|
||||
total: mem.total,
|
||||
free: mem.free,
|
||||
available: mem.free,
|
||||
})
|
||||
}
|
||||
|
||||
123
src/linux/mod.rs
Normal file
123
src/linux/mod.rs
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
pub mod disk;
|
||||
pub mod gpu;
|
||||
pub mod hwmon;
|
||||
pub mod power;
|
||||
pub mod sensors;
|
||||
|
||||
use self::disk::zfs::pools;
|
||||
use self::disk::*;
|
||||
use self::sensors::*;
|
||||
use crate::linux::disk::zfs::arcstats;
|
||||
use crate::linux::gpu::{update_gpu_power, utilization};
|
||||
use crate::linux::power::power_usage;
|
||||
use crate::{hostname, Error, MultiSensorSource, Result, SensorData, SensorSource};
|
||||
use std::fmt::Write;
|
||||
use std::sync::Mutex;
|
||||
use sysconf::SysconfError;
|
||||
|
||||
impl From<SysconfError> for Error {
|
||||
fn from(_: SysconfError) -> Self {
|
||||
Error::Other("Unsupported sysconf".into())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Sensors {
|
||||
pub hostname: String,
|
||||
cpu: Mutex<CpuTimeSource>,
|
||||
temp: Mutex<TemperatureSource>,
|
||||
net: Mutex<NetworkSource>,
|
||||
mem: Mutex<MemorySource>,
|
||||
disk_stats: Mutex<DiskStatSource>,
|
||||
disk_usage: Mutex<DiskUsageSource>,
|
||||
}
|
||||
|
||||
impl Sensors {
|
||||
pub fn new() -> Result<Sensors> {
|
||||
std::thread::spawn(update_gpu_power);
|
||||
|
||||
Ok(Sensors {
|
||||
hostname: hostname()?,
|
||||
cpu: Mutex::new(CpuTimeSource::new()?),
|
||||
temp: Mutex::new(TemperatureSource::new()?),
|
||||
net: Mutex::new(NetworkSource::new()?),
|
||||
mem: Mutex::new(MemorySource::new()?),
|
||||
disk_stats: Mutex::new(DiskStatSource::new()?),
|
||||
disk_usage: Mutex::new(DiskUsageSource::new()?),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_metrics(sensors: &Sensors) -> Result<String> {
|
||||
let hostname = &sensors.hostname;
|
||||
let mut disk_source = sensors.disk_stats.lock().unwrap();
|
||||
let mut disk_usage_source = sensors.disk_usage.lock().unwrap();
|
||||
let disks = disk_source.read()?;
|
||||
let disk_usage = disk_usage_source.read()?;
|
||||
let cpu = sensors.cpu.lock().unwrap().read()?;
|
||||
let memory = sensors.mem.lock().unwrap().read()?;
|
||||
let temperatures = sensors.temp.lock().unwrap().read()?;
|
||||
let mut net = sensors.net.lock().unwrap();
|
||||
let networks = net.read()?;
|
||||
let pools = pools();
|
||||
let mut result = String::with_capacity(256);
|
||||
|
||||
cpu.write(&mut result, &hostname);
|
||||
memory.write(&mut result, &hostname);
|
||||
|
||||
for pool in pools {
|
||||
writeln!(
|
||||
&mut result,
|
||||
"zfs_pool_size{{host=\"{}\", pool=\"{}\"}} {}",
|
||||
hostname, pool.name, pool.size
|
||||
)
|
||||
.ok();
|
||||
writeln!(
|
||||
&mut result,
|
||||
"zfs_pool_free{{host=\"{}\", pool=\"{}\"}} {}",
|
||||
hostname, pool.name, pool.free
|
||||
)
|
||||
.ok();
|
||||
}
|
||||
for network in networks {
|
||||
if let Ok(network) = network {
|
||||
network.write(&mut result, &hostname);
|
||||
}
|
||||
}
|
||||
for disk in disks {
|
||||
if let Ok(disk) = disk {
|
||||
disk.write(&mut result, hostname);
|
||||
}
|
||||
}
|
||||
|
||||
for disk in disk_usage {
|
||||
if let Ok(disk) = disk {
|
||||
disk.write(&mut result, hostname);
|
||||
}
|
||||
}
|
||||
for (label, temp) in temperatures {
|
||||
if temp != 0.0 {
|
||||
writeln!(
|
||||
&mut result,
|
||||
"temperature{{host=\"{}\", sensor=\"{}\"}} {:.1}",
|
||||
hostname, label, temp
|
||||
)
|
||||
.ok();
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(power) = power_usage()? {
|
||||
power.write(&mut result, &sensors.hostname);
|
||||
}
|
||||
if let Some(arc) = arcstats()? {
|
||||
arc.write(&mut result, &sensors.hostname);
|
||||
}
|
||||
if let Some(memory) = gpu::memory() {
|
||||
memory.write(&mut result, &sensors.hostname)
|
||||
}
|
||||
|
||||
for usage in utilization() {
|
||||
usage.write(&mut result, &sensors.hostname);
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
use crate::gpu::gpu_power;
|
||||
use color_eyre::{Report, Result};
|
||||
use crate::linux::gpu::gpu_power;
|
||||
use crate::{Error, Result};
|
||||
use std::fmt::Write;
|
||||
use std::fs::{read_dir, read_to_string};
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
|
|
@ -63,7 +63,7 @@ pub fn power_usage() -> Result<Option<PowerUsage>> {
|
|||
if package
|
||||
.file_name()
|
||||
.to_str()
|
||||
.ok_or_else(|| Report::msg("Invalid name"))?
|
||||
.ok_or_else(|| Error::Other("Invalid name".into()))?
|
||||
.starts_with("intel-rapl")
|
||||
{
|
||||
let mut package_path = package.path();
|
||||
|
|
@ -86,7 +86,7 @@ pub fn power_usage() -> Result<Option<PowerUsage>> {
|
|||
}
|
||||
|
||||
usage.gpu_uj = gpu_power();
|
||||
if let Some(nvidia_power) = crate::gpu::nvidia::power() {
|
||||
if let Some(nvidia_power) = crate::linux::gpu::nvidia::power() {
|
||||
usage.gpu_uj = nvidia_power;
|
||||
}
|
||||
|
||||
|
|
@ -1,67 +1,11 @@
|
|||
use crate::hwmon::{Device, FileSource};
|
||||
use crate::{Error, MultiSensorSource, Result, SensorData, SensorSource};
|
||||
use std::array::IntoIter;
|
||||
use std::fmt::Write;
|
||||
use crate::data::{CpuTime, Memory, NetStats, Temperatures};
|
||||
use crate::linux::hwmon::{Device, FileSource};
|
||||
use crate::{Error, MultiSensorSource, Result, SensorSource};
|
||||
use std::fs::File;
|
||||
use std::io;
|
||||
use std::io::{BufRead, BufReader, ErrorKind, Read, Seek};
|
||||
use sysconf::{sysconf, SysconfVariable};
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct Temperatures {
|
||||
cpu: f32,
|
||||
gpu: f32,
|
||||
}
|
||||
|
||||
impl IntoIterator for Temperatures {
|
||||
type Item = (&'static str, f32);
|
||||
type IntoIter = IntoIter<Self::Item, 2>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
[("cpu", self.cpu), ("gpu", self.gpu)].into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl SensorData for Temperatures {
|
||||
fn write<W: Write>(&self, mut w: W, hostname: &str) {
|
||||
for (label, temp) in self.clone() {
|
||||
if temp != 0.0 {
|
||||
writeln!(
|
||||
&mut w,
|
||||
"temperature{{host=\"{}\", sensor=\"{}\"}} {:.1}",
|
||||
hostname, label, temp
|
||||
)
|
||||
.ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct Memory {
|
||||
pub total: u64,
|
||||
pub free: u64,
|
||||
pub available: u64,
|
||||
}
|
||||
|
||||
impl SensorData for Memory {
|
||||
fn write<W: Write>(&self, mut w: W, hostname: &str) {
|
||||
writeln!(
|
||||
&mut w,
|
||||
"memory_total{{host=\"{}\"}} {}",
|
||||
hostname, self.total
|
||||
)
|
||||
.ok();
|
||||
writeln!(
|
||||
&mut w,
|
||||
"memory_available{{host=\"{}\"}} {}",
|
||||
hostname, self.available
|
||||
)
|
||||
.ok();
|
||||
writeln!(&mut w, "memory_free{{host=\"{}\"}} {}", hostname, self.free).ok();
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TemperatureSource {
|
||||
cpu_sensors: Vec<FileSource>,
|
||||
gpu_sensors: Vec<FileSource>,
|
||||
|
|
@ -117,10 +61,16 @@ impl SensorSource for TemperatureSource {
|
|||
type Data = Temperatures;
|
||||
|
||||
fn read(&mut self) -> Result<Self::Data> {
|
||||
Ok(Temperatures {
|
||||
let mut result = Temperatures {
|
||||
cpu: average_sensors(&mut self.cpu_sensors) / 1000.0,
|
||||
gpu: average_sensors(&mut self.gpu_sensors) / 1000.0,
|
||||
})
|
||||
};
|
||||
|
||||
if let Some(gpu) = super::gpu::nvidia::temperature() {
|
||||
result.gpu = gpu;
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -165,14 +115,6 @@ impl SensorSource for MemorySource {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct CpuTime(f32);
|
||||
|
||||
impl SensorData for CpuTime {
|
||||
fn write<W: Write>(&self, mut w: W, hostname: &str) {
|
||||
writeln!(w, "cpu_time{{host=\"{}\"}} {:.3}", hostname, self.0).ok();
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CpuTimeSource {
|
||||
source: BufReader<File>,
|
||||
buff: Vec<u8>,
|
||||
|
|
@ -216,32 +158,6 @@ impl SensorSource for CpuTimeSource {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct NetStats {
|
||||
pub interface: String,
|
||||
pub bytes_sent: u64,
|
||||
pub bytes_received: u64,
|
||||
}
|
||||
|
||||
impl SensorData for NetStats {
|
||||
fn write<W: Write>(&self, mut w: W, hostname: &str) {
|
||||
if self.bytes_received > 0 || self.bytes_sent > 0 {
|
||||
writeln!(
|
||||
&mut w,
|
||||
"net_sent{{host=\"{}\", network=\"{}\"}} {}",
|
||||
hostname, self.interface, self.bytes_sent
|
||||
)
|
||||
.ok();
|
||||
writeln!(
|
||||
&mut w,
|
||||
"net_received{{host=\"{}\", network=\"{}\"}} {}",
|
||||
hostname, self.interface, self.bytes_received
|
||||
)
|
||||
.ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct NetworkSource {
|
||||
source: File,
|
||||
buff: String,
|
||||
|
|
@ -326,9 +242,3 @@ impl<'a> Iterator for NetworkStatParser<'a> {
|
|||
Some(NetworkSource::parse_line(line))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn hostname() -> Result<String> {
|
||||
hostname::get()?
|
||||
.into_string()
|
||||
.map_err(|_| Error::InvalidHostName)
|
||||
}
|
||||
12
src/main.rs
12
src/main.rs
|
|
@ -3,10 +3,7 @@ use color_eyre::{Report, Result};
|
|||
use futures_util::pin_mut;
|
||||
use futures_util::StreamExt;
|
||||
use libmdns::Responder;
|
||||
use palantir::disk::zfs::arcstats;
|
||||
use palantir::docker::{get_docker, stat, Container};
|
||||
use palantir::gpu::{gpu_metrics, update_gpu_power};
|
||||
use palantir::power::power_usage;
|
||||
use palantir::{get_metrics, Sensors};
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
|
|
@ -39,13 +36,6 @@ async fn serve_inner(docker: Option<Docker>, sensors: &Sensors) -> Result<String
|
|||
container.write(&mut metrics, &sensors.hostname);
|
||||
}
|
||||
}
|
||||
if let Some(power) = power_usage()? {
|
||||
power.write(&mut metrics, &sensors.hostname);
|
||||
}
|
||||
if let Some(arc) = arcstats()? {
|
||||
arc.write(&mut metrics, &sensors.hostname);
|
||||
}
|
||||
gpu_metrics(&mut metrics, &sensors.hostname);
|
||||
|
||||
Ok(metrics)
|
||||
}
|
||||
|
|
@ -86,8 +76,6 @@ async fn main() -> Result<()> {
|
|||
));
|
||||
}
|
||||
|
||||
std::thread::spawn(update_gpu_power);
|
||||
|
||||
let metrics = warp::path!("metrics")
|
||||
.and(docker)
|
||||
.and(sensors)
|
||||
|
|
|
|||
33
src/sys/mod.rs
Normal file
33
src/sys/mod.rs
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
use crate::data::Temperatures;
|
||||
use crate::hostname;
|
||||
use crate::Result;
|
||||
use std::fmt::Write;
|
||||
use sysinfo::{ComponentExt, System, SystemExt};
|
||||
|
||||
pub struct Sensors {
|
||||
pub hostname: String,
|
||||
}
|
||||
|
||||
impl Sensors {
|
||||
pub fn new() -> Result<Sensors> {
|
||||
let s = System::new_all();
|
||||
for component in s.components() {
|
||||
println!("{} :{}°C", component.label(), component.temperature());
|
||||
}
|
||||
|
||||
Ok(Sensors {
|
||||
hostname: hostname()?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn temps() -> Temperatures {
|
||||
Temperatures { cpu: 0.0, gpu: 0.0 }
|
||||
}
|
||||
|
||||
pub fn get_metrics(sensors: &Sensors) -> Result<String> {
|
||||
let hostname = &sensors.hostname;
|
||||
let mut result = String::with_capacity(256);
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue