Convert Jetty 8.0 groovy to java (#7975)
related to https://github.com/open-telemetry/opentelemetry-java-instrumentation/issues/7195
This commit is contained in:
parent
995baa8888
commit
468aa9e777
|
@ -29,3 +29,11 @@ dependencies {
|
|||
latestDepTestLibrary("org.eclipse.jetty:jetty-server:10.+") // see jetty-11.0 module
|
||||
latestDepTestLibrary("org.eclipse.jetty:jetty-servlet:10.+") // see jetty-11.0 module
|
||||
}
|
||||
|
||||
// jetty-server 10+ requires Java 11
|
||||
val latestDepTest = findProperty("testLatestDeps") as Boolean
|
||||
if (latestDepTest) {
|
||||
otelJava {
|
||||
minJavaVersionSupported.set(JavaVersion.VERSION_11)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,144 +0,0 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import io.opentelemetry.api.common.AttributeKey
|
||||
import io.opentelemetry.instrumentation.test.AgentTestTrait
|
||||
import io.opentelemetry.instrumentation.test.asserts.TraceAssert
|
||||
import io.opentelemetry.instrumentation.test.base.HttpServerTest
|
||||
import io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint
|
||||
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes
|
||||
import org.eclipse.jetty.server.Request
|
||||
import org.eclipse.jetty.server.Response
|
||||
import org.eclipse.jetty.server.Server
|
||||
import org.eclipse.jetty.server.handler.AbstractHandler
|
||||
import org.eclipse.jetty.server.handler.ErrorHandler
|
||||
import spock.lang.Shared
|
||||
|
||||
import javax.servlet.DispatcherType
|
||||
import javax.servlet.ServletException
|
||||
import javax.servlet.http.HttpServletRequest
|
||||
import javax.servlet.http.HttpServletResponse
|
||||
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.CAPTURE_HEADERS
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.ERROR
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.EXCEPTION
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.INDEXED_CHILD
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.NOT_FOUND
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.QUERY_PARAM
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.REDIRECT
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.SUCCESS
|
||||
|
||||
class JettyHandlerTest extends HttpServerTest<Server> implements AgentTestTrait {
|
||||
|
||||
static ErrorHandler errorHandler = new ErrorHandler() {
|
||||
@Override
|
||||
protected void handleErrorPage(HttpServletRequest request, Writer writer, int code, String message) throws IOException {
|
||||
Throwable th = (Throwable) request.getAttribute("javax.servlet.error.exception")
|
||||
message = th ? th.message : message
|
||||
if (message) {
|
||||
writer.write(message)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Shared
|
||||
TestHandler testHandler = new TestHandler()
|
||||
|
||||
@Override
|
||||
Server startServer(int port) {
|
||||
def server = new Server(port)
|
||||
server.setHandler(handler())
|
||||
server.addBean(errorHandler)
|
||||
server.start()
|
||||
return server
|
||||
}
|
||||
|
||||
AbstractHandler handler() {
|
||||
testHandler
|
||||
}
|
||||
|
||||
@Override
|
||||
void stopServer(Server server) {
|
||||
server.stop()
|
||||
}
|
||||
|
||||
@Override
|
||||
Set<AttributeKey<?>> httpAttributes(ServerEndpoint endpoint) {
|
||||
def attributes = super.httpAttributes(endpoint)
|
||||
attributes.remove(SemanticAttributes.HTTP_ROUTE)
|
||||
attributes
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean hasResponseSpan(ServerEndpoint endpoint) {
|
||||
endpoint == REDIRECT || endpoint == ERROR
|
||||
}
|
||||
|
||||
@Override
|
||||
void responseSpan(TraceAssert trace, int index, Object parent, String method, ServerEndpoint endpoint) {
|
||||
switch (endpoint) {
|
||||
case REDIRECT:
|
||||
redirectSpan(trace, index, parent)
|
||||
break
|
||||
case ERROR:
|
||||
sendErrorSpan(trace, index, parent)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
static void handleRequest(Request request, HttpServletResponse response) {
|
||||
ServerEndpoint endpoint = ServerEndpoint.forPath(request.requestURI)
|
||||
controller(endpoint) {
|
||||
response.contentType = "text/plain"
|
||||
switch (endpoint) {
|
||||
case SUCCESS:
|
||||
response.status = endpoint.status
|
||||
response.writer.print(endpoint.body)
|
||||
break
|
||||
case QUERY_PARAM:
|
||||
response.status = endpoint.status
|
||||
response.writer.print(request.queryString)
|
||||
break
|
||||
case REDIRECT:
|
||||
response.sendRedirect(endpoint.body)
|
||||
break
|
||||
case ERROR:
|
||||
response.sendError(endpoint.status, endpoint.body)
|
||||
break
|
||||
case CAPTURE_HEADERS:
|
||||
response.setHeader("X-Test-Response", request.getHeader("X-Test-Request"))
|
||||
response.status = endpoint.status
|
||||
response.writer.print(endpoint.body)
|
||||
break
|
||||
case EXCEPTION:
|
||||
throw new Exception(endpoint.body)
|
||||
case INDEXED_CHILD:
|
||||
INDEXED_CHILD.collectSpanAttributes { name -> request.getParameter(name) }
|
||||
response.status = endpoint.status
|
||||
response.writer.print(endpoint.body)
|
||||
break
|
||||
default:
|
||||
response.status = NOT_FOUND.status
|
||||
response.writer.print(NOT_FOUND.body)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class TestHandler extends AbstractHandler {
|
||||
@Override
|
||||
void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
|
||||
//This line here is to verify that we don't break Jetty if it wants to cast to implementation class
|
||||
//See https://github.com/open-telemetry/opentelemetry-java-instrumentation/issues/1096
|
||||
Response jettyResponse = response as Response
|
||||
if (baseRequest.dispatcherType != DispatcherType.ERROR) {
|
||||
handleRequest(baseRequest, jettyResponse)
|
||||
baseRequest.handled = true
|
||||
} else {
|
||||
errorHandler.handle(target, baseRequest, baseRequest, response)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,98 +0,0 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import io.opentelemetry.api.trace.SpanKind
|
||||
import io.opentelemetry.instrumentation.test.AgentInstrumentationSpecification
|
||||
import org.eclipse.jetty.util.thread.QueuedThreadPool
|
||||
|
||||
import static org.junit.jupiter.api.Assumptions.assumeTrue
|
||||
|
||||
class QueuedThreadPoolTest extends AgentInstrumentationSpecification {
|
||||
|
||||
def "QueueThreadPool 'dispatch' propagates"() {
|
||||
setup:
|
||||
def pool = new QueuedThreadPool()
|
||||
// run test only if QueuedThreadPool has dispatch method
|
||||
// dispatch method was removed in jetty 9.1
|
||||
assumeTrue(pool.metaClass.getMetaMethod("dispatch", Runnable) != null)
|
||||
pool.start()
|
||||
|
||||
new Runnable() {
|
||||
@Override
|
||||
void run() {
|
||||
runWithSpan("parent") {
|
||||
// this child will have a span
|
||||
def child1 = new JavaAsyncChild()
|
||||
// this child won't
|
||||
def child2 = new JavaAsyncChild(false, false)
|
||||
pool.dispatch(child1)
|
||||
pool.dispatch(child2)
|
||||
child1.waitForCompletion()
|
||||
child2.waitForCompletion()
|
||||
}
|
||||
}
|
||||
}.run()
|
||||
|
||||
expect:
|
||||
assertTraces(1) {
|
||||
trace(0, 2) {
|
||||
span(0) {
|
||||
name "parent"
|
||||
kind SpanKind.INTERNAL
|
||||
hasNoParent()
|
||||
}
|
||||
span(1) {
|
||||
name "asyncChild"
|
||||
kind SpanKind.INTERNAL
|
||||
childOf span(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cleanup:
|
||||
pool.stop()
|
||||
}
|
||||
|
||||
def "QueueThreadPool 'dispatch' propagates lambda"() {
|
||||
setup:
|
||||
def pool = new QueuedThreadPool()
|
||||
// run test only if QueuedThreadPool has dispatch method
|
||||
// dispatch method was removed in jetty 9.1
|
||||
assumeTrue(pool.metaClass.getMetaMethod("dispatch", Runnable) != null)
|
||||
pool.start()
|
||||
|
||||
JavaAsyncChild child = new JavaAsyncChild(true, true)
|
||||
new Runnable() {
|
||||
@Override
|
||||
void run() {
|
||||
runWithSpan("parent") {
|
||||
pool.dispatch(JavaLambdaMaker.lambda(child))
|
||||
}
|
||||
}
|
||||
}.run()
|
||||
// We block in child to make sure spans close in predictable order
|
||||
child.unblock()
|
||||
child.waitForCompletion()
|
||||
|
||||
expect:
|
||||
assertTraces(1) {
|
||||
trace(0, 2) {
|
||||
span(0) {
|
||||
name "parent"
|
||||
kind SpanKind.INTERNAL
|
||||
hasNoParent()
|
||||
}
|
||||
span(1) {
|
||||
name "asyncChild"
|
||||
kind SpanKind.INTERNAL
|
||||
childOf span(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cleanup:
|
||||
pool.stop()
|
||||
}
|
||||
}
|
|
@ -3,6 +3,8 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.javaagent.instrumentation.jetty.v8_0;
|
||||
|
||||
import io.opentelemetry.api.GlobalOpenTelemetry;
|
||||
import io.opentelemetry.api.trace.Tracer;
|
||||
import java.util.concurrent.Callable;
|
|
@ -3,6 +3,8 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.javaagent.instrumentation.jetty.v8_0;
|
||||
|
||||
public class JavaLambdaMaker {
|
||||
|
||||
@SuppressWarnings("FunctionalExpressionCanBeFolded")
|
|
@ -0,0 +1,175 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.javaagent.instrumentation.jetty.v8_0;
|
||||
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.HttpServerTestOptions.DEFAULT_HTTP_ATTRIBUTES;
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.ERROR;
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.EXCEPTION;
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.INDEXED_CHILD;
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.NOT_FOUND;
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.REDIRECT;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import io.opentelemetry.api.common.Attributes;
|
||||
import io.opentelemetry.api.trace.SpanKind;
|
||||
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
|
||||
import io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpServerTest;
|
||||
import io.opentelemetry.instrumentation.testing.junit.http.HttpServerInstrumentationExtension;
|
||||
import io.opentelemetry.instrumentation.testing.junit.http.HttpServerTestOptions;
|
||||
import io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint;
|
||||
import io.opentelemetry.sdk.testing.assertj.SpanDataAssert;
|
||||
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.util.Collections;
|
||||
import javax.servlet.DispatcherType;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Response;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
import org.eclipse.jetty.server.handler.ErrorHandler;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
|
||||
public class JettyHandlerTest extends AbstractHttpServerTest<Server> {
|
||||
|
||||
@RegisterExtension
|
||||
static final InstrumentationExtension testing = HttpServerInstrumentationExtension.forAgent();
|
||||
|
||||
private static final ErrorHandler errorHandler =
|
||||
new ErrorHandler() {
|
||||
@Override
|
||||
protected void handleErrorPage(
|
||||
HttpServletRequest request, Writer writer, int code, String message)
|
||||
throws IOException {
|
||||
Throwable th = (Throwable) request.getAttribute("javax.servlet.error.exception");
|
||||
String errorMsg = th != null ? th.getMessage() : message;
|
||||
if (errorMsg != null) {
|
||||
writer.write(errorMsg);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private static final TestHandler testHandler = new TestHandler();
|
||||
|
||||
@Override
|
||||
protected Server setupServer() {
|
||||
Server server = new Server(port);
|
||||
server.setHandler(testHandler);
|
||||
server.addBean(errorHandler);
|
||||
try {
|
||||
server.start();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return server;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void stopServer(Server server) {
|
||||
try {
|
||||
server.stop();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(HttpServerTestOptions options) {
|
||||
options.setHttpAttributes(
|
||||
unused ->
|
||||
Sets.difference(
|
||||
DEFAULT_HTTP_ATTRIBUTES, Collections.singleton(SemanticAttributes.HTTP_ROUTE)));
|
||||
options.setHasResponseSpan(endpoint -> endpoint == REDIRECT || endpoint == ERROR);
|
||||
options.setExpectedException(new IllegalStateException(EXCEPTION.getBody()));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SpanDataAssert assertResponseSpan(
|
||||
SpanDataAssert span, String method, ServerEndpoint endpoint) {
|
||||
if (endpoint == REDIRECT) {
|
||||
span.satisfies(spanData -> assertThat(spanData.getName()).endsWith(".sendRedirect"));
|
||||
} else if (endpoint == ERROR) {
|
||||
span.satisfies(spanData -> assertThat(spanData.getName()).endsWith(".sendError"));
|
||||
}
|
||||
span.hasKind(SpanKind.INTERNAL).hasAttributesSatisfying(Attributes::isEmpty);
|
||||
return span;
|
||||
}
|
||||
|
||||
private static void handleRequest(Request request, HttpServletResponse response) {
|
||||
ServerEndpoint endpoint = ServerEndpoint.forPath(request.getRequestURI());
|
||||
controller(
|
||||
endpoint,
|
||||
() -> {
|
||||
try {
|
||||
return response(request, response, endpoint);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static HttpServletResponse response(
|
||||
Request request, HttpServletResponse response, ServerEndpoint endpoint) throws IOException {
|
||||
response.setContentType("text/plain");
|
||||
switch (endpoint) {
|
||||
case SUCCESS:
|
||||
response.setStatus(endpoint.getStatus());
|
||||
response.getWriter().print(endpoint.getBody());
|
||||
break;
|
||||
case QUERY_PARAM:
|
||||
response.setStatus(endpoint.getStatus());
|
||||
response.getWriter().print(request.getQueryString());
|
||||
break;
|
||||
case REDIRECT:
|
||||
response.sendRedirect(endpoint.getBody());
|
||||
break;
|
||||
case ERROR:
|
||||
response.sendError(endpoint.getStatus(), endpoint.getBody());
|
||||
break;
|
||||
case CAPTURE_HEADERS:
|
||||
response.setHeader("X-Test-Response", request.getHeader("X-Test-Request"));
|
||||
response.setStatus(endpoint.getStatus());
|
||||
response.getWriter().print(endpoint.getBody());
|
||||
break;
|
||||
case EXCEPTION:
|
||||
throw new IllegalStateException(endpoint.getBody());
|
||||
case INDEXED_CHILD:
|
||||
INDEXED_CHILD.collectSpanAttributes(name -> request.getParameter(name));
|
||||
response.setStatus(endpoint.getStatus());
|
||||
response.getWriter().print(endpoint.getBody());
|
||||
break;
|
||||
default:
|
||||
response.setStatus(NOT_FOUND.getStatus());
|
||||
response.getWriter().print(NOT_FOUND.getBody());
|
||||
break;
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
private static class TestHandler extends AbstractHandler {
|
||||
@Override
|
||||
public void handle(
|
||||
String target,
|
||||
Request baseRequest,
|
||||
HttpServletRequest request,
|
||||
HttpServletResponse response)
|
||||
throws IOException, ServletException {
|
||||
// This line here is to verify that we don't break Jetty if it wants to cast to implementation
|
||||
// class
|
||||
Response jettyResponse = (Response) response;
|
||||
if (baseRequest.getDispatcherType() != DispatcherType.ERROR) {
|
||||
handleRequest(baseRequest, jettyResponse);
|
||||
baseRequest.setHandled(true);
|
||||
} else {
|
||||
errorHandler.handle(target, baseRequest, baseRequest, response);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.javaagent.instrumentation.jetty.v8_0;
|
||||
|
||||
import static org.junit.jupiter.api.Assumptions.assumeTrue;
|
||||
|
||||
import io.opentelemetry.api.trace.SpanKind;
|
||||
import io.opentelemetry.instrumentation.testing.junit.AgentInstrumentationExtension;
|
||||
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
|
||||
import java.lang.reflect.Method;
|
||||
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
|
||||
class QueuedThreadPoolTest {
|
||||
|
||||
@RegisterExtension
|
||||
private static final InstrumentationExtension testing = AgentInstrumentationExtension.create();
|
||||
|
||||
@Test
|
||||
void dispatchPropagates() throws Exception {
|
||||
QueuedThreadPool pool = new QueuedThreadPool();
|
||||
// run test only if QueuedThreadPool has dispatch method
|
||||
// dispatch method was removed in jetty 9.1
|
||||
Method dispatch = null;
|
||||
try {
|
||||
dispatch = QueuedThreadPool.class.getMethod("dispatch", Runnable.class);
|
||||
} catch (NoSuchMethodException ignore) {
|
||||
// ignore
|
||||
}
|
||||
assumeTrue(dispatch != null);
|
||||
pool.start();
|
||||
|
||||
Method finalDispatch = dispatch;
|
||||
testing.runWithSpan(
|
||||
"parent",
|
||||
() -> {
|
||||
// this child will have a span
|
||||
JavaAsyncChild child1 = new JavaAsyncChild();
|
||||
// this child won't
|
||||
JavaAsyncChild child2 = new JavaAsyncChild(false, false);
|
||||
if (finalDispatch != null) {
|
||||
finalDispatch.invoke(pool, child1);
|
||||
finalDispatch.invoke(pool, child2);
|
||||
child1.waitForCompletion();
|
||||
child2.waitForCompletion();
|
||||
}
|
||||
});
|
||||
|
||||
testing.waitAndAssertTraces(
|
||||
trace ->
|
||||
trace.hasSpansSatisfyingExactlyInAnyOrder(
|
||||
span -> span.hasName("parent").hasKind(SpanKind.INTERNAL).hasNoParent(),
|
||||
span ->
|
||||
span.hasName("asyncChild")
|
||||
.hasKind(SpanKind.INTERNAL)
|
||||
.hasParent(trace.getSpan(0))));
|
||||
|
||||
pool.stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
void dispatchPropagatesLambda() throws Exception {
|
||||
QueuedThreadPool pool = new QueuedThreadPool();
|
||||
// run test only if QueuedThreadPool has dispatch method
|
||||
// dispatch method was removed in jetty 9.1
|
||||
Method dispatch = null;
|
||||
try {
|
||||
dispatch = QueuedThreadPool.class.getMethod("dispatch", Runnable.class);
|
||||
} catch (NoSuchMethodException ignore) {
|
||||
// ignore
|
||||
}
|
||||
assumeTrue(dispatch != null);
|
||||
pool.start();
|
||||
|
||||
JavaAsyncChild child = new JavaAsyncChild(true, true);
|
||||
Method finalDispatch = dispatch;
|
||||
testing.runWithSpan(
|
||||
"parent",
|
||||
() -> {
|
||||
if (finalDispatch != null) {
|
||||
finalDispatch.invoke(pool, JavaLambdaMaker.lambda(child));
|
||||
}
|
||||
});
|
||||
|
||||
// We block in child to make sure spans close in predictable order
|
||||
child.unblock();
|
||||
child.waitForCompletion();
|
||||
|
||||
testing.waitAndAssertTraces(
|
||||
trace ->
|
||||
trace.hasSpansSatisfyingExactlyInAnyOrder(
|
||||
span -> span.hasName("parent").hasKind(SpanKind.INTERNAL).hasNoParent(),
|
||||
span ->
|
||||
span.hasName("asyncChild")
|
||||
.hasKind(SpanKind.INTERNAL)
|
||||
.hasParent(trace.getSpan(0))));
|
||||
|
||||
pool.stop();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue