Skip to main content

sentry_tracing/layer/
error.rs

1use sentry_core::protocol::Event as SentryEvent;
2use tracing_core::{Event, Subscriber};
3use tracing_subscriber::layer::{Context, Layer};
4use tracing_subscriber::registry::LookupSpan;
5
6use crate::converters::event_from_event_impl;
7
8/// Captures tracing events as Sentry error events.
9///
10/// Using this layer alongside the legacy [`SentryLayer`](super::SentryLayer) is unsupported.
11/// Use either the legacy layer or the individual layers, not both.
12#[must_use]
13#[derive(Default)]
14pub struct ErrorLayer {
15    with_span_attributes: bool,
16}
17
18impl ErrorLayer {
19    /// Creates a layer that captures tracing events as Sentry error events.
20    ///
21    /// Most applications should start with [`LogLayer`](super::LogLayer), and add this layer if
22    /// `ERROR` events should also be captured as Sentry error events. Combine it with
23    /// [`BreadcrumbLayer`](super::BreadcrumbLayer) to attach the events leading up to each error.
24    ///
25    /// # Filtering
26    ///
27    /// Configure a level filter to limit error-event volume. We recommend capturing only `ERROR`
28    /// events, as shown below.
29    ///
30    /// <div class="warning">
31    ///
32    /// **Do not use this layer without a filter.** An unfiltered layer captures every tracing
33    /// event, including `DEBUG` and `TRACE`, as a Sentry error event. This can quickly exhaust
34    /// your Sentry error quota.
35    ///
36    /// </div>
37    ///
38    /// ```rust
39    /// # use tracing_subscriber::prelude::*;
40    /// use sentry::integrations::tracing::ErrorLayer;
41    /// use tracing_subscriber::filter::LevelFilter;
42    ///
43    /// tracing_subscriber::registry()
44    ///     .with(ErrorLayer::new().with_filter(LevelFilter::ERROR))
45    ///     .init();
46    ///
47    /// // This will be captured ...
48    /// tracing::error!("ERROR event");
49    ///
50    /// // ... but this will not be, due to LevelFilter::ERROR being set.
51    /// tracing::warn!("WARN event");
52    /// ```
53    ///
54    /// # Event conversion
55    ///
56    /// With the default converter:
57    ///
58    /// - String, numeric, and boolean fields prefixed with `tags.` become Sentry tags, with the
59    ///   prefix removed.
60    /// - Other data fields are stored in the `Rust Tracing Fields` context on the Sentry error event.
61    /// - Record an error as `&dyn std::error::Error` to capture its exception type and source chain.
62    pub fn new() -> Self {
63        Self::default()
64    }
65
66    /// Include attributes of parent spans in error events.
67    ///
68    /// We can only include spans captured by a [`super::SpanLayer`] on the same subscriber. So,
69    /// this option only has any effect when the `SpanLayer` is installed.
70    ///
71    /// # Filtering
72    ///
73    /// Parent-span attributes are included only when the span is accepted by both `SpanLayer`
74    /// and `ErrorLayer`. A level filter such as `LevelFilter::ERROR` therefore omits attributes
75    /// from less severe spans.
76    ///
77    /// To include attributes from all spans captured by `SpanLayer`, we recommend accepting all
78    /// spans in this layer's filter, while filtering events to the desired level, like so:
79    ///
80    ///
81    pub fn enable_span_attributes(mut self) -> Self {
82        self.with_span_attributes = true;
83        self
84    }
85
86    /// Capture an error event on the current `Hub`.
87    pub(super) fn capture(&self, event: SentryEvent<'static>) {
88        sentry_core::capture_event(event);
89    }
90
91    /// Capture a tracing event as a Sentry error event.
92    pub(super) fn capture_tracing_event<S>(&self, event: &Event, ctx: Context<'_, S>)
93    where
94        S: Subscriber + for<'a> LookupSpan<'a>,
95    {
96        let sentry_event = event_from_event_impl(event, self.with_span_attributes.then_some(&ctx));
97        self.capture(sentry_event);
98    }
99}
100
101impl<S> Layer<S> for ErrorLayer
102where
103    S: Subscriber + for<'a> LookupSpan<'a>,
104{
105    fn on_event(&self, event: &Event, ctx: Context<'_, S>) {
106        self.capture_tracing_event(event, ctx);
107    }
108}