Skip to content

Commit acbfe6f

Browse files
authored
Merge branch 'main' into lcian/fix/cowal-iterator
2 parents 6223546 + 762ee2d commit acbfe6f

File tree

15 files changed

+404
-18
lines changed

15 files changed

+404
-18
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,4 @@ distributions/
2020
sentry-spring-boot-starter-jakarta/src/main/resources/META-INF/spring.factories
2121
sentry-samples/sentry-samples-spring-boot-jakarta/spy.log
2222
spy.log
23+
buildSrc/.kotlin/

CHANGELOG.md

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22

33
## Unreleased
44

5+
### Behavioural Changes
6+
7+
- Use `java.net.URI` for parsing URLs in `UrlUtils` ([#4210](https://github.com/getsentry/sentry-java/pull/4210))
8+
- This could affect grouping for issues with messages containing URLs that fall in known corner cases that were handled incorrectly previously (e.g. email in URL path)
9+
510
### Fixes
611

712
- Add support for setting in-app-includes/in-app-excludes via AndroidManifest.xml ([#4240](https://github.com/getsentry/sentry-java/pull/4240))
@@ -11,11 +16,17 @@
1116
### Features
1217

1318
- The SDK now automatically propagates the trace-context to the native layer. This allows to connect errors on different layers of the application. ([#4137](https://github.com/getsentry/sentry-java/pull/4137))
19+
- Capture OpenTelemetry span events ([#3564](https://github.com/getsentry/sentry-java/pull/3564))
20+
- OpenTelemetry spans may have exceptions attached to them (`openTelemetrySpan.recordException`). We can now send those to Sentry as errors.
21+
- Set `capture-open-telemetry-events=true` in `sentry.properties` to enable it
22+
- Set `sentry.capture-open-telemetry-events=true` in Springs `application.properties` to enable it
23+
- Set `sentry.captureOpenTelemetryEvents: true` in Springs `application.yml` to enable it
1424

15-
### Behavioural Changes
25+
### Internal
1626

17-
- Use `java.net.URI` for parsing URLs in `UrlUtils` ([#4210](https://github.com/getsentry/sentry-java/pull/4210))
18-
- This could affect grouping for issues with messages containing URLs that fall in known corner cases that were handled incorrectly previously (e.g. email in URL path)
27+
- Also use port when checking if a request is made to Sentry DSN ([#4231](https://github.com/getsentry/sentry-java/pull/4231))
28+
- For our OpenTelemetry integration we check if a span is for a request to Sentry
29+
- We now also consider the port when performing this check
1930

2031
### Dependencies
2132

sentry-opentelemetry/sentry-opentelemetry-core/src/main/java/io/sentry/opentelemetry/OpenTelemetryAttributesExtractor.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,13 +105,20 @@ private static Map<String, String> collectHeaders(
105105
return headers;
106106
}
107107

108+
@SuppressWarnings("deprecation")
108109
public @Nullable String extractUrl(
109110
final @NotNull Attributes attributes, final @NotNull SentryOptions options) {
110111
final @Nullable String urlFull = attributes.get(UrlAttributes.URL_FULL);
111112
if (urlFull != null) {
112113
return urlFull;
113114
}
114115

116+
final @Nullable String deprecatedUrl =
117+
attributes.get(io.opentelemetry.semconv.SemanticAttributes.HTTP_URL);
118+
if (deprecatedUrl != null) {
119+
return deprecatedUrl;
120+
}
121+
115122
final String urlString = buildUrlString(attributes, options);
116123
if (!urlString.isEmpty()) {
117124
return urlString;

sentry-opentelemetry/sentry-opentelemetry-core/src/main/java/io/sentry/opentelemetry/OtelInternalSpanDetectionUtil.java

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import io.opentelemetry.api.common.Attributes;
44
import io.opentelemetry.api.trace.SpanKind;
5-
import io.opentelemetry.semconv.UrlAttributes;
65
import io.sentry.DsnUtil;
76
import io.sentry.IScopes;
87
import java.util.Arrays;
@@ -17,6 +16,8 @@ public final class OtelInternalSpanDetectionUtil {
1716

1817
private static final @NotNull List<SpanKind> spanKindsConsideredForSentryRequests =
1918
Arrays.asList(SpanKind.CLIENT, SpanKind.INTERNAL);
19+
private static final @NotNull OpenTelemetryAttributesExtractor attributesExtractor =
20+
new OpenTelemetryAttributesExtractor();
2021

2122
@SuppressWarnings("deprecation")
2223
public static boolean isSentryRequest(
@@ -27,14 +28,8 @@ public static boolean isSentryRequest(
2728
return false;
2829
}
2930

30-
final @Nullable String httpUrl =
31-
attributes.get(io.opentelemetry.semconv.SemanticAttributes.HTTP_URL);
32-
if (DsnUtil.urlContainsDsnHost(scopes.getOptions(), httpUrl)) {
33-
return true;
34-
}
35-
36-
final @Nullable String fullUrl = attributes.get(UrlAttributes.URL_FULL);
37-
if (DsnUtil.urlContainsDsnHost(scopes.getOptions(), fullUrl)) {
31+
String url = attributesExtractor.extractUrl(attributes, scopes.getOptions());
32+
if (DsnUtil.urlContainsDsnHost(scopes.getOptions(), url)) {
3833
return true;
3934
}
4035

@@ -43,10 +38,7 @@ public static boolean isSentryRequest(
4338
final @NotNull String spotlightUrl =
4439
optionsSpotlightUrl != null ? optionsSpotlightUrl : "http://localhost:8969/stream";
4540

46-
if (containsSpotlightUrl(fullUrl, spotlightUrl)) {
47-
return true;
48-
}
49-
if (containsSpotlightUrl(httpUrl, spotlightUrl)) {
41+
if (containsSpotlightUrl(url, spotlightUrl)) {
5042
return true;
5143
}
5244
}

sentry-opentelemetry/sentry-opentelemetry-core/src/main/java/io/sentry/opentelemetry/OtelSentrySpanProcessor.java

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,25 @@
88
import io.opentelemetry.sdk.trace.ReadWriteSpan;
99
import io.opentelemetry.sdk.trace.ReadableSpan;
1010
import io.opentelemetry.sdk.trace.SpanProcessor;
11+
import io.opentelemetry.sdk.trace.data.EventData;
12+
import io.opentelemetry.sdk.trace.data.ExceptionEventData;
1113
import io.sentry.Baggage;
14+
import io.sentry.DateUtils;
1215
import io.sentry.IScopes;
1316
import io.sentry.PropagationContext;
1417
import io.sentry.ScopesAdapter;
1518
import io.sentry.Sentry;
1619
import io.sentry.SentryDate;
20+
import io.sentry.SentryEvent;
1721
import io.sentry.SentryLevel;
1822
import io.sentry.SentryLongDate;
1923
import io.sentry.SentryTraceHeader;
2024
import io.sentry.SpanId;
2125
import io.sentry.TracesSamplingDecision;
26+
import io.sentry.exception.ExceptionMechanismException;
27+
import io.sentry.protocol.Mechanism;
2228
import io.sentry.protocol.SentryId;
29+
import java.util.List;
2330
import org.jetbrains.annotations.NotNull;
2431
import org.jetbrains.annotations.Nullable;
2532

@@ -143,9 +150,46 @@ public void onEnd(final @NotNull ReadableSpan spanBeingEnded) {
143150
final @NotNull SentryDate finishDate =
144151
new SentryLongDate(spanBeingEnded.toSpanData().getEndEpochNanos());
145152
sentrySpan.updateEndDate(finishDate);
153+
154+
maybeCaptureSpanEventsAsExceptions(spanBeingEnded, sentrySpan);
146155
}
147156
}
148157

158+
private void maybeCaptureSpanEventsAsExceptions(
159+
final @NotNull ReadableSpan spanBeingEnded, final @NotNull IOtelSpanWrapper sentrySpan) {
160+
final @NotNull IScopes spanScopes = sentrySpan.getScopes();
161+
if (spanScopes.getOptions().isCaptureOpenTelemetryEvents()) {
162+
final @NotNull List<EventData> events = spanBeingEnded.toSpanData().getEvents();
163+
for (EventData event : events) {
164+
if (event instanceof ExceptionEventData) {
165+
final @NotNull ExceptionEventData exceptionEvent = (ExceptionEventData) event;
166+
captureException(spanScopes, exceptionEvent, sentrySpan);
167+
}
168+
}
169+
}
170+
}
171+
172+
private void captureException(
173+
final @NotNull IScopes scopes,
174+
final @NotNull ExceptionEventData exceptionEvent,
175+
final @NotNull IOtelSpanWrapper sentrySpan) {
176+
final @NotNull Throwable exception = exceptionEvent.getException();
177+
final Mechanism mechanism = new Mechanism();
178+
mechanism.setType("OpenTelemetrySpanEvent");
179+
mechanism.setHandled(true);
180+
// This is potentially the wrong Thread as it's the current thread meaning the thread where
181+
// the span is being ended on. This may not match the thread where the exception occurred.
182+
final Throwable mechanismException =
183+
new ExceptionMechanismException(mechanism, exception, Thread.currentThread());
184+
185+
final SentryEvent event = new SentryEvent(mechanismException);
186+
event.setTimestamp(DateUtils.nanosToDate(exceptionEvent.getEpochNanos()));
187+
event.setLevel(SentryLevel.ERROR);
188+
event.getContexts().setTrace(sentrySpan.getSpanContext());
189+
190+
scopes.captureEvent(event);
191+
}
192+
149193
@Override
150194
public boolean isEndRequired() {
151195
return true;

sentry-opentelemetry/sentry-opentelemetry-core/src/test/kotlin/OpenTelemetryAttributesExtractorTest.kt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import io.opentelemetry.api.common.AttributeKey
44
import io.opentelemetry.sdk.internal.AttributesMap
55
import io.opentelemetry.sdk.trace.data.SpanData
66
import io.opentelemetry.semconv.HttpAttributes
7+
import io.opentelemetry.semconv.SemanticAttributes
78
import io.opentelemetry.semconv.ServerAttributes
89
import io.opentelemetry.semconv.UrlAttributes
910
import io.sentry.Scope
@@ -202,6 +203,19 @@ class OpenTelemetryAttributesExtractorTest {
202203
assertEquals("https://sentry.io/some/path", url)
203204
}
204205

206+
@Test
207+
fun `returns deprecated URL if present`() {
208+
givenAttributes(
209+
mapOf(
210+
SemanticAttributes.HTTP_URL to "https://sentry.io/some/path"
211+
)
212+
)
213+
214+
val url = whenExtractingUrl()
215+
216+
assertEquals("https://sentry.io/some/path", url)
217+
}
218+
205219
@Test
206220
fun `returns reconstructed URL if attributes present`() {
207221
givenAttributes(

0 commit comments

Comments
 (0)