rama_http/layer/trace/make_span.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
use crate::Request;
use tracing::{Level, Span};
use super::DEFAULT_MESSAGE_LEVEL;
/// Trait used to generate [`Span`]s from requests. [`Trace`] wraps all request handling in this
/// span.
///
/// [`Span`]: tracing::Span
/// [`Trace`]: super::Trace
pub trait MakeSpan<B>: Send + Sync + 'static {
/// Make a span from a request.
fn make_span(&self, request: &Request<B>) -> Span;
}
impl<B> MakeSpan<B> for Span {
fn make_span(&self, _request: &Request<B>) -> Span {
self.clone()
}
}
impl<F, B> MakeSpan<B> for F
where
F: Fn(&Request<B>) -> Span + Send + Sync + 'static,
{
fn make_span(&self, request: &Request<B>) -> Span {
self(request)
}
}
/// The default way [`Span`]s will be created for [`Trace`].
///
/// [`Span`]: tracing::Span
/// [`Trace`]: super::Trace
#[derive(Debug, Clone)]
pub struct DefaultMakeSpan {
level: Level,
include_headers: bool,
}
impl DefaultMakeSpan {
/// Create a new `DefaultMakeSpan`.
pub const fn new() -> Self {
Self {
level: DEFAULT_MESSAGE_LEVEL,
include_headers: false,
}
}
/// Set the [`Level`] used for the [tracing span].
///
/// Defaults to [`Level::DEBUG`].
///
/// [tracing span]: https://docs.rs/tracing/latest/tracing/#spans
pub const fn level(mut self, level: Level) -> Self {
self.level = level;
self
}
/// Set the [`Level`] used for the [tracing span].
///
/// Defaults to [`Level::DEBUG`].
///
/// [tracing span]: https://docs.rs/tracing/latest/tracing/#spans
pub fn set_level(&mut self, level: Level) -> &mut Self {
self.level = level;
self
}
/// Include request headers on the [`Span`].
///
/// By default headers are not included.
///
/// [`Span`]: tracing::Span
pub const fn include_headers(mut self, include_headers: bool) -> Self {
self.include_headers = include_headers;
self
}
/// Include request headers on the [`Span`].
///
/// By default headers are not included.
///
/// [`Span`]: tracing::Span
pub fn set_include_headers(&mut self, include_headers: bool) -> &mut Self {
self.include_headers = include_headers;
self
}
}
impl Default for DefaultMakeSpan {
fn default() -> Self {
Self::new()
}
}
impl<B> MakeSpan<B> for DefaultMakeSpan {
fn make_span(&self, request: &Request<B>) -> Span {
// This ugly macro is needed, unfortunately, because `tracing::span!`
// required the level argument to be static. Meaning we can't just pass
// `self.level`.
macro_rules! make_span {
($level:expr) => {
if self.include_headers {
tracing::span!(
$level,
"request",
method = %request.method(),
uri = %request.uri(),
version = ?request.version(),
headers = ?request.headers(),
)
} else {
tracing::span!(
$level,
"request",
method = %request.method(),
uri = %request.uri(),
version = ?request.version(),
)
}
}
}
match self.level {
Level::ERROR => make_span!(Level::ERROR),
Level::WARN => make_span!(Level::WARN),
Level::INFO => make_span!(Level::INFO),
Level::DEBUG => make_span!(Level::DEBUG),
Level::TRACE => make_span!(Level::TRACE),
}
}
}