getsentry/sentry-rust

Make Event to be not 'static

tomocrafter opened this issue · 2 comments

I want to customize the Event with before_send callback and adding the fingerprint that getting from event.contexts.
but since Event is Event<'static> so it needs static lifetime, therefore adding dynamic string to fingerprint is not straightforward (by using Box::leak, we can make string to be 'static lifetime but as name suggests, it causes memory leak).

event.request = Some(sentry::protocol::Request {

            before_send: Some(Arc::new(|mut event| {
                let tracing_fields = event.contexts.get("Rust Tracing Fields");
                if let Some(Context::Other(fields)) = tracing_fields {
                    let fingerprint = fields.get("fingerprint");
                    if let Some(Value::String(fingerprint)) = fingerprint {
                        event.fingerprint = Cow::Borrowed(&[
                            Cow::Borrowed("{{ default }}"),
                            Cow::Borrowed(&fingerprint), // <-- Here, fingerprint is not 'static, therefore error occurs.
                        ])
                    }
                }
                Some(event)
            })),

I would like to have Event as not 'static, and allow me to modify it dynamically.
Thank you.

Hi! All the references with lifetime 'a in Event are behind Cow smart pointers. For example, fingerprint has the type Cow<'a, [Cow<'a, str>]>. In case you're not familiar, a Cow<'a, T> is either a reference &'a T or the "owned form" of T. For example, a Cow<'a, str> is either a &'a str or a String. You can always get a Cow<'static, T> by using the owned form of T. For fingerprint, that means using Vec and String.

Here is a small example on the Rust playground that shows how it works: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=e9a894986b86e0d2a2540f96b1142718

Please let me know if that resolves your issue.

Edited to add: Here is your example snippet with my suggestion applied:

            before_send: Some(Arc::new(|mut event| {
                let tracing_fields = event.contexts.get("Rust Tracing Fields");
                if let Some(Context::Other(fields)) = tracing_fields {
                    let fingerprint = fields.get("fingerprint");
                    if let Some(Value::String(fingerprint)) = fingerprint {
                        event.fingerprint = Cow::Owned(vec![ // <-- This needs to be Owned because it's dynamic
                            Cow::Borrowed("{{ default }}"), // <-- This can be Borrowed because it's hardcoded
                            Cow::Owned(fingerprint.clone()), // <-- This needs to be Owned because it's dynamic
                        ])
                    }
                }
                Some(event)
            })),

Wow, I misunderstood Cow smart pointer. Your suggestion compiled and worked as expected!
Thank you!