-
Notifications
You must be signed in to change notification settings - Fork 103
ref(processing): Use new transactions processor #5379
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
base: master
Are you sure you want to change the base?
Conversation
| pub struct ExpandedTransaction<C> { | ||
| headers: EnvelopeHeaders, | ||
| transaction: T, // might be empty | ||
| event: Annotated<Event>, |
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.
I changed this from a wrapper type that implements Counted to a phantom-data-style field, for three reasons:
- Quantities for the wrapper type could not be inferred correctly because we need to check
flags.spans_extractedto get the quantities. - Consistency with the spans processor.
- Simpler code.
| } else if work.transaction.0.value().is_none() && profile_item.sampled() { | ||
| // A profile with `sampled=true` should never be without a transaction | ||
| record_keeper.reject_err( | ||
| Outcome::Invalid(DiscardReason::Profiling("missing_transaction")), | ||
| work.profile.take(), | ||
| ); |
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.
This is leftover code, there is always a transaction.
| {"reason": "release-version", "category": "span", "quantity": 2}, | ||
| {"reason": "release-version", "category": "span_indexed", "quantity": 2}, |
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.
This now counts quantities correctly when the transaction is filtered.
| }, | ||
| "blacklistedIps": ["127.43.33.22"], | ||
| "trustedRelays": [], | ||
| "transactionMetrics": {"version": 3}, |
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.
This is now a requirement, otherwise debug assertions will fail.
| (DataCategory.TRANSACTION, 1, "invalid_transaction"), | ||
| (DataCategory.TRANSACTION_INDEXED, 1, "invalid_transaction"), | ||
| (DataCategory.SPAN, 1, "invalid_span"), | ||
| (DataCategory.SPAN, 2, "invalid_transaction"), |
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.
This now counts embedded spans correctly.
| metrics_extracted, | ||
| spans_extracted, | ||
| } = ctx; | ||
| // TODO(follow-up): this function should always extract metrics. Dynamic sampling should validate |
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.
Wanna link to a GH issue here?
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.
Done: #5403
| #[cfg(debug_assertions)] | ||
| event.ensure_span_count(); |
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.
Doesn't that mess with the Managed assertions and we may get misaccounting in prod, but not in tests because this is ran in tests but not in production?
Or is this there to specifically defuse these Managed assertions and it's okay if we misaccount in prod until the transaction is parsed?
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.
Or is this there to specifically defuse these Managed assertions and it's okay if we misaccount in prod until the transaction is parsed?
Yes, I believe it's not worth shallow-parsing in prod, because it gets properly parsed immediately afterwards.
| category: _, | ||
| } = self; | ||
| debug_assert!(flags.metrics_extracted); | ||
| let mut quantities = smallvec![(DataCategory::TransactionIndexed, 1),]; |
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.
| let mut quantities = smallvec![(DataCategory::TransactionIndexed, 1),]; | |
| let mut quantities = smallvec![(DataCategory::TransactionIndexed, 1)]; |
| let limits = rate_limiter | ||
| .try_consume(scoping.item(DataCategory::Transaction), 1) | ||
| .await; |
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.
If the transaction is limited, we can already drop the entire payload and don't need to consider attachments and profiles, right?
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.
Yes, I thought I had an early return here, good catch.
| // If there is a transaction limit, drop everything. | ||
| // This also affects profiles that lost their transaction due to sampling. | ||
| let limits = rate_limiter | ||
| .try_consume(scoping.item(DataCategory::TransactionIndexed), 1) |
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.
I think you need to check both categories here, that's what the EnvelopeLimiter does.
Note fn is_event_active() checks both categories, indexed and non-indexed as well.
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.
Naivly I would now expect transaction rate limits never to apply, what is strange, I would've expected a test to fail here. Am I missing something?
The spans processor always only rate limits total + indexed, it extracts the metrics only after rate limiting. I think this is also what we should do here.
Then you also don't have to implement RateLimited twice.
| ($($variant:ident => $ty:ty,)*) => { | ||
| /// All known [`Processor`] outputs. | ||
| #[derive(Debug)] | ||
| #[allow(clippy::large_enum_variant)] |
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.
| #[allow(clippy::large_enum_variant)] | |
| #[expect(clippy::large_enum_variant), reason = "..."] |
Alternatively we can also box the transaction output, I think that kinda depends why the lint triggers, if it's just because of a small-ish amount it's fine, if there is a large discrepancy maybe it's worth boxing.
| } | ||
|
|
||
| Ok(()) | ||
| } |
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.
Bug: Rate limiting doesn't check indexed transaction quota
The rate limiting implementation for ExpandedTransaction<TotalAndIndexed> only checks the Transaction category quota, but the quantities() method reports both Transaction and TransactionIndexed categories. This means TransactionIndexed quota limits are never enforced for transactions before metrics extraction. In contrast, the ExpandedTransaction<Indexed> rate limiting correctly checks both categories (lines 537-546). Without checking the indexed category, rate limits on indexed transactions can be bypassed.
Additional Locations (1)
| let main = match self.limiter.enforce_quotas(&mut indexed, ctx).await { | ||
| Err(e) => { | ||
| if let Error::RateLimited(rate_limits) = e.inner() { | ||
| if rate_limits.is_any_limited(&[scoping.item(DataCategory::Transaction)]) { |
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.
Bug: Transaction rate limit check missing TransactionIndexed category
The enforce_quotas error handling for transactions only checks DataCategory::Transaction to decide if an event should be dropped. It misses DataCategory::TransactionIndexed limits, which the RateLimited implementation correctly checks. This causes transactions to not be dropped when only TransactionIndexed is rate-limited, and related integration tests are currently disabled.
Closes INGEST-610.