Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions sentry-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ test = ["client"]

[dependencies]
sentry-types = { version = "0.19.1", path = "../sentry-types" }
serde = { version = "1.0.104", features = ["derive"] }
lazy_static = "1.4.0"
im = { version = "14.2.0", optional = true }
rand = { version = "0.7.3", optional = true }
Expand Down
24 changes: 24 additions & 0 deletions sentry-core/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -261,3 +261,27 @@ pub fn last_event_id() -> Option<Uuid> {
Hub::with(|hub| hub.last_event_id())
}}
}

/// Start a new session for Release Health.
///
/// This is still **experimental** for the moment and is not recommended to be
/// used with a very high volume of sessions (_request-mode_ sessions).
///
/// # Examples
///
/// ```
/// sentry::start_session();
///
/// // capturing any event / error here will update the sessions `errors` count,
/// // up until we call `sentry::end_session`.
///
/// sentry::end_session();
/// ```
pub fn start_session() {
Hub::with_active(|hub| hub.start_session())
}

/// End the current Release Health Session.
pub fn end_session() {
Hub::with_active(|hub| hub.end_session())
}
36 changes: 30 additions & 6 deletions sentry-core/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use rand::random;
use crate::constants::SDK_INFO;
use crate::protocol::{ClientSdkInfo, Event};
use crate::types::{Dsn, Uuid};
use crate::{ClientOptions, Hub, Integration, Scope, Transport};
use crate::{ClientOptions, Envelope, Hub, Integration, Scope, Transport};

