Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JAX-RS ApplicationPath annotation #2824

Merged
merged 8 commits into from
Apr 21, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
ext {
skipPublish = true
}
apply from: "$rootDir/gradle/java.gradle"

repositories {
maven { url 'https://repo.gradle.org/gradle/libs-releases' }
}
laurit marked this conversation as resolved.
Show resolved Hide resolved

dependencies {
compileOnly "javax:javaee-api:7.0"

api project(':testing-common')
implementation deps.opentelemetryApi

def arquillianVersion = '1.4.0.Final'
implementation "org.jboss.arquillian.junit:arquillian-junit-container:${arquillianVersion}"
implementation "org.jboss.arquillian.protocol:arquillian-protocol-servlet:${arquillianVersion}"
implementation 'org.jboss.arquillian.spock:arquillian-spock-container:1.0.0.CR1'
api "org.jboss.shrinkwrap.resolver:shrinkwrap-resolver-gradle-depchain:3.1.3"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

import static io.opentelemetry.api.trace.SpanKind.SERVER

import io.opentelemetry.instrumentation.test.AgentInstrumentationSpecification
import io.opentelemetry.instrumentation.test.utils.OkHttpUtils
import okhttp3.HttpUrl
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import org.jboss.arquillian.container.test.api.Deployment
import org.jboss.arquillian.container.test.api.RunAsClient
import org.jboss.arquillian.spock.ArquillianSputnik
import org.jboss.arquillian.test.api.ArquillianResource
import org.jboss.shrinkwrap.api.ShrinkWrap
import org.jboss.shrinkwrap.api.asset.EmptyAsset
import org.jboss.shrinkwrap.api.spec.WebArchive
import org.junit.runner.RunWith
import spock.lang.Unroll
import test.CdiRestResource
import test.EjbRestResource
import test.RestApplication

@RunWith(ArquillianSputnik)
@RunAsClient
abstract class ArquillianRestTest extends AgentInstrumentationSpecification {

static OkHttpClient client = OkHttpUtils.client()

@ArquillianResource
static URI url

@Deployment
static WebArchive createDeployment() {
return ShrinkWrap.create(WebArchive)
.addClass(RestApplication)
.addClass(CdiRestResource)
.addClass(EjbRestResource)
.addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml")
}

def getContextRoot() {
return url.getPath()
}

@Unroll
def "test #path"() {
when:
Request request = new Request.Builder().url(HttpUrl.get(url.resolve(path))).build()
Response response = client.newCall(request).execute()

then:
response.withCloseable {
assert response.code() == 200
assert response.body().string() == "hello"
true
}

and:
assertTraces(1) {
trace(0, 2) {
span(0) {
name getContextRoot() + path
kind SERVER
hasNoParent()
}
span(1) {
name className + ".hello"
childOf span(0)
}
}
}

where:
path | className
"rest-app/cdiHello" | "CdiRestResource"
"rest-app/ejbHello" | "EjbRestResource"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;

@ApplicationPath("/")
@ApplicationPath("/rest-app/")
public class RestApplication extends Application {

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<arquillian xmlns="http://jboss.org/schema/arquillian"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://jboss.org/schema/arquillian
http://jboss.org/schema/arquillian/arquillian_1_0.xsd">

<defaultProtocol type="Servlet 3.0" />

<container qualifier="wildfly-embedded" default="true">
<configuration>
<property name="jbossHome">build/server/wildfly-18.0.0.Final</property>
<property name="modulePath">build/server/wildfly-18.0.0.Final/modules</property>
</configuration>
</container>
</arquillian>
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import io.opentelemetry.instrumentation.api.tracer.BaseTracer;
import io.opentelemetry.instrumentation.api.tracer.ServerSpan;
import io.opentelemetry.javaagent.instrumentation.api.ClassHierarchyIterable;
import io.opentelemetry.javaagent.instrumentation.api.jaxrs.JaxrsContextPath;
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
Expand Down Expand Up @@ -66,6 +67,7 @@ public void updateSpanNames(
// empty when method and class don't have a jax-rs path annotation, this can happen when
// creating an "abort" span, see RequestContextHelper.
if (!pathBasedSpanName.isEmpty()) {
pathBasedSpanName = JaxrsContextPath.prepend(context, pathBasedSpanName);
pathBasedSpanName = ServletContextPath.prepend(context, pathBasedSpanName);
}
if (serverSpan == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,19 @@ muzzle {
group = "org.apache.cxf"
module = "cxf-rt-frontend-jaxrs"
versions = "[3.2,)"
extraDependency "javax.servlet:javax.servlet-api:3.1.0"
}
pass {
group = "org.apache.tomee"
module = "openejb-cxf-rs"
versions = "(7,)"
extraDependency "javax.servlet:javax.servlet-api:3.1.0"
}
}

dependencies {
compileOnly group: 'javax.ws.rs', name: 'javax.ws.rs-api', version: '2.0'
compileOnly group: 'javax.servlet', name: 'javax.servlet-api', version: '3.1.0'
library group: 'org.apache.cxf', name: 'cxf-rt-frontend-jaxrs', version: '3.2.0'

implementation project(':instrumentation:jaxrs:jaxrs-2.0:jaxrs-2.0-common:javaagent')
Expand All @@ -21,6 +29,7 @@ dependencies {

testImplementation project(':instrumentation:jaxrs:jaxrs-2.0:jaxrs-2.0-testing')
testImplementation group: 'javax.xml.bind', name: 'jaxb-api', version: '2.2.3'
testImplementation group: 'org.eclipse.jetty', name: 'jetty-webapp', version: '9.4.6.v20170531'

testLibrary group: 'org.apache.cxf', name: 'cxf-rt-transports-http-jetty', version: '3.2.0'
testLibrary group: 'org.apache.cxf', name: 'cxf-rt-ws-policy', version: '3.2.0'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@

package io.opentelemetry.javaagent.instrumentation.jaxrs.v2_0;

import static java.util.Arrays.asList;

import com.google.auto.service.AutoService;
import io.opentelemetry.javaagent.tooling.InstrumentationModule;
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
import java.util.Collections;
import java.util.List;

@AutoService(InstrumentationModule.class)
Expand All @@ -19,6 +20,9 @@ public CxfInstrumentationModule() {

@Override
public List<TypeInstrumentation> typeInstrumentations() {
return Collections.singletonList(new CxfRequestContextInstrumentation());
return asList(
new CxfRequestContextInstrumentation(),
new CxfServletControllerInstrumentation(),
new CxfRsHttpListenerInstrumentation());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.javaagent.instrumentation.jaxrs.v2_0;

import static java.util.Collections.singletonMap;
import static net.bytebuddy.matcher.ElementMatchers.isMethod;
import static net.bytebuddy.matcher.ElementMatchers.named;

import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope;
import io.opentelemetry.javaagent.instrumentation.api.jaxrs.JaxrsContextPath;
import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge;
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
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;

// TomEE specific instrumentation
public class CxfRsHttpListenerInstrumentation implements TypeInstrumentation {

@Override
public ElementMatcher<TypeDescription> typeMatcher() {
return named("org.apache.openejb.server.cxf.rs.CxfRsHttpListener");
}

@Override
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
return singletonMap(
isMethod().and(named("doInvoke")),
CxfRsHttpListenerInstrumentation.class.getName() + "$InvokeAdvice");
}

public static class InvokeAdvice {

@Advice.OnMethodEnter(suppress = Throwable.class)
public static void onEnter(
@Advice.FieldValue("pattern") String pattern, @Advice.Local("otelScope") Scope scope) {
Context context = JaxrsContextPath.init(Java8BytecodeBridge.currentContext(), pattern);
if (context != null) {
scope = context.makeCurrent();
}
}

@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static void stopSpan(@Advice.Local("otelScope") Scope scope) {
if (scope != null) {
scope.close();
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.javaagent.instrumentation.jaxrs.v2_0;

import static net.bytebuddy.matcher.ElementMatchers.isMethod;
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.instrumentation.api.jaxrs.JaxrsContextPath;
import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge;
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
import java.util.Collections;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;

public class CxfServletControllerInstrumentation implements TypeInstrumentation {

@Override
public ElementMatcher<TypeDescription> typeMatcher() {
return named("org.apache.cxf.transport.servlet.ServletController");
}

@Override
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {
return Collections.singletonMap(
isMethod()
.and(isPublic())
.and(named("invokeDestination"))
.and(takesArgument(0, named("javax.servlet.http.HttpServletRequest"))),
CxfServletControllerInstrumentation.class.getName() + "$InvokeAdvice");
}

public static class InvokeAdvice {

@Advice.OnMethodEnter(suppress = Throwable.class)
public static void onEnter(
@Advice.Argument(0) HttpServletRequest httpServletRequest,
@Advice.Local("otelScope") Scope scope) {
Context context =
JaxrsContextPath.init(
Java8BytecodeBridge.currentContext(), httpServletRequest.getServletPath());
if (context != null) {
scope = context.makeCurrent();
}
}

@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static void stopSpan(@Advice.Local("otelScope") Scope scope) {
if (scope != null) {
scope.close();
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

class CxfJettyHttpServerTest extends JaxRsJettyHttpServerTest {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" metadata-complete="false"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">

<servlet>
<servlet-name>CXFNonSpringJaxrsServlet</servlet-name>
<servlet-class>org.apache.cxf.jaxrs.servlet.CXFNonSpringJaxrsServlet</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>JaxRsApplicationPathTestApplication</param-value>
</init-param>
<async-supported>true</async-supported>
</servlet>

<servlet-mapping>
<servlet-name>CXFNonSpringJaxrsServlet</servlet-name>
<url-pattern>/rest-app/*</url-pattern>
</servlet-mapping>
</web-app>
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,29 @@ muzzle {
group = "org.glassfish.jersey.core"
module = "jersey-server"
versions = "[2.0,3.0.0)"
extraDependency "javax.servlet:javax.servlet-api:3.1.0"
}
pass {
group = "org.glassfish.jersey.containers"
module = "jersey-container-servlet"
versions = "[2.0,3.0.0)"
extraDependency "javax.servlet:javax.servlet-api:3.1.0"
}
}

dependencies {
compileOnly group: 'javax.ws.rs', name: 'javax.ws.rs-api', version: '2.0'
compileOnly group: 'org.glassfish.jersey.core', name: 'jersey-server', version: '2.0'
compileOnly group: 'javax.servlet', name: 'javax.servlet-api', version: '3.1.0'
library group: 'org.glassfish.jersey.core', name: 'jersey-server', version: '2.0'
library group: 'org.glassfish.jersey.containers', name: 'jersey-container-servlet', version: '2.0'

implementation project(':instrumentation:jaxrs:jaxrs-2.0:jaxrs-2.0-common:javaagent')

testInstrumentation project(':instrumentation:servlet:servlet-3.0:javaagent')
testInstrumentation project(':instrumentation:servlet:servlet-javax-common:javaagent')

testImplementation project(':instrumentation:jaxrs:jaxrs-2.0:jaxrs-2.0-testing')
testImplementation group: 'org.eclipse.jetty', name: 'jetty-webapp', version: '8.0.0.v20110901'

// First version with DropwizardTestSupport:
testLibrary group: 'io.dropwizard', name: 'dropwizard-testing', version: '0.8.0'
Expand Down