Skip to content

Commit

Permalink
Track exceptions thrown during JAX-RS processing in the current span
Browse files Browse the repository at this point in the history
  • Loading branch information
geoand committed Jul 4, 2023
1 parent 13e515e commit 14edff8
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
import io.quarkus.deployment.annotations.BuildProducer;
import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.opentelemetry.deployment.spi.OpenTelemetryTracerEnabledBuildItem;
import io.quarkus.opentelemetry.resteasy.reactive.runtime.AttachExceptionHandler;
import io.quarkus.opentelemetry.resteasy.reactive.runtime.OpenTelemetryReactiveServerFilter;
import io.quarkus.resteasy.reactive.server.deployment.PreExceptionMapperHandlerBuildItem;
import io.quarkus.resteasy.reactive.spi.CustomContainerRequestFilterBuildItem;

public class OpenTelemetryResteasyReactiveProcessor {
Expand All @@ -21,4 +23,9 @@ void registerResteasyReactiveProvider(Optional<OpenTelemetryTracerEnabledBuildIt
containerRequestFilterBuildItemBuildProducer
.produce(new CustomContainerRequestFilterBuildItem(OpenTelemetryReactiveServerFilter.class.getName()));
}

@BuildStep
PreExceptionMapperHandlerBuildItem attachException() {
return new PreExceptionMapperHandlerBuildItem(new AttachExceptionHandler());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package io.quarkus.opentelemetry.resteasy.reactive.runtime;

import org.jboss.resteasy.reactive.server.core.ResteasyReactiveRequestContext;
import org.jboss.resteasy.reactive.server.spi.ServerRestHandler;

import io.opentelemetry.instrumentation.api.instrumenter.LocalRootSpan;

public class AttachExceptionHandler implements ServerRestHandler {
@Override
public void handle(ResteasyReactiveRequestContext requestContext) throws Exception {
Throwable throwable = requestContext.getThrowable();
if (throwable != null) { // should always be true
LocalRootSpan.current().recordException(throwable);
}
}
}
5 changes: 5 additions & 0 deletions integration-tests/opentelemetry-reactive/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,11 @@
<artifactId>wiremock-jre8-standalone</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>

<!-- Minimal test dependencies to *-deployment artifacts for consistent build order -->
<dependency>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,18 @@ public Uni<String> helloPost(String body) {
return Uni.createFrom().item("Hello " + body).onItem().delayIt().by(Duration.ofSeconds(2))
.eventually((Runnable) span::end);
}

@Path("blockingException")
@GET
public String blockingException() {
throw new RuntimeException("dummy");
}

@Path("reactiveException")
@GET
public Uni<String> reactiveException() {
return Uni.createFrom().item(() -> {
throw new RuntimeException("dummy2");
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import static io.restassured.RestAssured.given;
import static java.net.HttpURLConnection.HTTP_OK;
import static java.util.stream.Collectors.toSet;
import static org.assertj.core.api.Assertions.*;
import static org.awaitility.Awaitility.await;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.junit.jupiter.api.Assertions.assertEquals;
Expand Down Expand Up @@ -53,6 +54,46 @@ void get() {
assertEquals(spans.get(0).get("traceId"), spans.get(1).get("traceId"));
}

@Test
void blockingException() {
given()
.when()
.get("/reactive/blockingException")
.then()
.statusCode(500);

assertExceptionRecorded();
}

@Test
void reactiveException() {
given()
.when()
.get("/reactive/reactiveException")
.then()
.statusCode(500);

assertExceptionRecorded();
}

private static void assertExceptionRecorded() {
await().atMost(5, TimeUnit.SECONDS).until(() -> getSpans().size() == 1);
List<Map<String, Object>> spans = getSpans();
assertThat(spans).singleElement().satisfies(span -> {
assertThat(span).containsKey("events").extractingByKey("events").isInstanceOfSatisfying(List.class, (ev) -> {
assertThat((List<Map<String, Object>>) ev).singleElement().isInstanceOfSatisfying(Map.class, e -> {
assertThat(e).containsKey("exception").extractingByKey("exception").isInstanceOfSatisfying(Map.class,
ex -> {
assertThat((Map<String, Object>) ex).containsKey("stackTrace").extractingByKey("stackTrace")
.isInstanceOfSatisfying(List.class, st -> {
assertThat(st).hasSizeGreaterThan(5);
});
});
});
});
});
}

@Test
void post() {
given()
Expand Down

0 comments on commit 14edff8

Please sign in to comment.