Skip to content

Commit

Permalink
Improve JFR integration in Quarkus REST
Browse files Browse the repository at this point in the history
We are now able to capture events for all
HTTP requests that are meant to be handled
by Quarkus REST, whether they were successfully
handled or not.

Fixes: quarkusio#44976
  • Loading branch information
geoand committed Dec 11, 2024
1 parent a390e8a commit 21a9657
Show file tree
Hide file tree
Showing 18 changed files with 429 additions and 135 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@
import io.quarkus.jfr.runtime.OTelIdProducer;
import io.quarkus.jfr.runtime.QuarkusIdProducer;
import io.quarkus.jfr.runtime.config.JfrRuntimeConfig;
import io.quarkus.jfr.runtime.http.rest.ClassicServerRecorderProducer;
import io.quarkus.jfr.runtime.http.rest.JfrClassicServerFilter;
import io.quarkus.jfr.runtime.http.rest.JfrReactiveServerFilter;
import io.quarkus.jfr.runtime.http.rest.ReactiveServerRecorderProducer;
import io.quarkus.jfr.runtime.http.rest.classic.ClassicServerFilter;
import io.quarkus.jfr.runtime.http.rest.classic.ClassicServerRecorderProducer;
import io.quarkus.jfr.runtime.http.rest.reactive.ReactiveServerFilters;
import io.quarkus.jfr.runtime.http.rest.reactive.ReactiveServerRecorderProducer;
import io.quarkus.jfr.runtime.http.rest.reactive.ServerStartRecordingHandler;
import io.quarkus.resteasy.common.spi.ResteasyJaxrsProviderBuildItem;
import io.quarkus.resteasy.reactive.server.spi.GlobalHandlerCustomizerBuildItem;
import io.quarkus.resteasy.reactive.spi.CustomContainerRequestFilterBuildItem;

@BuildSteps
Expand Down Expand Up @@ -52,7 +54,8 @@ void registerRequestIdProducer(Capabilities capabilities,
@BuildStep
void registerRestIntegration(Capabilities capabilities,
BuildProducer<CustomContainerRequestFilterBuildItem> filterBeans,
BuildProducer<AdditionalBeanBuildItem> additionalBeans) {
BuildProducer<AdditionalBeanBuildItem> additionalBeans,
BuildProducer<GlobalHandlerCustomizerBuildItem> globalHandlerCustomizerProducer) {

if (capabilities.isPresent(Capability.RESTEASY_REACTIVE)) {

Expand All @@ -61,7 +64,10 @@ void registerRestIntegration(Capabilities capabilities,
.build());

filterBeans
.produce(new CustomContainerRequestFilterBuildItem(JfrReactiveServerFilter.class.getName()));
.produce(new CustomContainerRequestFilterBuildItem(ReactiveServerFilters.class.getName()));

globalHandlerCustomizerProducer
.produce(new GlobalHandlerCustomizerBuildItem(new ServerStartRecordingHandler.Customizer()));
}
}

Expand All @@ -76,7 +82,7 @@ void registerResteasyClassicIntegration(Capabilities capabilities,
.build());

resteasyJaxrsProviderBuildItemBuildProducer
.produce(new ResteasyJaxrsProviderBuildItem(JfrClassicServerFilter.class.getName()));
.produce(new ResteasyJaxrsProviderBuildItem(ClassicServerFilter.class.getName()));
}
}

Expand Down

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.quarkus.jfr.runtime.http.rest;
package io.quarkus.jfr.runtime.http.rest.classic;

import java.io.IOException;

Expand All @@ -14,16 +14,16 @@
import io.quarkus.arc.Arc;

