use opentelemetry::KeyValue;
#[cfg(any(feature = "detector-aws-ecs", feature = "detector-aws-lambda"))]
use opentelemetry::{Array, StringValue, Value};
#[cfg(feature = "_detector-http")]
pub(super) fn blocking_client(timeout: std::time::Duration) -> ureq::Agent {
ureq::Agent::config_builder()
.proxy(None)
.timeout_global(Some(timeout))
.build()
.into()
}
#[cfg(feature = "detector-aws-eks")]
#[cfg_attr(
not(feature = "internal-logs"),
allow(unused_variables, clippy::manual_ok_err) // without logging this is just `Result::ok`
)]
pub(super) fn debug_on_error<T, E: std::error::Error>(
detector: &'static str,
result: Result<T, E>,
) -> Option<T> {
match result {
Ok(value) => Some(value),
Err(error) => {
#[cfg(feature = "internal-logs")]
tracing::debug!(%detector, %error, "Detector error");
None
}
}
}
#[cfg_attr(
not(feature = "internal-logs"),
allow(unused_variables, clippy::manual_ok_err) // without logging this is just `Result::ok`
)]
pub(super) fn info_on_error<T, E: std::error::Error>(
detector: &'static str,
result: Result<T, E>,
) -> Option<T> {
match result {
Ok(value) => Some(value),
Err(error) => {
#[cfg(feature = "internal-logs")]
tracing::info!(%detector, %error, "Detector error");
None
}
}
}
#[cfg_attr(
not(feature = "internal-logs"),
allow(unused_variables, clippy::manual_ok_err) // without logging this is just `Result::ok`
)]
pub(super) fn warn_on_error<T, E: std::error::Error>(
detector: &'static str,
result: Result<T, E>,
) -> Option<T> {
match result {
Ok(value) => Some(value),
Err(error) => {
#[cfg(feature = "internal-logs")]
tracing::warn!(%detector, %error, "Detector error");
None
}
}
}
pub(super) fn opt_kv(key: &'static str, value: Option<String>) -> Option<KeyValue> {
value.and_then(non_empty).map(|v| KeyValue::new(key, v))
}
#[cfg(any(feature = "detector-aws-ecs", feature = "detector-aws-lambda"))]
pub(super) fn opt_kv_array(key: &'static str, value: Option<String>) -> Option<KeyValue> {
value
.and_then(non_empty)
.map(|v| KeyValue::new(key, Value::Array(Array::from(vec![StringValue::from(v)]))))
}
pub(super) fn non_empty(value: String) -> Option<String> {
let trimmed = value.trim();
if trimmed.is_empty() {
None
} else if trimmed.len() == value.len() {
Some(value)
} else {
Some(trimmed.to_owned())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn non_empty_some() {
let result = non_empty("hello".to_owned());
assert_eq!(result, Some("hello".to_owned()));
let result = non_empty(" hello world ".to_owned());
assert_eq!(result, Some("hello world".to_owned()));
let result = non_empty("\t content\n".to_owned());
assert_eq!(result, Some("content".to_owned()));
}
#[test]
fn non_empty_none() {
assert_eq!(non_empty("".to_owned()), None);
assert_eq!(non_empty(" ".to_owned()), None);
assert_eq!(non_empty("\t\n\r".to_owned()), None);
}
#[test]
fn opt_kv_some() {
let kv = opt_kv("my.key", Some("my-value".to_owned()));
let kv = kv.expect("expected Some(KeyValue)");
assert_eq!(kv.key.as_str(), "my.key");
assert_eq!(kv.value, opentelemetry::Value::String("my-value".into()));
let kv = opt_kv("trimmed.key", Some(" trimmed ".to_owned()));
let kv = kv.expect("expected Some(KeyValue) after trimming");
assert_eq!(kv.key.as_str(), "trimmed.key");
assert_eq!(kv.value, opentelemetry::Value::String("trimmed".into()));
}
#[test]
fn opt_kv_none() {
assert!(opt_kv("k", None).is_none());
assert!(opt_kv("k", Some("".to_owned())).is_none());
assert!(opt_kv("k", Some(" ".to_owned())).is_none());
}
#[cfg(feature = "detector-aws-ecs")]
#[test]
fn opt_kv_array_some() {
let kv = opt_kv_array("array.key", Some("v".to_owned()));
let kv = kv.expect("expected Some(KeyValue)");
assert_eq!(kv.key.as_str(), "array.key");
let expected = Value::Array(Array::from(vec![StringValue::from("v")]));
assert_eq!(kv.value, expected);
}
#[cfg(feature = "detector-aws-ecs")]
#[test]
fn opt_kv_array_none() {
assert!(opt_kv_array("k", None).is_none());
assert!(opt_kv_array("k", Some("".to_owned())).is_none());
assert!(opt_kv_array("k", Some(" ".to_owned())).is_none());
}
}