Add instrumentation and tests for Grizzly 2.x Http Server
ADD
dd-java-agent/instrumentation/grizzly-2/grizzly-2.gradle
+muzzle {
+ pass {
+ group = "org.glassfish.grizzly"
+ module = 'grizzly-http-server'
+ versions = "[2.0,)"
+ assertInverse = true
+ }
+ // Not bothering to test against 1.x since it has a different package name.
+ // https://mvnrepository.com/artifact/com.sun.grizzly/grizzly-http
+}
+
+apply from: "${rootDir}/gradle/java.gradle"
+
+apply plugin: 'org.unbroken-dome.test-sets'
+
+testSets {
+ latestDepTest {
+ dirName = 'test'
+ }
+}
+
+dependencies {
+ compileOnly group: 'org.glassfish.grizzly', name: 'grizzly-http-server', version: '2.0'
+
+ testCompile project(':dd-java-agent:instrumentation:java-concurrent')
+
+ testCompile group: 'javax.xml.bind', name: 'jaxb-api', version: '2.2.3'
+ testCompile group: 'javax.ws.rs', name: 'javax.ws.rs-api', version: '2.0'
+ testCompile group: 'org.glassfish.grizzly', name: 'grizzly-http-server', version: '2.0'
+ testCompile group: 'org.glassfish.jersey.containers', name: 'jersey-container-grizzly2-http', version: '2.0'
+
+ latestDepTestCompile group: 'org.glassfish.grizzly', name: 'grizzly-http-server', version: '+'
+ latestDepTestCompile group: 'org.glassfish.jersey.containers', name: 'jersey-container-grizzly2-http', version: '+'
+ latestDepTestCompile group: 'org.glassfish.jersey.inject', name: 'jersey-hk2', version: '+'
+}

ADD
dd-java-agent/instrumentation/grizzly-2/src/main/java/datadog/trace/instrumentation/grizzly/GrizzlyDecorator.java
+package datadog.trace.instrumentation.grizzly;
+
+import datadog.trace.agent.decorator.HttpServerDecorator;
+import java.net.URI;
+import java.net.URISyntaxException;
+import org.glassfish.grizzly.http.server.Request;
+import org.glassfish.grizzly.http.server.Response;
+
+public class GrizzlyDecorator extends HttpServerDecorator<Request, Request, Response> {
+ public static final GrizzlyDecorator DECORATE = new GrizzlyDecorator();
+
+ @Override
+ protected String method(final Request request) {
+ return request.getMethod().getMethodString();
+ }
+
+ @Override
+ protected URI url(final Request request) throws URISyntaxException {
+ return new URI(request.getRequestURL().toString());
+ }
+
+ @Override
+ protected String peerHostname(final Request request) {
+ return request.getRemoteHost();
+ }
+
+ @Override
+ protected String peerHostIP(final Request request) {
+ return request.getRemoteAddr();
+ }
+
+ @Override
+ protected Integer peerPort(final Request request) {
+ return request.getRemotePort();
+ }
+
+ @Override
+ protected Integer status(final Response containerResponse) {
+ return containerResponse.getStatus();
+ }
+
+ @Override
+ protected String[] instrumentationNames() {
+ return new String[] {"jersey"};
+ }
+
+ @Override
+ protected String component() {
+ return "jersey";
+ }
+}

ADD
dd-java-agent/instrumentation/grizzly-2/src/main/java/datadog/trace/instrumentation/grizzly/GrizzlyHttpHandlerInstrumentation.java
+package datadog.trace.instrumentation.grizzly;
+
+import static datadog.trace.instrumentation.grizzly.GrizzlyDecorator.DECORATE;
+import static io.opentracing.propagation.Format.Builtin.TEXT_MAP;
+import static java.util.Collections.singletonMap;
+import static net.bytebuddy.matcher.ElementMatchers.isMethod;
+import static net.bytebuddy.matcher.ElementMatchers.named;
+import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
+
+import com.google.auto.service.AutoService;
+import datadog.trace.agent.tooling.Instrumenter;
+import datadog.trace.context.TraceScope;
+import io.opentracing.Scope;
+import io.opentracing.Span;
+import io.opentracing.SpanContext;
+import io.opentracing.Tracer;
+import io.opentracing.util.GlobalTracer;
+import java.util.Map;
+import net.bytebuddy.asm.Advice;
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.description.type.TypeDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.glassfish.grizzly.http.server.AfterServiceListener;
+import org.glassfish.grizzly.http.server.Request;
+
+@AutoService(Instrumenter.class)
+public class GrizzlyHttpHandlerInstrumentation extends Instrumenter.Default {
+
+ public GrizzlyHttpHandlerInstrumentation() {
+ super("grizzly");
+ }
+
+ @Override
+ public ElementMatcher<TypeDescription> typeMatcher() {
+ return named("org.glassfish.grizzly.http.server.HttpHandler");
+ }
+
+ @Override
+ public String[] helperClassNames() {
+ return new String[] {
+ "datadog.trace.agent.decorator.BaseDecorator",
+ "datadog.trace.agent.decorator.ServerDecorator",
+ "datadog.trace.agent.decorator.HttpServerDecorator",
+ packageName + ".GrizzlyDecorator",
+ packageName + ".GrizzlyRequestExtractAdapter",
+ packageName + ".GrizzlyRequestExtractAdapter$MultivaluedMapFlatIterator",
+ getClass().getName() + "$SpanClosingListener"
+ };
+ }
+
+ @Override
+ public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
+ return singletonMap(
+ isMethod()
+ .and(named("doHandle"))
+ .and(takesArgument(0, named("org.glassfish.grizzly.http.server.Request")))
+ .and(takesArgument(1, named("org.glassfish.grizzly.http.server.Response"))),
+ HandleAdvice.class.getName());
+ }
+
+ public static class HandleAdvice {
+
+ @Advice.OnMethodEnter(suppress = Throwable.class)
+ public static Scope methodEnter(@Advice.Argument(0) final Request request) {
+ if (request.getAttribute(SpanClosingListener.GRIZZLY_SPAN_SPAN) != null) {
+ return null;
+ }
+
+ final Tracer tracer = GlobalTracer.get();
+ final SpanContext parentContext =
+ tracer.extract(TEXT_MAP, new GrizzlyRequestExtractAdapter(request));
+ final Span span =
+ tracer.buildSpan("grizzly.request").ignoreActiveSpan().asChildOf(parentContext).start();
+ DECORATE.afterStart(span);
+ DECORATE.onConnection(span, request);
+ DECORATE.onRequest(span, request);
+
+ final Scope scope = tracer.scopeManager().activate(span, false);
+ if (scope instanceof TraceScope) {
+ ((TraceScope) scope).setAsyncPropagation(true);
+ }
+
+ request.setAttribute(SpanClosingListener.GRIZZLY_SPAN_SPAN, span);
+ request.addAfterServiceListener(SpanClosingListener.LISTENER);
+
+ return scope;
+ }
+
+ @Advice.OnMethodExit(suppress = Throwable.class, onThrowable = Throwable.class)
+ public static void methodExit(
+ @Advice.Enter final Scope scope, @Advice.Thrown final Throwable throwable) {
+ if (scope == null) {
+ return;
+ }
+
+ if (throwable != null) {
+ final Span span = scope.span();
+ DECORATE.onError(span, throwable);
+ DECORATE.beforeFinish(span);
+ span.finish();
+ }
+ scope.close();
+ }
+ }
+
+ public static class SpanClosingListener implements AfterServiceListener {
+ public static final String GRIZZLY_SPAN_SPAN = "datadog.grizzly.span";
+ public static final SpanClosingListener LISTENER = new SpanClosingListener();
+
+ @Override
+ public void onAfterService(final Request request) {
+ final Object spanAttr = request.getAttribute(GRIZZLY_SPAN_SPAN);
+ if (spanAttr instanceof Span) {
+ request.removeAttribute(GRIZZLY_SPAN_SPAN);
+ final Span span = (Span) spanAttr;
+ DECORATE.onResponse(span, request.getResponse());
+ DECORATE.beforeFinish(span);
+ span.finish();
+ }
+ }
+ }
+}

