ref(relay): Limit maximum number of logs produced by expansion - #6263
Conversation
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Want reviews to match your repository better? Bugbot Learning can learn team-specific rules from PR activity. A team admin can enable Learning in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 409e55f. Configure here.
| return Err(TooManyExpandedLogs); | ||
| } | ||
|
|
||
| Ok(()) |
There was a problem hiding this comment.
Debug quantity mismatch on limit
Medium Severity
When expansion hits TooManyExpandedLogs, produce has already called records.modify_by for each log emitted so far, but expand returns None and process::expand still finishes try_map with empty logs via unwrap_or_default. Debug RecordKeeper::success then fails quantity balancing and panics.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 409e55f. Configure here.
| pub max_log_size: ByteSize, | ||
| /// The maximum number of logs that can result from a log expansion. |
There was a problem hiding this comment.
max_expanded_log_count is only enforced for integrations, not log containers
The new max_expanded_log_count limit only applies to log integrations (OTel, Vercel, NEL) and not to LogItems::Container. A container with many small logs bypasses the count cap entirely, causing unbounded per-request CPU and memory usage during normalization, filtering, and scrubbing.
Evidence
relay-server/src/processing/logs/process.rs:expand()receivesmax_expanded_log_countbut only passes it tointegrations::expand()forLogItems::Integration.- For
LogItems::Container, it callsexpand_log_container()with no count parameter, so the cap is never checked. - A container is bounded by
max_container_size(default 12 MB), but with small logs that still allows tens or hundreds of thousands of items—far above themax_expanded_log_countdefault of 1000. - Every log from the container then goes through
validate::size,normalize,filter,scrub, andnormalize_derivedwith no early count-based rejection, unlike the integration path whereproduce()returnsErr(TooManyExpandedLogs)once the cap is exceeded.
Identified by Warden · wrdn-dos-review · MG4-3M7
| if logs.len() > max_expanded_log_count { | ||
| return Err(TooManyExpandedLogs); | ||
| } |
There was a problem hiding this comment.
I think this check isn't enough, as we're already deserializing (either via serde_json or prost) the entire array.
There was a problem hiding this comment.
So, it's the entire array, but we've only expanded (with accompanying attributes) logs.len() full log entries. It's the amplification by the attributes that can make this size a lot larger than we'd like.
There was a problem hiding this comment.
Parsing is already too much. The amplification of attributes is just a bigger multiplier. The OurLog struct is 208 bytes, the minimum size for a valid log item is 2 bytes in JSON (3 if we count the ,, 2 in protobuf). That is a 100x memory multiplier without considering the attribute amplification. With a size limit of 12 MiB per container, that means in a parsed state this is ~1 GiB. Then we have additional overheads like WithHeader<OurLog> and over-allocation of the Vec (capacity). To fully address the issue we already need to limit the count during parsing.


No description provided.