Skip to content
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

Fix: Breadcrumbs added on forked context are now captured #629

Open
wants to merge 14 commits into
base: main
Choose a base branch
from

Conversation

lucas-zimerman
Copy link
Collaborator

@lucas-zimerman lucas-zimerman commented Apr 17, 2024

This PR brings more native context data to be synced with captured events and also allows hint breadcrumbs to be properly registered, for example:

    Sentry.captureException(new Error(`${Date.now()}: a test error occurred`), (context) => {
      return context.addBreadcrumb({ message: 'test' });
    });

will now be registered on the event, including the native events:
image

Additional notes on the PR:

  • No Required changes were needed to support it on iOS.
  • Android had an required refactor in order to capture Envelopes no longer by files.
  • some iOS specific properties are now working with both Android and iOS
  • Improved the device context sync on both Android and iOS.

🛑 Blocked by

Closes #263

@lucas-zimerman lucas-zimerman changed the title Fix: Merge breadcrumbs from envelope with native breadcrumbs. Fix: Breadcrumbs added on hints are now captured Apr 17, 2024
…version. Added tests. used a better name for the new function that joins two groups of breadcrumbs. Removed comment from java layer. Removed duplicated tests on the wrapper test file
@lucas-zimerman lucas-zimerman marked this pull request as ready for review April 18, 2024 21:16
@lucas-zimerman lucas-zimerman changed the title Fix: Breadcrumbs added on hints are now captured Fix: Breadcrumbs added on forked context are now captured Apr 18, 2024
}
});

describe('Device Context Breadcrumb filter', () => {
Copy link
Member

@krystofwoldrich krystofwoldrich Apr 19, 2024

Choose a reason for hiding this comment

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

We should add test for user set timeout timestamp. Something like this:

const jsList = [
  { timestamp: 2, message: 'new js' },
  { timestamp: 1, message: 'new js' },
] as Breadcrumb[];
const nativeList = [
  { timestamp: 2, message: 'new native' },
  { timestamp: 2, message: 'new js' },
  { timestamp: 1, message: 'new js' },
  { timestamp: 3, message: 'new native' },
] as Breadcrumb[];
const expected = [
  { timestamp: 2, message: 'new native' },
  { timestamp: 2, message: 'new js' },
  { timestamp: 1, message: 'new js' },
  { timestamp: 3, message: 'new native' },
] as Breadcrumb[];

src/wrapper.ts Outdated Show resolved Hide resolved
Copy link
Contributor

This pull request has gone three weeks without activity. In another week, I will close it.

But! If you comment or otherwise update it, I will reset the clock, and if you label it Status: Backlog or Status: In Progress, I will leave it alone ... forever!


"A weed is but an unloved flower." ― Ella Wheeler Wilcox 🥀

catch (Throwable e) {
final String errorMessage ="Error while capturing envelope";
logger.log(Level.WARNING, errorMessage);
call.reject(errorMessage);
Copy link
Member

Choose a reason for hiding this comment

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

I see previously this was call.reject(String.valueOf(e));? Does this change the error in any way?


private static final ILogger logger = new AndroidLogger(NAME);

public static Object convertToWritable(Object serialized) {
Copy link
Member

Choose a reason for hiding this comment

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

Can this return JSObject directly?

import io.sentry.SentryLevel;
import io.sentry.android.core.AndroidLogger;

public class CapSentryMapConverter {
Copy link
Member

Choose a reason for hiding this comment

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

Can we add unit tests for this class?

Comment on lines +104 to +145
private _mergeUniqueBreadcrumbs(jsList: Breadcrumb[], nativeList: Breadcrumb[], maxBreadcrumbs: number): Breadcrumb[] {
// Ensure both lists are ordered by timestamp.
const orderedNativeList = [...nativeList].sort((a, b) => (a.timestamp ?? 0) - (b.timestamp ?? 0));
const orderedJsList = [...jsList].sort((a, b) => (a.timestamp ?? 0) - (b.timestamp ?? 0));

const combinedList: Breadcrumb[] = [];
let jsIndex = 0;
let natIndex = 0;

while (jsIndex < orderedJsList.length && natIndex < orderedNativeList.length && combinedList.length < maxBreadcrumbs)
{
const jsBreadcrumb = orderedJsList[jsIndex];
const natBreadcrumb = orderedNativeList[natIndex];

if (jsBreadcrumb.timestamp === natBreadcrumb.timestamp &&
jsBreadcrumb.message === natBreadcrumb.message) {
combinedList.push(jsBreadcrumb);
jsIndex++;
natIndex++;
}
else if (jsBreadcrumb.timestamp && natBreadcrumb.timestamp &&
jsBreadcrumb.timestamp < natBreadcrumb.timestamp)
{
combinedList.push(jsBreadcrumb);
jsIndex++;
}
else {
combinedList.push(natBreadcrumb);
natIndex++;
}
}

// Add remaining breadcrumbs from the JavaScript and Native list if space allows.
while (jsIndex < orderedJsList.length && combinedList.length < maxBreadcrumbs) {
combinedList.push(orderedJsList[jsIndex++]);
}

while (natIndex < orderedNativeList.length && combinedList.length < maxBreadcrumbs) {
combinedList.push(orderedNativeList[natIndex++]);
}
return combinedList;
}
Copy link
Member

Choose a reason for hiding this comment

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

The function works, but I think we should consider marking the JS crumbs during the creation on native layers, as then we can also filter then on the native layers and only return the native crumbs.

The native solution would be faster and required less memory.

We could do JSBreadcrumb extends Breadcrumb and then filter breadcrumb instanceof JSBreadcrumb.

Copy link
Member

Choose a reason for hiding this comment

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

Because Breadcrumb is final (https://github.com/getsentry/sentry-java/blob/9596bb93199a1032cb255a62bea32020bd04c9ac/sentry/src/main/java/io/sentry/Breadcrumb.java#L20), thank @lucas-zimerman for pointing that out, we can extend it.

But the class has property called unknown marked for internal use. We could add a flag to it.

Breadcrumb crumb = new Breadcrumb();
crumb.getUnknown().put("hybrid", true);

@romtsn @markushi I don't know current usage of the unknown field, could this cause any issue/would it work?

Copy link
Member

Choose a reason for hiding this comment

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

unknown is used across our protocol classes to store attributes which are not defined within sentry-native. This avoids any data loss, achieving ~serialize(deserialize(breadcrumbJson)) == breadcrumbJson.

Copy link
Member

Choose a reason for hiding this comment

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

So yes it would work, but all unknown fields end up in the network requests as well - which is probably something we want to have anyway at some point?
To be honest I'd prefer some explicit field, e.g. breadcrumb.origin.

Copy link
Member

Choose a reason for hiding this comment

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

Got it thanks, breadcrumb.origin at first I think it could be runtime only, not included in the serialization, not transferred over network. I can see it being used later in the product, but currently there are no plans and there might never be.

We only want to solve a technical problem of efficiently filter js breadcrumbs from all the crumbs currently present on the scope.

Copy link
Member

@romtsn romtsn May 28, 2024

Choose a reason for hiding this comment

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

yeah, let's please not use unknown - it exists to work-around JVM's static type system exclusively. A new field is the cleanest way imo, but we could also open the Breadcrumb class for extension, should not be a problem

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I also like the idea of breadcrumb.origin, it could also help in the future to know if a breadcrumb was originated from the JavaScript layer or native

Copy link

Choose a reason for hiding this comment

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

I also like the idea of breadcrumb.origin, it could also help in the future to know if a breadcrumb was originated from the JavaScript layer or native

Hey @lucas-zimerman 👋
I've drafted an iOS PR and was wondering if you have any early feedback on it. Does the approach chosen unblock this PR?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

It surelly does thank you!

Copy link
Contributor

This pull request has gone three weeks without activity. In another week, I will close it.

But! If you comment or otherwise update it, I will reset the clock, and if you label it Status: Backlog or Status: In Progress, I will leave it alone ... forever!


"A weed is but an unloved flower." ― Ella Wheeler Wilcox 🥀

Copy link
Contributor

This pull request has gone three weeks without activity. In another week, I will close it.

But! If you comment or otherwise update it, I will reset the clock, and if you label it Status: Backlog or Status: In Progress, I will leave it alone ... forever!


"A weed is but an unloved flower." ― Ella Wheeler Wilcox 🥀

Copy link
Contributor

github-actions bot commented Sep 7, 2024

This pull request has gone three weeks without activity. In another week, I will close it.

But! If you comment or otherwise update it, I will reset the clock, and if you label it Status: Backlog or Status: In Progress, I will leave it alone ... forever!


"A weed is but an unloved flower." ― Ella Wheeler Wilcox 🥀

Copy link
Contributor

This pull request has gone three weeks without activity. In another week, I will close it.

But! If you comment or otherwise update it, I will reset the clock, and if you label it Status: Backlog or Status: In Progress, I will leave it alone ... forever!


"A weed is but an unloved flower." ― Ella Wheeler Wilcox 🥀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Refactor Breadcrumb filters
5 participants