Add instrumentation for jetty 12 (#10575)
Co-authored-by: Jean Bisutti <jean.bisutti@gmail.com>
This commit is contained in:
parent
86c3263868
commit
c8f2cc5a9b
|
@ -175,17 +175,26 @@ These are the supported libraries and frameworks:
|
|||
|
||||
These are the application servers that the smoke tests are run against:
|
||||
|
||||
| Application server | Version | JVM | OS |
|
||||
| ------------------------------------------------------------------------------------- | --------------------------- | ----------------- | ------------------------------------- |
|
||||
| [Jetty](https://www.eclipse.org/jetty/) | 9.4.x, 10.0.x, 11.0.x | OpenJDK 8, 11, 17 | [`ubuntu-latest`], [`windows-latest`] |
|
||||
| [Payara](https://www.payara.fish/) | 5.0.x, 5.1.x | OpenJDK 8, 11 | [`ubuntu-latest`], [`windows-latest`] |
|
||||
| [Tomcat](http://tomcat.apache.org/) | 7.0.x | OpenJDK 8 | [`ubuntu-latest`], [`windows-latest`] |
|
||||
| [Tomcat](http://tomcat.apache.org/) | 7.0.x, 8.5.x, 9.0.x, 10.0.x | OpenJDK 8, 11, 17 | [`ubuntu-latest`], [`windows-latest`] |
|
||||
| [TomEE](https://tomee.apache.org/) | 7.x, 8.x | OpenJDK 8, 11, 17 | [`ubuntu-latest`], [`windows-latest`] |
|
||||
| [Open Liberty](https://openliberty.io/) | 21.x, 22.x, 23.x | OpenJDK 8, 11, 17 | [`ubuntu-latest`], [`windows-latest`] |
|
||||
| [Websphere Traditional](https://www.ibm.com/uk-en/cloud/websphere-application-server) | 8.5.5.x, 9.0.x | IBM JDK 8 | Red Hat Enterprise Linux 8.4 |
|
||||
| [WildFly](https://www.wildfly.org/) | 13.x | OpenJDK 8 | [`ubuntu-latest`], [`windows-latest`] |
|
||||
| [WildFly](https://www.wildfly.org/) | 17.x, 21.x, 25.x | OpenJDK 8, 11, 17 | [`ubuntu-latest`], [`windows-latest`] |
|
||||
| Application server | Version | JVM | OS |
|
||||
|---------------------------------------------------------------------------------------|------------------------------------------|------------------------------------------------|---------------------------------------|
|
||||
| [Jetty](https://www.eclipse.org/jetty/) | 9.4.53 | OpenJDK 8, 11, 17, 21<br/>OpenJ9 8, 11, 17, 21 | [`ubuntu-latest`], [`windows-latest`] |
|
||||
| [Jetty](https://www.eclipse.org/jetty/) | 10.0.19, 11.0.19 | OpenJDK 11, 17, 21<br/>OpenJ9 11, 17, 21 | [`ubuntu-latest`], [`windows-latest`] |
|
||||
| [Jetty](https://www.eclipse.org/jetty/) | 12.0.6 | OpenJDK 17, 21<br/>OpenJ9 17, 21 | [`ubuntu-latest`], [`windows-latest`] |
|
||||
| [Open Liberty](https://openliberty.io/) | 20.0.0.12 | OpenJDK 8, 11<br/>OpenJ9 8, 11 | [`ubuntu-latest`], [`windows-latest`] |
|
||||
| [Open Liberty](https://openliberty.io/) | 21.0.0.12, 22.0.0.12 | OpenJDK 8, 11, 17<br/>OpenJ9 8, 11, 17 | [`ubuntu-latest`], [`windows-latest`] |
|
||||
| [Open Liberty](https://openliberty.io/) | 23.0.0.12 | OpenJDK 8, 11, 17, 20<br/>OpenJ9 8, 11, 17, 20 | [`ubuntu-latest`], [`windows-latest`] |
|
||||
| [Payara](https://www.payara.fish/) | 5.2020.6, 5.2021.8 | OpenJDK 8, 11<br/>OpenJ9 8, 11 | [`ubuntu-latest`], [`windows-latest`] |
|
||||
| [Payara](https://www.payara.fish/) | 6.2023.12 | OpenJDK 11, 17<br/>OpenJ9 11, 17, 21 | [`ubuntu-latest`], [`windows-latest`] |
|
||||
| [Tomcat](http://tomcat.apache.org/) | 7.0.109 | OpenJDK 8<br/>OpenJ9 8 | [`ubuntu-latest`], [`windows-latest`] |
|
||||
| [Tomcat](http://tomcat.apache.org/) | 8.5.98, 9.0.85 | OpenJDK 8, 11, 17, 21<br/>OpenJ9 8, 11, 17, 21 | [`ubuntu-latest`], [`windows-latest`] |
|
||||
| [Tomcat](http://tomcat.apache.org/) | 10.1.18 | OpenJDK 11, 17, 21<br/>OpenJ9 11, 17, 21 | [`ubuntu-latest`], [`windows-latest`] |
|
||||
| [TomEE](https://tomee.apache.org/) | 7.0.9, 7.1.4 | OpenJDK 8<br/>OpenJ9 8 | [`ubuntu-latest`], [`windows-latest`] |
|
||||
| [TomEE](https://tomee.apache.org/) | 8.0.16 | OpenJDK 8, 11, 17, 21<br/>OpenJ9 8, 11, 17, 21 | [`ubuntu-latest`], [`windows-latest`] |
|
||||
| [TomEE](https://tomee.apache.org/) | 9.1.2 | OpenJDK 11, 17, 21<br/>OpenJ9 11, 17, 21 | [`ubuntu-latest`], [`windows-latest`] |
|
||||
| [Websphere Traditional](https://www.ibm.com/uk-en/cloud/websphere-application-server) | 8.5.5.22, 9.0.5.14 | IBM JDK 8 | Red Hat Enterprise Linux 8.4 |
|
||||
| [WildFly](https://www.wildfly.org/) | 13.0.0.Final | OpenJDK 8<br/>OpenJ9 8 | [`ubuntu-latest`], [`windows-latest`] |
|
||||
| [WildFly](https://www.wildfly.org/) | 17.0.1.Final, 21.0.0.Final | OpenJDK 8, 11, 17, 21<br/>OpenJ9 8, 11, 17, 21 | [`ubuntu-latest`], [`windows-latest`] |
|
||||
| [WildFly](https://www.wildfly.org/) | 28.0.1.Final, 29.0.1.Final, 30.0.1.Final | OpenJDK 11, 17, 21<br/>OpenJ9 11, 17, 21 | [`ubuntu-latest`], [`windows-latest`] |
|
||||
|
||||
[`ubuntu-latest`]: https://github.com/actions/runner-images#available-images
|
||||
[`windows-latest`]: https://github.com/actions/runner-images#available-images
|
||||
|
@ -194,10 +203,10 @@ These are the application servers that the smoke tests are run against:
|
|||
|
||||
These are the JVMs and operating systems that the integration tests are run against:
|
||||
|
||||
| JVM | Versions | OS |
|
||||
| ----------------------------------------------------------------------------------------- | --------- | ------------------------------------- |
|
||||
| [OpenJDK (Eclipse Temurin)](https://adoptium.net/) | 8, 11, 17 | [`ubuntu-latest`], [`windows-latest`] |
|
||||
| [OpenJ9 (IBM Semeru Runtimes)](https://developer.ibm.com/languages/java/semeru-runtimes/) | 8, 11, 17 | [`ubuntu-latest`] |
|
||||
| JVM | Versions | OS |
|
||||
| ----------------------------------------------------------------------------------------- |---------------| ------------------------------------- |
|
||||
| [OpenJDK (Eclipse Temurin)](https://adoptium.net/) | 8, 11, 17, 21 | [`ubuntu-latest`], [`windows-latest`] |
|
||||
| [OpenJ9 (IBM Semeru Runtimes)](https://developer.ibm.com/languages/java/semeru-runtimes/) | 8, 11, 17 | [`ubuntu-latest`] |
|
||||
|
||||
## Disabled instrumentations
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ dependencies {
|
|||
bootstrap(project(":instrumentation:servlet:servlet-common:bootstrap"))
|
||||
|
||||
testInstrumentation(project(":instrumentation:jetty:jetty-8.0:javaagent"))
|
||||
testInstrumentation(project(":instrumentation:jetty:jetty-12.0:javaagent"))
|
||||
|
||||
// jetty-servlet does not exist in jetty 12, so we don't need to explicitly pin it to 11.+
|
||||
testLibrary("org.eclipse.jetty:jetty-servlet:11.0.0")
|
||||
|
|
|
@ -40,7 +40,7 @@ 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> {
|
||||
class JettyHandlerTest extends AbstractHttpServerTest<Server> {
|
||||
|
||||
@RegisterExtension
|
||||
static final InstrumentationExtension testing = HttpServerInstrumentationExtension.forAgent();
|
||||
|
@ -62,25 +62,17 @@ public class JettyHandlerTest extends AbstractHttpServerTest<Server> {
|
|||
private static final TestHandler testHandler = new TestHandler();
|
||||
|
||||
@Override
|
||||
protected Server setupServer() {
|
||||
protected Server setupServer() throws Exception {
|
||||
Server server = new Server(port);
|
||||
server.setHandler(testHandler);
|
||||
server.addBean(errorHandler);
|
||||
try {
|
||||
server.start();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
server.start();
|
||||
return server;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void stopServer(Server server) {
|
||||
try {
|
||||
server.stop();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
protected void stopServer(Server server) throws Exception {
|
||||
server.stop();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
plugins {
|
||||
id("otel.javaagent-instrumentation")
|
||||
}
|
||||
|
||||
muzzle {
|
||||
pass {
|
||||
group.set("org.eclipse.jetty")
|
||||
module.set("jetty-server")
|
||||
versions.set("[12,)")
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
library("org.eclipse.jetty:jetty-server:12.0.0")
|
||||
|
||||
bootstrap(project(":instrumentation:servlet:servlet-common:bootstrap"))
|
||||
implementation(project(":instrumentation:servlet:servlet-common:javaagent"))
|
||||
|
||||
testInstrumentation(project(":instrumentation:jetty:jetty-8.0:javaagent"))
|
||||
testInstrumentation(project(":instrumentation:jetty:jetty-11.0:javaagent"))
|
||||
|
||||
testLibrary("org.eclipse.jetty.ee10:jetty-ee10-servlet:12.0.0")
|
||||
}
|
||||
|
||||
otelJava {
|
||||
minJavaVersionSupported.set(JavaVersion.VERSION_17)
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.javaagent.instrumentation.jetty.v12_0;
|
||||
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
|
||||
import io.opentelemetry.javaagent.bootstrap.servlet.AppServerBridge;
|
||||
import io.opentelemetry.javaagent.instrumentation.servlet.ServletHelper;
|
||||
import javax.annotation.Nullable;
|
||||
import org.eclipse.jetty.server.HttpStream;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Response;
|
||||
|
||||
public class Jetty12Helper {
|
||||
private final Instrumenter<Request, Response> instrumenter;
|
||||
|
||||
Jetty12Helper(Instrumenter<Request, Response> instrumenter) {
|
||||
this.instrumenter = instrumenter;
|
||||
}
|
||||
|
||||
public boolean shouldStart(Context parentContext, Request request) {
|
||||
return instrumenter.shouldStart(parentContext, request);
|
||||
}
|
||||
|
||||
public Context start(Context parentContext, Request request, Response response) {
|
||||
Context context = instrumenter.start(parentContext, request);
|
||||
request.addFailureListener(throwable -> end(context, request, response, throwable));
|
||||
// detect request completion
|
||||
// https://github.com/jetty/jetty.project/blob/52d94174e2c7a6e794c6377dcf9cd3ed0b9e1806/jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/handler/EventsHandler.java#L75
|
||||
request.addHttpStreamWrapper(
|
||||
stream ->
|
||||
new HttpStream.Wrapper(stream) {
|
||||
@Override
|
||||
public void succeeded() {
|
||||
end(context, request, response, null);
|
||||
super.succeeded();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failed(Throwable throwable) {
|
||||
end(context, request, response, throwable);
|
||||
super.failed(throwable);
|
||||
}
|
||||
});
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
public void end(Context context, Request request, Response response, @Nullable Throwable error) {
|
||||
if (error == null) {
|
||||
error = AppServerBridge.getException(context);
|
||||
}
|
||||
if (error == null) {
|
||||
error = (Throwable) request.getAttribute(ServletHelper.ASYNC_EXCEPTION_ATTRIBUTE);
|
||||
}
|
||||
|
||||
instrumenter.end(context, request, response, error);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.javaagent.instrumentation.jetty.v12_0;
|
||||
|
||||
import io.opentelemetry.instrumentation.api.semconv.http.HttpServerAttributesGetter;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketAddress;
|
||||
import java.util.List;
|
||||
import javax.annotation.Nullable;
|
||||
import org.eclipse.jetty.http.HttpURI;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Response;
|
||||
|
||||
class Jetty12HttpAttributesGetter implements HttpServerAttributesGetter<Request, Response> {
|
||||
|
||||
@Override
|
||||
public String getHttpRequestMethod(Request request) {
|
||||
return request.getMethod();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getHttpRequestHeader(Request request, String name) {
|
||||
return request.getHeaders().getValuesList(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getHttpResponseStatusCode(
|
||||
Request request, Response response, @Nullable Throwable error) {
|
||||
if (!response.isCommitted() && error != null) {
|
||||
return 500;
|
||||
}
|
||||
return response.getStatus();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getHttpResponseHeader(Request request, Response response, String name) {
|
||||
return response.getHeaders().getValuesList(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public String getUrlScheme(Request request) {
|
||||
HttpURI uri = request.getHttpURI();
|
||||
return uri == null ? null : uri.getScheme();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getUrlPath(Request request) {
|
||||
HttpURI uri = request.getHttpURI();
|
||||
return uri == null ? null : uri.getPath();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getUrlQuery(Request request) {
|
||||
HttpURI uri = request.getHttpURI();
|
||||
return uri == null ? null : uri.getQuery();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getNetworkProtocolName(Request request, @Nullable Response unused) {
|
||||
String protocol = request.getConnectionMetaData().getProtocol();
|
||||
if (protocol != null && protocol.startsWith("HTTP/")) {
|
||||
return "http";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getNetworkProtocolVersion(Request request, @Nullable Response unused) {
|
||||
String protocol = request.getConnectionMetaData().getProtocol();
|
||||
if (protocol.startsWith("HTTP/")) {
|
||||
return protocol.substring("HTTP/".length());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public InetSocketAddress getNetworkPeerInetSocketAddress(
|
||||
Request request, @Nullable Response unused) {
|
||||
SocketAddress address = request.getConnectionMetaData().getRemoteSocketAddress();
|
||||
return address instanceof InetSocketAddress ? (InetSocketAddress) address : null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public InetSocketAddress getNetworkLocalInetSocketAddress(
|
||||
Request request, @Nullable Response unused) {
|
||||
SocketAddress address = request.getConnectionMetaData().getLocalSocketAddress();
|
||||
return address instanceof InetSocketAddress ? (InetSocketAddress) address : null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.javaagent.instrumentation.jetty.v12_0;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import io.opentelemetry.javaagent.extension.ignore.IgnoredTypesBuilder;
|
||||
import io.opentelemetry.javaagent.extension.ignore.IgnoredTypesConfigurer;
|
||||
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
|
||||
|
||||
@AutoService(IgnoredTypesConfigurer.class)
|
||||
public class Jetty12IgnoredTypesConfigurer implements IgnoredTypesConfigurer {
|
||||
|
||||
@Override
|
||||
public void configure(IgnoredTypesBuilder builder, ConfigProperties config) {
|
||||
// handling pipelined request sends HttpConnection instance (implements Runnable) to executor
|
||||
// while scope from the previous request is still active
|
||||
builder.ignoreTaskClass("org.eclipse.jetty.server.internal.HttpConnection");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.javaagent.instrumentation.jetty.v12_0;
|
||||
|
||||
import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasClassesNamed;
|
||||
import static java.util.Collections.singletonList;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||
import java.util.List;
|
||||
import net.bytebuddy.matcher.ElementMatcher;
|
||||
|
||||
@AutoService(InstrumentationModule.class)
|
||||
public class Jetty12InstrumentationModule extends InstrumentationModule {
|
||||
|
||||
public Jetty12InstrumentationModule() {
|
||||
super("jetty", "jetty-12.0");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ElementMatcher.Junction<ClassLoader> classLoaderMatcher() {
|
||||
return hasClassesNamed("org.eclipse.jetty.server.Request$Handler");
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TypeInstrumentation> typeInstrumentations() {
|
||||
return singletonList(new Jetty12ServerInstrumentation());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.javaagent.instrumentation.jetty.v12_0;
|
||||
|
||||
import io.opentelemetry.javaagent.bootstrap.http.HttpServerResponseMutator;
|
||||
import org.eclipse.jetty.server.Response;
|
||||
|
||||
public enum Jetty12ResponseMutator implements HttpServerResponseMutator<Response> {
|
||||
INSTANCE;
|
||||
|
||||
@Override
|
||||
public void appendHeader(Response response, String name, String value) {
|
||||
response.getHeaders().add(name, value);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.javaagent.instrumentation.jetty.v12_0;
|
||||
|
||||
import static io.opentelemetry.javaagent.instrumentation.jetty.v12_0.Jetty12Singletons.helper;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.isPublic;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
|
||||
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.context.Scope;
|
||||
import io.opentelemetry.javaagent.bootstrap.Java8BytecodeBridge;
|
||||
import io.opentelemetry.javaagent.bootstrap.http.HttpServerResponseCustomizerHolder;
|
||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
||||
import net.bytebuddy.asm.Advice;
|
||||
import net.bytebuddy.description.type.TypeDescription;
|
||||
import net.bytebuddy.matcher.ElementMatcher;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Response;
|
||||
|
||||
class Jetty12ServerInstrumentation implements TypeInstrumentation {
|
||||
|
||||
@Override
|
||||
public ElementMatcher<TypeDescription> typeMatcher() {
|
||||
return named("org.eclipse.jetty.server.Server");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transform(TypeTransformer transformer) {
|
||||
transformer.applyAdviceToMethod(
|
||||
named("handle")
|
||||
.and(takesArgument(0, named("org.eclipse.jetty.server.Request")))
|
||||
.and(takesArgument(1, named("org.eclipse.jetty.server.Response")))
|
||||
.and(takesArgument(2, named("org.eclipse.jetty.util.Callback")))
|
||||
.and(isPublic()),
|
||||
this.getClass().getName() + "$HandlerAdvice");
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public static class HandlerAdvice {
|
||||
|
||||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||
public static void onEnter(
|
||||
@Advice.This Object source,
|
||||
@Advice.Argument(0) Request request,
|
||||
@Advice.Argument(1) Response response,
|
||||
@Advice.Local("otelContext") Context context,
|
||||
@Advice.Local("otelScope") Scope scope) {
|
||||
|
||||
Context parentContext = Java8BytecodeBridge.currentContext();
|
||||
if (!helper().shouldStart(parentContext, request)) {
|
||||
return;
|
||||
}
|
||||
|
||||
context = helper().start(parentContext, request, response);
|
||||
scope = context.makeCurrent();
|
||||
|
||||
HttpServerResponseCustomizerHolder.getCustomizer()
|
||||
.customize(context, response, Jetty12ResponseMutator.INSTANCE);
|
||||
}
|
||||
|
||||
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
||||
public static void stopSpan(
|
||||
@Advice.Argument(0) Request request,
|
||||
@Advice.Argument(1) Response response,
|
||||
@Advice.Thrown Throwable throwable,
|
||||
@Advice.Local("otelContext") Context context,
|
||||
@Advice.Local("otelScope") Scope scope) {
|
||||
if (scope == null) {
|
||||
return;
|
||||
}
|
||||
scope.close();
|
||||
if (throwable != null) {
|
||||
helper().end(context, request, response, throwable);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.javaagent.instrumentation.jetty.v12_0;
|
||||
|
||||
import io.opentelemetry.api.GlobalOpenTelemetry;
|
||||
import io.opentelemetry.instrumentation.api.incubator.semconv.http.HttpExperimentalAttributesExtractor;
|
||||
import io.opentelemetry.instrumentation.api.incubator.semconv.http.HttpServerExperimentalMetrics;
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.InstrumenterBuilder;
|
||||
import io.opentelemetry.instrumentation.api.semconv.http.HttpServerAttributesExtractor;
|
||||
import io.opentelemetry.instrumentation.api.semconv.http.HttpServerMetrics;
|
||||
import io.opentelemetry.instrumentation.api.semconv.http.HttpServerRoute;
|
||||
import io.opentelemetry.instrumentation.api.semconv.http.HttpSpanNameExtractor;
|
||||
import io.opentelemetry.instrumentation.api.semconv.http.HttpSpanStatusExtractor;
|
||||
import io.opentelemetry.javaagent.bootstrap.internal.CommonConfig;
|
||||
import io.opentelemetry.javaagent.bootstrap.servlet.AppServerBridge;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Response;
|
||||
|
||||
public final class Jetty12Singletons {
|
||||
private static final String INSTRUMENTATION_NAME = "io.opentelemetry.jetty-12.0";
|
||||
|
||||
private static final Instrumenter<Request, Response> INSTRUMENTER;
|
||||
|
||||
static {
|
||||
Jetty12HttpAttributesGetter httpAttributesGetter = new Jetty12HttpAttributesGetter();
|
||||
|
||||
InstrumenterBuilder<Request, Response> builder =
|
||||
Instrumenter.<Request, Response>builder(
|
||||
GlobalOpenTelemetry.get(),
|
||||
INSTRUMENTATION_NAME,
|
||||
HttpSpanNameExtractor.builder(httpAttributesGetter)
|
||||
.setKnownMethods(CommonConfig.get().getKnownHttpRequestMethods())
|
||||
.build())
|
||||
.setSpanStatusExtractor(HttpSpanStatusExtractor.create(httpAttributesGetter))
|
||||
.addAttributesExtractor(
|
||||
HttpServerAttributesExtractor.builder(httpAttributesGetter)
|
||||
.setCapturedRequestHeaders(CommonConfig.get().getServerRequestHeaders())
|
||||
.setCapturedResponseHeaders(CommonConfig.get().getServerResponseHeaders())
|
||||
.setKnownMethods(CommonConfig.get().getKnownHttpRequestMethods())
|
||||
.build())
|
||||
.addContextCustomizer(
|
||||
HttpServerRoute.builder(httpAttributesGetter)
|
||||
.setKnownMethods(CommonConfig.get().getKnownHttpRequestMethods())
|
||||
.build())
|
||||
.addContextCustomizer(
|
||||
(context, request, attributes) ->
|
||||
new AppServerBridge.Builder()
|
||||
.captureServletAttributes()
|
||||
.recordException()
|
||||
.init(context))
|
||||
.addOperationMetrics(HttpServerMetrics.get());
|
||||
if (CommonConfig.get().shouldEmitExperimentalHttpServerTelemetry()) {
|
||||
builder
|
||||
.addAttributesExtractor(HttpExperimentalAttributesExtractor.create(httpAttributesGetter))
|
||||
.addOperationMetrics(HttpServerExperimentalMetrics.get());
|
||||
}
|
||||
INSTRUMENTER = builder.buildServerInstrumenter(Jetty12TextMapGetter.INSTANCE);
|
||||
}
|
||||
|
||||
private static final Jetty12Helper HELPER = new Jetty12Helper(INSTRUMENTER);
|
||||
|
||||
public static Jetty12Helper helper() {
|
||||
return HELPER;
|
||||
}
|
||||
|
||||
private Jetty12Singletons() {}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.javaagent.instrumentation.jetty.v12_0;
|
||||
|
||||
import io.opentelemetry.context.propagation.TextMapGetter;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
|
||||
enum Jetty12TextMapGetter implements TextMapGetter<Request> {
|
||||
INSTANCE;
|
||||
|
||||
@Override
|
||||
public Iterable<String> keys(Request carrier) {
|
||||
return carrier.getHeaders().getFieldNamesCollection();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String get(Request carrier, String key) {
|
||||
return carrier.getHeaders().get(key);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,137 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.javaagent.instrumentation.jetty.v12_0;
|
||||
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.HttpServerTestOptions.DEFAULT_HTTP_ATTRIBUTES;
|
||||
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;
|
||||
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.SemanticAttributes;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Collections;
|
||||
import org.eclipse.jetty.server.Handler;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Response;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
|
||||
class Jetty12HandlerTest extends AbstractHttpServerTest<Server> {
|
||||
|
||||
@RegisterExtension
|
||||
static final InstrumentationExtension testing = HttpServerInstrumentationExtension.forAgent();
|
||||
|
||||
private final TestHandler testHandler = new TestHandler();
|
||||
|
||||
@Override
|
||||
protected Server setupServer() throws Exception {
|
||||
Server server = new Server(port);
|
||||
server.setHandler(testHandler);
|
||||
server.start();
|
||||
return server;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void stopServer(Server server) throws Exception {
|
||||
server.stop();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(HttpServerTestOptions options) {
|
||||
options.setHttpAttributes(
|
||||
unused ->
|
||||
Sets.difference(
|
||||
DEFAULT_HTTP_ATTRIBUTES, Collections.singleton(SemanticAttributes.HTTP_ROUTE)));
|
||||
options.setExpectedException(new IllegalStateException(EXCEPTION.getBody()));
|
||||
options.setHasResponseCustomizer(endpoint -> endpoint != EXCEPTION);
|
||||
}
|
||||
|
||||
@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 void handleRequest(Request request, Response response) {
|
||||
ServerEndpoint endpoint = ServerEndpoint.forPath(request.getHttpURI().getPath());
|
||||
controller(
|
||||
endpoint,
|
||||
() -> {
|
||||
try {
|
||||
response(request, response, endpoint);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
private void response(Request request, Response response, ServerEndpoint endpoint)
|
||||
throws IOException {
|
||||
if (SUCCESS.equals(endpoint)) {
|
||||
response.setStatus(endpoint.getStatus());
|
||||
response.write(true, StandardCharsets.UTF_8.encode(endpoint.getBody()), Callback.NOOP);
|
||||
} else if (QUERY_PARAM.equals(endpoint)) {
|
||||
response.setStatus(endpoint.getStatus());
|
||||
response.write(
|
||||
true, StandardCharsets.UTF_8.encode(request.getHttpURI().getQuery()), Callback.NOOP);
|
||||
} else if (REDIRECT.equals(endpoint)) {
|
||||
response.setStatus(endpoint.getStatus());
|
||||
response.getHeaders().add("Location", "http://localhost:" + port + endpoint.getBody());
|
||||
} else if (ERROR.equals(endpoint)) {
|
||||
response.setStatus(endpoint.getStatus());
|
||||
response.write(true, StandardCharsets.UTF_8.encode(endpoint.getBody()), Callback.NOOP);
|
||||
} else if (CAPTURE_HEADERS.equals(endpoint)) {
|
||||
response.getHeaders().add("X-Test-Response", request.getHeaders().get("X-Test-Request"));
|
||||
response.setStatus(endpoint.getStatus());
|
||||
response.write(true, StandardCharsets.UTF_8.encode(endpoint.getBody()), Callback.NOOP);
|
||||
} else if (EXCEPTION.equals(endpoint)) {
|
||||
throw new IllegalStateException(endpoint.getBody());
|
||||
} else if (INDEXED_CHILD.equals(endpoint)) {
|
||||
INDEXED_CHILD.collectSpanAttributes(
|
||||
name -> Request.extractQueryParameters(request).getValue(name));
|
||||
response.setStatus(endpoint.getStatus());
|
||||
response.write(true, StandardCharsets.UTF_8.encode(endpoint.getBody()), Callback.NOOP);
|
||||
} else {
|
||||
response.setStatus(NOT_FOUND.getStatus());
|
||||
response.write(true, StandardCharsets.UTF_8.encode(NOT_FOUND.getBody()), Callback.NOOP);
|
||||
}
|
||||
}
|
||||
|
||||
private class TestHandler extends Handler.Abstract {
|
||||
|
||||
@Override
|
||||
public boolean handle(Request baseRequest, Response response, Callback callback) {
|
||||
handleRequest(baseRequest, response);
|
||||
|
||||
callback.succeeded();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -23,6 +23,7 @@ dependencies {
|
|||
|
||||
testInstrumentation(project(":instrumentation:servlet:servlet-javax-common:javaagent"))
|
||||
testInstrumentation(project(":instrumentation:jetty:jetty-11.0:javaagent"))
|
||||
testInstrumentation(project(":instrumentation:jetty:jetty-12.0:javaagent"))
|
||||
|
||||
testLibrary("org.eclipse.jetty:jetty-servlet:8.0.0.v20110901")
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ 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> {
|
||||
class JettyHandlerTest extends AbstractHttpServerTest<Server> {
|
||||
|
||||
@RegisterExtension
|
||||
static final InstrumentationExtension testing = HttpServerInstrumentationExtension.forAgent();
|
||||
|
@ -62,25 +62,17 @@ public class JettyHandlerTest extends AbstractHttpServerTest<Server> {
|
|||
private static final TestHandler testHandler = new TestHandler();
|
||||
|
||||
@Override
|
||||
protected Server setupServer() {
|
||||
protected Server setupServer() throws Exception {
|
||||
Server server = new Server(port);
|
||||
server.setHandler(testHandler);
|
||||
server.addBean(errorHandler);
|
||||
try {
|
||||
server.start();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
server.start();
|
||||
return server;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void stopServer(Server server) {
|
||||
try {
|
||||
server.stop();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
protected void stopServer(Server server) throws Exception {
|
||||
server.stop();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -17,7 +17,9 @@ dependencies {
|
|||
|
||||
compileOnly("jakarta.servlet:jakarta.servlet-api:5.0.0")
|
||||
|
||||
testImplementation(project(":instrumentation:servlet:servlet-common:bootstrap"))
|
||||
testInstrumentation(project(":instrumentation:jetty:jetty-11.0:javaagent"))
|
||||
|
||||
testImplementation(project(":instrumentation:servlet:servlet-5.0:testing"))
|
||||
|
||||
testLibrary("org.eclipse.jetty:jetty-server:11.0.0")
|
||||
testLibrary("org.eclipse.jetty:jetty-servlet:11.0.0")
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import io.opentelemetry.javaagent.instrumentation.servlet.v5_0.RequestDispatcherServlet
|
||||
import jakarta.servlet.Servlet
|
||||
import jakarta.servlet.ServletException
|
||||
import jakarta.servlet.http.HttpServletRequest
|
||||
|
@ -10,6 +11,8 @@ import org.eclipse.jetty.server.Server
|
|||
import org.eclipse.jetty.server.handler.ErrorHandler
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler
|
||||
import spock.lang.IgnoreIf
|
||||
import test.AbstractServlet5Test
|
||||
import test.TestServlet5
|
||||
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.AUTH_REQUIRED
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.CAPTURE_HEADERS
|
||||
|
@ -120,6 +123,13 @@ class JettyServlet5TestAsync extends JettyServlet5Test {
|
|||
boolean errorEndpointUsesSendError() {
|
||||
false
|
||||
}
|
||||
|
||||
@Override
|
||||
String getMetricsInstrumentationName() {
|
||||
// with async requests the span is started in one instrumentation (server instrumentation)
|
||||
// but ended from another (servlet instrumentation)
|
||||
"io.opentelemetry.servlet-5.0"
|
||||
}
|
||||
}
|
||||
|
||||
@IgnoreIf({ !jvm.java11Compatible })
|
||||
|
@ -129,6 +139,13 @@ class JettyServlet5TestFakeAsync extends JettyServlet5Test {
|
|||
Class<Servlet> servlet() {
|
||||
TestServlet5.FakeAsync
|
||||
}
|
||||
|
||||
@Override
|
||||
String getMetricsInstrumentationName() {
|
||||
// with async requests the span is started in one instrumentation (server instrumentation)
|
||||
// but ended from another (servlet instrumentation)
|
||||
"io.opentelemetry.servlet-5.0"
|
||||
}
|
||||
}
|
||||
|
||||
@IgnoreIf({ !jvm.java11Compatible })
|
||||
|
@ -220,6 +237,13 @@ class JettyServlet5TestDispatchImmediate extends JettyDispatchTest {
|
|||
addServlet(context, "/dispatch" + INDEXED_CHILD.path, TestServlet5.DispatchImmediate)
|
||||
addServlet(context, "/dispatch/recursive", TestServlet5.DispatchRecursive)
|
||||
}
|
||||
|
||||
@Override
|
||||
String getMetricsInstrumentationName() {
|
||||
// with async requests the span is started in one instrumentation (server instrumentation)
|
||||
// but ended from another (servlet instrumentation)
|
||||
"io.opentelemetry.servlet-5.0"
|
||||
}
|
||||
}
|
||||
|
||||
@IgnoreIf({ !jvm.java11Compatible })
|
||||
|
@ -251,6 +275,13 @@ class JettyServlet5TestDispatchAsync extends JettyDispatchTest {
|
|||
boolean errorEndpointUsesSendError() {
|
||||
false
|
||||
}
|
||||
|
||||
@Override
|
||||
String getMetricsInstrumentationName() {
|
||||
// with async requests the span is started in one instrumentation (server instrumentation)
|
||||
// but ended from another (servlet instrumentation)
|
||||
"io.opentelemetry.servlet-5.0"
|
||||
}
|
||||
}
|
||||
|
||||
abstract class JettyDispatchTest extends JettyServlet5Test {
|
||||
|
|
|
@ -13,6 +13,8 @@ import org.eclipse.jetty.server.Server
|
|||
import org.eclipse.jetty.server.handler.ErrorHandler
|
||||
import org.eclipse.jetty.servlet.ServletHandler
|
||||
import spock.lang.IgnoreIf
|
||||
import test.AbstractServlet5Test
|
||||
import test.TestServlet5
|
||||
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.EXCEPTION
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
import io.opentelemetry.instrumentation.test.asserts.TraceAssert
|
||||
import io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint
|
||||
import io.opentelemetry.javaagent.instrumentation.servlet.v5_0.RequestDispatcherServlet
|
||||
import io.opentelemetry.testing.internal.armeria.common.AggregatedHttpResponse
|
||||
import jakarta.servlet.Servlet
|
||||
import jakarta.servlet.ServletException
|
||||
|
@ -20,6 +21,8 @@ import org.apache.tomcat.JarScanFilter
|
|||
import org.apache.tomcat.JarScanType
|
||||
import spock.lang.Shared
|
||||
import spock.lang.Unroll
|
||||
import test.AbstractServlet5Test
|
||||
import test.TestServlet5
|
||||
|
||||
import java.nio.file.Files
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
plugins {
|
||||
id("otel.javaagent-testing")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
library("org.eclipse.jetty.ee10:jetty-ee10-servlet:12.0.6")
|
||||
|
||||
testInstrumentation(project(":instrumentation:servlet:servlet-5.0:javaagent"))
|
||||
testInstrumentation(project(":instrumentation:jetty:jetty-8.0:javaagent"))
|
||||
testInstrumentation(project(":instrumentation:jetty:jetty-11.0:javaagent"))
|
||||
testInstrumentation(project(":instrumentation:jetty:jetty-12.0:javaagent"))
|
||||
|
||||
testImplementation(project(":instrumentation:servlet:servlet-5.0:testing"))
|
||||
}
|
||||
|
||||
otelJava {
|
||||
minJavaVersionSupported.set(JavaVersion.VERSION_17)
|
||||
}
|
||||
|
||||
tasks {
|
||||
withType<Test>().configureEach {
|
||||
jvmArgs("-Dotel.instrumentation.servlet.experimental.capture-request-parameters=test-parameter")
|
||||
}
|
||||
}
|
|
@ -0,0 +1,241 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import io.opentelemetry.javaagent.instrumentation.servlet.v5_0.RequestDispatcherServlet
|
||||
import jakarta.servlet.Servlet
|
||||
import jakarta.servlet.ServletException
|
||||
import org.eclipse.jetty.ee10.servlet.ServletContextHandler
|
||||
import org.eclipse.jetty.server.Request
|
||||
import org.eclipse.jetty.server.Response
|
||||
import org.eclipse.jetty.server.Server
|
||||
import org.eclipse.jetty.util.Callback
|
||||
import test.AbstractServlet5Test
|
||||
import test.TestServlet5
|
||||
|
||||
import java.nio.charset.StandardCharsets
|
||||
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.AUTH_REQUIRED
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.CAPTURE_HEADERS
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.CAPTURE_PARAMETERS
|
||||
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.QUERY_PARAM
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.REDIRECT
|
||||
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.SUCCESS
|
||||
|
||||
abstract class Jetty12Servlet5Test extends AbstractServlet5Test<Object, Object> {
|
||||
|
||||
@Override
|
||||
boolean testNotFound() {
|
||||
false
|
||||
}
|
||||
|
||||
@Override
|
||||
Throwable expectedException() {
|
||||
new ServletException(EXCEPTION.body)
|
||||
}
|
||||
|
||||
@Override
|
||||
Object startServer(int port) {
|
||||
def jettyServer = new Server(port)
|
||||
jettyServer.connectors.each {
|
||||
it.setHost('localhost')
|
||||
}
|
||||
|
||||
ServletContextHandler servletContext = new ServletContextHandler(contextPath)
|
||||
servletContext.errorHandler = new Request.Handler() {
|
||||
|
||||
@Override
|
||||
boolean handle(Request request, Response response, Callback callback) throws Exception {
|
||||
String message = (String) request.getAttribute("org.eclipse.jetty.server.error_message")
|
||||
if (message != null) {
|
||||
response.write(true, StandardCharsets.UTF_8.encode(message), Callback.NOOP)
|
||||
}
|
||||
callback.succeeded()
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
setupServlets(servletContext)
|
||||
jettyServer.setHandler(servletContext)
|
||||
|
||||
jettyServer.start()
|
||||
|
||||
return jettyServer
|
||||
}
|
||||
|
||||
@Override
|
||||
void stopServer(Object serverObject) {
|
||||
Server server = (Server) serverObject
|
||||
server.stop()
|
||||
server.destroy()
|
||||
}
|
||||
|
||||
@Override
|
||||
String getContextPath() {
|
||||
return "/jetty-context"
|
||||
}
|
||||
|
||||
@Override
|
||||
void addServlet(Object handlerObject, String path, Class<Servlet> servlet) {
|
||||
ServletContextHandler handler = (ServletContextHandler) handlerObject
|
||||
handler.addServlet(servlet, path)
|
||||
}
|
||||
}
|
||||
|
||||
class JettyServlet5TestSync extends Jetty12Servlet5Test {
|
||||
|
||||
@Override
|
||||
Class<Servlet> servlet() {
|
||||
TestServlet5.Sync
|
||||
}
|
||||
}
|
||||
|
||||
class JettyServlet5TestAsync extends Jetty12Servlet5Test {
|
||||
|
||||
@Override
|
||||
Class<Servlet> servlet() {
|
||||
TestServlet5.Async
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean errorEndpointUsesSendError() {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
class JettyServlet5TestFakeAsync extends Jetty12Servlet5Test {
|
||||
|
||||
@Override
|
||||
Class<Servlet> servlet() {
|
||||
TestServlet5.FakeAsync
|
||||
}
|
||||
}
|
||||
|
||||
class JettyServlet5TestForward extends JettyDispatchTest {
|
||||
@Override
|
||||
Class<Servlet> servlet() {
|
||||
TestServlet5.Sync // dispatch to sync servlet
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setupServlets(Object context) {
|
||||
super.setupServlets(context)
|
||||
|
||||
addServlet(context, "/dispatch" + SUCCESS.path, RequestDispatcherServlet.Forward)
|
||||
addServlet(context, "/dispatch" + HTML_PRINT_WRITER.path, RequestDispatcherServlet.Forward)
|
||||
addServlet(context, "/dispatch" + HTML_SERVLET_OUTPUT_STREAM.path, RequestDispatcherServlet.Forward)
|
||||
addServlet(context, "/dispatch" + QUERY_PARAM.path, RequestDispatcherServlet.Forward)
|
||||
addServlet(context, "/dispatch" + REDIRECT.path, RequestDispatcherServlet.Forward)
|
||||
addServlet(context, "/dispatch" + ERROR.path, RequestDispatcherServlet.Forward)
|
||||
addServlet(context, "/dispatch" + EXCEPTION.path, RequestDispatcherServlet.Forward)
|
||||
addServlet(context, "/dispatch" + AUTH_REQUIRED.path, RequestDispatcherServlet.Forward)
|
||||
addServlet(context, "/dispatch" + CAPTURE_HEADERS.path, RequestDispatcherServlet.Forward)
|
||||
addServlet(context, "/dispatch" + CAPTURE_PARAMETERS.path, RequestDispatcherServlet.Forward)
|
||||
addServlet(context, "/dispatch" + INDEXED_CHILD.path, RequestDispatcherServlet.Forward)
|
||||
}
|
||||
}
|
||||
|
||||
class JettyServlet5TestInclude extends JettyDispatchTest {
|
||||
@Override
|
||||
Class<Servlet> servlet() {
|
||||
TestServlet5.Sync // dispatch to sync servlet
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean testRedirect() {
|
||||
false
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean testCapturedHttpHeaders() {
|
||||
false
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean testError() {
|
||||
false
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setupServlets(Object context) {
|
||||
super.setupServlets(context)
|
||||
|
||||
addServlet(context, "/dispatch" + SUCCESS.path, RequestDispatcherServlet.Include)
|
||||
addServlet(context, "/dispatch" + HTML_PRINT_WRITER.path, RequestDispatcherServlet.Include)
|
||||
addServlet(context, "/dispatch" + HTML_SERVLET_OUTPUT_STREAM.path, RequestDispatcherServlet.Include)
|
||||
addServlet(context, "/dispatch" + QUERY_PARAM.path, RequestDispatcherServlet.Include)
|
||||
addServlet(context, "/dispatch" + REDIRECT.path, RequestDispatcherServlet.Include)
|
||||
addServlet(context, "/dispatch" + ERROR.path, RequestDispatcherServlet.Include)
|
||||
addServlet(context, "/dispatch" + EXCEPTION.path, RequestDispatcherServlet.Include)
|
||||
addServlet(context, "/dispatch" + AUTH_REQUIRED.path, RequestDispatcherServlet.Include)
|
||||
addServlet(context, "/dispatch" + CAPTURE_HEADERS.path, RequestDispatcherServlet.Include)
|
||||
addServlet(context, "/dispatch" + CAPTURE_PARAMETERS.path, RequestDispatcherServlet.Include)
|
||||
addServlet(context, "/dispatch" + INDEXED_CHILD.path, RequestDispatcherServlet.Include)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class JettyServlet5TestDispatchImmediate extends JettyDispatchTest {
|
||||
@Override
|
||||
Class<Servlet> servlet() {
|
||||
TestServlet5.Sync
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setupServlets(Object context) {
|
||||
super.setupServlets(context)
|
||||
addServlet(context, "/dispatch" + HTML_PRINT_WRITER.path, TestServlet5.DispatchImmediate)
|
||||
addServlet(context, "/dispatch" + HTML_SERVLET_OUTPUT_STREAM.path, TestServlet5.DispatchImmediate)
|
||||
addServlet(context, "/dispatch" + SUCCESS.path, TestServlet5.DispatchImmediate)
|
||||
addServlet(context, "/dispatch" + QUERY_PARAM.path, TestServlet5.DispatchImmediate)
|
||||
addServlet(context, "/dispatch" + ERROR.path, TestServlet5.DispatchImmediate)
|
||||
addServlet(context, "/dispatch" + EXCEPTION.path, TestServlet5.DispatchImmediate)
|
||||
addServlet(context, "/dispatch" + REDIRECT.path, TestServlet5.DispatchImmediate)
|
||||
addServlet(context, "/dispatch" + AUTH_REQUIRED.path, TestServlet5.DispatchImmediate)
|
||||
addServlet(context, "/dispatch" + CAPTURE_HEADERS.path, TestServlet5.DispatchImmediate)
|
||||
addServlet(context, "/dispatch" + CAPTURE_PARAMETERS.path, TestServlet5.DispatchImmediate)
|
||||
addServlet(context, "/dispatch" + INDEXED_CHILD.path, TestServlet5.DispatchImmediate)
|
||||
addServlet(context, "/dispatch/recursive", TestServlet5.DispatchRecursive)
|
||||
}
|
||||
}
|
||||
|
||||
class JettyServlet5TestDispatchAsync extends JettyDispatchTest {
|
||||
@Override
|
||||
Class<Servlet> servlet() {
|
||||
TestServlet5.Async
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setupServlets(Object context) {
|
||||
super.setupServlets(context)
|
||||
|
||||
addServlet(context, "/dispatch" + SUCCESS.path, TestServlet5.DispatchAsync)
|
||||
addServlet(context, "/dispatch" + HTML_PRINT_WRITER.path, TestServlet5.DispatchAsync)
|
||||
addServlet(context, "/dispatch" + HTML_SERVLET_OUTPUT_STREAM.path, TestServlet5.DispatchAsync)
|
||||
addServlet(context, "/dispatch" + QUERY_PARAM.path, TestServlet5.DispatchAsync)
|
||||
addServlet(context, "/dispatch" + ERROR.path, TestServlet5.DispatchAsync)
|
||||
addServlet(context, "/dispatch" + EXCEPTION.path, TestServlet5.DispatchAsync)
|
||||
addServlet(context, "/dispatch" + REDIRECT.path, TestServlet5.DispatchAsync)
|
||||
addServlet(context, "/dispatch" + AUTH_REQUIRED.path, TestServlet5.DispatchAsync)
|
||||
addServlet(context, "/dispatch" + CAPTURE_HEADERS.path, TestServlet5.DispatchAsync)
|
||||
addServlet(context, "/dispatch" + CAPTURE_PARAMETERS.path, TestServlet5.DispatchAsync)
|
||||
addServlet(context, "/dispatch" + INDEXED_CHILD.path, TestServlet5.DispatchAsync)
|
||||
addServlet(context, "/dispatch/recursive", TestServlet5.DispatchRecursive)
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean errorEndpointUsesSendError() {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
abstract class JettyDispatchTest extends Jetty12Servlet5Test {
|
||||
@Override
|
||||
URI buildAddress() {
|
||||
return new URI("http://localhost:$port$contextPath/dispatch/")
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
plugins {
|
||||
id("otel.java-conventions")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api(project(":testing-common"))
|
||||
api(project(":instrumentation:servlet:servlet-common:bootstrap"))
|
||||
|
||||
compileOnly("jakarta.servlet:jakarta.servlet-api:5.0.0")
|
||||
}
|
|
@ -3,6 +3,8 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package test
|
||||
|
||||
import io.opentelemetry.api.trace.SpanKind
|
||||
import io.opentelemetry.instrumentation.api.internal.HttpConstants
|
||||
import io.opentelemetry.instrumentation.test.AgentTestTrait
|
|
@ -3,6 +3,8 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package test
|
||||
|
||||
import io.opentelemetry.instrumentation.test.base.HttpServerTest
|
||||
import io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint
|
||||
import jakarta.servlet.RequestDispatcher
|
|
@ -3,6 +3,8 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.javaagent.instrumentation.servlet.v5_0;
|
||||
|
||||
import io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint;
|
||||
import jakarta.servlet.RequestDispatcher;
|
||||
import jakarta.servlet.ServletContext;
|
||||
|
@ -14,12 +16,11 @@ import jakarta.servlet.http.HttpServletResponse;
|
|||
import java.io.IOException;
|
||||
|
||||
public class RequestDispatcherServlet {
|
||||
/* There's something about the getRequestDispatcher call that breaks horribly when these classes
|
||||
* are written in groovy.
|
||||
*/
|
||||
|
||||
@WebServlet(asyncSupported = true)
|
||||
public static class Forward extends HttpServlet {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
protected void service(HttpServletRequest req, HttpServletResponse resp)
|
||||
throws ServletException, IOException {
|
||||
|
@ -32,6 +33,8 @@ public class RequestDispatcherServlet {
|
|||
|
||||
@WebServlet(asyncSupported = true)
|
||||
public static class Include extends HttpServlet {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
protected void service(HttpServletRequest req, HttpServletResponse resp)
|
||||
throws ServletException, IOException {
|
|
@ -14,7 +14,7 @@ public class ServletHelper<REQUEST, RESPONSE> extends BaseServletHelper<REQUEST,
|
|||
ServletHelper.class.getName() + ".AsyncListener";
|
||||
private static final String ASYNC_LISTENER_RESPONSE_ATTRIBUTE =
|
||||
ServletHelper.class.getName() + ".AsyncListenerResponse";
|
||||
private static final String ASYNC_EXCEPTION_ATTRIBUTE =
|
||||
public static final String ASYNC_EXCEPTION_ATTRIBUTE =
|
||||
ServletHelper.class.getName() + ".AsyncException";
|
||||
public static final String CONTEXT_ATTRIBUTE = ServletHelper.class.getName() + ".Context";
|
||||
|
||||
|
|
|
@ -321,6 +321,7 @@ include(":instrumentation:jedis:jedis-4.0:javaagent")
|
|||
include(":instrumentation:jedis:jedis-common:javaagent")
|
||||
include(":instrumentation:jetty:jetty-8.0:javaagent")
|
||||
include(":instrumentation:jetty:jetty-11.0:javaagent")
|
||||
include(":instrumentation:jetty:jetty-12.0:javaagent")
|
||||
include(":instrumentation:jetty:jetty-common:javaagent")
|
||||
include(":instrumentation:jetty-httpclient:jetty-httpclient-9.2:javaagent")
|
||||
include(":instrumentation:jetty-httpclient:jetty-httpclient-9.2:library")
|
||||
|
@ -502,6 +503,8 @@ include(":instrumentation:servlet:servlet-3.0:javaagent")
|
|||
include(":instrumentation:servlet:servlet-3.0:javaagent-unit-tests")
|
||||
include(":instrumentation:servlet:servlet-5.0:javaagent")
|
||||
include(":instrumentation:servlet:servlet-5.0:javaagent-unit-tests")
|
||||
include(":instrumentation:servlet:servlet-5.0:jetty12-testing")
|
||||
include(":instrumentation:servlet:servlet-5.0:testing")
|
||||
include(":instrumentation:spark-2.3:javaagent")
|
||||
include(":instrumentation:spring:spring-batch-3.0:javaagent")
|
||||
include(":instrumentation:spring:spring-boot-actuator-autoconfigure-2.0:javaagent")
|
||||
|
|
|
@ -57,7 +57,7 @@ abstract class AppServerTest extends SmokeTest {
|
|||
@Override
|
||||
protected String getTargetImage(String jdk, String serverVersion, boolean windows) {
|
||||
String platformSuffix = windows ? "-windows" : ""
|
||||
String extraTag = "20240209.7847080088"
|
||||
String extraTag = "20240216.7928274208"
|
||||
String fullSuffix = "${serverVersion}-jdk$jdk$platformSuffix-$extraTag"
|
||||
return getTargetImagePrefix() + ":" + fullSuffix
|
||||
}
|
||||
|
|
|
@ -98,3 +98,19 @@ class Jetty11Jdk21 extends JettySmokeTest {
|
|||
@AppServer(version = "11.0.19", jdk = "21-openj9")
|
||||
class Jetty11Jdk21Openj9 extends JettySmokeTest {
|
||||
}
|
||||
|
||||
@AppServer(version = "12.0.6", jdk = "17")
|
||||
class Jetty12Jdk17 extends JettySmokeTest {
|
||||
}
|
||||
|
||||
@AppServer(version = "12.0.6", jdk = "17-openj9")
|
||||
class Jetty12Jdk17Openj9 extends JettySmokeTest {
|
||||
}
|
||||
|
||||
@AppServer(version = "12.0.6", jdk = "21")
|
||||
class Jetty12Jdk21 extends JettySmokeTest {
|
||||
}
|
||||
|
||||
@AppServer(version = "12.0.6", jdk = "21-openj9")
|
||||
class Jetty12Jdk21Openj9 extends JettySmokeTest {
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue