Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
- Pass OpenTelemetry span attributes into TracesSampler callback ([#4253](https://github.com/getsentry/sentry-java/pull/4253))
- `SamplingContext` now has a `getAttribute` method that grants access to OpenTelemetry span attributes via their String key (e.g. `http.request.method`)
- Fix AbstractMethodError when using SentryTraced for Jetpack Compose ([#4255](https://github.com/getsentry/sentry-java/pull/4255))
- Assume `http.client` for span `op` if not a root span ([#4257](https://github.com/getsentry/sentry-java/pull/4257))
- Avoid unnecessary copies when using `CopyOnWriteArrayList` ([#4247](https://github.com/getsentry/sentry-java/pull/4247))
- This affects in particular `SentryTracer.getLatestActiveSpan` which would have previously copied all child span references. This may have caused `OutOfMemoryError` on certain devices due to high frequency of calling the method.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,23 +18,16 @@ public final class SpanDescriptionExtractor {
@SuppressWarnings("deprecation")
public @NotNull OtelSpanInfo extractSpanInfo(
final @NotNull SpanData otelSpan, final @Nullable IOtelSpanWrapper sentrySpan) {
if (!isInternalSpanKind(otelSpan)) {
Copy link
Member

Choose a reason for hiding this comment

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

Could you explain why we removed this check?

Copy link
Member Author

Choose a reason for hiding this comment

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

The problem we had before (see #3904) was that when span kind was set to neither CLIENT nor SERVER we would generate http as op (without .client or .server suffix).

The default span kind is INTERNAL. So if a customer manually instruments using OTel, doesn't set span kind and has HTTP span attributes set, the SpanDescriptionExtractor wouldn't know whether it's an incoming or outgoing request.

Having this check in place would prevent the changes in this PR from taking effect.

final @NotNull Attributes attributes = otelSpan.getAttributes();

final @Nullable String httpMethod = attributes.get(HttpAttributes.HTTP_REQUEST_METHOD);
if (httpMethod != null) {
return descriptionForHttpMethod(otelSpan, httpMethod);
}
final @NotNull Attributes attributes = otelSpan.getAttributes();

final @Nullable String httpRequestMethod = attributes.get(HttpAttributes.HTTP_REQUEST_METHOD);
if (httpRequestMethod != null) {
return descriptionForHttpMethod(otelSpan, httpRequestMethod);
}
final @Nullable String httpMethod = attributes.get(HttpAttributes.HTTP_REQUEST_METHOD);
if (httpMethod != null) {
return descriptionForHttpMethod(otelSpan, httpMethod);
}

final @Nullable String dbSystem = attributes.get(DbIncubatingAttributes.DB_SYSTEM);
if (dbSystem != null) {
return descriptionForDbSystem(otelSpan);
}
final @Nullable String dbSystem = attributes.get(DbIncubatingAttributes.DB_SYSTEM);
if (dbSystem != null) {
return descriptionForDbSystem(otelSpan);
}

final @NotNull String name = otelSpan.getName();
Expand All @@ -44,10 +37,6 @@ public final class SpanDescriptionExtractor {
return new OtelSpanInfo(name, description, TransactionNameSource.CUSTOM);
}

private boolean isInternalSpanKind(final @NotNull SpanData otelSpan) {
return SpanKind.INTERNAL.equals(otelSpan.getKind());
}

@SuppressWarnings("deprecation")
private OtelSpanInfo descriptionForHttpMethod(
final @NotNull SpanData otelSpan, final @NotNull String httpMethod) {
Expand All @@ -60,6 +49,12 @@ private OtelSpanInfo descriptionForHttpMethod(
opBuilder.append(".client");
} else if (SpanKind.SERVER.equals(kind)) {
opBuilder.append(".server");
} else {
// we cannot be certain that a root span is a server span as it might simply be a client span
// without parent
if (!isRootSpan(otelSpan)) {
opBuilder.append(".client");
}
}
final @Nullable String httpTarget = attributes.get(HttpIncubatingAttributes.HTTP_TARGET);
final @Nullable String httpRoute = attributes.get(HttpAttributes.HTTP_ROUTE);
Expand Down Expand Up @@ -92,6 +87,10 @@ private OtelSpanInfo descriptionForHttpMethod(
return new OtelSpanInfo(op, description, transactionNameSource);
}

private static boolean isRootSpan(SpanData otelSpan) {
return !otelSpan.getParentSpanContext().isValid() || otelSpan.getParentSpanContext().isRemote();
}

@SuppressWarnings("deprecation")
private OtelSpanInfo descriptionForDbSystem(final @NotNull SpanData otelSpan) {
final @NotNull Attributes attributes = otelSpan.getAttributes();
Expand Down
Loading
Loading