-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add modules to support Jetty 12 (#3515)
Notable changes: 1. The `HttpChannel.Listener` interface doesn't exist anymore. The instrumented class here isn't ported for Jetty 12. 2. Jetty 12 doesn't have dependencies on the Servlet API in the `jetty-server` module. To allow multiple EE version implementations, the `InstrumentedHandler` implementation is moved out to a separate `EEx` module. The core `metrics-jetty12` module contains an abstract base class for implementations. Perspectively, the `metrics-jetty12` module should contain an implementation which doesn't require the servlet classes. However, the Dropwizard framework is servlet-only at the moment. The implementation without the servlet classes is therefore deferred until requested. 3. The constructors of `InstrumentedQueuedThreadPool` are aligned with the super class' constructors.
- Loading branch information
Showing
11 changed files
with
1,388 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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> |
173 changes: 173 additions & 0 deletions
173
...etty12-ee10/src/main/java/io/dropwizard/metrics/jetty12/ee10/InstrumentedEE10Handler.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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(); | ||
} | ||
} | ||
} | ||
} |
Oops, something went wrong.