ADD
dd-java-agent/instrumentation/grizzly-2/src/main/java/datadog/trace/instrumentation/grizzly/GrizzlyRequestExtractAdapter.java
+package datadog.trace.instrumentation.grizzly;
+
+import io.opentracing.propagation.TextMap;
+import java.util.AbstractMap;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.glassfish.grizzly.http.server.Request;
+
+public class GrizzlyRequestExtractAdapter implements TextMap {
+
+ private final Map<String, List<String>> headers;
+
+ public GrizzlyRequestExtractAdapter(final Request request) {
+ headers = headersToMultiMap(request);
+ }
+
+ @Override
+ public Iterator<Map.Entry<String, String>> iterator() {
+ return new MultivaluedMapFlatIterator<>(headers.entrySet());
+ }
+
+ @Override
+ public void put(final String key, final String value) {
+ throw new UnsupportedOperationException("This class should be used only with Tracer.inject()!");
+ }
+
+ protected Map<String, List<String>> headersToMultiMap(final Request request) {
+ final Map<String, List<String>> headersResult = new HashMap<>();
+
+ for (final String headerName : request.getHeaderNames()) {
+ final List<String> valuesList = new ArrayList<>(1);
+
+ for (final String values : request.getHeaders(headerName)) {
+ valuesList.add(values);
+ }
+ headersResult.put(headerName, valuesList);
+ }
+
+ return headersResult;
+ }
+
+ public static final class MultivaluedMapFlatIterator<K, V> implements Iterator<Map.Entry<K, V>> {
+
+ private final Iterator<Map.Entry<K, List<V>>> mapIterator;
+ private Map.Entry<K, List<V>> mapEntry;
+ private Iterator<V> listIterator;
+
+ public MultivaluedMapFlatIterator(final Set<Map.Entry<K, List<V>>> multiValuesEntrySet) {
+ mapIterator = multiValuesEntrySet.iterator();
+ }
+
+ @Override
+ public boolean hasNext() {
+ if (listIterator != null && listIterator.hasNext()) {
+ return true;
+ }
+
+ return mapIterator.hasNext();
+ }
+
+ @Override
+ public Map.Entry<K, V> next() {
+ if (mapEntry == null || (!listIterator.hasNext() && mapIterator.hasNext())) {
+ mapEntry = mapIterator.next();
+ listIterator = mapEntry.getValue().iterator();
+ }
+
+ if (listIterator.hasNext()) {
+ return new AbstractMap.SimpleImmutableEntry<>(mapEntry.getKey(), listIterator.next());
+ } else {
+ return new AbstractMap.SimpleImmutableEntry<>(mapEntry.getKey(), null);
+ }
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ }
+}

ADD
dd-java-agent/instrumentation/grizzly-2/src/test/groovy/GrizzlyAsyncTest.groovy
+import datadog.trace.agent.test.asserts.ListWriterAssert
+import groovy.transform.stc.ClosureParams
+import groovy.transform.stc.SimpleType
+import javax.ws.rs.GET
+import javax.ws.rs.Path
+import javax.ws.rs.container.AsyncResponse
+import javax.ws.rs.container.Suspended
+import javax.ws.rs.core.Response
+import org.glassfish.grizzly.http.server.HttpServer
+import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory
+import org.glassfish.jersey.server.ResourceConfig
+
+import java.util.concurrent.ExecutorService
+import java.util.concurrent.Executors
+
+import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.ERROR
+import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.EXCEPTION
+import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.REDIRECT
+import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.SUCCESS
+
+class GrizzlyAsyncTest extends GrizzlyTest {
+
+ @Override
+ HttpServer startServer(int port) {
+ ResourceConfig rc = new ResourceConfig()
+ rc.register(SimpleExceptionMapper)
+ rc.register(ServiceResource)
+ GrizzlyHttpServerFactory.createHttpServer(new URI("http://localhost:$port"), rc)
+ }
+
+ @Path("/")
+ static class ServiceResource {
+ private ExecutorService executor = Executors.newSingleThreadExecutor()
+
+ @GET
+ @Path("success")
+ void success(@Suspended AsyncResponse ar) {
+ executor.execute {
+ controller(SUCCESS) {
+ ar.resume(Response.status(SUCCESS.status).entity(SUCCESS.body).build())
+ }
+ }
+ }
+
+ @GET
+ @Path("redirect")
+ void redirect(@Suspended AsyncResponse ar) {
+ executor.execute {
+ controller(REDIRECT) {
+ ar.resume(Response.status(REDIRECT.status).location(new URI(REDIRECT.body)).build())
+ }
+ }
+ }
+
+ @GET
+ @Path("error")
+ void error(@Suspended AsyncResponse ar) {
+ executor.execute {
+ controller(ERROR) {
+ ar.resume(Response.status(ERROR.status).entity(ERROR.body).build())
+ }
+ }
+ }
+
+ @GET
+ @Path("exception")
+ void exception(@Suspended AsyncResponse ar) {
+ executor.execute {
+ try {
+ controller(EXCEPTION) {
+ throw new Exception(EXCEPTION.body)
+ }
+ } catch (Exception e) {
+ ar.resume(e)
+ }
+ }
+ }
+ }
+
+ void cleanAndAssertTraces(
+ final int size,
+ @ClosureParams(value = SimpleType, options = "datadog.trace.agent.test.asserts.ListWriterAssert")
+ @DelegatesTo(value = ListWriterAssert, strategy = Closure.DELEGATE_FIRST)
+ final Closure spec) {
+ // If this is failing, make sure HttpServerTestAdvice is applied correctly.
+ TEST_WRITER.waitForTraces(size * 2)
+
+ // AsyncResponse.resume closes the handler span before the controller returns, so we need to manually reorder it.
+ TEST_WRITER.each {
+ def controllerSpan = it.find {
+ it.operationName == "controller"
+ }
+ if (controllerSpan) {
+ it.remove(controllerSpan)
+ it.add(controllerSpan)
+ }
+ }
+ super.cleanAndAssertTraces(size, spec)
+ }
+}

ADD
dd-java-agent/instrumentation/grizzly-2/src/test/groovy/GrizzlyIOStrategyTest.groovy
+import org.glassfish.grizzly.IOStrategy
+import org.glassfish.grizzly.http.server.HttpServer
+import org.glassfish.grizzly.strategies.LeaderFollowerNIOStrategy
+import org.glassfish.grizzly.strategies.SameThreadIOStrategy
+import org.glassfish.grizzly.strategies.SimpleDynamicNIOStrategy
+import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory
+import org.glassfish.jersey.server.ResourceConfig
+
+abstract class GrizzlyIOStrategyTest extends GrizzlyTest {
+ @Override
+ HttpServer startServer(int port) {
+ ResourceConfig rc = new ResourceConfig()
+ rc.register(SimpleExceptionMapper)
+ rc.register(ServiceResource)
+ def server = GrizzlyHttpServerFactory.createHttpServer(new URI("http://localhost:$port"), rc)
+ server.getListener("grizzly").getTransport().setIOStrategy(strategy())
+ // Default in NIOTransportBuilder is WorkerThreadIOStrategy, so don't need to retest that.s
+ return server
+ }
+
+ abstract IOStrategy strategy()
+}
+
+class LeaderFollowerTest extends GrizzlyIOStrategyTest {
+
+ @Override
+ IOStrategy strategy() {
+ return LeaderFollowerNIOStrategy.instance
+ }
+}
+
+class SameThreadTest extends GrizzlyIOStrategyTest {
+
+ @Override
+ IOStrategy strategy() {
+ return SameThreadIOStrategy.instance
+ }
+}
+
+class SimpleDynamicTest extends GrizzlyIOStrategyTest {
+
+ @Override
+ IOStrategy strategy() {
+ return SimpleDynamicNIOStrategy.instance
+ }
+}

ADD
dd-java-agent/instrumentation/grizzly-2/src/test/groovy/GrizzlyTest.groovy
+import datadog.trace.agent.test.base.HttpServerTest
+import datadog.trace.instrumentation.grizzly.GrizzlyDecorator
+import javax.ws.rs.GET
+import javax.ws.rs.NotFoundException
+import javax.ws.rs.Path
+import javax.ws.rs.core.Response
+import javax.ws.rs.ext.ExceptionMapper
+import org.glassfish.grizzly.http.server.HttpServer
+import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory
+import org.glassfish.jersey.server.ResourceConfig
+
+import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.ERROR
+import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.EXCEPTION
+import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.REDIRECT
+import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.SUCCESS
+
+class GrizzlyTest extends HttpServerTest<HttpServer, GrizzlyDecorator> {
+
+ @Override
+ HttpServer startServer(int port) {
+ ResourceConfig rc = new ResourceConfig()
+ rc.register(SimpleExceptionMapper)
+ rc.register(ServiceResource)
+ GrizzlyHttpServerFactory.createHttpServer(new URI("http://localhost:$port"), rc)
+ }
+
+ @Override
+ void stopServer(HttpServer server) {
+ server.stop()
+ }
+
+ @Override
+ GrizzlyDecorator decorator() {
+ return GrizzlyDecorator.DECORATE
+ }
+
+ @Override
+ String expectedOperationName() {
+ return "grizzly.request"
+ }
+
+ static class SimpleExceptionMapper implements ExceptionMapper<Throwable> {
+
+ @Override
+ Response toResponse(Throwable exception) {
+ if (exception instanceof NotFoundException) {
+ return exception.getResponse()
+ }
+ Response.status(500).entity(exception.message).build()
+ }
+ }
+
+ @Path("/")
+ static class ServiceResource {
+
+ @GET
+ @Path("success")
+ Response success() {
+ controller(SUCCESS) {
+ Response.status(SUCCESS.status).entity(SUCCESS.body).build()
+ }
+ }
+
+ @GET
+ @Path("redirect")
+ Response redirect() {
+ controller(REDIRECT) {
+ Response.status(REDIRECT.status).location(new URI(REDIRECT.body)).build()
+ }
+ }
+
+ @GET
+ @Path("error")
+ Response error() {
+ controller(ERROR) {
+ Response.status(ERROR.status).entity(ERROR.body).build()
+ }
+ }
+
+ @GET
+ @Path("exception")
+ Response exception() {
+ controller(EXCEPTION) {
+ throw new Exception(EXCEPTION.body)
+ }
+ return null
+ }
+ }
+}

ADD
dd-java-agent/instrumentation/grizzly-2/src/test/groovy/GrizzlyTestInstrumentation.java
+import static net.bytebuddy.matcher.ElementMatchers.named;
+
+import com.google.auto.service.AutoService;
+import datadog.trace.agent.test.base.HttpServerTestAdvice;
+import datadog.trace.agent.tooling.Instrumenter;
+import net.bytebuddy.agent.builder.AgentBuilder;
+
+@AutoService(Instrumenter.class)
+public class GrizzlyTestInstrumentation implements Instrumenter {
+
+ @Override
+ public AgentBuilder instrument(final AgentBuilder agentBuilder) {
+ return agentBuilder
+ .type(named("org.glassfish.grizzly.http.server.HttpHandlerChain"))
+ .transform(
+ new AgentBuilder.Transformer.ForAdvice()
+ .advice(named("doHandle"), HttpServerTestAdvice.ServerEntryAdvice.class.getName()));
+ }
+}

MODIFY
dd-java-agent/instrumentation/java-concurrent/src/main/java/datadog/trace/instrumentation/java/concurrent/AbstractExecutorInstrumentation.java
dd-java-agent/instrumentation/java-concurrent/src/main/java/datadog/trace/instrumentation/java/concurrent/AbstractExecutorInstrumentation.java
@@ -44,44 +44,45 @@ public abstract class AbstractExecutorInstrumentation extends Instrumenter.Defau
WHITELISTED_EXECUTORS_PREFIXES = Collections.emptyList();
} else {
final String[] whitelist = {
- "java.util.concurrent.AbstractExecutorService",
- "java.util.concurrent.ThreadPoolExecutor",
- "java.util.concurrent.ScheduledThreadPoolExecutor",
- "java.util.concurrent.ForkJoinPool",
- "java.util.concurrent.Executors$FinalizableDelegatedExecutorService",
- "java.util.concurrent.Executors$DelegatedExecutorService",
- "javax.management.NotificationBroadcasterSupport$1",
- "kotlinx.coroutines.scheduling.CoroutineScheduler",
- "scala.concurrent.Future$InternalCallbackExecutor$",
- "scala.concurrent.impl.ExecutionContextImpl",
- "scala.concurrent.impl.ExecutionContextImpl$$anon$1",
- "scala.concurrent.forkjoin.ForkJoinPool",
- "scala.concurrent.impl.ExecutionContextImpl$$anon$3",
- "akka.dispatch.MessageDispatcher",
+ "akka.actor.ActorSystemImpl$$anon$1",
+ "akka.dispatch.BalancingDispatcher",
"akka.dispatch.Dispatcher",
"akka.dispatch.Dispatcher$LazyExecutorServiceDelegate",
- "akka.actor.ActorSystemImpl$$anon$1",
- "akka.dispatch.ForkJoinExecutorConfigurator$AkkaForkJoinPool",
+ "akka.dispatch.ExecutionContexts$sameThreadExecutionContext$",
"akka.dispatch.forkjoin.ForkJoinPool",
- "akka.dispatch.BalancingDispatcher",
- "akka.dispatch.ThreadPoolConfig$ThreadPoolExecutorServiceFactory$$anon$1",
+ "akka.dispatch.ForkJoinExecutorConfigurator$AkkaForkJoinPool",
+ "akka.dispatch.MessageDispatcher",
"akka.dispatch.PinnedDispatcher",
- "akka.dispatch.ExecutionContexts$sameThreadExecutionContext$",
- "play.api.libs.streams.Execution$trampoline$",
- "io.netty.channel.MultithreadEventLoopGroup",
- "io.netty.util.concurrent.MultithreadEventExecutorGroup",
- "io.netty.util.concurrent.AbstractEventExecutorGroup",
+ "akka.dispatch.ThreadPoolConfig$ThreadPoolExecutorServiceFactory$$anon$1",
+ "com.google.common.util.concurrent.AbstractListeningExecutorService",
+ "com.google.common.util.concurrent.MoreExecutors$ListeningDecorator",
+ "com.google.common.util.concurrent.MoreExecutors$ScheduledListeningDecorator",
"io.netty.channel.epoll.EpollEventLoopGroup",
+ "io.netty.channel.MultithreadEventLoopGroup",
+ "io.netty.channel.nio.NioEventLoop",
"io.netty.channel.nio.NioEventLoopGroup",
- "io.netty.util.concurrent.GlobalEventExecutor",
- "io.netty.util.concurrent.AbstractScheduledEventExecutor",
+ "io.netty.channel.SingleThreadEventLoop",
"io.netty.util.concurrent.AbstractEventExecutor",
+ "io.netty.util.concurrent.AbstractEventExecutorGroup",
+ "io.netty.util.concurrent.AbstractScheduledEventExecutor",
+ "io.netty.util.concurrent.GlobalEventExecutor",
+ "io.netty.util.concurrent.MultithreadEventExecutorGroup",
"io.netty.util.concurrent.SingleThreadEventExecutor",
- "io.netty.channel.nio.NioEventLoop",
- "io.netty.channel.SingleThreadEventLoop",
- "com.google.common.util.concurrent.AbstractListeningExecutorService",
- "com.google.common.util.concurrent.MoreExecutors$ListeningDecorator",
- "com.google.common.util.concurrent.MoreExecutors$ScheduledListeningDecorator",
+ "java.util.concurrent.AbstractExecutorService",
+ "java.util.concurrent.Executors$DelegatedExecutorService",
+ "java.util.concurrent.Executors$FinalizableDelegatedExecutorService",
+ "java.util.concurrent.ForkJoinPool",
+ "java.util.concurrent.ScheduledThreadPoolExecutor",
+ "java.util.concurrent.ThreadPoolExecutor",
+ "javax.management.NotificationBroadcasterSupport$1",
+ "kotlinx.coroutines.scheduling.CoroutineScheduler",
+ "org.glassfish.grizzly.threadpool.GrizzlyExecutorService",
+ "play.api.libs.streams.Execution$trampoline$",
+ "scala.concurrent.forkjoin.ForkJoinPool",
+ "scala.concurrent.Future$InternalCallbackExecutor$",
+ "scala.concurrent.impl.ExecutionContextImpl",
+ "scala.concurrent.impl.ExecutionContextImpl$$anon$1",
+ "scala.concurrent.impl.ExecutionContextImpl$$anon$3",
};
final Set<String> executors = new HashSet<>(Config.get().getTraceExecutors());

MODIFY
settings.gradle
settings.gradle
@@ -43,6 +43,7 @@ include ':dd-java-agent:instrumentation:elasticsearch:transport-5.3'
include ':dd-java-agent:instrumentation:elasticsearch:transport-6'
include ':dd-java-agent:instrumentation:glassfish'
include ':dd-java-agent:instrumentation:google-http-client'
+include ':dd-java-agent:instrumentation:grizzly-2'
include ':dd-java-agent:instrumentation:grpc-1.5'
include ':dd-java-agent:instrumentation:hibernate'
include ':dd-java-agent:instrumentation:hibernate:core-3.3'

Add instrumentation and tests for Grizzly 2.x Http Server