use std::str::FromStr;
use std::time::Duration;
use std::{fmt, path::PathBuf};
use url::Url;
use crate::{metrics, CollectionLabels, ExporterMetricsSwitch, ExporterPollIntervals};
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum CertificateValidationOptions {
None,
Full,
Partial,
}
impl FromStr for CertificateValidationOptions {
type Err = serde_qs::Error;
fn from_str(input: &str) -> Result<Self, Self::Err> {
serde_qs::from_str(input)
}
}
#[derive(Debug, Clone)]
pub struct ExporterOptions {
pub elasticsearch_url: Url,
pub elasticsearch_global_timeout: Duration,
pub elasticsearch_query_fields: CollectionLabels,
pub elasticsearch_query_filter_path: CollectionLabels,
pub elasticsearch_subsystem_timeouts: ExporterPollIntervals,
pub elasticsearch_path_parameters: CollectionLabels,
pub elasticsearch_certificate_path: Option<PathBuf>,
pub elasticsearch_certificate_validation: Option<CertificateValidationOptions>,
pub exporter_skip_labels: CollectionLabels,
pub exporter_include_labels: CollectionLabels,
pub exporter_skip_metrics: CollectionLabels,
pub exporter_skip_zero_metrics: bool,
pub exporter_metrics_enabled: ExporterMetricsSwitch,
pub exporter_metrics_namespace: String,
pub exporter_metadata_refresh_interval: Duration,
pub exporter_poll_default_interval: Duration,
pub exporter_poll_intervals: ExporterPollIntervals,
pub exporter_metrics_lifetime_interval: ExporterPollIntervals,
pub exporter_metrics_lifetime_default_interval: Duration,
}
impl ExporterOptions {
pub(crate) fn enable_metadata_refresh(&self) -> bool {
let cluster_subsystems = Self::nodes_subsystems();
self.exporter_metrics_enabled
.iter()
.any(|(k, v)| cluster_subsystems.contains(&k.as_str()) && *v)
}
pub fn is_metric_enabled(&self, subsystem: &'static str) -> bool {
self.exporter_metrics_enabled.contains_key(subsystem)
}
pub fn query_fields_for_subsystem(&self, subsystem: &'static str) -> Vec<&str> {
self.elasticsearch_query_fields
.get(subsystem)
.map(|params| params.iter().map(AsRef::as_ref).collect::<Vec<&str>>())
.unwrap_or_default()
}
pub fn query_filter_path_for_subsystem(&self, subsystem: &'static str) -> Vec<&str> {
self.elasticsearch_query_filter_path
.get(subsystem)
.map(|params| params.iter().map(AsRef::as_ref).collect::<Vec<&str>>())
.unwrap_or_default()
}
pub fn path_parameters_for_subsystem(&self, subsystem: &'static str) -> Vec<&str> {
self.elasticsearch_path_parameters
.get(subsystem)
.map(|params| params.iter().map(AsRef::as_ref).collect::<Vec<&str>>())
.unwrap_or_default()
}
pub fn timeout_for_subsystem(&self, subsystem: &'static str) -> Duration {
*self
.elasticsearch_subsystem_timeouts
.get(subsystem)
.unwrap_or(&self.elasticsearch_global_timeout)
}
pub fn cat_subsystems() -> &'static [&'static str] {
use metrics::_cat::*;
&[
allocation::SUBSYSTEM,
shards::SUBSYSTEM,
indices::SUBSYSTEM,
segments::SUBSYSTEM,
nodes::SUBSYSTEM,
recovery::SUBSYSTEM,
health::SUBSYSTEM,
pending_tasks::SUBSYSTEM,
aliases::SUBSYSTEM,
thread_pool::SUBSYSTEM,
plugins::SUBSYSTEM,
fielddata::SUBSYSTEM,
nodeattrs::SUBSYSTEM,
repositories::SUBSYSTEM,
templates::SUBSYSTEM,
transforms::SUBSYSTEM,
]
}
pub fn cluster_subsystems() -> &'static [&'static str] {
use metrics::_cluster::*;
&[health::SUBSYSTEM]
}
pub fn nodes_subsystems() -> &'static [&'static str] {
use metrics::_nodes::*;
&[usage::SUBSYSTEM, stats::SUBSYSTEM, info::SUBSYSTEM]
}
pub fn stats_subsystems() -> &'static [&'static str] {
use metrics::_stats::*;
&[_all::SUBSYSTEM]
}
}
fn switch_to_string(output: &mut String, field: &'static str, switches: &ExporterMetricsSwitch) {
output.push('\n');
output.push_str(&format!("{}:", field));
for (k, v) in switches.iter() {
output.push('\n');
output.push_str(&format!(" - {}: {}", k, v));
}
}
fn collection_labels_to_string(
output: &mut String,
field: &'static str,
labels: &CollectionLabels,
) {
output.push('\n');
output.push_str(&format!("{}:", field));
for (k, v) in labels.iter() {
output.push('\n');
output.push_str(&format!(" - {}: {}", k, v.join(",")));
}
}
fn poll_duration_to_string(
output: &mut String,
field: &'static str,
labels: &ExporterPollIntervals,
) {
output.push('\n');
output.push_str(&format!("{}:", field));
for (k, v) in labels.iter() {
output.push('\n');
output.push_str(&format!(" - {}: {:?}", k, v));
}
}
fn vec_to_string(output: &mut String, field: &'static str, fields: &[&'static str]) {
output.push('\n');
output.push_str(&format!("{}:", field));
for field in fields.iter() {
output.push('\n');
output.push_str(&format!(" - {}", field));
}
}
impl fmt::Display for ExporterOptions {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut output = String::from("Proper Elasticsearch exporter");
output.push('\n');
vec_to_string(
&mut output,
"Available /_cat subsystems",
Self::cat_subsystems(),
);
vec_to_string(
&mut output,
"Available /_cluster subsystems",
Self::cluster_subsystems(),
);
vec_to_string(
&mut output,
"Available /_nodes subsystems",
Self::nodes_subsystems(),
);
vec_to_string(
&mut output,
"Available /_stats subsystems",
Self::stats_subsystems(),
);
output.push('\n');
output.push('\n');
output.push_str("Exporter settings:");
output.push('\n');
output.push_str(&format!("elasticsearch_url: {}", self.elasticsearch_url));
output.push('\n');
output.push_str(&format!(
"elasticsearch_global_timeout: {:?}",
self.elasticsearch_global_timeout
));
collection_labels_to_string(
&mut output,
"elasticsearch_query_fields",
&self.elasticsearch_query_fields,
);
collection_labels_to_string(
&mut output,
"elasticsearch_query_filter_path",
&self.elasticsearch_query_filter_path,
);
poll_duration_to_string(
&mut output,
"elasticsearch_subsystem_timeouts",
&self.elasticsearch_subsystem_timeouts,
);
collection_labels_to_string(
&mut output,
"elasticsearch_path_parameters",
&self.elasticsearch_path_parameters,
);
collection_labels_to_string(
&mut output,
"exporter_skip_labels",
&self.exporter_skip_labels,
);
collection_labels_to_string(
&mut output,
"exporter_include_labels",
&self.exporter_include_labels,
);
collection_labels_to_string(
&mut output,
"exporter_skip_metrics",
&self.exporter_skip_metrics,
);
output.push('\n');
output.push_str(&format!(
"exporter_poll_default_interval: {:?}",
self.exporter_poll_default_interval
));
poll_duration_to_string(
&mut output,
"exporter_poll_intervals",
&self.exporter_poll_intervals,
);
output.push('\n');
output.push_str(&format!(
"exporter_skip_zero_metrics: {:?}",
self.exporter_skip_zero_metrics
));
switch_to_string(
&mut output,
"exporter_metrics_enabled",
&self.exporter_metrics_enabled,
);
output.push('\n');
output.push_str(&format!(
"exporter_metrics_namespace: {}",
self.exporter_metrics_namespace
));
output.push('\n');
output.push_str(&format!(
"exporter_metadata_refresh_interval: {:?}",
self.exporter_metadata_refresh_interval
));
output.push('\n');
output.push_str(&format!(
"exporter_metrics_lifetime_default_interval: {:?}",
self.exporter_metrics_lifetime_default_interval
));
poll_duration_to_string(
&mut output,
"exporter_metrics_lifetime_interval",
&self.exporter_metrics_lifetime_interval,
);
output.push('\n');
write!(f, "{}", output)
}
}