Move metrics related code into metrics.rs
To improve readability metrics related code moves to `metrics.rs`.
This commit is contained in:
parent
3a95ecfd11
commit
5e1d433c38
2 changed files with 105 additions and 99 deletions
113
src/main.rs
113
src/main.rs
|
@ -1,9 +1,11 @@
|
||||||
mod cli;
|
mod cli;
|
||||||
mod filters;
|
mod filters;
|
||||||
|
mod metrics;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
cli::Opts,
|
cli::Opts,
|
||||||
filters::{FilterType, IpFilter},
|
filters::{FilterType, IpFilter},
|
||||||
|
metrics::Metrics,
|
||||||
};
|
};
|
||||||
use anyhow::{anyhow, bail, Result};
|
use anyhow::{anyhow, bail, Result};
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
|
@ -12,7 +14,6 @@ use log::{debug, error, info, trace, warn};
|
||||||
use rocket::{
|
use rocket::{
|
||||||
data::{FromData, ToByteUnit},
|
data::{FromData, ToByteUnit},
|
||||||
futures::TryFutureExt,
|
futures::TryFutureExt,
|
||||||
get,
|
|
||||||
http::{HeaderMap, Status},
|
http::{HeaderMap, Status},
|
||||||
outcome::Outcome::{self, Failure, Success},
|
outcome::Outcome::{self, Failure, Success},
|
||||||
post, routes,
|
post, routes,
|
||||||
|
@ -27,7 +28,7 @@ use std::{
|
||||||
fs::File,
|
fs::File,
|
||||||
io::BufReader,
|
io::BufReader,
|
||||||
net::{IpAddr, Ipv4Addr, SocketAddr},
|
net::{IpAddr, Ipv4Addr, SocketAddr},
|
||||||
sync::atomic::{AtomicUsize, Ordering},
|
sync::atomic::Ordering,
|
||||||
};
|
};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
|
@ -47,19 +48,6 @@ pub enum WebhookeyError {
|
||||||
Serde(serde_json::Error),
|
Serde(serde_json::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
|
||||||
struct WebhookeyMetrics {
|
|
||||||
requests_received: AtomicUsize,
|
|
||||||
requests_invalid: AtomicUsize,
|
|
||||||
hooks_successful: AtomicUsize,
|
|
||||||
hooks_forbidden: AtomicUsize,
|
|
||||||
hooks_unmatched: AtomicUsize,
|
|
||||||
commands_executed: AtomicUsize,
|
|
||||||
commands_execution_failed: AtomicUsize,
|
|
||||||
commands_successful: AtomicUsize,
|
|
||||||
commands_failed: AtomicUsize,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Serialize)]
|
#[derive(Debug, Deserialize, Serialize)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
struct MetricsConfig {
|
struct MetricsConfig {
|
||||||
|
@ -69,7 +57,7 @@ struct MetricsConfig {
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Serialize)]
|
#[derive(Debug, Deserialize, Serialize)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
struct Config {
|
pub struct Config {
|
||||||
metrics: Option<MetricsConfig>,
|
metrics: Option<MetricsConfig>,
|
||||||
hooks: BTreeMap<String, Hook>,
|
hooks: BTreeMap<String, Hook>,
|
||||||
}
|
}
|
||||||
|
@ -311,48 +299,6 @@ fn get_config() -> Result<File> {
|
||||||
bail!("No configuration file found.");
|
bail!("No configuration file found.");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_metrics(metrics: &WebhookeyMetrics) -> String {
|
|
||||||
format!(
|
|
||||||
r"# HELP webhookey_requests_received Number of requests received
|
|
||||||
# TYPE webhookey_requests_received gauge
|
|
||||||
webhookey_requests_received {}
|
|
||||||
# HELP webhookey_requests_invalid Number of invalid requests received
|
|
||||||
# TYPE webhookey_requests_invalid gauge
|
|
||||||
webhookey_requests_invalid {}
|
|
||||||
# HELP webhookey_hooks_successful Number of successfully executed hooks
|
|
||||||
# TYPE webhookey_hooks_successful gauge
|
|
||||||
webhookey_hooks_sucessful {}
|
|
||||||
# HELP webhookey_hooks_forbidden Number of forbidden requests
|
|
||||||
# TYPE webhookey_hooks_forbidden gauge
|
|
||||||
webhookey_hooks_forbidden {}
|
|
||||||
# HELP webhookey_hooks_unmatched Number of unmatched requests
|
|
||||||
# TYPE webhookey_hooks_unmatched gauge
|
|
||||||
webhookey_hooks_unmatched {}
|
|
||||||
# HELP webhookey_commands_executed Number of commands executed
|
|
||||||
# TYPE webhookey_commands_executed gauge
|
|
||||||
webhookey_commands_executed {}
|
|
||||||
# HELP webhookey_commands_execution_failed Number of commands failed to execute
|
|
||||||
# TYPE webhookey_commands_execution_failed gauge
|
|
||||||
webhookey_commands_execution_failed {}
|
|
||||||
# HELP webhookey_commands_successful Number of executed commands returning return code 0
|
|
||||||
# TYPE webhookey_commands_successful gauge
|
|
||||||
webhookey_commands_successful {}
|
|
||||||
# HELP webhookey_commands_failed Number of executed commands returning different return code than 0
|
|
||||||
# TYPE webhookey_commands_failed gauge
|
|
||||||
webhookey_commands_failed {}
|
|
||||||
",
|
|
||||||
metrics.requests_received.load(Ordering::Relaxed),
|
|
||||||
metrics.requests_invalid.load(Ordering::Relaxed),
|
|
||||||
metrics.hooks_successful.load(Ordering::Relaxed),
|
|
||||||
metrics.hooks_forbidden.load(Ordering::Relaxed),
|
|
||||||
metrics.hooks_unmatched.load(Ordering::Relaxed),
|
|
||||||
metrics.commands_executed.load(Ordering::Relaxed),
|
|
||||||
metrics.commands_execution_failed.load(Ordering::Relaxed),
|
|
||||||
metrics.commands_successful.load(Ordering::Relaxed),
|
|
||||||
metrics.commands_failed.load(Ordering::Relaxed),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[rocket::async_trait]
|
#[rocket::async_trait]
|
||||||
impl<'r> FromData<'r> for Hooks {
|
impl<'r> FromData<'r> for Hooks {
|
||||||
type Error = WebhookeyError;
|
type Error = WebhookeyError;
|
||||||
|
@ -363,7 +309,7 @@ impl<'r> FromData<'r> for Hooks {
|
||||||
) -> Outcome<Self, (Status, Self::Error), Data<'r>> {
|
) -> Outcome<Self, (Status, Self::Error), Data<'r>> {
|
||||||
{
|
{
|
||||||
request
|
request
|
||||||
.guard::<&State<WebhookeyMetrics>>()
|
.guard::<&State<Metrics>>()
|
||||||
.await
|
.await
|
||||||
.unwrap() // TODO: Check if unwrap need to be fixed
|
.unwrap() // TODO: Check if unwrap need to be fixed
|
||||||
.requests_received
|
.requests_received
|
||||||
|
@ -378,7 +324,7 @@ impl<'r> FromData<'r> for Hooks {
|
||||||
.unwrap_or(IpAddr::V4(Ipv4Addr::UNSPECIFIED));
|
.unwrap_or(IpAddr::V4(Ipv4Addr::UNSPECIFIED));
|
||||||
|
|
||||||
request
|
request
|
||||||
.guard::<&State<WebhookeyMetrics>>()
|
.guard::<&State<Metrics>>()
|
||||||
.await
|
.await
|
||||||
.unwrap() // TODO: Check if unwrap need to be fixed
|
.unwrap() // TODO: Check if unwrap need to be fixed
|
||||||
.hooks_unmatched
|
.hooks_unmatched
|
||||||
|
@ -394,7 +340,7 @@ impl<'r> FromData<'r> for Hooks {
|
||||||
error!("{}", WebhookeyError::Unauthorized(e));
|
error!("{}", WebhookeyError::Unauthorized(e));
|
||||||
|
|
||||||
request
|
request
|
||||||
.guard::<&State<WebhookeyMetrics>>()
|
.guard::<&State<Metrics>>()
|
||||||
.await
|
.await
|
||||||
.unwrap() // TODO: Check if unwrap need to be fixed
|
.unwrap() // TODO: Check if unwrap need to be fixed
|
||||||
.hooks_forbidden
|
.hooks_forbidden
|
||||||
|
@ -406,7 +352,7 @@ impl<'r> FromData<'r> for Hooks {
|
||||||
error!("{}", e);
|
error!("{}", e);
|
||||||
|
|
||||||
request
|
request
|
||||||
.guard::<&State<WebhookeyMetrics>>()
|
.guard::<&State<Metrics>>()
|
||||||
.await
|
.await
|
||||||
.unwrap() // TODO: Check if unwrap need to be fixed
|
.unwrap() // TODO: Check if unwrap need to be fixed
|
||||||
.requests_invalid
|
.requests_invalid
|
||||||
|
@ -419,11 +365,7 @@ impl<'r> FromData<'r> for Hooks {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[post("/", format = "json", data = "<hooks>")]
|
#[post("/", format = "json", data = "<hooks>")]
|
||||||
async fn receive_hook<'a>(
|
async fn receive_hook<'a>(address: SocketAddr, hooks: Hooks, metrics: &State<Metrics>) -> Status {
|
||||||
address: SocketAddr,
|
|
||||||
hooks: Hooks,
|
|
||||||
metrics: &State<WebhookeyMetrics>,
|
|
||||||
) -> Status {
|
|
||||||
info!("Post request received from: {}", address);
|
info!("Post request received from: {}", address);
|
||||||
|
|
||||||
hooks.inner.iter().for_each(|(name, command)| {
|
hooks.inner.iter().for_each(|(name, command)| {
|
||||||
|
@ -455,33 +397,6 @@ async fn receive_hook<'a>(
|
||||||
Status::Ok
|
Status::Ok
|
||||||
}
|
}
|
||||||
|
|
||||||
#[get("/metrics")]
|
|
||||||
async fn metrics(
|
|
||||||
address: SocketAddr,
|
|
||||||
metrics: &State<WebhookeyMetrics>,
|
|
||||||
config: &State<Config>,
|
|
||||||
) -> Option<String> {
|
|
||||||
// Are metrics configured?
|
|
||||||
if let Some(metrics_config) = &config.metrics {
|
|
||||||
// Are metrics enabled?
|
|
||||||
if metrics_config.enabled {
|
|
||||||
// Is a filter configured?
|
|
||||||
if let Some(filter) = &metrics_config.ip_filter {
|
|
||||||
// Does the request match the filter?
|
|
||||||
if filter.validate(&address.ip()) {
|
|
||||||
return Some(get_metrics(metrics));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return Some(get_metrics(metrics));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
warn!("Forbidden request for metrics: {:?}", address);
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
#[rocket::main]
|
#[rocket::main]
|
||||||
async fn main() -> Result<()> {
|
async fn main() -> Result<()> {
|
||||||
env_logger::init();
|
env_logger::init();
|
||||||
|
@ -502,9 +417,9 @@ async fn main() -> Result<()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
rocket::build()
|
rocket::build()
|
||||||
.mount("/", routes![receive_hook, metrics])
|
.mount("/", routes![receive_hook, metrics::metrics])
|
||||||
.manage(config)
|
.manage(config)
|
||||||
.manage(WebhookeyMetrics::default())
|
.manage(Metrics::default())
|
||||||
.launch()
|
.launch()
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
@ -548,7 +463,7 @@ mod tests {
|
||||||
let rocket = rocket::build()
|
let rocket = rocket::build()
|
||||||
.mount("/", routes![receive_hook])
|
.mount("/", routes![receive_hook])
|
||||||
.manage(config)
|
.manage(config)
|
||||||
.manage(WebhookeyMetrics::default());
|
.manage(Metrics::default());
|
||||||
|
|
||||||
let client = Client::tracked(rocket).await.unwrap();
|
let client = Client::tracked(rocket).await.unwrap();
|
||||||
let response = client
|
let response = client
|
||||||
|
@ -764,7 +679,7 @@ mod tests {
|
||||||
let rocket = rocket::build()
|
let rocket = rocket::build()
|
||||||
.mount("/", routes![receive_hook])
|
.mount("/", routes![receive_hook])
|
||||||
.manage(config)
|
.manage(config)
|
||||||
.manage(WebhookeyMetrics::default());
|
.manage(Metrics::default());
|
||||||
|
|
||||||
let client = Client::tracked(rocket).await.unwrap();
|
let client = Client::tracked(rocket).await.unwrap();
|
||||||
|
|
||||||
|
@ -822,7 +737,7 @@ mod tests {
|
||||||
let rocket = rocket::build()
|
let rocket = rocket::build()
|
||||||
.mount("/", routes![receive_hook])
|
.mount("/", routes![receive_hook])
|
||||||
.manage(config)
|
.manage(config)
|
||||||
.manage(WebhookeyMetrics::default());
|
.manage(Metrics::default());
|
||||||
|
|
||||||
let client = Client::tracked(rocket).await.unwrap();
|
let client = Client::tracked(rocket).await.unwrap();
|
||||||
|
|
||||||
|
|
91
src/metrics.rs
Normal file
91
src/metrics.rs
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
use crate::Config;
|
||||||
|
use log::warn;
|
||||||
|
use rocket::{get, State};
|
||||||
|
use std::{
|
||||||
|
net::SocketAddr,
|
||||||
|
sync::atomic::{AtomicUsize, Ordering},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
pub struct Metrics {
|
||||||
|
pub requests_received: AtomicUsize,
|
||||||
|
pub requests_invalid: AtomicUsize,
|
||||||
|
pub hooks_successful: AtomicUsize,
|
||||||
|
pub hooks_forbidden: AtomicUsize,
|
||||||
|
pub hooks_unmatched: AtomicUsize,
|
||||||
|
pub commands_executed: AtomicUsize,
|
||||||
|
pub commands_execution_failed: AtomicUsize,
|
||||||
|
pub commands_successful: AtomicUsize,
|
||||||
|
pub commands_failed: AtomicUsize,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[get("/metrics")]
|
||||||
|
pub async fn metrics(
|
||||||
|
address: SocketAddr,
|
||||||
|
metrics: &State<Metrics>,
|
||||||
|
config: &State<Config>,
|
||||||
|
) -> Option<String> {
|
||||||
|
// Are metrics configured?
|
||||||
|
if let Some(metrics_config) = &config.metrics {
|
||||||
|
// Are metrics enabled?
|
||||||
|
if metrics_config.enabled {
|
||||||
|
// Is a filter configured?
|
||||||
|
if let Some(filter) = &metrics_config.ip_filter {
|
||||||
|
// Does the request match the filter?
|
||||||
|
if filter.validate(&address.ip()) {
|
||||||
|
return Some(metrics.get_metrics());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Some(metrics.get_metrics());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
warn!("Forbidden request for metrics: {:?}", address);
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Metrics {
|
||||||
|
fn get_metrics(&self) -> String {
|
||||||
|
format!(
|
||||||
|
r"# HELP webhookey_requests_received Number of requests received
|
||||||
|
# TYPE webhookey_requests_received gauge
|
||||||
|
webhookey_requests_received {}
|
||||||
|
# HELP webhookey_requests_invalid Number of invalid requests received
|
||||||
|
# TYPE webhookey_requests_invalid gauge
|
||||||
|
webhookey_requests_invalid {}
|
||||||
|
# HELP webhookey_hooks_successful Number of successfully executed hooks
|
||||||
|
# TYPE webhookey_hooks_successful gauge
|
||||||
|
webhookey_hooks_sucessful {}
|
||||||
|
# HELP webhookey_hooks_forbidden Number of forbidden requests
|
||||||
|
# TYPE webhookey_hooks_forbidden gauge
|
||||||
|
webhookey_hooks_forbidden {}
|
||||||
|
# HELP webhookey_hooks_unmatched Number of unmatched requests
|
||||||
|
# TYPE webhookey_hooks_unmatched gauge
|
||||||
|
webhookey_hooks_unmatched {}
|
||||||
|
# HELP webhookey_commands_executed Number of commands executed
|
||||||
|
# TYPE webhookey_commands_executed gauge
|
||||||
|
webhookey_commands_executed {}
|
||||||
|
# HELP webhookey_commands_execution_failed Number of commands failed to execute
|
||||||
|
# TYPE webhookey_commands_execution_failed gauge
|
||||||
|
webhookey_commands_execution_failed {}
|
||||||
|
# HELP webhookey_commands_successful Number of executed commands returning return code 0
|
||||||
|
# TYPE webhookey_commands_successful gauge
|
||||||
|
webhookey_commands_successful {}
|
||||||
|
# HELP webhookey_commands_failed Number of executed commands returning different return code than 0
|
||||||
|
# TYPE webhookey_commands_failed gauge
|
||||||
|
webhookey_commands_failed {}
|
||||||
|
",
|
||||||
|
self.requests_received.load(Ordering::Relaxed),
|
||||||
|
self.requests_invalid.load(Ordering::Relaxed),
|
||||||
|
self.hooks_successful.load(Ordering::Relaxed),
|
||||||
|
self.hooks_forbidden.load(Ordering::Relaxed),
|
||||||
|
self.hooks_unmatched.load(Ordering::Relaxed),
|
||||||
|
self.commands_executed.load(Ordering::Relaxed),
|
||||||
|
self.commands_execution_failed.load(Ordering::Relaxed),
|
||||||
|
self.commands_successful.load(Ordering::Relaxed),
|
||||||
|
self.commands_failed.load(Ordering::Relaxed),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue