diff --git a/sentry-core/src/performance.rs b/sentry-core/src/performance.rs index 44fa9597..64758101 100644 --- a/sentry-core/src/performance.rs +++ b/sentry-core/src/performance.rs @@ -8,6 +8,12 @@ const MAX_SPANS: usize = 1_000; // global API: +/// Start a new Performance Monitoring Transaction. +/// +/// The transaction needs to be explicitly finished via [`Transaction::finish`], +/// otherwise it will be discarded. +/// The transaction itself also represents the root span in the span hierarchy. +/// Child spans can be started with the [`Transaction::start_child`] method. pub fn start_transaction(ctx: TransactionContext) -> Transaction { let client = Hub::with_active(|hub| hub.client()); Transaction::new(client, ctx) @@ -16,6 +22,9 @@ pub fn start_transaction(ctx: TransactionContext) -> Transaction { // Hub API: impl Hub { + /// Start a new Performance Monitoring Transaction. + /// + /// See the global [`start_transaction`] for more documentation. pub fn start_transaction(&self, ctx: TransactionContext) -> Transaction { Transaction::new(self.client(), ctx) } @@ -23,6 +32,10 @@ impl Hub { // "Context" Types: +/// The Transaction Context used to start a new Performance Monitoring Transaction. +/// +/// The Transaction Context defines the metadata for a Performance Monitoring +/// Transaction, and also the connection point for distributed tracing. #[derive(Debug)] pub struct TransactionContext { name: String, @@ -32,11 +45,24 @@ pub struct TransactionContext { } impl TransactionContext { + /// Creates a new Transaction Context with the given `name` and `op`. + /// + /// See + /// for an explanation of a Transaction's `name`, and + /// for conventions + /// around an `operation`'s value. + /// + /// See also the [`TransactionContext::continue_from_headers`] function that + /// can be used for distributed tracing. #[must_use = "this must be used with `start_transaction`"] pub fn new(name: &str, op: &str) -> Self { Self::continue_from_headers(name, op, []) } + /// Creates a new Transaction Context based on the distributed tracing `headers`. + /// + /// The `headers` in particular need to include the `sentry-trace` header, + /// which is used to associate the transaction with a distributed trace. #[must_use = "this must be used with `start_transaction`"] pub fn continue_from_headers<'a, I: IntoIterator>( name: &str, @@ -62,13 +88,18 @@ impl TransactionContext { parent_span_id, } } + + // TODO: `sampled` flag } // global API types: +/// A wrapper that groups a [`Transaction`] and a [`Span`] together. #[derive(Clone, Debug)] pub enum TransactionOrSpan { + /// A [`Transaction`]. Transaction(Transaction), + /// A [`Span`]. Span(Span), } @@ -85,6 +116,7 @@ impl From for TransactionOrSpan { } impl TransactionOrSpan { + /// Returns the headers needed for distributed tracing. pub fn iter_headers(&self) -> TraceHeadersIter { match self { TransactionOrSpan::Transaction(transaction) => transaction.iter_headers(), @@ -92,11 +124,15 @@ impl TransactionOrSpan { } } + /// Starts a new child Span with the given `op` and `description`. + /// + /// The span must be explicitly finished via [`Span::finish`], as it will + /// otherwise not be sent to Sentry. #[must_use = "a span must be explicitly closed via `finish()`"] - pub fn start_child(&self, op: &str) -> Span { + pub fn start_child(&self, op: &str, description: &str) -> Span { match self { - TransactionOrSpan::Transaction(transaction) => transaction.start_child(op), - TransactionOrSpan::Span(span) => span.start_child(op), + TransactionOrSpan::Transaction(transaction) => transaction.start_child(op, description), + TransactionOrSpan::Span(span) => span.start_child(op, description), } } @@ -128,6 +164,11 @@ struct TransactionInner { type TransactionArc = Arc>; +/// A running Performance Monitoring Transaction. +/// +/// The transaction needs to be explicitly finished via [`Transaction::finish`], +/// otherwise neither the transaction nor any of its child spans will be sent +/// to Sentry. #[derive(Clone, Debug)] pub struct Transaction { inner: TransactionArc, @@ -160,6 +201,7 @@ impl Transaction { } } + /// Returns the headers needed for distributed tracing. pub fn iter_headers(&self) -> TraceHeadersIter { let inner = self.inner.lock().unwrap(); let trace = SentryTrace(inner.context.trace_id, inner.context.span_id, None); @@ -168,6 +210,10 @@ impl Transaction { } } + /// Finishes the Transaction. + /// + /// This records the end timestamp and sends the transaction together with + /// all finished child spans to Sentry. pub fn finish(self) { let mut inner = self.inner.lock().unwrap(); if let Some(mut transaction) = inner.transaction.take() { @@ -185,13 +231,17 @@ impl Transaction { } } + /// Starts a new child Span with the given `op` and `description`. + /// + /// The span must be explicitly finished via [`Span::finish`]. #[must_use = "a span must be explicitly closed via `finish()`"] - pub fn start_child(&self, op: &str) -> Span { + pub fn start_child(&self, op: &str, description: &str) -> Span { let inner = self.inner.lock().unwrap(); let span = protocol::Span { trace_id: inner.context.trace_id, parent_span_id: Some(inner.context.span_id), op: Some(op.into()), + description: Some(description.into()), ..Default::default() }; Span { @@ -201,6 +251,10 @@ impl Transaction { } } +/// A running Performance Monitoring Span. +/// +/// The span needs to be explicitly finished via [`Span::finish`], otherwise it +/// will not be sent to Sentry. #[derive(Clone, Debug)] pub struct Span { transaction: TransactionArc, @@ -208,6 +262,7 @@ pub struct Span { } impl Span { + /// Returns the headers needed for distributed tracing. pub fn iter_headers(&self) -> TraceHeadersIter { let trace = SentryTrace(self.span.trace_id, self.span.span_id, None); TraceHeadersIter { @@ -215,6 +270,10 @@ impl Span { } } + /// Finishes the Span. + /// + /// This will record the end timestamp and add the span to the transaction + /// in which it was started. pub fn finish(mut self) { self.span.finish(); let mut inner = self.transaction.lock().unwrap(); @@ -225,12 +284,16 @@ impl Span { } } + /// Starts a new child Span with the given `op` and `description`. + /// + /// The span must be explicitly finished via [`Span::finish`]. #[must_use = "a span must be explicitly closed via `finish()`"] - pub fn start_child(&self, op: &str) -> Span { + pub fn start_child(&self, op: &str, description: &str) -> Span { let span = protocol::Span { trace_id: self.span.trace_id, parent_span_id: Some(self.span.span_id), op: Some(op.into()), + description: Some(description.into()), ..Default::default() }; Span { @@ -240,6 +303,10 @@ impl Span { } } +/// An Iterator over HTTP header names and values needed for distributed tracing. +/// +/// This currently only yields the `sentry-trace` header, but other headers +/// may be added in the future. pub struct TraceHeadersIter { sentry_trace: Option, }