-
Notifications
You must be signed in to change notification settings - Fork 94
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(profiles): Emit "accepted" outcomes for profiles filtered by sampling #2054
Changes from all commits
eb990ae
186fbde
85607c8
959446d
ea765b6
9572e48
5730320
3b30ad3
d11c6e3
9bf35d6
8ab5975
66bb6b9
3b36552
a301458
bdae22e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1070,6 +1070,54 @@ impl EnvelopeProcessorService { | |
}) | ||
} | ||
|
||
/// Count the number of profiles that are in the envelope and emit accepted outcome. | ||
/// | ||
/// "processed" profiles are an abstract data category that does not represent actual data | ||
/// going through our pipeline. Instead, the number of accepted "processed" profiles is counted as | ||
/// | ||
/// ```text | ||
/// processed_profiles = indexed_profiles + sampled_profiles | ||
/// ``` | ||
/// | ||
/// The "processed" outcome for sampled profiles is generated by the Kafka producer | ||
/// (see `transform_outcome` in [`crate::actors::store`]), but for "indexed" profiles, we count | ||
/// the corresponding number of processed profiles here. | ||
/// | ||
/// NOTE: Instead of emitting a [processed](`DataCategory::Profile`) outcome here, | ||
/// we could also do it in sentry, in the same place where the [indexed](`DataCategory::ProfileIndexed`) | ||
/// outcome is logged. We do it here to be consistent with profiles that are dropped by dynamic sampling, | ||
/// which also count as "processed" even though they did not pass through the `process_profiles` step yet. | ||
/// | ||
/// | ||
/// In the future, we might actually extract metrics from profiles before dynamic sampling, | ||
/// like we do for transactions. At that point, this code should be removed, and we should | ||
/// enforce rate limits and emit outcomes based on the collect profile metric, as we do for | ||
/// transactions. | ||
#[cfg(feature = "processing")] | ||
fn count_processed_profiles(&self, state: &mut ProcessEnvelopeState) { | ||
let profile_count: usize = state | ||
.managed_envelope | ||
.envelope() | ||
.items() | ||
.filter(|item| item.ty() == &ItemType::Profile) | ||
.map(|item| item.quantity()) | ||
.sum(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Technically, the SDKs will only send 1 profile per envelope. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Makes sense, but Relay does not enforce that AFAIK, so its safer to handle the case where there's multiple profiles. |
||
|
||
if profile_count == 0 { | ||
return; | ||
} | ||
|
||
self.outcome_aggregator.send(TrackOutcome { | ||
timestamp: state.managed_envelope.received_at(), | ||
scoping: state.managed_envelope.scoping(), | ||
outcome: Outcome::Accepted, | ||
event_id: None, | ||
remote_addr: None, | ||
category: DataCategory::Profile, | ||
quantity: profile_count as u32, // truncates to `u32::MAX` | ||
}) | ||
} | ||
|
||
/// Process profiles and set the profile ID in the profile context on the transaction if successful | ||
#[cfg(feature = "processing")] | ||
fn process_profiles(&self, state: &mut ProcessEnvelopeState) { | ||
|
@@ -2245,6 +2293,9 @@ impl EnvelopeProcessorService { | |
self.process_replays(state)?; | ||
self.filter_profiles(state); | ||
|
||
// After filtering, we need to update the envelope summary: | ||
state.managed_envelope.update(); | ||
|
||
if state.creates_event() { | ||
// Some envelopes only create events in processing relays; for example, unreal events. | ||
// This makes it possible to get in this code block while not really having an event in | ||
|
@@ -2276,6 +2327,11 @@ impl EnvelopeProcessorService { | |
|
||
if_processing!({ | ||
self.enforce_quotas(state)?; | ||
// Any profile that reaches this point counts as "processed", regardless of whether | ||
// they survive the actual `process_profiles` step. This is to be consistent with | ||
// profiles that are dropped by dynamic sampling, which also count as "processed" | ||
// even though they did not pass through the `process_profiles` step yet. | ||
self.count_processed_profiles(state); | ||
// We need the event parsed in order to set the profile context on it | ||
self.process_profiles(state); | ||
self.process_check_ins(state); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The sentence ends here kind of leaving you hanging at the end.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!