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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
//! Support for automatic breadcrumb, event, and trace capturing from `tracing` events and spans.
//!
//! The `tracing` crate is supported in four ways:
//! - `tracing` events can be captured as Sentry events. These are grouped and show up in the Sentry
//! [issues](https://docs.sentry.io/product/issues/) page, representing high severity issues to be
//! acted upon.
//! - `tracing` events can be captured as [breadcrumbs](https://docs.sentry.io/product/issues/issue-details/breadcrumbs/).
//! Breadcrumbs create a trail of what happened prior to an event, and are therefore sent only when
//! an event is captured, either manually through e.g. `sentry::capture_message` or through integrations
//! (e.g. the panic integration is enabled (default) and a panic happens).
//! - `tracing` events can be captured as traditional [structured logs](https://docs.sentry.io/product/explore/logs/).
//! The `tracing` fields are captured as attributes on the logs, which can be queried in the Logs
//! explorer. (Available on crate feature `logs`)
//! - `tracing` spans can be captured as Sentry spans. These can be used to provide more contextual
//! information for errors, diagnose [performance
//! issues](https://docs.sentry.io/product/insights/overview/), and capture additional attributes to
//! aggregate and compute [metrics](https://docs.sentry.io/product/explore/trace-explorer/).
//!
//! By default, events above `Info` are recorded as breadcrumbs, events above `Error` are captured
//! as error events, and spans above `Info` are recorded as spans.
//!
//! # Configuration
//!
//! To fully enable the tracing integration, set the traces sample rate and add a layer to the
//! tracing subscriber:
//!
//! ```
//! use tracing_subscriber::prelude::*;
//!
//! let _guard = sentry::init(sentry::ClientOptions {
//! // Enable capturing of traces; set this a to lower value in production:
//! traces_sample_rate: 1.0,
//! ..sentry::ClientOptions::default()
//! });
//!
//! // Register the Sentry tracing layer to capture breadcrumbs, events, and spans:
//! tracing_subscriber::registry()
//! .with(tracing_subscriber::fmt::layer())
//! .with(sentry::integrations::tracing::layer())
//! .init();
//! ```
//!
//! You can customize the behavior of the layer by providing an explicit event filter, to customize which events
//! are captured by Sentry and the data type they are mapped to.
//! Similarly, you can provide a span filter to customize which spans are captured by Sentry.
//!
//! ```
//! use sentry::integrations::tracing::EventFilter;
//! use tracing_subscriber::prelude::*;
//!
//! let sentry_layer = sentry::integrations::tracing::layer()
//! .event_filter(|md| match *md.level() {
//! tracing::Level::ERROR => EventFilter::Event,
//! _ => EventFilter::Ignore,
//! })
//! .span_filter(|md| matches!(*md.level(), tracing::Level::ERROR | tracing::Level::WARN));
//!
//! tracing_subscriber::registry()
//! .with(tracing_subscriber::fmt::layer())
//! .with(sentry_layer)
//! .init();
//! ```
//!
//! In addition, a custom event mapper can be provided, to fully customize if and how `tracing` events are converted to Sentry data.
//!
//! Note that if both an event mapper and event filter are set, the mapper takes precedence, thus the
//! filter has no effect.
//!
//! # Capturing breadcrumbs
//!
//! Tracing events automatically create breadcrumbs that are attached to the current scope in
//! Sentry. They show up on errors and transactions captured within this scope as shown in the
//! examples below.
//!
//! Fields passed to the event macro are automatically tracked as structured data in Sentry. For
//! breadcrumbs, they are shown directly with the breadcrumb message. For other types of data, read
//! below.
//!
//! ```
//! for i in 0..10 {
//! tracing::debug!(number = i, "Generates a breadcrumb");
//! }
//! ```
//!
//! # Capturing logs
//!
//! Tracing events can be captured as traditional structured logs in Sentry.
//! This is gated by the `logs` feature flag and requires setting up a custom Event filter/mapper
//! to capture logs. You also need to pass `enable_logs: true` in your `sentry::init` call.
//!
//! ```
//! // assuming `tracing::Level::INFO => EventFilter::Log` in your `event_filter`
//! for i in 0..10 {
//! tracing::info!(number = i, my.key = "val", my.num = 42, "This is a log");
//! }
//! ```
//!
//! The fields of a `tracing` event are captured as attributes of the log.
//! Logs can be viewed and queried in the Logs explorer based on message and attributes.
//! Fields containing dots will be displayed as nested under their common prefix in the UI.
//!
//! # Tracking Errors
//!
//! The easiest way to emit errors is by logging an event with `ERROR` level. This will create a
//! grouped issue in Sentry. To add custom information, prepend the message with fields. It is also
//! possible to add Sentry tags if a field is prefixed with `"tags."`
//!
//! ```
//! tracing::error!(
//! field = "value", // will become a context field
//! tags.custom = "value", // will become a tag in Sentry
//! "this is an error with a custom tag",
//! );
//! ```
//!
//! To track [error structs](std::error::Error), assign a reference to error trait object as field
//! in one of the logging macros. By convention, it is recommended to use the `ERROR` level and
//! assign it to a field called `error`, although the integration will also work with all other
//! levels and field names.
//!
//! All other fields passed to the macro are captured in a custom "Tracing Fields" context in
//! Sentry.
//!
//! ```
//! use std::error::Error;
//! use std::io;
//!
//! let custom_error = io::Error::new(io::ErrorKind::Other, "oh no");
//! tracing::error!(error = &custom_error as &dyn Error);
//! ```
//!
//! It is also possible to combine error messages with error structs. In Sentry, this creates issues
//! grouped by the message and location of the error log, and adds the passed error as nested
//! source.
//!
//! ```
//! use std::error::Error;
//! use std::io;
//!
//! let custom_error = io::Error::new(io::ErrorKind::Other, "oh no");
//! tracing::error!(error = &custom_error as &dyn Error, "my operation failed");
//! ```
//!
//! # Sending multiple items to Sentry
//!
//! To map a `tracing` event to multiple items in Sentry, you can combine multiple event filters
//! using the bitwise or operator:
//!
//! ```
//! use sentry::integrations::tracing::EventFilter;
//! use tracing_subscriber::prelude::*;
//!
//! let sentry_layer = sentry::integrations::tracing::layer()
//! .event_filter(|md| match *md.level() {
//! tracing::Level::ERROR => EventFilter::Event | EventFilter::Log,
//! tracing::Level::TRACE => EventFilter::Ignore,
//! _ => EventFilter::Log,
//! })
//! .span_filter(|md| matches!(*md.level(), tracing::Level::ERROR | tracing::Level::WARN));
//!
//! tracing_subscriber::registry()
//! .with(tracing_subscriber::fmt::layer())
//! .with(sentry_layer)
//! .init();
//! ```
//!
//! If you're using a custom event mapper instead of an event filter, use `EventMapping::Combined`.
//!
//! # Tracing Spans
//!
//! The integration automatically tracks `tracing` spans as spans in Sentry. A convenient way to do
//! this is with the `#[instrument]` attribute macro, which creates a span/transaction for the function
//! in Sentry.
//!
//! Function arguments are added as context fields automatically, which can be configured through
//! attribute arguments. Refer to documentation of the macro for more information.
//!
//! ```
//! use std::time::Duration;
//!
//! use tracing_subscriber::prelude::*;
//!
//! // Functions instrumented by tracing automatically
//! // create spans/transactions around their execution.
//! #[tracing::instrument]
//! async fn outer() {
//! for i in 0..10 {
//! inner(i).await;
//! }
//! }
//!
//! // This creates spans inside the outer transaction, unless called directly.
//! #[tracing::instrument]
//! async fn inner(i: u32) {
//! // Also works, since log events are ingested by the tracing system
//! tracing::debug!(number = i, "Generates a breadcrumb");
//!
//! tokio::time::sleep(Duration::from_millis(100)).await;
//! }
//! ```
//!
//! By default, the name of the span sent to Sentry matches the name of the `tracing` span, which
//! is the name of the function when using `tracing::instrument`, or the name passed to the
//! `tracing::<level>_span` macros.
//!
//! By default, the `op` of the span sent to Sentry is `default`.
//!
//! ## Special Span Fields
//!
//! Some fields on spans are treated specially by the Sentry tracing integration:
//! - `sentry.name`: overrides the span name sent to Sentry.
//! This is useful to customize the span name when using `#[tracing::instrument]`, or to update
//! it retroactively (using `span.record`) after the span has been created.
//! - `sentry.op`: overrides the span `op` sent to Sentry.
//! - `sentry.trace`: in Sentry, the `sentry-trace` header is sent with HTTP requests to achieve distributed tracing.
//! If the value of this field is set to the value of a valid `sentry-trace` header, which
//! other Sentry SDKs send automatically with outgoing requests, then the SDK will continue the trace using the given distributed tracing information.
//! This is useful to achieve distributed tracing at service boundaries by using only the
//! `tracing` API.
//! Note that `sentry.trace` will only be effective on span creation (it cannot be applied retroactively)
//! and requires the span it's applied to to be a root span, i.e. no span should active upon its
//! creation.
//!
//!
//! Example:
//!
//! ```
//! #[tracing::instrument(skip_all, fields(
//! sentry.name = "GET /payments",
//! sentry.op = "http.server",
//! sentry.trace = headers.get("sentry-trace").unwrap_or(&"".to_owned()),
//! ))]
//! async fn handle_request(headers: std::collections::HashMap<String, String>) {
//! // ...
//! }
//! ```
pub use *;
pub use *;
const TAGS_PREFIX: &str = "tags.";
const SENTRY_OP_FIELD: &str = "sentry.op";
const SENTRY_NAME_FIELD: &str = "sentry.name";
const SENTRY_TRACE_FIELD: &str = "sentry.trace";