impl<T: Into<ClientOptions>> From<T> for Client {
fn from(o: T) -> Client {
Expand Down Expand Up @@ -142,6 +142,14 @@ impl Client {
mut event: Event<'static>,
scope: Option<&Scope>,
) -> Option<Event<'static>> {
if let Some(scope) = scope {
scope.update_session_from_event(&event);
}

if !self.sample_should_send() {
return None;
}

// event_id and sdk_info are set before the processors run so that the
// processors can poke around in that data.
if event.event_id.is_nil() {
Expand Down Expand Up @@ -236,17 +244,33 @@ impl Client {
/// Captures an event and sends it to sentry.
pub fn capture_event(&self, event: Event<'static>, scope: Option<&Scope>) -> Uuid {
if let Some(ref transport) = *self.transport.read().unwrap() {
if self.sample_should_send() {
if let Some(event) = self.prepare_event(event, scope) {
let event_id = event.event_id;
transport.send_envelope(event.into());
return event_id;
if let Some(event) = self.prepare_event(event, scope) {
let event_id = event.event_id;
let mut envelope: Envelope = event.into();
let session_item = scope.and_then(|scope| {
scope
.session
.lock()
.unwrap()
.as_mut()
.and_then(|session| session.create_envelope_item())
});
if let Some(session_item) = session_item {
envelope.add(session_item);
}
transport.send_envelope(envelope);
return event_id;
}
}
Default::default()
}

pub(crate) fn capture_envelope(&self, envelope: Envelope) {
if let Some(ref transport) = *self.transport.read().unwrap() {
transport.send_envelope(envelope);
}
}

/// Drains all pending events and shuts down the transport behind the
/// client. After shutting down the transport is removed.
///
Expand Down
8 changes: 8 additions & 0 deletions sentry-core/src/clientoptions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,12 @@ pub struct ClientOptions {
/// The timeout on client drop for draining events on shutdown.
pub shutdown_timeout: Duration,
// Other options not documented in Unified API
/// Enable Release Health Session tracking.
///
/// When automatic session tracking is enabled, a new "user-mode" session
/// is started at the time of `sentry::init`, and will persist for the
/// application lifetime.
pub auto_session_tracking: bool,
/// Border frames which indicate a border from a backtrace to
/// useless internals. Some are automatically included.
pub extra_border_frames: Vec<&'static str>,
Expand Down Expand Up @@ -147,6 +153,7 @@ impl fmt::Debug for ClientOptions {
.field("http_proxy", &self.http_proxy)
.field("https_proxy", &self.https_proxy)
.field("shutdown_timeout", &self.shutdown_timeout)
.field("auto_session_tracking", &self.auto_session_tracking)
.field("extra_border_frames", &self.extra_border_frames)
.field("trim_backtraces", &self.trim_backtraces)
.field("user_agent", &self.user_agent)
Expand Down Expand Up @@ -176,6 +183,7 @@ impl Default for ClientOptions {
http_proxy: None,
https_proxy: None,
shutdown_timeout: Duration::from_secs(2),
auto_session_tracking: false,
extra_border_frames: vec![],
trim_backtraces: true,
user_agent: Cow::Borrowed(&USER_AGENT),
Expand Down
31 changes: 19 additions & 12 deletions sentry-core/src/envelope.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
use std::io::Write;

use crate::protocol::Event;
use crate::session::Session;
use crate::types::Uuid;

#[derive(Clone, Debug, PartialEq)]
#[derive(Clone, Debug)]
#[non_exhaustive]
enum EnvelopeItem {
pub(crate) enum EnvelopeItem {
Event(Event<'static>),
Session(Session),
// TODO:
// * Session,
// * Attachment,
// etc…
}
Expand All @@ -27,7 +28,7 @@ impl From<Event<'static>> for EnvelopeItem {
///
/// See the [documentation on Envelopes](https://develop.sentry.dev/sdk/envelopes/)
/// for more details.
#[derive(Clone, Default, Debug, PartialEq)]
#[derive(Clone, Default, Debug)]
pub struct Envelope {
event_id: Option<Uuid>,
items: Vec<EnvelopeItem>,
Expand All @@ -39,6 +40,13 @@ impl Envelope {
Default::default()
}

pub(crate) fn add<I>(&mut self, item: I)
where
I: Into<EnvelopeItem>,
{
self.items.push(item.into());
}

/// Returns the Envelopes Uuid, if any.
pub fn uuid(&self) -> Option<&Uuid> {
self.event_id.as_ref()
Expand All @@ -48,12 +56,11 @@ impl Envelope {
///
/// [`Event`]: protocol/struct.Event.html
pub fn event(&self) -> Option<&Event<'static>> {
// until we actually add more items:
#[allow(clippy::unnecessary_filter_map)]
self.items
.iter()
.filter_map(|item| match item {
EnvelopeItem::Event(event) => Some(event),
_ => None,
})
.next()
}
Expand All @@ -77,14 +84,13 @@ impl Envelope {
// write each item:
for item in &self.items {
// we write them to a temporary buffer first, since we need their length
serde_json::to_writer(
&mut item_buf,
match item {
EnvelopeItem::Event(event) => event,
},
)?;
match item {
EnvelopeItem::Event(event) => serde_json::to_writer(&mut item_buf, event)?,
EnvelopeItem::Session(session) => serde_json::to_writer(&mut item_buf, session)?,
}
let item_type = match item {
EnvelopeItem::Event(_) => "event",
EnvelopeItem::Session(_) => "session",
};
writeln!(
writer,
Expand Down Expand Up @@ -113,6 +119,7 @@ impl From<Event<'static>> for Envelope {
#[cfg(test)]
mod test {
use super::*;

fn to_buf(envelope: Envelope) -> Vec<u8> {
let mut vec = Vec::new();
envelope.to_writer(&mut vec).unwrap();
Expand Down
43 changes: 42 additions & 1 deletion sentry-core/src/hub.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@ use std::thread;
use std::time::Duration;

use crate::protocol::{Breadcrumb, Event, Level};
use crate::session::{Session, SessionStatus};
use crate::types::Uuid;
use crate::{event_from_error, Integration, IntoBreadcrumbs, Scope, ScopeGuard};
#[cfg(feature = "client")]
use crate::{scope::Stack, Client};
use crate::{scope::Stack, Client, Envelope};

#[cfg(feature = "client")]
lazy_static::lazy_static! {
Expand Down Expand Up @@ -311,6 +312,46 @@ impl Hub {
})
}

/// Start a new session for Release Health.
///
/// See the global [`start_session`](fn.start_session.html)
/// for more documentation.
pub fn start_session(&self) {
with_client_impl! {{
self.inner.with_mut(|stack| {
let top = stack.top_mut();
if let Some(session) = Session::from_stack(top) {
// When creating a *new* session, we make sure it is unique,
// as to no inherit *backwards* to any parents.
let mut scope = Arc::make_mut(&mut top.scope);
scope.session = Arc::new(Mutex::new(Some(session)));
}
})
}}
}

/// End the current Release Health Session.
///
/// See the global [`end_session`](fn.end_session.html)
/// for more documentation.
pub fn end_session(&self) {
with_client_impl! {{
self.inner.with_mut(|stack| {
let top = stack.top_mut();
if let Some(mut session) = top.scope.session.lock().unwrap().take() {
session.close();
if let Some(item) = session.create_envelope_item() {
let mut envelope = Envelope::new();
envelope.add(item);
if let Some(ref client) = top.client {
client.capture_envelope(envelope);
}
}
}
})
}}
}

/// Pushes a new scope.
///
/// This returns a guard that when dropped will pop the scope again.
Expand Down
1 change: 1 addition & 0 deletions sentry-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ mod hub;
mod integration;
mod intodsn;
mod scope;
mod session;
mod transport;

// public api or exports from this crate
Expand Down
14 changes: 7 additions & 7 deletions sentry-core/src/scope/noop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,6 @@ use std::fmt;

use crate::protocol::{Context, Event, Level, User, Value};

/// The minimal scope.
///
/// In minimal API mode all modification functions are available as normally
/// just that generally calling them is impossible.
#[derive(Debug, Clone)]
pub struct Scope;

/// A minimal API scope guard.
///
/// Doesn't do anything but can be debug formatted.
Expand All @@ -21,6 +14,13 @@ impl fmt::Debug for ScopeGuard {
}
}

/// The minimal scope.
///
/// In minimal API mode all modification functions are available as normally
/// just that generally calling them is impossible.
#[derive(Debug, Clone)]
pub struct Scope;

impl Scope {
/// Clear the scope.
///
Expand Down
16 changes: 13 additions & 3 deletions sentry-core/src/scope/real.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use std::borrow::Cow;
use std::fmt;
use std::sync::{Arc, PoisonError, RwLock};
use std::sync::{Arc, Mutex, PoisonError, RwLock};

use crate::protocol::{Breadcrumb, Context, Event, Level, User, Value};
use crate::session::Session;
use crate::Client;

#[derive(Debug)]
Expand Down Expand Up @@ -41,6 +42,7 @@ pub struct Scope {
pub(crate) tags: im::HashMap<String, String>,
pub(crate) contexts: im::HashMap<String, Context>,
pub(crate) event_processors: im::Vector<Arc<EventProcessor>>,
pub(crate) session: Arc<Mutex<Option<Session>>>,
}

impl fmt::Debug for Scope {
Expand All @@ -55,6 +57,7 @@ impl fmt::Debug for Scope {
.field("tags", &self.tags)
.field("contexts", &self.contexts)
.field("event_processors", &self.event_processors.len())
.field("session", &self.session)
.finish()
}
}
Expand All @@ -71,6 +74,7 @@ impl Default for Scope {
tags: Default::default(),
contexts: Default::default(),
event_processors: Default::default(),
session: Default::default(),
}
}
}
Expand All @@ -89,8 +93,8 @@ impl Stack {
}

pub fn push(&mut self) {
let scope = self.layers[self.layers.len() - 1].clone();
self.layers.push(scope);
let layer = self.layers[self.layers.len() - 1].clone();
self.layers.push(layer);
}

pub fn pop(&mut self) {
Expand Down Expand Up @@ -257,4 +261,10 @@ impl Scope {

Some(event)
}

pub(crate) fn update_session_from_event(&self, event: &Event<'static>) {
if let Some(session) = self.session.lock().unwrap().as_mut() {
session.update_from_event(event);
}
}
}
Loading