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

Add modules to support Jetty 12 #3515

Merged
merged 4 commits into from Aug 25, 2023
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
10 changes: 10 additions & 0 deletions metrics-bom/pom.xml
Expand Up @@ -130,6 +130,16 @@
<artifactId>metrics-jetty11</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.dropwizard.metrics</groupId>
<artifactId>metrics-jetty12</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.dropwizard.metrics</groupId>
<artifactId>metrics-jetty12-ee10</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.dropwizard.metrics</groupId>
<artifactId>metrics-jmx</artifactId>
Expand Down
138 changes: 138 additions & 0 deletions metrics-jetty12-ee10/pom.xml
@@ -0,0 +1,138 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>io.dropwizard.metrics</groupId>
<artifactId>metrics-parent</artifactId>
<version>4.2.20-SNAPSHOT</version>
</parent>

<artifactId>metrics-jetty12-ee10</artifactId>
<name>Metrics Integration for Jetty 12.x and higher with Jakarta EE 10</name>
<packaging>bundle</packaging>
<description>
A set of extensions for Jetty 12.x and higher which provide instrumentation of thread pools, connector
metrics, and application latency and utilization. This module uses the Servlet API from Jakarta EE 10.
</description>

<properties>
<javaModuleName>io.dropwizard.metrics.jetty12.ee10</javaModuleName>

<maven.compiler.release>17</maven.compiler.release>

<slf4j.version>2.0.7</slf4j.version>
</properties>

<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.dropwizard.metrics</groupId>
<artifactId>metrics-bom</artifactId>
<version>${project.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-bom</artifactId>
<version>${jetty12.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.ee10</groupId>
<artifactId>jetty-ee10-bom</artifactId>
<version>${jetty12.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy</artifactId>
<version>${byte-buddy.version}</version>
</dependency>
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<version>${servlet6.version}</version>
</dependency>
</dependencies>
</dependencyManagement>

<dependencies>
<dependency>
<groupId>io.dropwizard.metrics</groupId>
<artifactId>metrics-core</artifactId>
</dependency>
<dependency>
<groupId>io.dropwizard.metrics</groupId>
<artifactId>metrics-annotation</artifactId>
</dependency>
<dependency>
<groupId>io.dropwizard.metrics</groupId>
<artifactId>metrics-jetty12</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-util</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.ee10</groupId>
<artifactId>jetty-ee10-servlet</artifactId>
</dependency>
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>${assertj.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>${mockito.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-client</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-http</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>${slf4j.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
@@ -0,0 +1,173 @@
package io.dropwizard.metrics.jetty12.ee10;

import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.annotation.ResponseMeteredLevel;
import io.dropwizard.metrics.jetty12.AbstractInstrumentedHandler;
import jakarta.servlet.AsyncEvent;
import jakarta.servlet.AsyncListener;
import org.eclipse.jetty.ee10.servlet.AsyncContextState;
import org.eclipse.jetty.ee10.servlet.ServletApiRequest;
import org.eclipse.jetty.ee10.servlet.ServletApiResponse;
import org.eclipse.jetty.ee10.servlet.ServletContextRequest;
import org.eclipse.jetty.ee10.servlet.ServletRequestState;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Response;
import org.eclipse.jetty.util.Callback;

import java.io.IOException;
import java.util.concurrent.TimeUnit;

import static com.codahale.metrics.annotation.ResponseMeteredLevel.COARSE;

/**
* A Jetty {@link Handler} which records various metrics about an underlying {@link Handler}
* instance. This {@link Handler} requires a {@link org.eclipse.jetty.ee10.servlet.ServletContextHandler} to be present.
* For correct behaviour, the {@link org.eclipse.jetty.ee10.servlet.ServletContextHandler} should be before this handler
* in the handler chain. To achieve this, one can use
* {@link org.eclipse.jetty.ee10.servlet.ServletContextHandler#insertHandler(Singleton)}.
*/
public class InstrumentedEE10Handler extends AbstractInstrumentedHandler {
private AsyncListener listener;

/**
* Create a new instrumented handler using a given metrics registry.
*
* @param registry the registry for the metrics
*/
public InstrumentedEE10Handler(MetricRegistry registry) {
super(registry, null);
}

/**
* Create a new instrumented handler using a given metrics registry.
*
* @param registry the registry for the metrics
* @param prefix the prefix to use for the metrics names
*/
public InstrumentedEE10Handler(MetricRegistry registry, String prefix) {
super(registry, prefix, COARSE);
}

/**
* Create a new instrumented handler using a given metrics registry.
*
* @param registry the registry for the metrics
* @param prefix the prefix to use for the metrics names
* @param responseMeteredLevel the level to determine individual/aggregate response codes that are instrumented
*/
public InstrumentedEE10Handler(MetricRegistry registry, String prefix, ResponseMeteredLevel responseMeteredLevel) {
super(registry, prefix, responseMeteredLevel);
}

@Override
protected void doStart() throws Exception {
super.doStart();

this.listener = new AsyncAttachingListener();
}

@Override
protected void doStop() throws Exception {
super.doStop();
}

@Override
public boolean handle(Request request, Response response, Callback callback) throws Exception {
ServletContextRequest servletContextRequest = Request.as(request, ServletContextRequest.class);

// only handle servlet requests with the InstrumentedHandler
// because it depends on the ServletRequestState
if (servletContextRequest == null) {
return super.handle(request, response, callback);
}

activeDispatches.inc();

final long start;
final ServletRequestState state = servletContextRequest.getServletRequestState();
if (state.isInitial()) {
// new request
activeRequests.inc();
start = Request.getTimeStamp(request);
state.addListener(listener);
} else {
// resumed request
start = System.currentTimeMillis();
activeSuspended.dec();
if (state.getState() == ServletRequestState.State.HANDLING) {
asyncDispatches.mark();
}
}

boolean handled = false;

try {
handled = super.handle(request, response, callback);
} finally {
final long now = System.currentTimeMillis();
final long dispatched = now - start;

activeDispatches.dec();
dispatches.update(dispatched, TimeUnit.MILLISECONDS);

if (state.isSuspended()) {
activeSuspended.inc();
} else if (state.isInitial()) {
updateResponses(request, response, start, handled);
}
// else onCompletion will handle it.
}

return handled;
}

private class AsyncAttachingListener implements AsyncListener {

@Override
public void onTimeout(AsyncEvent event) throws IOException {}

@Override
public void onStartAsync(AsyncEvent event) throws IOException {
event.getAsyncContext().addListener(new InstrumentedAsyncListener());
}

@Override
public void onError(AsyncEvent event) throws IOException {}

@Override
public void onComplete(AsyncEvent event) throws IOException {}
};

private class InstrumentedAsyncListener implements AsyncListener {
private final long startTime;

InstrumentedAsyncListener() {
this.startTime = System.currentTimeMillis();
}

@Override
public void onTimeout(AsyncEvent event) throws IOException {
asyncTimeouts.mark();
}

@Override
public void onStartAsync(AsyncEvent event) throws IOException {
}

@Override
public void onError(AsyncEvent event) throws IOException {
}

@Override
public void onComplete(AsyncEvent event) throws IOException {
final AsyncContextState state = (AsyncContextState) event.getAsyncContext();
final ServletApiRequest request = (ServletApiRequest) state.getRequest();
final ServletApiResponse response = (ServletApiResponse) state.getResponse();
updateResponses(request.getRequest(), response.getResponse(), startTime, true);
if (!state.getServletChannelState().isSuspended()) {
activeSuspended.dec();
}
}
}
}