intiial import of new code
This commit is contained in:
parent
c9e1824371
commit
c151212db9
44
Cargo.lock
generated
44
Cargo.lock
generated
@ -1,5 +1,7 @@
|
|||||||
# This file is automatically @generated by Cargo.
|
# This file is automatically @generated by Cargo.
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ansi_term"
|
name = "ansi_term"
|
||||||
version = "0.11.0"
|
version = "0.11.0"
|
||||||
@ -445,27 +447,6 @@ dependencies = [
|
|||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "peshming"
|
|
||||||
version = "0.4.1"
|
|
||||||
dependencies = [
|
|
||||||
"anyhow",
|
|
||||||
"async-anyhow-logger",
|
|
||||||
"chrono",
|
|
||||||
"clap",
|
|
||||||
"fern",
|
|
||||||
"futures",
|
|
||||||
"futures-util",
|
|
||||||
"hyper",
|
|
||||||
"lazy_static",
|
|
||||||
"log",
|
|
||||||
"prometheus",
|
|
||||||
"serde",
|
|
||||||
"tokio",
|
|
||||||
"tokio-icmp-echo",
|
|
||||||
"toml",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pin-project"
|
name = "pin-project"
|
||||||
version = "1.0.7"
|
version = "1.0.7"
|
||||||
@ -604,6 +585,27 @@ dependencies = [
|
|||||||
"bitflags",
|
"bitflags",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rexaping"
|
||||||
|
version = "0.4.1"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"async-anyhow-logger",
|
||||||
|
"chrono",
|
||||||
|
"clap",
|
||||||
|
"fern",
|
||||||
|
"futures",
|
||||||
|
"futures-util",
|
||||||
|
"hyper",
|
||||||
|
"lazy_static",
|
||||||
|
"log",
|
||||||
|
"prometheus",
|
||||||
|
"serde",
|
||||||
|
"tokio",
|
||||||
|
"tokio-icmp-echo",
|
||||||
|
"toml",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "scopeguard"
|
name = "scopeguard"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
|
12
Cargo.toml
12
Cargo.toml
@ -1,12 +1,12 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "peshming"
|
name = "rexaping"
|
||||||
version = "0.4.1"
|
version = "0.5.0"
|
||||||
license = "AGPL-3.0-only"
|
license = "AGPL-3.0-only"
|
||||||
authors = ["Jan Christian Grünhage <jan.christian@gruenhage.xyz>"]
|
authors = ["Marek Isalski <marek@faelix.net>", "Jan Christian Grünhage <jan.christian@gruenhage.xyz>"]
|
||||||
repository = "https://git.jcg.re/jcgruenhage/peshming"
|
repository = "https://gitea.faelix.net/FAELIX/rexaping"
|
||||||
keywords = ["ping", "icmp", "prometheus"]
|
keywords = ["ping", "icmp", "prometheus"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
description = "Pings configured hosts in a configurable intervals and exposes metrics for prometheus."
|
description = "Pings configured hosts in a configurable intervals and labels, and exposes metrics for prometheus."
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
prometheus = "0.12"
|
prometheus = "0.12"
|
||||||
|
19
README.md
19
README.md
@ -1,21 +1,22 @@
|
|||||||
## peshming
|
## rexaping
|
||||||
It's a prometheus exporter pinging hosts in the background.
|
It's a prometheus exporter pinging hosts in the background.
|
||||||
It's been inspired by [meshping](https://bitbucket.org/Svedrin/meshping),
|
It's been forked from [peshming](https://git.jcg.re/jcgruenhage/peshming),
|
||||||
but instead of managing targets using a redis db this is using a simple config file.
|
but only allowing targets to specify an interval, the config file can enrich
|
||||||
In addition, this tool allows to set a ping frequency per target.
|
the Prometheus metrics with additional labels.
|
||||||
|
|
||||||
The name peshming is intended as a placeholder until
|
The name rexaping is a play on exaping, a tool with the same purpose
|
||||||
someone comes up with something better.
|
originally written in Python for Exa Networks.
|
||||||
|
|
||||||
### Usage:
|
### Usage:
|
||||||
```
|
```
|
||||||
$ peshming --help
|
$ rexaping --help
|
||||||
peshming 0.2.3
|
rexaping 0.2.3
|
||||||
|
Marek Isalski <marek@faelix.net>
|
||||||
Jan Christian Grünhage <jan.christian@gruenhage.xyz>
|
Jan Christian Grünhage <jan.christian@gruenhage.xyz>
|
||||||
Pings configured hosts in a configurable intervals and exposes metrics for prometheus.
|
Pings configured hosts in a configurable intervals and exposes metrics for prometheus.
|
||||||
|
|
||||||
USAGE:
|
USAGE:
|
||||||
peshming [FLAGS] <config>
|
rexaping [FLAGS] <config>
|
||||||
|
|
||||||
FLAGS:
|
FLAGS:
|
||||||
-h, --help Prints help information
|
-h, --help Prints help information
|
||||||
|
@ -7,5 +7,5 @@ listener = "[::]:9898"
|
|||||||
# will ping the primary and secondary IP of cloudflare's 1.1.1.1 DNS service
|
# will ping the primary and secondary IP of cloudflare's 1.1.1.1 DNS service
|
||||||
# every 500ms, or twice per second.
|
# every 500ms, or twice per second.
|
||||||
[hosts]
|
[hosts]
|
||||||
"1.1.1.1" = 500
|
"1.1.1.1" = { interval = "500", device = "one.one.one.one", interface="eth1111" }
|
||||||
"1.0.0.1" = 500
|
"1.0.0.1" = { interval = "500", device = "one.one.one.one", interface="eth1001" }
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
* *
|
* *
|
||||||
* Copyright (C) 2019-2020 Jan Christian Grünhage *
|
* Copyright (C) 2019-2020 Jan Christian Grünhage *
|
||||||
* Copyright (C) 2020 Famedly GmbH *
|
* Copyright (C) 2020 Famedly GmbH *
|
||||||
|
* Copyright (C) 2021-2022 Faelix Limited *
|
||||||
* *
|
* *
|
||||||
* This program is free software: you can redistribute it and/or modify *
|
* This program is free software: you can redistribute it and/or modify *
|
||||||
* it under the terms of the GNU Affero General Public License as *
|
* it under the terms of the GNU Affero General Public License as *
|
||||||
@ -26,7 +27,7 @@ use std::collections::HashMap;
|
|||||||
#[derive(Serialize, Deserialize, Clone)]
|
#[derive(Serialize, Deserialize, Clone)]
|
||||||
pub(crate) struct Config {
|
pub(crate) struct Config {
|
||||||
pub(crate) listener: std::net::SocketAddr,
|
pub(crate) listener: std::net::SocketAddr,
|
||||||
pub(crate) hosts: HashMap<std::net::IpAddr, u64>,
|
pub(crate) hosts: HashMap<std::net::IpAddr, HashMap<String, String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup_clap() -> clap::ArgMatches<'static> {
|
fn setup_clap() -> clap::ArgMatches<'static> {
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
* *
|
* *
|
||||||
* Copyright (C) 2019-2020 Jan Christian Grünhage *
|
* Copyright (C) 2019-2020 Jan Christian Grünhage *
|
||||||
* Copyright (C) 2020 Famedly GmbH *
|
* Copyright (C) 2020 Famedly GmbH *
|
||||||
|
* Copyright (C) 2021-2022 Faelix Limited *
|
||||||
* *
|
* *
|
||||||
* This program is free software: you can redistribute it and/or modify *
|
* This program is free software: you can redistribute it and/or modify *
|
||||||
* it under the terms of the GNU Affero General Public License as *
|
* it under the terms of the GNU Affero General Public License as *
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
* *
|
* *
|
||||||
* Copyright (C) 2019-2020 Jan Christian Grünhage *
|
* Copyright (C) 2019-2020 Jan Christian Grünhage *
|
||||||
* Copyright (C) 2020 Famedly GmbH *
|
* Copyright (C) 2020 Famedly GmbH *
|
||||||
|
* Copyright (C) 2021-2022 Faelix Limited *
|
||||||
* *
|
* *
|
||||||
* This program is free software: you can redistribute it and/or modify *
|
* This program is free software: you can redistribute it and/or modify *
|
||||||
* it under the terms of the GNU Affero General Public License as *
|
* it under the terms of the GNU Affero General Public License as *
|
||||||
|
58
src/ping.rs
58
src/ping.rs
@ -3,6 +3,7 @@
|
|||||||
* *
|
* *
|
||||||
* Copyright (C) 2019-2020 Jan Christian Grünhage *
|
* Copyright (C) 2019-2020 Jan Christian Grünhage *
|
||||||
* Copyright (C) 2020 Famedly GmbH *
|
* Copyright (C) 2020 Famedly GmbH *
|
||||||
|
* Copyright (C) 2021-2022 Faelix Limited *
|
||||||
* *
|
* *
|
||||||
* This program is free software: you can redistribute it and/or modify *
|
* This program is free software: you can redistribute it and/or modify *
|
||||||
* it under the terms of the GNU Affero General Public License as *
|
* it under the terms of the GNU Affero General Public License as *
|
||||||
@ -21,39 +22,54 @@ use crate::config::Config;
|
|||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use async_anyhow_logger::catch;
|
use async_anyhow_logger::catch;
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use log::{info, trace};
|
use log::{trace};
|
||||||
use prometheus::*;
|
use prometheus::*;
|
||||||
use std::net::IpAddr;
|
use std::net::IpAddr;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use tokio_icmp_echo::{PingFuture, Pinger};
|
use tokio_icmp_echo::{PingFuture, Pinger};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref PING_HISTOGRAM: HistogramVec = register_histogram_vec!(
|
static ref PING_HISTOGRAM: HistogramVec = register_histogram_vec!(
|
||||||
"ping_rtt_milliseconds",
|
"ping_rtt_milliseconds",
|
||||||
"The ping round trip time in milliseconds",
|
"The ping round trip time in milliseconds",
|
||||||
&["target"],
|
&["target", "device", "interface", "expected", "team", "priority"],
|
||||||
vec![
|
vec![
|
||||||
0.5, 1.0, 5.0, 10.0, 15.0, 20.0, 25.0, 50.0, 75.0, 100.0, 150.0, 200.0, 250.0, 300.0,
|
0.125, 0.25, 0.5, 1.0, 1.5, 2.0, 2.5, 5.0, 7.5, 10.0, 15.0, 20.0, 25.0, 30.0,
|
||||||
350.0, 400.0, 450.0, 500.0, 550.0, 600.0, 650.0, 700.0, 750.0, 800.0, 900.0, 1000.0,
|
35.0, 40.0, 45.0, 50.0, 55.0, 60.0, 65.0, 70.0, 75.0, 80.0, 90.0, 100.0,
|
||||||
1250.0, 1500.0, 1750.0, 2000.0
|
125.0, 150.0, 175.0, 200.0, 250.0, 300.0, 400.0, 500.0, 750.0, 1000.0, 2000.0, 4000.0
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
static ref PING_COUNTER: IntCounterVec =
|
||||||
|
register_int_counter_vec!("ping_replies", "Number of ICMP ping responses received", &["target"]).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) async fn start_pinging_hosts(config: &Config) -> Result<()> {
|
pub(crate) async fn start_pinging_hosts(config: &Config) -> Result<()> {
|
||||||
let pinger = Pinger::new().await.context("Couldn't create pinger")?;
|
let pinger = Pinger::new().await.context("Couldn't create pinger")?;
|
||||||
let mut handles = vec![];
|
let mut handles = vec![];
|
||||||
for (host, interval) in config.hosts.clone() {
|
let mut interval;
|
||||||
info!("Spawn ping task for {}", host);
|
|
||||||
handles.push(tokio::spawn(ping_host(pinger.clone(), host, interval)));
|
for (target, hostdata) in config.hosts.clone() {
|
||||||
|
let hd_interval = hostdata.get("interval");
|
||||||
|
match hd_interval {
|
||||||
|
Some(ival) => {
|
||||||
|
interval = ival.parse()?;
|
||||||
|
},
|
||||||
|
_ => interval = 1000,
|
||||||
|
}
|
||||||
|
|
||||||
|
handles.push(tokio::spawn(ping_host(pinger.clone(), target, interval, hostdata)));
|
||||||
}
|
}
|
||||||
let (result, _, _) = futures::future::select_all(handles).await;
|
let (result, _, _) = futures::future::select_all(handles).await;
|
||||||
result??;
|
result??;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn ping_host(pinger: Pinger, host: IpAddr, interval: u64) -> Result<()> {
|
async fn ping_host(pinger: Pinger, host: IpAddr, interval: u64, hostdata: HashMap<String, String>) -> Result<()> {
|
||||||
let mut pingchain = pinger.chain(host).timeout(Duration::from_secs(3));
|
let mut pingchain = pinger.chain(host).timeout(Duration::from_secs(3));
|
||||||
let mut interval = tokio::time::interval(Duration::from_millis(interval));
|
let mut interval = tokio::time::interval(Duration::from_millis(interval));
|
||||||
let host_string = host.to_string();
|
let host_string = host.to_string();
|
||||||
@ -62,23 +78,41 @@ async fn ping_host(pinger: Pinger, host: IpAddr, interval: u64) -> Result<()> {
|
|||||||
tokio::spawn(catch(handle_ping_result(
|
tokio::spawn(catch(handle_ping_result(
|
||||||
pingchain.send(),
|
pingchain.send(),
|
||||||
host_string.clone(),
|
host_string.clone(),
|
||||||
|
hostdata.clone(),
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_ping_result(result: PingFuture, host: String) -> Result<()> {
|
async fn handle_ping_result(result: PingFuture, host: String, hostdata: HashMap<String, String>) -> Result<()> {
|
||||||
let pong = result.await.context(format!("Couldn't ping {}", &host))?;
|
let pong = result.await.context(format!("Couldn't ping {}", &host))?;
|
||||||
|
|
||||||
|
let empty = "".to_string();
|
||||||
|
let device = hostdata.get("device").unwrap_or(&empty);
|
||||||
|
let interface = hostdata.get("interface").unwrap_or(&empty);
|
||||||
|
let team = hostdata.get("team").unwrap_or(&empty);
|
||||||
|
|
||||||
|
let up = "up".to_string();
|
||||||
|
let expected = hostdata.get("expected").unwrap_or(&up);
|
||||||
|
|
||||||
|
let notice = "notice".to_string();
|
||||||
|
let severity = hostdata.get("severity").unwrap_or(¬ice);
|
||||||
|
|
||||||
match pong {
|
match pong {
|
||||||
Some(time) => {
|
Some(time) => {
|
||||||
let ms = time.as_millis();
|
let ms = time.as_millis();
|
||||||
trace!("Received pong from {} after {} ms", &host, &ms);
|
trace!("Received pong from {} after {} ms", &host, &ms);
|
||||||
PING_HISTOGRAM
|
PING_HISTOGRAM
|
||||||
.with_label_values(&[&host])
|
.with_label_values(&[&host, device, interface, expected, team, severity])
|
||||||
.observe(ms as f64);
|
.observe(ms as f64);
|
||||||
|
//PING_COUNTER
|
||||||
|
// .with_label_values(&[&host])
|
||||||
|
// .collect();
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
trace!("Received no response from {} within timeout", &host);
|
trace!("Received no response from {} within timeout", &host);
|
||||||
PING_HISTOGRAM.with_label_values(&[&host]).observe(3000.0);
|
PING_HISTOGRAM
|
||||||
|
.with_label_values(&[&host, device, interface, expected, team, severity])
|
||||||
|
.observe(4000.0);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user