Skip to content

Commit 40107d5

Browse files
committed
feat: add span / transaction collection to sentry-tracing
1 parent 37fceed commit 40107d5

File tree

5 files changed

+466
-42
lines changed

5 files changed

+466
-42
lines changed

Diff for: sentry-core/src/client.rs

+11
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,17 @@ impl Client {
337337
random::<f32>() <= rate
338338
}
339339
}
340+
341+
/// Returns a random boolean with a probability defined
342+
/// by the [`ClientOptions`]'s `traces_sample_rate`
343+
pub fn sample_traces_should_send(&self) -> bool {
344+
let rate = self.options.traces_sample_rate;
345+
if rate >= 1.0 {
346+
true
347+
} else {
348+
random::<f32>() <= rate
349+
}
350+
}
340351
}
341352

342353
// Make this unwind safe. It's not out of the box because of the

Diff for: sentry-core/src/clientoptions.rs

+4
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ pub struct ClientOptions {
7272
pub environment: Option<Cow<'static, str>>,
7373
/// The sample rate for event submission. (0.0 - 1.0, defaults to 1.0)
7474
pub sample_rate: f32,
75+
/// The sample rate for tracing transactions. (0.0 - 1.0, defaults to 0.0)
76+
pub traces_sample_rate: f32,
7577
/// Maximum number of breadcrumbs. (defaults to 100)
7678
pub max_breadcrumbs: usize,
7779
/// Attaches stacktraces to messages.
@@ -179,6 +181,7 @@ impl fmt::Debug for ClientOptions {
179181
.field("release", &self.release)
180182
.field("environment", &self.environment)
181183
.field("sample_rate", &self.sample_rate)
184+
.field("traces_sample_rate", &self.traces_sample_rate)
182185
.field("max_breadcrumbs", &self.max_breadcrumbs)
183186
.field("attach_stacktrace", &self.attach_stacktrace)
184187
.field("send_default_pii", &self.send_default_pii)
@@ -210,6 +213,7 @@ impl Default for ClientOptions {
210213
release: None,
211214
environment: None,
212215
sample_rate: 1.0,
216+
traces_sample_rate: 0.0,
213217
max_breadcrumbs: 100,
214218
attach_stacktrace: false,
215219
send_default_pii: false,

Diff for: sentry-tracing/src/converters.rs

+66-9
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,15 @@
11
use std::collections::BTreeMap;
22

3-
use sentry_core::protocol::{Event, Value};
3+
use sentry_core::protocol::{self, Event, TraceContext, Value};
44
use sentry_core::{Breadcrumb, Level};
5-
use tracing_core::field::{Field, Visit};
5+
use tracing_core::{
6+
field::{Field, Visit},
7+
span, Subscriber,
8+
};
9+
use tracing_subscriber::layer::Context;
10+
use tracing_subscriber::registry::LookupSpan;
11+
12+
use crate::Trace;
613

714
/// Converts a [`tracing_core::Level`] to a Sentry [`Level`]
815
pub fn convert_tracing_level(level: &tracing_core::Level) -> Level {
@@ -15,7 +22,9 @@ pub fn convert_tracing_level(level: &tracing_core::Level) -> Level {
1522
}
1623

1724
/// Extracts the message and metadata from an event
18-
pub fn extract_data(event: &tracing_core::Event) -> (Option<String>, BTreeMap<String, Value>) {
25+
pub fn extract_event_data(
26+
event: &tracing_core::Event,
27+
) -> (Option<String>, BTreeMap<String, Value>) {
1928
// Find message of the event, if any
2029
let mut data = BTreeMapRecorder::default();
2130
event.record(&mut data);
@@ -28,6 +37,21 @@ pub fn extract_data(event: &tracing_core::Event) -> (Option<String>, BTreeMap<St
2837
(message, data.0)
2938
}
3039

40+
/// Extracts the message and metadata from a span
41+
pub fn extract_span_data(attrs: &span::Attributes) -> (Option<String>, BTreeMap<String, Value>) {
42+
let mut data = BTreeMapRecorder::default();
43+
attrs.record(&mut data);
44+
45+
// Find message of the span, if any
46+
let message = data
47+
.0
48+
.remove("message")
49+
.map(|v| v.as_str().map(|s| s.to_owned()))
50+
.flatten();
51+
52+
(message, data.0)
53+
}
54+
3155
#[derive(Default)]
3256
/// Records all fields of [`tracing_core::Event`] for easy access
3357
struct BTreeMapRecorder(pub BTreeMap<String, Value>);
@@ -58,7 +82,7 @@ impl Visit for BTreeMapRecorder {
5882

5983
/// Creates a [`Breadcrumb`] from a given [`tracing_core::Event`]
6084
pub fn breadcrumb_from_event(event: &tracing_core::Event) -> Breadcrumb {
61-
let (message, data) = extract_data(event);
85+
let (message, data) = extract_event_data(event);
6286
Breadcrumb {
6387
category: Some(event.metadata().target().to_owned()),
6488
ty: "log".into(),
@@ -70,22 +94,55 @@ pub fn breadcrumb_from_event(event: &tracing_core::Event) -> Breadcrumb {
7094
}
7195

7296
/// Creates an [`Event`] from a given [`tracing_core::Event`]
73-
pub fn event_from_event(event: &tracing_core::Event) -> Event<'static> {
74-
let (message, extra) = extract_data(event);
75-
Event {
97+
pub fn event_from_event<S>(event: &tracing_core::Event, ctx: Context<S>) -> Event<'static>
98+
where
99+
S: Subscriber + for<'a> LookupSpan<'a>,
100+
{
101+
let (message, extra) = extract_event_data(event);
102+
103+
let mut result = Event {
76104
logger: Some(event.metadata().target().to_owned()),
77105
level: convert_tracing_level(event.metadata().level()),
78106
message,
79107
extra,
80108
..Default::default()
109+
};
110+
111+
let parent = event
112+
.parent()
113+
.and_then(|id| ctx.span(id))
114+
.or_else(|| ctx.lookup_current());
115+
116+
if let Some(parent) = parent {
117+
let extensions = parent.extensions();
118+
if let Some(trace) = extensions.get::<Trace>() {
119+
let context = protocol::Context::from(TraceContext {
120+
span_id: trace.span.span_id,
121+
trace_id: trace.span.trace_id,
122+
..TraceContext::default()
123+
});
124+
125+
result.contexts.insert(context.type_name().into(), context);
126+
result.transaction = parent
127+
.parent()
128+
.into_iter()
129+
.flat_map(|span| span.scope())
130+
.last()
131+
.map(|root| root.name().into());
132+
}
81133
}
134+
135+
result
82136
}
83137

84138
/// Creates an exception [`Event`] from a given [`tracing_core::Event`]
85-
pub fn exception_from_event(event: &tracing_core::Event) -> Event<'static> {
139+
pub fn exception_from_event<S>(event: &tracing_core::Event, ctx: Context<S>) -> Event<'static>
140+
where
141+
S: Subscriber + for<'a> LookupSpan<'a>,
142+
{
86143
// TODO: Exception records in Sentry need a valid type, value and full stack trace to support
87144
// proper grouping and issue metadata generation. tracing_core::Record does not contain sufficient
88145
// information for this. However, it may contain a serialized error which we can parse to emit
89146
// an exception record.
90-
event_from_event(event)
147+
event_from_event(event, ctx)
91148
}

0 commit comments

Comments
 (0)