mirror of
https://codeberg.org/icewind/palantir.git
synced 2026-06-03 10:14:09 +02:00
network sensor
This commit is contained in:
parent
5dd7380e2b
commit
f06b8ab698
5 changed files with 495 additions and 423 deletions
749
Cargo.lock
generated
749
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
|
@ -34,7 +34,7 @@
|
|||
|
||||
# `nix develop`
|
||||
devShell = pkgs.mkShell {
|
||||
nativeBuildInputs = with pkgs; [rustc cargo bacon];
|
||||
nativeBuildInputs = with pkgs; [cargo bacon];
|
||||
};
|
||||
})
|
||||
// {
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
use crate::{Error, Result};
|
||||
use crate::{Error, Result, SensorData};
|
||||
use ahash::{AHashSet, AHasher};
|
||||
use once_cell::sync::Lazy;
|
||||
use regex::Regex;
|
||||
use std::ffi::CString;
|
||||
use std::fmt::Write;
|
||||
use std::fs::File;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::io::{BufRead, BufReader};
|
||||
|
|
@ -17,6 +18,25 @@ pub struct IoStats {
|
|||
pub bytes_received: u64,
|
||||
}
|
||||
|
||||
impl SensorData for IoStats {
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct DiskUsage {
|
||||
pub name: String,
|
||||
|
|
|
|||
27
src/lib.rs
27
src/lib.rs
|
|
@ -53,8 +53,9 @@ pub fn get_metrics() -> Result<String> {
|
|||
let memory = memory()?;
|
||||
let mut temp_source = TemperatureSource::new()?;
|
||||
let temperatures = temp_source.read()?;
|
||||
let mut net_source = NetworkSource::new()?;
|
||||
let networks = net_source.read()?;
|
||||
let pools = pools();
|
||||
let networks = network_stats()?;
|
||||
let mut result = String::with_capacity(256);
|
||||
|
||||
cpu.write(&mut result, &hostname);
|
||||
|
|
@ -75,19 +76,8 @@ pub fn get_metrics() -> Result<String> {
|
|||
.ok();
|
||||
}
|
||||
for network in networks {
|
||||
if network.bytes_received > 0 || network.bytes_sent > 0 {
|
||||
writeln!(
|
||||
&mut result,
|
||||
"net_sent{{host=\"{}\", network=\"{}\"}} {}",
|
||||
hostname, network.interface, network.bytes_sent
|
||||
)
|
||||
.ok();
|
||||
writeln!(
|
||||
&mut result,
|
||||
"net_received{{host=\"{}\", network=\"{}\"}} {}",
|
||||
hostname, network.interface, network.bytes_received
|
||||
)
|
||||
.ok();
|
||||
if let Ok(network) = network {
|
||||
network.write(&mut result, &hostname);
|
||||
}
|
||||
}
|
||||
for disk in disks {
|
||||
|
|
@ -146,3 +136,12 @@ pub trait SensorSource {
|
|||
|
||||
fn read(&mut self) -> Result<Self::Data>;
|
||||
}
|
||||
|
||||
pub trait MultiSensorSource {
|
||||
type Data: SensorData;
|
||||
type Iter<'a>: Iterator<Item = Result<Self::Data>>
|
||||
where
|
||||
Self: 'a;
|
||||
|
||||
fn read(&mut self) -> Result<Self::Iter<'_>>;
|
||||
}
|
||||
|
|
|
|||
126
src/sensors.rs
126
src/sensors.rs
|
|
@ -1,11 +1,11 @@
|
|||
use crate::disk::IoStats;
|
||||
use crate::hwmon::{Device, FileSource};
|
||||
use crate::{Error, Result, SensorData, SensorSource};
|
||||
use crate::{Error, MultiSensorSource, Result, SensorData, SensorSource};
|
||||
use std::array::IntoIter;
|
||||
use std::fmt::Write;
|
||||
use std::fs::File;
|
||||
use std::io;
|
||||
use std::io::{BufRead, BufReader, ErrorKind, Seek};
|
||||
use std::io::{BufRead, BufReader, ErrorKind, Read, Seek};
|
||||
use sysconf::{sysconf, SysconfVariable};
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
|
|
@ -201,49 +201,89 @@ impl SensorSource for CpuTimeSource {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn network_stats() -> Result<impl Iterator<Item = IoStats>> {
|
||||
let stat = BufReader::new(File::open("/proc/net/dev")?);
|
||||
Ok(stat
|
||||
.lines()
|
||||
.filter_map(Result::ok)
|
||||
.filter(|line: &String| {
|
||||
let trimmed = line.trim_start();
|
||||
trimmed.starts_with("en") || trimmed.starts_with("eth")
|
||||
pub struct NetworkSource {
|
||||
source: File,
|
||||
buff: String,
|
||||
}
|
||||
|
||||
impl NetworkSource {
|
||||
pub fn new() -> Result<NetworkSource> {
|
||||
Ok(NetworkSource {
|
||||
source: File::open("/proc/net/dev")?,
|
||||
buff: String::new(),
|
||||
})
|
||||
.filter_map(|line: String| {
|
||||
let mut parts = line.trim_start().split_ascii_whitespace();
|
||||
if let (
|
||||
Some(interface),
|
||||
Some(bytes_received),
|
||||
_packets,
|
||||
_err,
|
||||
_drop,
|
||||
_fifo,
|
||||
_frame,
|
||||
_compressed,
|
||||
_multicast,
|
||||
Some(bytes_sent),
|
||||
) = (
|
||||
parts.next(),
|
||||
parts.next(),
|
||||
parts.next(),
|
||||
parts.next(),
|
||||
parts.next(),
|
||||
parts.next(),
|
||||
parts.next(),
|
||||
parts.next(),
|
||||
parts.next(),
|
||||
parts.next(),
|
||||
) {
|
||||
Some(IoStats {
|
||||
interface: interface.trim_end_matches(':').into(),
|
||||
bytes_sent: bytes_sent.parse().ok()?,
|
||||
bytes_received: bytes_received.parse().ok()?,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
||||
fn parse_line(line: &str) -> Result<IoStats> {
|
||||
let mut parts = line.trim_start().split_ascii_whitespace();
|
||||
if let (
|
||||
Some(interface),
|
||||
Some(bytes_received),
|
||||
_packets,
|
||||
_err,
|
||||
_drop,
|
||||
_fifo,
|
||||
_frame,
|
||||
_compressed,
|
||||
_multicast,
|
||||
Some(bytes_sent),
|
||||
) = (
|
||||
parts.next(),
|
||||
parts.next(),
|
||||
parts.next(),
|
||||
parts.next(),
|
||||
parts.next(),
|
||||
parts.next(),
|
||||
parts.next(),
|
||||
parts.next(),
|
||||
parts.next(),
|
||||
parts.next(),
|
||||
) {
|
||||
Ok(IoStats {
|
||||
interface: interface.trim_end_matches(':').into(),
|
||||
bytes_sent: bytes_sent.parse()?,
|
||||
bytes_received: bytes_received.parse()?,
|
||||
})
|
||||
} else {
|
||||
Err(Error::Io(ErrorKind::InvalidData.into()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl MultiSensorSource for NetworkSource {
|
||||
type Data = IoStats;
|
||||
type Iter<'a> = NetworkStatParser<'a>;
|
||||
|
||||
fn read(&mut self) -> Result<Self::Iter<'_>> {
|
||||
self.buff.clear();
|
||||
self.source.rewind()?;
|
||||
self.source.read_to_string(&mut self.buff)?;
|
||||
|
||||
Ok(NetworkStatParser {
|
||||
lines: self.buff.lines(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub struct NetworkStatParser<'a> {
|
||||
lines: std::str::Lines<'a>,
|
||||
}
|
||||
|
||||
impl<'a> Iterator for NetworkStatParser<'a> {
|
||||
type Item = Result<IoStats>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let line = loop {
|
||||
let line = self.lines.next()?;
|
||||
let trimmed = line.trim_start();
|
||||
if trimmed.starts_with("en") || trimmed.starts_with("eth") || trimmed.starts_with("wlp")
|
||||
{
|
||||
break trimmed;
|
||||
}
|
||||
}))
|
||||
};
|
||||
|
||||
Some(NetworkSource::parse_line(line))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn hostname() -> Result<String> {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue