Skip to content

Commit

Permalink
Add modules to support Jetty 12
Browse files Browse the repository at this point in the history
  • Loading branch information
zUniQueX committed Aug 19, 2023
1 parent 31f775b commit f5c0ee9
Show file tree
Hide file tree
Showing 11 changed files with 1,390 additions and 0 deletions.
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
139 changes: 139 additions & 0 deletions metrics-jetty12-ee10/pom.xml
@@ -0,0 +1,139 @@
<?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.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>

<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();
}
}
}
}

0 comments on commit f5c0ee9

Please sign in to comment.