use hyper::header::HeaderName;
use crate::App;
const DEFAULT_SPAN_HEADER_NAME: &str = "request-id";
#[derive(Debug, Clone)]
#[cfg_attr(feature = "config", derive(serde::Deserialize))]
#[cfg_attr(feature = "config", serde(default))]
pub struct TracingConfig {
pub(super) include_header: bool,
#[cfg_attr(feature = "config", serde(deserialize_with = "deser_header_name"))]
pub(super) span_header_name: HeaderName,
}
impl Default for TracingConfig {
#[inline]
fn default() -> Self {
Self {
include_header: false,
span_header_name: HeaderName::from_static(DEFAULT_SPAN_HEADER_NAME),
}
}
}
#[cfg(feature = "config")]
fn deser_header_name<'de, D: serde::Deserializer<'de>>(d: D) -> Result<HeaderName, D::Error> {
use serde::Deserialize;
let s = String::deserialize(d)?;
HeaderName::try_from(s.as_str()).map_err(serde::de::Error::custom)
}
impl TracingConfig {
pub fn new() -> Self {
Self::default()
}
pub fn with_header(mut self) -> Self {
self.include_header = true;
self
}
pub fn without_header(mut self) -> Self {
self.include_header = false;
self
}
pub fn with_header_name(mut self, name: impl AsRef<str>) -> Self {
self.span_header_name =
HeaderName::try_from(name.as_ref()).expect("invalid HTTP header name");
self
}
}
impl App {
pub fn with_default_tracing(mut self) -> Self {
self.tracing_config = Some(TracingConfig::default());
self
}
pub fn with_tracing<T>(mut self, config: T) -> Self
where
T: FnOnce(TracingConfig) -> TracingConfig,
{
self.tracing_config = Some(config(self.tracing_config.unwrap_or_default()));
self
}
pub fn set_tracing(mut self, config: TracingConfig) -> Self {
self.tracing_config = Some(config);
self
}
}
#[cfg(test)]
mod tests {
use hyper::header::HeaderName;
use super::{DEFAULT_SPAN_HEADER_NAME, TracingConfig};
use crate::App;
#[test]
fn it_creates_new() {
let tracing_config = TracingConfig::new();
assert!(!tracing_config.include_header);
assert_eq!(tracing_config.span_header_name, DEFAULT_SPAN_HEADER_NAME);
}
#[test]
fn it_creates_default() {
let tracing_config = TracingConfig::default();
assert!(!tracing_config.include_header);
assert_eq!(tracing_config.span_header_name, DEFAULT_SPAN_HEADER_NAME);
}
#[test]
fn it_creates_with_include_header() {
let tracing_config = TracingConfig::new().with_header();
assert!(tracing_config.include_header);
assert_eq!(tracing_config.span_header_name, DEFAULT_SPAN_HEADER_NAME);
}
#[test]
fn it_creates_without_include_header() {
let tracing_config = TracingConfig::new().with_header().without_header();
assert!(!tracing_config.include_header);
assert_eq!(tracing_config.span_header_name, DEFAULT_SPAN_HEADER_NAME);
}
#[test]
fn it_creates_with_header_name() {
let tracing_config = TracingConfig::new()
.with_header()
.with_header_name("correlation-id");
assert!(tracing_config.include_header);
assert_eq!(tracing_config.span_header_name, "correlation-id");
}
#[test]
fn it_creates_app_with_default_tracing() {
let app = App::new().with_default_tracing();
let tracing_config = app.tracing_config.unwrap();
assert!(!tracing_config.include_header);
assert_eq!(
tracing_config.span_header_name,
HeaderName::from_static(DEFAULT_SPAN_HEADER_NAME)
)
}
#[test]
fn it_creates_app_with_span_header() {
let app = App::new().set_tracing(TracingConfig::new().with_header());
let tracing_config = app.tracing_config.unwrap();
assert!(tracing_config.include_header);
assert_eq!(
tracing_config.span_header_name,
HeaderName::from_static(DEFAULT_SPAN_HEADER_NAME)
)
}
#[test]
fn it_creates_app_with_span_header_name() {
let app = App::new()
.with_tracing(|tracing| tracing.with_header().with_header_name("correlation-id"));
let tracing_config = app.tracing_config.unwrap();
assert!(tracing_config.include_header);
assert_eq!(tracing_config.span_header_name, "correlation-id")
}
}