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

POTEL 1 - Use OpenTelemetry for Performance and Scopes propagation #3399

Open
wants to merge 53 commits into
base: 8.x.x
Choose a base branch
from

Conversation

adinauer
Copy link
Member

@adinauer adinauer commented Apr 30, 2024

📜 Description

  • Rely on Context for Scopes propagation by hooking into OpenTelemetry Context storage
  • Fork Scopes when new OpenTelemetry spans are created
  • Add a util for figuring out which storage mechanism for Scopes to use on startup
    • If our OpenTelemetry code is available, it'll use Context based storage
    • Otherwise it'll default to our own ThreadLocal based storage
  • SpanProcessor and Propagator are also involved in Scopes forking
  • SpanExporter combines OpenTelemetry spans into Sentry transactions and sends them
  • Add a new Gradle module sentry-opentelemetry-bootstrap so certain classes can be added to the bootstrap classloader
  • We use a global storage for linking OpenTelemetry spans and Sentry Scopes

💡 Motivation and Context

Make Java SDK more compatible with OpenTelemetry by forking Scopes along OpenTelemetry and using OpenTelemetry Context for propagation of Scopes.

💚 How did you test it?

📝 Checklist

  • I reviewed the submitted code.
  • 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.
  • 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

adinauer and others added 30 commits March 27, 2024 16:30
Copy link
Contributor

github-actions bot commented Apr 30, 2024

Fails
🚫 Please consider adding a changelog entry for the next release.
Messages
📖 Do not forget to update Sentry-docs with your feature once the pull request gets approved.

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

- POTEL 1 - Use OpenTelemetry for Performance and `Scopes` propagation ([#3399](https://github.com/getsentry/sentry-java/pull/3399))

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

Generated by 🚫 dangerJS against 9b41d51

Copy link
Contributor

github-actions bot commented Apr 30, 2024

Performance metrics 🚀

  Plain With Sentry Diff
Startup time 375.65 ms 447.29 ms 71.64 ms
Size 1.70 MiB 2.28 MiB 596.71 KiB

Baseline results on branch: 8.x.x

Startup times

Revision Plain With Sentry Diff
3e1e45b 373.72 ms 439.33 ms 65.60 ms
9f2c855 424.20 ms 506.34 ms 82.14 ms

App size

Revision Plain With Sentry Diff
3e1e45b 1.70 MiB 2.28 MiB 596.32 KiB
9f2c855 1.70 MiB 2.28 MiB 596.32 KiB

Previous results on branch: feat/potel-1-context-forking-and-basics

Startup times

Revision Plain With Sentry Diff
9931715 374.85 ms 431.48 ms 56.62 ms
9a9af11 376.72 ms 442.33 ms 65.61 ms
f5f9136 395.57 ms 504.94 ms 109.36 ms

App size

Revision Plain With Sentry Diff
9931715 1.70 MiB 2.28 MiB 596.01 KiB
9a9af11 1.70 MiB 2.28 MiB 596.17 KiB
f5f9136 1.70 MiB 2.28 MiB 596.01 KiB

Base automatically changed from feat/hsm-42-remove-hub to 8.x.x May 2, 2024 13:17
public final class OtelContextScopesStorage implements IScopesStorage {

@Override
public ISentryLifecycleToken set(@Nullable IScopes scopes) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

@NotNull annotation missing, as defined in the interface


private static @Nullable IScopes getCurrentSpanScopesFromGlobalStorage(
final @NotNull Context context) {
@Nullable final Span span = Span.fromContext(context);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Shouldn't this be Span.fromContextOrNull()?
As Span.fromContext() would return PropagatedSpan.INVALID if the key is not present in the context, thus the null check here would not work

Copy link
Member Author

Choose a reason for hiding this comment

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

good catch

* can exist.
*/
@ApiStatus.Internal
public final class SentryWeakSpanStorage {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should we rename this to SentryWeakScopesStorage ?

Copy link
Member Author

Choose a reason for hiding this comment

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

We likely have to change what's stored in follow up PRs.

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

public final class PotelSentrySpanProcessor implements SpanProcessor {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Indirectly related, but the old SentrySpanProcessor can be deleted as it isn't used anymore, right?

Copy link
Member Author

Choose a reason for hiding this comment

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

We'll keep it around for a while and maybe deprecate it so users can upgrade to the new version when they need it. There should either be some config to switch between POTel and old way of OTel or separate dependencies.

@@ -140,7 +144,11 @@ private static class VersionInfoHolder {

private SdkTracerProviderBuilder configureSdkTracerProvider(
SdkTracerProviderBuilder tracerProvider, ConfigProperties config) {
return tracerProvider.addSpanProcessor(new SentrySpanProcessor());
// TODO [POTEL] configurable or separate packages for old vs new way
Copy link
Collaborator

Choose a reason for hiding this comment

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

Do we want to keep the old way around?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, see above.

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

/**
Copy link
Collaborator

Choose a reason for hiding this comment

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

We should update the class comment here at some point

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah

private final @NotNull String id;

// TODO [POTEL] should this be ReadableSpan? if so weak or strong ref?
private @Nullable SpanData span;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Do we ever need to store a ReadableSpan for information that is not stored in a SpanData?
If we get a ReadableSpan as input from somewhere we could call ReadableSpan.toSpanData

Copy link
Member Author

Choose a reason for hiding this comment

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

Let's revisit this when implementation is further along. Currently we may not need ReadableSpan.

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.

None yet

2 participants