rama_http/layer/trace/
on_failure.rs

1use super::{DEFAULT_ERROR_LEVEL, Latency};
2use rama_utils::latency::LatencyUnit;
3use std::{fmt, time::Duration};
4use tracing::{Level, Span};
5
6/// Trait used to tell [`Trace`] what to do when a request fails.
7///
8/// See the [module docs](../trace/index.html#on_failure) for details on exactly when the
9/// `on_failure` callback is called.
10///
11/// [`Trace`]: super::Trace
12pub trait OnFailure<FailureClass>: Send + Sync + 'static {
13    /// Do the thing.
14    ///
15    /// `latency` is the duration since the request was received.
16    ///
17    /// `span` is the `tracing` [`Span`], corresponding to this request, produced by the closure
18    /// passed to [`TraceLayer::make_span_with`]. It can be used to [record field values][record]
19    /// that weren't known when the span was created.
20    ///
21    /// [`Span`]: https://docs.rs/tracing/latest/tracing/span/index.html
22    /// [record]: https://docs.rs/tracing/latest/tracing/span/struct.Span.html#method.record
23    /// [`TraceLayer::make_span_with`]: crate::layer::trace::TraceLayer::make_span_with
24    fn on_failure(&self, failure_classification: FailureClass, latency: Duration, span: &Span);
25}
26
27impl<FailureClass> OnFailure<FailureClass> for () {
28    #[inline]
29    fn on_failure(&self, _: FailureClass, _: Duration, _: &Span) {}
30}
31
32impl<F, FailureClass> OnFailure<FailureClass> for F
33where
34    F: Fn(FailureClass, Duration, &Span) + Send + Sync + 'static,
35{
36    fn on_failure(&self, failure_classification: FailureClass, latency: Duration, span: &Span) {
37        self(failure_classification, latency, span)
38    }
39}
40
41/// The default [`OnFailure`] implementation used by [`Trace`].
42///
43/// [`Trace`]: super::Trace
44#[derive(Clone, Debug)]
45pub struct DefaultOnFailure {
46    level: Level,
47    latency_unit: LatencyUnit,
48}
49
50impl Default for DefaultOnFailure {
51    fn default() -> Self {
52        Self {
53            level: DEFAULT_ERROR_LEVEL,
54            latency_unit: LatencyUnit::Millis,
55        }
56    }
57}
58
59impl DefaultOnFailure {
60    /// Create a new `DefaultOnFailure`.
61    pub fn new() -> Self {
62        Self::default()
63    }
64
65    /// Set the [`Level`] used for [tracing events].
66    ///
67    /// Defaults to [`Level::ERROR`].
68    ///
69    /// [tracing events]: https://docs.rs/tracing/latest/tracing/#events
70    pub fn level(mut self, level: Level) -> Self {
71        self.level = level;
72        self
73    }
74
75    /// Set the [`Level`] used for [tracing events].
76    ///
77    /// Defaults to [`Level::ERROR`].
78    ///
79    /// [tracing events]: https://docs.rs/tracing/latest/tracing/#events
80    pub fn set_level(&mut self, level: Level) -> &mut Self {
81        self.level = level;
82        self
83    }
84
85    /// Set the [`LatencyUnit`] latencies will be reported in.
86    ///
87    /// Defaults to [`LatencyUnit::Millis`].
88    pub fn latency_unit(mut self, latency_unit: LatencyUnit) -> Self {
89        self.latency_unit = latency_unit;
90        self
91    }
92
93    /// Set the [`LatencyUnit`] latencies will be reported in.
94    ///
95    /// Defaults to [`LatencyUnit::Millis`].
96    pub fn set_latency_unit(&mut self, latency_unit: LatencyUnit) -> &mut Self {
97        self.latency_unit = latency_unit;
98        self
99    }
100}
101
102impl<FailureClass> OnFailure<FailureClass> for DefaultOnFailure
103where
104    FailureClass: fmt::Display,
105{
106    fn on_failure(&self, failure_classification: FailureClass, latency: Duration, _: &Span) {
107        let latency = Latency {
108            unit: self.latency_unit,
109            duration: latency,
110        };
111        event_dynamic_lvl!(
112            self.level,
113            classification = %failure_classification,
114            %latency,
115            "response failed"
116        );
117    }
118}