Skip to content

Commit

Permalink
feat(tracing): Transactions and Spans can carry Request data (#439)
Browse files Browse the repository at this point in the history
This allows request data to be included in Transactions and Spans, which means they can provide more meaningful information about the operation(s) represented by these structs.

Signed-off-by: Jess Frazelle <github@jessfraz.com>

Co-authored-by: Betty Da <bda@sentry.io>
  • Loading branch information
jessfraz and relaxolotl committed Mar 9, 2022
1 parent 0009a2d commit 72a31a0
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 2 deletions.
12 changes: 12 additions & 0 deletions CHANGELOG.md
@@ -1,5 +1,17 @@
# Changelog

## Unreleased

**Features**:

- Request data can now be attached to Transactions and Spans via `set_transaction`. ([#439](https://github.com/getsentry/sentry-rust/pull/439))

**Thank you**:

Features, fixes and improvements in this release have been contributed by:

- [@jessfraz](https://github.com/jessfraz)

## 0.25.0

**Breaking Changes**:
Expand Down
51 changes: 51 additions & 0 deletions sentry-core/src/performance.rs
Expand Up @@ -202,6 +202,14 @@ impl TransactionOrSpan {
}
}

/// Set the HTTP request information for this Transaction/Span.
pub fn set_request(&self, request: protocol::Request) {
match self {
TransactionOrSpan::Transaction(transaction) => transaction.set_request(request),
TransactionOrSpan::Span(span) => span.set_request(request),
}
}

/// Returns the headers needed for distributed tracing.
pub fn iter_headers(&self) -> TraceHeadersIter {
match self {
Expand Down Expand Up @@ -355,6 +363,14 @@ impl Transaction {
inner.context.status = Some(status);
}

/// Set the HTTP request information for this Transaction.
pub fn set_request(&self, request: protocol::Request) {
let mut inner = self.inner.lock().unwrap();
if let Some(transaction) = inner.transaction.as_mut() {
transaction.request = Some(request);
}
}

/// Returns the headers needed for distributed tracing.
pub fn iter_headers(&self) -> TraceHeadersIter {
let inner = self.inner.lock().unwrap();
Expand Down Expand Up @@ -454,6 +470,41 @@ impl Span {
span.status = Some(status);
}

/// Set the HTTP request information for this Span.
pub fn set_request(&self, request: protocol::Request) {
let mut span = self.span.lock().unwrap();
// Extract values from the request to be used as data in the span.
if let Some(method) = request.method {
span.data.insert("method".into(), method.into());
}
if let Some(url) = request.url {
span.data.insert("url".into(), url.to_string().into());
}
if let Some(data) = request.data {
if let Ok(data) = serde_json::from_str::<serde_json::Value>(&data) {
span.data.insert("data".into(), data);
} else {
span.data.insert("data".into(), data.into());
}
}
if let Some(query_string) = request.query_string {
span.data.insert("query_string".into(), query_string.into());
}
if let Some(cookies) = request.cookies {
span.data.insert("cookies".into(), cookies.into());
}
if !request.headers.is_empty() {
if let Ok(headers) = serde_json::to_value(request.headers) {
span.data.insert("headers".into(), headers);
}
}
if !request.env.is_empty() {
if let Ok(env) = serde_json::to_value(request.env) {
span.data.insert("env".into(), env);
}
}
}

/// Returns the headers needed for distributed tracing.
pub fn iter_headers(&self) -> TraceHeadersIter {
let span = self.span.lock().unwrap();
Expand Down
7 changes: 6 additions & 1 deletion sentry-types/src/protocol/v7.rs
Expand Up @@ -15,7 +15,7 @@ use std::ops;
use std::str;
use std::time::SystemTime;

use ::debugid::{CodeId, DebugId};
use self::debugid::{CodeId, DebugId};
use serde::Serializer;
use serde::{Deserialize, Serialize};
use thiserror::Error;
Expand Down Expand Up @@ -1942,6 +1942,9 @@ pub struct Transaction<'a> {
/// Optional contexts.
#[serde(default, skip_serializing_if = "Map::is_empty")]
pub contexts: Map<String, Context>,
/// Optionally HTTP request data to be sent along.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub request: Option<Request>,
}

impl<'a> Default for Transaction<'a> {
Expand All @@ -1959,6 +1962,7 @@ impl<'a> Default for Transaction<'a> {
start_timestamp: SystemTime::now(),
spans: Default::default(),
contexts: Default::default(),
request: Default::default(),
}
}
}
Expand All @@ -1984,6 +1988,7 @@ impl<'a> Transaction<'a> {
start_timestamp: self.start_timestamp,
spans: self.spans,
contexts: self.contexts,
request: self.request,
}
}

Expand Down
14 changes: 14 additions & 0 deletions sentry/examples/performance-demo.rs
@@ -1,6 +1,8 @@
use std::thread;
use std::time::Duration;

use sentry::protocol::Request;

// cargo run --example performance-demo
fn main() {
let _sentry = sentry::init(sentry::ClientOptions {
Expand All @@ -12,6 +14,12 @@ fn main() {

let transaction =
sentry::start_transaction(sentry::TransactionContext::new("transaction", "root span"));
let tx_request = Request {
url: Some("https://honk.beep".parse().unwrap()),
method: Some("GET".to_string()),
..Request::default()
};
transaction.set_request(tx_request);
sentry::configure_scope(|scope| scope.set_span(Some(transaction.clone().into())));

main_span1();
Expand Down Expand Up @@ -76,6 +84,12 @@ where
sentry::start_transaction(ctx).into()
}
};
let span_request = Request {
url: Some("https://beep.beep".parse().unwrap()),
method: Some("GET".to_string()),
..Request::default()
};
span1.set_request(span_request);
sentry::configure_scope(|scope| scope.set_span(Some(span1.clone())));

let rv = f();
Expand Down
10 changes: 9 additions & 1 deletion sentry/tests/test_tracing.rs
@@ -1,7 +1,7 @@
#![cfg(feature = "test")]

use log_ as log;
use sentry::protocol::{Context, Value};
use sentry::protocol::{Context, Request, Value};
use tracing_ as tracing;
use tracing_subscriber::prelude::*;

Expand Down Expand Up @@ -146,6 +146,13 @@ fn test_set_transaction() {
|| {
let ctx = sentry::TransactionContext::new("old name", "ye, whatever");
let trx = sentry::start_transaction(ctx);
let request = Request {
url: Some("https://honk.beep".parse().unwrap()),
method: Some("GET".to_string()),
..Request::default()
};
trx.set_request(request);

sentry::configure_scope(|scope| scope.set_span(Some(trx.clone().into())));

sentry::configure_scope(|scope| scope.set_transaction(Some("new name")));
Expand All @@ -164,4 +171,5 @@ fn test_set_transaction() {
};

assert_eq!(transaction.name.as_deref().unwrap(), "new name");
assert!(transaction.request.is_some());
}

0 comments on commit 72a31a0

Please sign in to comment.