Merge pull request #948 from DataDog/tyler/grizzly
Add instrumentation and tests for Grizzly 2.x Http Server
This commit is contained in:
commit
473aca7c08
|
@ -0,0 +1,35 @@
|
||||||
|
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: '+'
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
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[] {"grizzly"};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String component() {
|
||||||
|
return "grizzly";
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,122 @@
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,84 @@
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,100 @@
|
||||||
|
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(AsyncServiceResource)
|
||||||
|
GrizzlyHttpServerFactory.createHttpServer(new URI("http://localhost:$port"), rc)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Path("/")
|
||||||
|
static class AsyncServiceResource {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,89 @@
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
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()));
|
||||||
|
}
|
||||||
|
}
|
|
@ -44,44 +44,45 @@ public abstract class AbstractExecutorInstrumentation extends Instrumenter.Defau
|
||||||
WHITELISTED_EXECUTORS_PREFIXES = Collections.emptyList();
|
WHITELISTED_EXECUTORS_PREFIXES = Collections.emptyList();
|
||||||
} else {
|
} else {
|
||||||
final String[] whitelist = {
|
final String[] whitelist = {
|
||||||
"java.util.concurrent.AbstractExecutorService",
|
"akka.actor.ActorSystemImpl$$anon$1",
|
||||||
"java.util.concurrent.ThreadPoolExecutor",
|
"akka.dispatch.BalancingDispatcher",
|
||||||
"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.dispatch.Dispatcher",
|
"akka.dispatch.Dispatcher",
|
||||||
"akka.dispatch.Dispatcher$LazyExecutorServiceDelegate",
|
"akka.dispatch.Dispatcher$LazyExecutorServiceDelegate",
|
||||||
"akka.actor.ActorSystemImpl$$anon$1",
|
|
||||||
"akka.dispatch.ForkJoinExecutorConfigurator$AkkaForkJoinPool",
|
|
||||||
"akka.dispatch.forkjoin.ForkJoinPool",
|
|
||||||
"akka.dispatch.BalancingDispatcher",
|
|
||||||
"akka.dispatch.ThreadPoolConfig$ThreadPoolExecutorServiceFactory$$anon$1",
|
|
||||||
"akka.dispatch.PinnedDispatcher",
|
|
||||||
"akka.dispatch.ExecutionContexts$sameThreadExecutionContext$",
|
"akka.dispatch.ExecutionContexts$sameThreadExecutionContext$",
|
||||||
"play.api.libs.streams.Execution$trampoline$",
|
"akka.dispatch.forkjoin.ForkJoinPool",
|
||||||
"io.netty.channel.MultithreadEventLoopGroup",
|
"akka.dispatch.ForkJoinExecutorConfigurator$AkkaForkJoinPool",
|
||||||
"io.netty.util.concurrent.MultithreadEventExecutorGroup",
|
"akka.dispatch.MessageDispatcher",
|
||||||
"io.netty.util.concurrent.AbstractEventExecutorGroup",
|
"akka.dispatch.PinnedDispatcher",
|
||||||
"io.netty.channel.epoll.EpollEventLoopGroup",
|
"akka.dispatch.ThreadPoolConfig$ThreadPoolExecutorServiceFactory$$anon$1",
|
||||||
"io.netty.channel.nio.NioEventLoopGroup",
|
|
||||||
"io.netty.util.concurrent.GlobalEventExecutor",
|
|
||||||
"io.netty.util.concurrent.AbstractScheduledEventExecutor",
|
|
||||||
"io.netty.util.concurrent.AbstractEventExecutor",
|
|
||||||
"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.AbstractListeningExecutorService",
|
||||||
"com.google.common.util.concurrent.MoreExecutors$ListeningDecorator",
|
"com.google.common.util.concurrent.MoreExecutors$ListeningDecorator",
|
||||||
"com.google.common.util.concurrent.MoreExecutors$ScheduledListeningDecorator",
|
"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.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",
|
||||||
|
"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());
|
final Set<String> executors = new HashSet<>(Config.get().getTraceExecutors());
|
||||||
|
|
|
@ -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:elasticsearch:transport-6'
|
||||||
include ':dd-java-agent:instrumentation:glassfish'
|
include ':dd-java-agent:instrumentation:glassfish'
|
||||||
include ':dd-java-agent:instrumentation:google-http-client'
|
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:grpc-1.5'
|
||||||
include ':dd-java-agent:instrumentation:hibernate'
|
include ':dd-java-agent:instrumentation:hibernate'
|
||||||
include ':dd-java-agent:instrumentation:hibernate:core-3.3'
|
include ':dd-java-agent:instrumentation:hibernate:core-3.3'
|
||||||
|
|
Loading…
Reference in New Issue