@Provider
public class JfrClassicServerFilter implements ContainerRequestFilter, ContainerResponseFilter {
public class ClassicServerFilter implements ContainerRequestFilter, ContainerResponseFilter {

private static final Logger LOG = Logger.getLogger(JfrClassicServerFilter.class);
private static final Logger LOG = Logger.getLogger(ClassicServerFilter.class);

@Override
public void filter(ContainerRequestContext requestContext) throws IOException {
if (LOG.isDebugEnabled()) {
LOG.debug("Enter Jfr Classic Request Filter");
}
Recorder recorder = Arc.container().instance(Recorder.class).get();
ClassicServerRecorder recorder = Arc.container().instance(ClassicServerRecorder.class).get();
recorder.recordStartEvent();
recorder.startPeriodEvent();
}
Expand All @@ -36,7 +36,7 @@ public void filter(ContainerRequestContext requestContext, ContainerResponseCont
}

if (isRecordable(responseContext)) {
Recorder recorder = Arc.container().instance(Recorder.class).get();
ClassicServerRecorder recorder = Arc.container().instance(ClassicServerRecorder.class).get();
recorder.endPeriodEvent();
recorder.recordEndEvent();
} else {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package io.quarkus.jfr.runtime.http.rest;
package io.quarkus.jfr.runtime.http.rest.classic;

import io.quarkus.jfr.runtime.IdProducer;
import io.quarkus.jfr.runtime.http.AbstractHttpEvent;
import io.quarkus.jfr.runtime.http.rest.RestEndEvent;
import io.quarkus.jfr.runtime.http.rest.RestPeriodEvent;
import io.quarkus.jfr.runtime.http.rest.RestStartEvent;

public class ServerRecorder implements Recorder {
public class ClassicServerRecorder {

private final String httpMethod;
private final String uri;
Expand All @@ -13,7 +16,8 @@ public class ServerRecorder implements Recorder {
private final IdProducer idProducer;
private RestPeriodEvent durationEvent;

public ServerRecorder(String httpMethod, String uri, String resourceClass, String resourceMethod, String client,
public ClassicServerRecorder(String httpMethod, String uri, String resourceClass, String resourceMethod,
String client,
IdProducer idProducer) {
this.httpMethod = httpMethod;
this.uri = uri;
Expand All @@ -23,7 +27,6 @@ public ServerRecorder(String httpMethod, String uri, String resourceClass, Strin
this.idProducer = idProducer;
}

@Override
public void recordStartEvent() {

RestStartEvent startEvent = new RestStartEvent();
Expand All @@ -34,7 +37,6 @@ public void recordStartEvent() {
}
}

@Override
public void recordEndEvent() {

RestEndEvent endEvent = new RestEndEvent();
Expand All @@ -45,13 +47,11 @@ public void recordEndEvent() {
}
}

@Override
public void startPeriodEvent() {
durationEvent = new RestPeriodEvent();
durationEvent.begin();
}

@Override
public void endPeriodEvent() {

durationEvent.end();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.quarkus.jfr.runtime.http.rest;
package io.quarkus.jfr.runtime.http.rest.classic;

import java.lang.reflect.Method;

Expand All @@ -25,7 +25,7 @@ public class ClassicServerRecorderProducer {

@Produces
@RequestScoped
public Recorder create() {
public ClassicServerRecorder create() {
String httpMethod = vertxRequest.method().name();
String uri = vertxRequest.path();
Class<?> resourceClass = resourceInfo.getResourceClass();
Expand All @@ -34,6 +34,6 @@ public Recorder create() {
String resourceMethodName = (resourceMethod == null) ? null : resourceMethod.getName();
String client = vertxRequest.remoteAddress().toString();

return new ServerRecorder(httpMethod, uri, resourceClassName, resourceMethodName, client, idProducer);
return new ClassicServerRecorder(httpMethod, uri, resourceClassName, resourceMethodName, client, idProducer);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package io.quarkus.jfr.runtime.http.rest.reactive;

import org.jboss.logging.Logger;
import org.jboss.resteasy.reactive.server.ServerRequestFilter;
import org.jboss.resteasy.reactive.server.ServerResponseFilter;
import org.jboss.resteasy.reactive.server.SimpleResourceInfo;

public class ReactiveServerFilters {

private static final Logger LOG = Logger.getLogger(ReactiveServerFilters.class);

private final ReactiveServerRecorder recorder;

public ReactiveServerFilters(ReactiveServerRecorder recorder) {
this.recorder = recorder;
}

/**
* Executed if request processing proceeded correctly.
* We now have to update the start event with the resource class and method data and also commit the event.
*/
@ServerRequestFilter
public void requestFilter(SimpleResourceInfo resourceInfo) {
Class<?> resourceClass = resourceInfo.getResourceClass();
if (resourceClass != null) { // should always be the case
String resourceClassName = resourceClass.getName();
String resourceMethodName = resourceInfo.getMethodName();
recorder
.updateResourceInfo(new ResourceInfo(resourceClassName, resourceMethodName))
.commitStartEventIfNecessary();
}

}

/**
* This will execute regardless of a processing failure or not.
* If there was a failure, we need to check if the start event was not commited
* (which happens when request was not matched to any resource method) and if so, commit it.
*/
@ServerResponseFilter
public void responseFilter() {
if (LOG.isDebugEnabled()) {
LOG.debug("Enter Jfr Reactive Response Filter");
}
recorder
.recordEndEvent()
.endPeriodEvent();
}

}
Loading

0 comments on commit 21a9657

Please sign in to comment.