From 89142ae607b3e2d8e4af04d7aefbf7dbd09db091 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20Drouet?= Date: Wed, 10 Mar 2021 19:12:12 +0100 Subject: [PATCH] feat(datadog): add tokio as optional dependency MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jérémie Drouet --- Cargo.toml | 3 +- src/exporters/datadog.rs | 22 ++++++++++----- src/lib.rs | 59 ++++++++++++++++++++++++++-------------- src/main.rs | 2 ++ 4 files changed, 57 insertions(+), 29 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c983a396..b87f2c09 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" [features] default = ["datadog"] -datadog = ["datadog-client"] +datadog = ["datadog-client", "tokio"] [dependencies] loggerv = "0.7.2" @@ -30,6 +30,7 @@ serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" datadog-client = { version = "0.1", optional = true } +tokio = { version = "1", features = ["full"], optional = true } [profile.release] lto = true diff --git a/src/exporters/datadog.rs b/src/exporters/datadog.rs index 3c8abb0d..046df1cd 100644 --- a/src/exporters/datadog.rs +++ b/src/exporters/datadog.rs @@ -5,6 +5,7 @@ use datadog_client::metrics::{Point, Serie, Type}; use std::collections::HashMap; use std::thread; use std::time::{Duration, Instant}; +use tokio::runtime::Runtime; fn merge(first: Vec, second: Vec) -> Vec { second.into_iter().fold(first, |mut res, item| { @@ -32,7 +33,10 @@ pub struct DatadogExporter { impl Exporter for DatadogExporter { /// Lanches runner() fn run(&mut self, parameters: ArgMatches) { - self.runner(¶meters); + let rt = Runtime::new().unwrap(); + rt.block_on(async move { + self.runner(¶meters).await; + }); } /// Returns options needed for that exporter, as a HashMap @@ -87,7 +91,7 @@ impl DatadogExporter { Client::new(config) } - fn runner(&mut self, parameters: &ArgMatches) { + async fn runner<'a>(&mut self, parameters: &ArgMatches<'a>) { if let Some(timeout) = parameters.value_of("timeout") { let now = Instant::now(); let timeout = timeout @@ -110,18 +114,22 @@ impl DatadogExporter { info!("Measurement step is: {}s", step_duration); while now.elapsed().as_secs() <= timeout { - self.iterate(parameters); + self.iterate(parameters).await; thread::sleep(Duration::new(step_duration, step_duration_nano)); } } else { - self.iterate(parameters); + self.iterate(parameters).await; } } - fn iterate(&mut self, parameters: &ArgMatches) { + async fn iterate<'a>(&mut self, parameters: &ArgMatches<'a>) { self.topology.refresh(); - let _series = self.collect_series(); - let _client = Self::build_client(parameters); + let series = self.collect_series(); + let client = Self::build_client(parameters); + match client.post_metrics(&series).await { + Ok(_) => log::debug!("metrics sent"), + Err(_) => log::warn!("unable to send metrics"), + }; } fn create_consumption_serie(&self) -> Serie { diff --git a/src/lib.rs b/src/lib.rs index 6d56df82..9f1e9431 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,8 +5,8 @@ pub mod exporters; pub mod sensors; use clap::ArgMatches; use exporters::{ - json::JSONExporter, prometheus::PrometheusExporter, qemu::QemuExporter, - riemann::RiemannExporter, stdout::StdoutExporter, Exporter, ExporterOption, + datadog::DatadogExporter, json::JSONExporter, prometheus::PrometheusExporter, + qemu::QemuExporter, riemann::RiemannExporter, stdout::StdoutExporter, Exporter, ExporterOption, }; use sensors::{powercap_rapl::PowercapRAPLSensor, Sensor}; use std::collections::HashMap; @@ -52,32 +52,44 @@ fn get_sensor(matches: &ArgMatches) -> Box { pub fn run(matches: ArgMatches) { loggerv::init_with_verbosity(matches.occurrences_of("v")).unwrap(); - let sensor_boxed = get_sensor(&matches); - let exporter_parameters; - if let Some(stdout_exporter_parameters) = matches.subcommand_matches("stdout") { - exporter_parameters = stdout_exporter_parameters.clone(); - let mut exporter = StdoutExporter::new(sensor_boxed); + let exporter_parameters = stdout_exporter_parameters.clone(); + let mut exporter = StdoutExporter::new(get_sensor(&matches)); exporter.run(exporter_parameters); - } else if let Some(json_exporter_parameters) = matches.subcommand_matches("json") { - exporter_parameters = json_exporter_parameters.clone(); - let mut exporter = JSONExporter::new(sensor_boxed); + return; + } + if let Some(json_exporter_parameters) = matches.subcommand_matches("json") { + let exporter_parameters = json_exporter_parameters.clone(); + let mut exporter = JSONExporter::new(get_sensor(&matches)); exporter.run(exporter_parameters); - } else if let Some(riemann_exporter_parameters) = matches.subcommand_matches("riemann") { - exporter_parameters = riemann_exporter_parameters.clone(); - let mut exporter = RiemannExporter::new(sensor_boxed); + return; + } + if let Some(riemann_exporter_parameters) = matches.subcommand_matches("riemann") { + let exporter_parameters = riemann_exporter_parameters.clone(); + let mut exporter = RiemannExporter::new(get_sensor(&matches)); exporter.run(exporter_parameters); - } else if let Some(prometheus_exporter_parameters) = matches.subcommand_matches("prometheus") { - exporter_parameters = prometheus_exporter_parameters.clone(); - let mut exporter = PrometheusExporter::new(sensor_boxed); + return; + } + if let Some(prometheus_exporter_parameters) = matches.subcommand_matches("prometheus") { + let exporter_parameters = prometheus_exporter_parameters.clone(); + let mut exporter = PrometheusExporter::new(get_sensor(&matches)); exporter.run(exporter_parameters); - } else if let Some(qemu_exporter_parameters) = matches.subcommand_matches("qemu") { - exporter_parameters = qemu_exporter_parameters.clone(); - let mut exporter = QemuExporter::new(sensor_boxed); + return; + } + if let Some(qemu_exporter_parameters) = matches.subcommand_matches("qemu") { + let exporter_parameters = qemu_exporter_parameters.clone(); + let mut exporter = QemuExporter::new(get_sensor(&matches)); exporter.run(exporter_parameters); - } else { - error!("Couldn't determine which exporter has been chosen."); + return; } + #[cfg(feature = "datadog")] + if let Some(datadog_exporter_parameters) = matches.subcommand_matches("datadog") { + let exporter_parameters = datadog_exporter_parameters.clone(); + let mut exporter = DatadogExporter::new(get_sensor(&matches)); + exporter.run(exporter_parameters); + return; + } + error!("Couldn't determine which exporter has been chosen."); } /// Returns options needed for each exporter as a HashMap. @@ -104,6 +116,11 @@ pub fn get_exporters_options() -> HashMap "Prometheus exporter exposes power consumption metrics on an http endpoint (/metrics is default) in prometheus accepted format", "riemann" => "Riemann exporter sends power consumption metrics to a Riemann server", "qemu" => "Qemu exporter watches all Qemu/KVM virtual machines running on the host and exposes metrics of each of them in a dedicated folder", + #[cfg(feature = "datadog")] + "datadog" => "Datadog exporter sends power consumption metrics to Datadog", _ => "Unknown exporter", } );