Skip to content

Conversation

@adinauer
Copy link
Member

@adinauer adinauer commented Nov 5, 2025

📜 Description

Previously discarded log count was only increased by 1 for the whole batch instead of counting discarded log items.

💡 Motivation and Context

Have correct client reports.

💚 How did you test it?

📝 Checklist

  • I added GH Issue ID & Linear ID
  • I added tests to verify the changes.
  • No new PII added or SDK only sends newly added PII if sendDefaultPII is enabled.
  • I updated the docs if needed.
  • I updated the wizard if needed.
  • Review from the native team if needed.
  • No breaking change or entry added to the changelog.
  • No breaking change for hybrid SDKs or communicated to hybrid SDKs.

🔮 Next steps

@github-actions
Copy link
Contributor

github-actions bot commented Nov 5, 2025

Fails
🚫 Please consider adding a changelog entry for the next release.

Instructions and example for changelog

Please add an entry to CHANGELOG.md to the "Unreleased" section. Make sure the entry includes this PR's number.

Example:

## Unreleased

### Fixes

- Fix log count in client reports ([#4869](https://github.com/getsentry/sentry-java/pull/4869))

If none of the above apply, you can opt out of this check by adding #skip-changelog to the PR description or adding a skip-changelog label.

Generated by 🚫 dangerJS against 3bd2cf0

final long count = logs.getItems().size();
recordLostEventInternal(reason.getReason(), itemCategory.getCategory(), count);
executeOnDiscard(reason, itemCategory, count);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Record lost log item when deserialization fails

When a log item envelope is lost but envelopeItem.getLogs(options.getSerializer()) returns null (e.g., due to deserialization failure), no lost event is recorded. The old code would have recorded 1 lost log item in this case. The fix should add an else clause to record 1 log item when logs == null, similar to how the Transaction case handles transaction == null.

Fix in Cursor Fix in Web

Copy link
Contributor

@alexander-alderman-webb alexander-alderman-webb Nov 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is okay because client reports are best effort? @adinauer

You could add a debug log in case deserialization failure has a non-zero chance of happening.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It shouldn't happen. If it does, I wouldn't know what to increase the count by. We could increment by 1 just to record something but it could also be 50 items in the batch that are lost.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And yeah I can add a log message

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there's no point sending a client report in this case; as you say, it shouldn't happen and there's no good count of dropped logs to record.

Comment on lines +104 to +110
} else if (itemCategory.equals(DataCategory.LogItem)) {
final @Nullable SentryLogEvents logs = envelopeItem.getLogs(options.getSerializer());
if (logs != null) {
final long count = logs.getItems().size();
recordLostEventInternal(reason.getReason(), itemCategory.getCategory(), count);
executeOnDiscard(reason, itemCategory, count);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: LogItem deserialization failures do not record lost items, leading to inaccurate client reports, unlike Transaction items.
Severity: CRITICAL | Confidence: 0.95

🔍 Detailed Analysis

When a LogItem envelope item fails to deserialize via envelopeItem.getLogs(options.getSerializer()) (either returning null or throwing an exception), the code responsible for recording lost items is skipped. This occurs because the recordLostEventInternal and executeOnDiscard calls are conditionally placed inside an if (logs != null) block. Consequently, client reports will not accurately reflect all lost LogItem events, specifically those that are malformed and fail deserialization. This behavior is inconsistent with how Transaction items are handled, where a lost item is recorded regardless of deserialization success.

💡 Suggested Fix

Move the recordLostEventInternal and executeOnDiscard calls for LogItem outside the if (logs != null) block. This ensures that a lost item is recorded even if LogItem deserialization fails, aligning its behavior with Transaction item handling.

🤖 Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.

Location:
sentry/src/main/java/io/sentry/clientreport/ClientReportRecorder.java#L104-L110

Potential issue: When a `LogItem` envelope item fails to deserialize via
`envelopeItem.getLogs(options.getSerializer())` (either returning `null` or throwing an
exception), the code responsible for recording lost items is skipped. This occurs
because the `recordLostEventInternal` and `executeOnDiscard` calls are conditionally
placed inside an `if (logs != null)` block. Consequently, client reports will not
accurately reflect all lost `LogItem` events, specifically those that are malformed and
fail deserialization. This behavior is inconsistent with how `Transaction` items are
handled, where a lost item is recorded regardless of deserialization success.

Did we get this right? 👍 / 👎 to inform future reviews.

@github-actions
Copy link
Contributor

github-actions bot commented Nov 5, 2025

Performance metrics 🚀

  Plain With Sentry Diff
Startup time 303.10 ms 357.29 ms 54.18 ms
Size 1.58 MiB 2.12 MiB 551.81 KiB

Baseline results on branch: main

Startup times

Revision Plain With Sentry Diff
2124a46 319.19 ms 415.04 ms 95.85 ms
b3d8889 420.46 ms 453.71 ms 33.26 ms
d217708 409.83 ms 474.72 ms 64.89 ms
3d205d0 352.15 ms 432.53 ms 80.38 ms
fcec2f2 357.47 ms 447.32 ms 89.85 ms
889ecea 367.58 ms 437.52 ms 69.94 ms
1df7eb6 397.04 ms 429.64 ms 32.60 ms
ce0a49e 532.00 ms 609.96 ms 77.96 ms
ee747ae 357.79 ms 421.84 ms 64.05 ms
b750b96 408.98 ms 480.32 ms 71.34 ms

App size

Revision Plain With Sentry Diff
2124a46 1.58 MiB 2.12 MiB 551.51 KiB
b3d8889 1.58 MiB 2.10 MiB 535.07 KiB
d217708 1.58 MiB 2.10 MiB 532.97 KiB
3d205d0 1.58 MiB 2.10 MiB 532.97 KiB
fcec2f2 1.58 MiB 2.12 MiB 551.50 KiB
889ecea 1.58 MiB 2.11 MiB 539.75 KiB
1df7eb6 1.58 MiB 2.10 MiB 532.97 KiB
ce0a49e 1.58 MiB 2.10 MiB 532.94 KiB
ee747ae 1.58 MiB 2.10 MiB 530.95 KiB
b750b96 1.58 MiB 2.10 MiB 533.19 KiB

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants