Skip to content

Commit

Permalink
feat: Basic attachment support (#466)
Browse files Browse the repository at this point in the history
  • Loading branch information
timfish committed May 25, 2022
1 parent 6e777c2 commit 995a0a8
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 4 deletions.
7 changes: 7 additions & 0 deletions sentry-core/src/client.rs
Expand Up @@ -278,6 +278,13 @@ impl Client {
envelope.add_item(session_item);
}
}

if let Some(scope) = scope {
for attachment in scope.attachments.iter().cloned() {
envelope.add_item(attachment);
}
}

transport.send_envelope(envelope);
return event_id;
}
Expand Down
13 changes: 12 additions & 1 deletion sentry-core/src/scope/real.rs
Expand Up @@ -4,7 +4,7 @@ use std::fmt;
use std::sync::{Arc, Mutex, PoisonError, RwLock};

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

Expand Down Expand Up @@ -46,6 +46,7 @@ pub struct Scope {
pub(crate) event_processors: Arc<Vec<EventProcessor>>,
pub(crate) session: Arc<Mutex<Option<Session>>>,
pub(crate) span: Arc<Option<TransactionOrSpan>>,
pub(crate) attachments: Arc<Vec<Attachment>>,
}

impl fmt::Debug for Scope {
Expand Down Expand Up @@ -218,6 +219,16 @@ impl Scope {
Arc::make_mut(&mut self.event_processors).push(Arc::new(f));
}

/// Adds an attachment to the scope
pub fn add_attachment(&mut self, attachment: Attachment) {
Arc::make_mut(&mut self.attachments).push(attachment);
}

/// Clears attachments from the scope
pub fn clear_attachments(&mut self) {
Arc::make_mut(&mut self.attachments).clear();
}

/// Applies the contained scoped data to fill an event.
pub fn apply_to_event(&self, mut event: Event<'static>) -> Option<Event<'static>> {
// TODO: event really should have an optional level
Expand Down
13 changes: 10 additions & 3 deletions sentry-types/src/protocol/attachment.rs
Expand Up @@ -37,13 +37,15 @@ impl AttachmentType {
}
}

#[derive(Clone, PartialEq)]
#[derive(Clone, PartialEq, Default)]
/// Represents an attachment item.
pub struct Attachment {
/// The actual attachment data.
pub buffer: Vec<u8>,
/// The filename of the attachment.
pub filename: String,
/// The Content Type of the attachment
pub content_type: Option<String>,
/// The special type of this attachment.
pub ty: Option<AttachmentType>,
}
Expand All @@ -56,10 +58,14 @@ impl Attachment {
{
writeln!(
writer,
r#"{{"type":"attachment","length":{length},"filename":"{filename}","attachment_type":"{at}"}}"#,
r#"{{"type":"attachment","length":{length},"filename":"{filename}","attachment_type":"{at}","content_type":"{ct}"}}"#,
filename = self.filename,
length = self.buffer.len(),
at = self.ty.unwrap_or_default().as_str()
at = self.ty.unwrap_or_default().as_str(),
ct = self
.content_type
.as_ref()
.unwrap_or(&"application/octet-stream".to_string())
)?;

writer.write_all(&self.buffer)?;
Expand All @@ -74,6 +80,7 @@ impl fmt::Debug for Attachment {
f.debug_struct("Attachment")
.field("buffer", &self.buffer.len())
.field("filename", &self.filename)
.field("content_type", &self.content_type)
.field("type", &self.ty)
.finish()
}
Expand Down
34 changes: 34 additions & 0 deletions sentry-types/src/protocol/envelope.rs
Expand Up @@ -65,6 +65,12 @@ impl From<Transaction<'static>> for EnvelopeItem {
}
}

impl From<Attachment> for EnvelopeItem {
fn from(attachment: Attachment) -> Self {
EnvelopeItem::Attachment(attachment)
}
}

/// An Iterator over the items of an Envelope.
#[derive(Clone)]
pub struct EnvelopeItemIter<'s> {
Expand Down Expand Up @@ -352,6 +358,34 @@ mod test {
r#"{"event_id":"22d00b3f-d1b1-4b5d-8d20-49d138cd8a9c"}
{"type":"transaction","length":200}
{"event_id":"22d00b3fd1b14b5d8d2049d138cd8a9c","start_timestamp":1595256674.296,"spans":[{"span_id":"d42cee9fc3e74f5c","trace_id":"335e53d614474acc9f89e632b776cc28","start_timestamp":1595256674.296}]}
"#
)
}

#[test]
fn test_event_with_attachment() {
let event_id = Uuid::parse_str("22d00b3f-d1b1-4b5d-8d20-49d138cd8a9c").unwrap();
let timestamp = timestamp("2020-07-20T14:51:14.296Z");
let event = Event {
event_id,
timestamp,
..Default::default()
};
let mut envelope: Envelope = event.into();

envelope.add_item(Attachment {
buffer: "some content".as_bytes().to_vec(),
filename: "file.txt".to_string(),
..Default::default()
});

assert_eq!(
to_str(envelope),
r#"{"event_id":"22d00b3f-d1b1-4b5d-8d20-49d138cd8a9c"}
{"type":"event","length":74}
{"event_id":"22d00b3fd1b14b5d8d2049d138cd8a9c","timestamp":1595256674.296}
{"type":"attachment","length":12,"filename":"file.txt","attachment_type":"event.attachment","content_type":"application/octet-stream"}
some content
"#
)
}
Expand Down
28 changes: 28 additions & 0 deletions sentry/tests/test_basic.rs
Expand Up @@ -3,6 +3,7 @@
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;

use sentry::protocol::{Attachment, EnvelopeItem};
use sentry::types::Uuid;

#[test]
Expand Down Expand Up @@ -173,3 +174,30 @@ fn test_attached_stacktrace() {
.flat_map(|ev| ev.threads.into_iter().filter_map(|thrd| thrd.stacktrace));
assert_eq!(stacktraces.count(), 3);
}

#[test]
fn test_attachment_sent_from_scope() {
let envelopes = sentry::test::with_captured_envelopes(|| {
sentry::with_scope(
|scope| {
scope.add_attachment(Attachment {
buffer: vec![1, 2, 3, 4, 5, 6, 7, 8, 9],
filename: "test-file.bin".to_string(),
..Default::default()
})
},
|| sentry::capture_message("test", sentry::Level::Error),
);
});

assert_eq!(envelopes.len(), 1);

let items = envelopes[0].items().collect::<Vec<_>>();

assert_eq!(items.len(), 2);
assert!(matches!(items[1],
EnvelopeItem::Attachment(attachment)
if attachment.filename == *"test-file.bin"
&& attachment.buffer == vec![1, 2, 3, 4, 5, 6, 7, 8, 9]
));
}

0 comments on commit 995a0a8

Please sign in to comment.