Remove JAXRS HttpClient instrumentation (#5430)
This commit is contained in:
parent
c8c115d13f
commit
c06d70d174
|
@ -11,6 +11,7 @@ import io.opentelemetry.instrumentation.api.instrumenter.PeerServiceAttributesEx
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientAttributesExtractor;
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientAttributesExtractor;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientMetrics;
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientMetrics;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor;
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor;
|
||||||
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanStatusExtractor;
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.net.NetClientAttributesExtractor;
|
import io.opentelemetry.instrumentation.api.instrumenter.net.NetClientAttributesExtractor;
|
||||||
import java.net.HttpURLConnection;
|
import java.net.HttpURLConnection;
|
||||||
|
|
||||||
|
@ -27,6 +28,7 @@ public final class HttpUrlConnectionSingletons {
|
||||||
GlobalOpenTelemetry.get(),
|
GlobalOpenTelemetry.get(),
|
||||||
"io.opentelemetry.http-url-connection",
|
"io.opentelemetry.http-url-connection",
|
||||||
HttpSpanNameExtractor.create(httpAttributesGetter))
|
HttpSpanNameExtractor.create(httpAttributesGetter))
|
||||||
|
.setSpanStatusExtractor(HttpSpanStatusExtractor.create(httpAttributesGetter))
|
||||||
.addAttributesExtractor(HttpClientAttributesExtractor.create(httpAttributesGetter))
|
.addAttributesExtractor(HttpClientAttributesExtractor.create(httpAttributesGetter))
|
||||||
.addAttributesExtractor(NetClientAttributesExtractor.create(netAttributesGetter))
|
.addAttributesExtractor(NetClientAttributesExtractor.create(netAttributesGetter))
|
||||||
.addAttributesExtractor(PeerServiceAttributesExtractor.create(netAttributesGetter))
|
.addAttributesExtractor(PeerServiceAttributesExtractor.create(netAttributesGetter))
|
||||||
|
|
|
@ -1,29 +1,9 @@
|
||||||
plugins {
|
plugins {
|
||||||
id("otel.javaagent-instrumentation")
|
id("otel.javaagent-testing")
|
||||||
}
|
|
||||||
|
|
||||||
muzzle {
|
|
||||||
pass {
|
|
||||||
group.set("javax.ws.rs")
|
|
||||||
module.set("javax.ws.rs-api")
|
|
||||||
versions.set("[2.0,)")
|
|
||||||
}
|
|
||||||
pass {
|
|
||||||
// We want to support the dropwizard clients too.
|
|
||||||
group.set("io.dropwizard")
|
|
||||||
module.set("dropwizard-client")
|
|
||||||
versions.set("[0.8.0,)")
|
|
||||||
assertInverse.set(true)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compileOnly("javax.ws.rs:javax.ws.rs-api:2.0.1")
|
testInstrumentation(project(":instrumentation:http-url-connection:javaagent"))
|
||||||
compileOnly("javax.annotation:javax.annotation-api:1.3.2")
|
|
||||||
|
|
||||||
testInstrumentation(project(":instrumentation:jaxrs-client:jaxrs-client-2.0:jaxrs-client-2.0-cxf-3.0:javaagent"))
|
|
||||||
testInstrumentation(project(":instrumentation:jaxrs-client:jaxrs-client-2.0:jaxrs-client-2.0-jersey-2.0:javaagent"))
|
|
||||||
testInstrumentation(project(":instrumentation:jaxrs-client:jaxrs-client-2.0:jaxrs-client-2.0-resteasy-3.0:javaagent"))
|
|
||||||
|
|
||||||
testImplementation("javax.ws.rs:javax.ws.rs-api:2.0.1")
|
testImplementation("javax.ws.rs:javax.ws.rs-api:2.0.1")
|
||||||
|
|
|
@ -30,6 +30,10 @@ import static io.opentelemetry.semconv.trace.attributes.SemanticAttributes.NetTr
|
||||||
|
|
||||||
abstract class JaxRsClientTest extends HttpClientTest<Invocation.Builder> implements AgentTestTrait {
|
abstract class JaxRsClientTest extends HttpClientTest<Invocation.Builder> implements AgentTestTrait {
|
||||||
|
|
||||||
|
boolean testRedirects() {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
Invocation.Builder buildRequest(String method, URI uri, Map<String, String> headers) {
|
Invocation.Builder buildRequest(String method, URI uri, Map<String, String> headers) {
|
||||||
return internalBuildRequest(uri, headers)
|
return internalBuildRequest(uri, headers)
|
||||||
|
@ -108,7 +112,7 @@ abstract class JaxRsClientTest extends HttpClientTest<Invocation.Builder> implem
|
||||||
"$SemanticAttributes.HTTP_METHOD" method
|
"$SemanticAttributes.HTTP_METHOD" method
|
||||||
"$SemanticAttributes.HTTP_STATUS_CODE" statusCode
|
"$SemanticAttributes.HTTP_STATUS_CODE" statusCode
|
||||||
"$SemanticAttributes.HTTP_FLAVOR" "1.1"
|
"$SemanticAttributes.HTTP_FLAVOR" "1.1"
|
||||||
"$SemanticAttributes.HTTP_RESPONSE_CONTENT_LENGTH" Long
|
"$SemanticAttributes.HTTP_USER_AGENT" { it == null || String }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
serverSpan(it, 1, span(0))
|
serverSpan(it, 1, span(0))
|
||||||
|
@ -131,11 +135,6 @@ class JerseyClientTest extends JaxRsClientTest {
|
||||||
return new JerseyClientBuilder().withConfig(config)
|
return new JerseyClientBuilder().withConfig(config)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
int maxRedirects() {
|
|
||||||
20
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
SingleConnection createSingleConnection(String host, int port) {
|
SingleConnection createSingleConnection(String host, int port) {
|
||||||
// Jersey JAX-RS client uses HttpURLConnection internally, which does not support pipelining nor
|
// Jersey JAX-RS client uses HttpURLConnection internally, which does not support pipelining nor
|
||||||
|
@ -154,10 +153,6 @@ class ResteasyClientTest extends JaxRsClientTest {
|
||||||
.establishConnectionTimeout(CONNECT_TIMEOUT_MS, TimeUnit.MILLISECONDS)
|
.establishConnectionTimeout(CONNECT_TIMEOUT_MS, TimeUnit.MILLISECONDS)
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean testRedirects() {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
SingleConnection createSingleConnection(String host, int port) {
|
SingleConnection createSingleConnection(String host, int port) {
|
||||||
return new ResteasySingleConnection(host, port)
|
return new ResteasySingleConnection(host, port)
|
||||||
|
@ -166,16 +161,24 @@ class ResteasyClientTest extends JaxRsClientTest {
|
||||||
|
|
||||||
class CxfClientTest extends JaxRsClientTest {
|
class CxfClientTest extends JaxRsClientTest {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
Throwable clientSpanError(URI uri, Throwable exception) {
|
||||||
|
switch (uri.toString()) {
|
||||||
|
case "http://localhost:61/": // unopened port
|
||||||
|
case "https://192.0.2.1/": // non routable address
|
||||||
|
if (exception.getCause() != null) {
|
||||||
|
exception = exception.getCause()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return exception
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
ClientBuilder builder() {
|
ClientBuilder builder() {
|
||||||
return new ClientBuilderImpl()
|
return new ClientBuilderImpl()
|
||||||
.property("http.connection.timeout", (long) CONNECT_TIMEOUT_MS)
|
.property("http.connection.timeout", (long) CONNECT_TIMEOUT_MS)
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean testRedirects() {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
SingleConnection createSingleConnection(String host, int port) {
|
SingleConnection createSingleConnection(String host, int port) {
|
||||||
// CXF JAX-RS client uses HttpURLConnection internally, which does not support pipelining nor
|
// CXF JAX-RS client uses HttpURLConnection internally, which does not support pipelining nor
|
|
@ -1,52 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright The OpenTelemetry Authors
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package io.opentelemetry.javaagent.instrumentation.jaxrsclient.v2_0;
|
|
||||||
|
|
||||||
import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.extendsClass;
|
|
||||||
import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasClassesNamed;
|
|
||||||
import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.implementsInterface;
|
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.returns;
|
|
||||||
|
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
|
||||||
import javax.ws.rs.client.Client;
|
|
||||||
import net.bytebuddy.asm.Advice;
|
|
||||||
import net.bytebuddy.description.type.TypeDescription;
|
|
||||||
import net.bytebuddy.implementation.bytecode.assign.Assigner;
|
|
||||||
import net.bytebuddy.matcher.ElementMatcher;
|
|
||||||
|
|
||||||
public class ClientBuilderInstrumentation implements TypeInstrumentation {
|
|
||||||
@Override
|
|
||||||
public ElementMatcher<ClassLoader> classLoaderOptimization() {
|
|
||||||
return hasClassesNamed("javax.ws.rs.client.ClientBuilder");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ElementMatcher<TypeDescription> typeMatcher() {
|
|
||||||
return extendsClass(named("javax.ws.rs.client.ClientBuilder"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void transform(TypeTransformer transformer) {
|
|
||||||
transformer.applyAdviceToMethod(
|
|
||||||
named("build").and(returns(implementsInterface(named("javax.ws.rs.client.Client")))),
|
|
||||||
this.getClass().getName() + "$BuildAdvice");
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
public static class BuildAdvice {
|
|
||||||
|
|
||||||
@Advice.OnMethodExit
|
|
||||||
public static void registerFeature(
|
|
||||||
@Advice.Return(typing = Assigner.Typing.DYNAMIC) Client client) {
|
|
||||||
// Register on the generated client instead of the builder
|
|
||||||
// The build() can be called multiple times and is not thread safe
|
|
||||||
// A client is only created once
|
|
||||||
client.register(ClientTracingFeature.class);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,19 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright The OpenTelemetry Authors
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package io.opentelemetry.javaagent.instrumentation.jaxrsclient.v2_0;
|
|
||||||
|
|
||||||
import io.opentelemetry.context.propagation.TextMapSetter;
|
|
||||||
import javax.ws.rs.client.ClientRequestContext;
|
|
||||||
|
|
||||||
enum ClientRequestContextHeaderSetter implements TextMapSetter<ClientRequestContext> {
|
|
||||||
INSTANCE;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void set(ClientRequestContext carrier, String key, String value) {
|
|
||||||
// Don't allow duplicates.
|
|
||||||
carrier.getHeaders().putSingle(key, value);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,23 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright The OpenTelemetry Authors
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package io.opentelemetry.javaagent.instrumentation.jaxrsclient.v2_0;
|
|
||||||
|
|
||||||
import javax.ws.rs.core.Feature;
|
|
||||||
import javax.ws.rs.core.FeatureContext;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
public class ClientTracingFeature implements Feature {
|
|
||||||
|
|
||||||
private static final Logger logger = LoggerFactory.getLogger(ClientTracingFeature.class);
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean configure(FeatureContext context) {
|
|
||||||
context.register(new ClientTracingFilter());
|
|
||||||
logger.debug("ClientTracingFilter registered");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,42 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright The OpenTelemetry Authors
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package io.opentelemetry.javaagent.instrumentation.jaxrsclient.v2_0;
|
|
||||||
|
|
||||||
import static io.opentelemetry.javaagent.instrumentation.jaxrsclient.v2_0.JaxRsClientSingletons.instrumenter;
|
|
||||||
|
|
||||||
import io.opentelemetry.context.Context;
|
|
||||||
import javax.annotation.Priority;
|
|
||||||
import javax.ws.rs.Priorities;
|
|
||||||
import javax.ws.rs.client.ClientRequestContext;
|
|
||||||
import javax.ws.rs.client.ClientRequestFilter;
|
|
||||||
import javax.ws.rs.client.ClientResponseContext;
|
|
||||||
import javax.ws.rs.client.ClientResponseFilter;
|
|
||||||
|
|
||||||
@Priority(Priorities.HEADER_DECORATOR)
|
|
||||||
public class ClientTracingFilter implements ClientRequestFilter, ClientResponseFilter {
|
|
||||||
public static final String CONTEXT_PROPERTY_NAME = "io.opentelemetry.javaagent.context";
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void filter(ClientRequestContext requestContext) {
|
|
||||||
Context parentContext = Context.current();
|
|
||||||
if (instrumenter().shouldStart(parentContext, requestContext)) {
|
|
||||||
Context context = instrumenter().start(parentContext, requestContext);
|
|
||||||
requestContext.setProperty(CONTEXT_PROPERTY_NAME, context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void filter(ClientRequestContext requestContext, ClientResponseContext responseContext) {
|
|
||||||
Object contextObj = requestContext.getProperty(CONTEXT_PROPERTY_NAME);
|
|
||||||
if (contextObj instanceof Context) {
|
|
||||||
Context context = (Context) contextObj;
|
|
||||||
instrumenter().end(context, requestContext, responseContext, null);
|
|
||||||
}
|
|
||||||
// we are done with this request, remove context so it could be gcd immediately in case request
|
|
||||||
// context stays around for whatever reason
|
|
||||||
requestContext.removeProperty(CONTEXT_PROPERTY_NAME);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,81 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright The OpenTelemetry Authors
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package io.opentelemetry.javaagent.instrumentation.jaxrsclient.v2_0;
|
|
||||||
|
|
||||||
import static java.util.Collections.emptyList;
|
|
||||||
|
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientAttributesGetter;
|
|
||||||
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
|
|
||||||
import java.util.List;
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
import javax.ws.rs.client.ClientRequestContext;
|
|
||||||
import javax.ws.rs.client.ClientResponseContext;
|
|
||||||
|
|
||||||
final class JaxRsClientHttpAttributesGetter
|
|
||||||
implements HttpClientAttributesGetter<ClientRequestContext, ClientResponseContext> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Nullable
|
|
||||||
public String method(ClientRequestContext httpRequest) {
|
|
||||||
return httpRequest.getMethod();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String url(ClientRequestContext httpRequest) {
|
|
||||||
return httpRequest.getUri().toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<String> requestHeader(ClientRequestContext httpRequest, String name) {
|
|
||||||
return httpRequest.getStringHeaders().getOrDefault(name, emptyList());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Nullable
|
|
||||||
public Long requestContentLength(
|
|
||||||
ClientRequestContext httpRequest, @Nullable ClientResponseContext httpResponse) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Nullable
|
|
||||||
public Long requestContentLengthUncompressed(
|
|
||||||
ClientRequestContext httpRequest, @Nullable ClientResponseContext httpResponse) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String flavor(
|
|
||||||
ClientRequestContext httpRequest, @Nullable ClientResponseContext httpResponse) {
|
|
||||||
return SemanticAttributes.HttpFlavorValues.HTTP_1_1;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Integer statusCode(ClientRequestContext httpRequest, ClientResponseContext httpResponse) {
|
|
||||||
return httpResponse.getStatus();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Nullable
|
|
||||||
public Long responseContentLength(
|
|
||||||
ClientRequestContext httpRequest, ClientResponseContext httpResponse) {
|
|
||||||
int length = httpResponse.getLength();
|
|
||||||
return length != -1 ? (long) length : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Nullable
|
|
||||||
public Long responseContentLengthUncompressed(
|
|
||||||
ClientRequestContext httpRequest, ClientResponseContext httpResponse) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<String> responseHeader(
|
|
||||||
ClientRequestContext httpRequest, ClientResponseContext httpResponse, String name) {
|
|
||||||
return httpResponse.getHeaders().getOrDefault(name, emptyList());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright The OpenTelemetry Authors
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package io.opentelemetry.javaagent.instrumentation.jaxrsclient.v2_0;
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
@AutoService(InstrumentationModule.class)
|
|
||||||
public class JaxRsClientInstrumentationModule extends InstrumentationModule {
|
|
||||||
|
|
||||||
public JaxRsClientInstrumentationModule() {
|
|
||||||
super("jaxrs-client", "jaxrs-client-2.0");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<TypeInstrumentation> typeInstrumentations() {
|
|
||||||
return singletonList(new ClientBuilderInstrumentation());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,42 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright The OpenTelemetry Authors
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package io.opentelemetry.javaagent.instrumentation.jaxrsclient.v2_0;
|
|
||||||
|
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.net.NetClientAttributesGetter;
|
|
||||||
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
import javax.ws.rs.client.ClientRequestContext;
|
|
||||||
import javax.ws.rs.client.ClientResponseContext;
|
|
||||||
|
|
||||||
final class JaxRsClientNetAttributesGetter
|
|
||||||
implements NetClientAttributesGetter<ClientRequestContext, ClientResponseContext> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String transport(ClientRequestContext request, @Nullable ClientResponseContext response) {
|
|
||||||
return SemanticAttributes.NetTransportValues.IP_TCP;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Nullable
|
|
||||||
public String peerName(ClientRequestContext request, @Nullable ClientResponseContext response) {
|
|
||||||
return request.getUri().getHost();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Integer peerPort(ClientRequestContext request, @Nullable ClientResponseContext response) {
|
|
||||||
int port = request.getUri().getPort();
|
|
||||||
if (port != -1) {
|
|
||||||
return port;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Nullable
|
|
||||||
public String peerIp(ClientRequestContext request, @Nullable ClientResponseContext response) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,55 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright The OpenTelemetry Authors
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package io.opentelemetry.javaagent.instrumentation.jaxrsclient.v2_0;
|
|
||||||
|
|
||||||
import io.opentelemetry.api.GlobalOpenTelemetry;
|
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.ErrorCauseExtractor;
|
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
|
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.PeerServiceAttributesExtractor;
|
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientAttributesExtractor;
|
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientMetrics;
|
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor;
|
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanStatusExtractor;
|
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.net.NetClientAttributesExtractor;
|
|
||||||
import javax.ws.rs.ProcessingException;
|
|
||||||
import javax.ws.rs.client.ClientRequestContext;
|
|
||||||
import javax.ws.rs.client.ClientResponseContext;
|
|
||||||
|
|
||||||
public class JaxRsClientSingletons {
|
|
||||||
private static final String INSTRUMENTATION_NAME = "io.opentelemetry.jaxrs-client-2.0";
|
|
||||||
|
|
||||||
private static final Instrumenter<ClientRequestContext, ClientResponseContext> INSTRUMENTER;
|
|
||||||
|
|
||||||
static {
|
|
||||||
JaxRsClientHttpAttributesGetter httpAttributesGetter = new JaxRsClientHttpAttributesGetter();
|
|
||||||
JaxRsClientNetAttributesGetter netAttributesGetter = new JaxRsClientNetAttributesGetter();
|
|
||||||
|
|
||||||
INSTRUMENTER =
|
|
||||||
Instrumenter.<ClientRequestContext, ClientResponseContext>builder(
|
|
||||||
GlobalOpenTelemetry.get(),
|
|
||||||
INSTRUMENTATION_NAME,
|
|
||||||
HttpSpanNameExtractor.create(httpAttributesGetter))
|
|
||||||
.setSpanStatusExtractor(HttpSpanStatusExtractor.create(httpAttributesGetter))
|
|
||||||
.setErrorCauseExtractor(
|
|
||||||
(throwable) -> {
|
|
||||||
if (throwable instanceof ProcessingException) {
|
|
||||||
throwable = throwable.getCause();
|
|
||||||
}
|
|
||||||
return ErrorCauseExtractor.jdk().extractCause(throwable);
|
|
||||||
})
|
|
||||||
.addAttributesExtractor(HttpClientAttributesExtractor.create(httpAttributesGetter))
|
|
||||||
.addAttributesExtractor(NetClientAttributesExtractor.create(netAttributesGetter))
|
|
||||||
.addAttributesExtractor(PeerServiceAttributesExtractor.create(netAttributesGetter))
|
|
||||||
.addRequestMetrics(HttpClientMetrics.get())
|
|
||||||
.newClientInstrumenter(ClientRequestContextHeaderSetter.INSTANCE);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Instrumenter<ClientRequestContext, ClientResponseContext> instrumenter() {
|
|
||||||
return INSTRUMENTER;
|
|
||||||
}
|
|
||||||
|
|
||||||
private JaxRsClientSingletons() {}
|
|
||||||
}
|
|
|
@ -1,17 +0,0 @@
|
||||||
plugins {
|
|
||||||
id("otel.javaagent-instrumentation")
|
|
||||||
}
|
|
||||||
|
|
||||||
muzzle {
|
|
||||||
pass {
|
|
||||||
group.set("org.apache.cxf")
|
|
||||||
module.set("cxf-rt-rs-client")
|
|
||||||
versions.set("[3.0.0,)")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
library("org.apache.cxf:cxf-rt-rs-client:3.0.0")
|
|
||||||
|
|
||||||
implementation(project(":instrumentation:jaxrs-client:jaxrs-client-2.0:jaxrs-client-2.0-common:javaagent"))
|
|
||||||
}
|
|
|
@ -1,46 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright The OpenTelemetry Authors
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package io.opentelemetry.javaagent.instrumentation.jaxrsclient.v2_0;
|
|
||||||
|
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
|
|
||||||
|
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
|
||||||
import java.util.Map;
|
|
||||||
import net.bytebuddy.asm.Advice;
|
|
||||||
import net.bytebuddy.description.type.TypeDescription;
|
|
||||||
import net.bytebuddy.matcher.ElementMatcher;
|
|
||||||
import org.apache.cxf.message.Message;
|
|
||||||
|
|
||||||
public class CxfAsyncClientConnectionErrorInstrumentation implements TypeInstrumentation {
|
|
||||||
@Override
|
|
||||||
public ElementMatcher<TypeDescription> typeMatcher() {
|
|
||||||
return named("org.apache.cxf.jaxrs.client.JaxrsClientCallback");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void transform(TypeTransformer transformer) {
|
|
||||||
transformer.applyAdviceToMethod(
|
|
||||||
named("handleException")
|
|
||||||
.and(
|
|
||||||
takesArgument(0, named(Map.class.getName()))
|
|
||||||
.and(takesArgument(1, named(Throwable.class.getName())))),
|
|
||||||
this.getClass().getName() + "$HandleExceptionAdvice");
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
public static class HandleExceptionAdvice {
|
|
||||||
|
|
||||||
@Advice.OnMethodExit(suppress = Throwable.class)
|
|
||||||
public static void handleError(
|
|
||||||
@Advice.Argument(0) Map<String, Object> map, @Advice.Argument(1) Throwable throwable) {
|
|
||||||
if (throwable != null && map instanceof Message) {
|
|
||||||
CxfClientUtil.handleException((Message) map, throwable);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,42 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright The OpenTelemetry Authors
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package io.opentelemetry.javaagent.instrumentation.jaxrsclient.v2_0;
|
|
||||||
|
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
|
|
||||||
|
|
||||||
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.apache.cxf.message.Message;
|
|
||||||
|
|
||||||
public class CxfClientConnectionErrorInstrumentation implements TypeInstrumentation {
|
|
||||||
@Override
|
|
||||||
public ElementMatcher<TypeDescription> typeMatcher() {
|
|
||||||
return named("org.apache.cxf.jaxrs.client.AbstractClient");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void transform(TypeTransformer transformer) {
|
|
||||||
transformer.applyAdviceToMethod(
|
|
||||||
named("preProcessResult").and(takesArgument(0, named("org.apache.cxf.message.Message"))),
|
|
||||||
this.getClass().getName() + "$PreProcessResultAdvice");
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
public static class PreProcessResultAdvice {
|
|
||||||
|
|
||||||
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
|
||||||
public static void handleError(
|
|
||||||
@Advice.Argument(0) Message message, @Advice.Thrown Throwable throwable) {
|
|
||||||
if (throwable != null) {
|
|
||||||
CxfClientUtil.handleException(message, throwable);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,32 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright The OpenTelemetry Authors
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package io.opentelemetry.javaagent.instrumentation.jaxrsclient.v2_0;
|
|
||||||
|
|
||||||
import static java.util.Arrays.asList;
|
|
||||||
|
|
||||||
import com.google.auto.service.AutoService;
|
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* JAX-RS Client API doesn't define a good point where we can handle connection failures, so we must
|
|
||||||
* handle these errors at the implementation level.
|
|
||||||
*/
|
|
||||||
@AutoService(InstrumentationModule.class)
|
|
||||||
public class CxfClientInstrumentationModule extends InstrumentationModule {
|
|
||||||
|
|
||||||
public CxfClientInstrumentationModule() {
|
|
||||||
super("jaxrs-client", "jaxrs-client-2.0", "cxf-client", "cxf-client-3.0");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<TypeInstrumentation> typeInstrumentations() {
|
|
||||||
return asList(
|
|
||||||
new CxfClientConnectionErrorInstrumentation(),
|
|
||||||
new CxfAsyncClientConnectionErrorInstrumentation());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,27 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright The OpenTelemetry Authors
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package io.opentelemetry.javaagent.instrumentation.jaxrsclient.v2_0;
|
|
||||||
|
|
||||||
import static io.opentelemetry.javaagent.instrumentation.jaxrsclient.v2_0.JaxRsClientSingletons.instrumenter;
|
|
||||||
|
|
||||||
import io.opentelemetry.context.Context;
|
|
||||||
import javax.ws.rs.client.ClientRequestContext;
|
|
||||||
import org.apache.cxf.jaxrs.client.spec.ClientRequestContextImpl;
|
|
||||||
import org.apache.cxf.message.Message;
|
|
||||||
|
|
||||||
public final class CxfClientUtil {
|
|
||||||
|
|
||||||
public static void handleException(Message message, Throwable throwable) {
|
|
||||||
ClientRequestContext context =
|
|
||||||
new ClientRequestContextImpl(message, /* responseContext= */ false);
|
|
||||||
Object prop = context.getProperty(ClientTracingFilter.CONTEXT_PROPERTY_NAME);
|
|
||||||
if (prop instanceof Context) {
|
|
||||||
instrumenter().end((Context) prop, context, null, throwable);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private CxfClientUtil() {}
|
|
||||||
}
|
|
|
@ -1,17 +0,0 @@
|
||||||
plugins {
|
|
||||||
id("otel.javaagent-instrumentation")
|
|
||||||
}
|
|
||||||
|
|
||||||
muzzle {
|
|
||||||
pass {
|
|
||||||
group.set("org.glassfish.jersey.core")
|
|
||||||
module.set("jersey-client")
|
|
||||||
versions.set("[2.0,3.0.0)")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
library("org.glassfish.jersey.core:jersey-client:2.0")
|
|
||||||
|
|
||||||
implementation(project(":instrumentation:jaxrs-client:jaxrs-client-2.0:jaxrs-client-2.0-common:javaagent"))
|
|
||||||
}
|
|
|
@ -1,69 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright The OpenTelemetry Authors
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package io.opentelemetry.javaagent.instrumentation.jaxrsclient.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.namedOneOf;
|
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
|
|
||||||
|
|
||||||
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.implementation.bytecode.assign.Assigner;
|
|
||||||
import net.bytebuddy.matcher.ElementMatcher;
|
|
||||||
import org.glassfish.jersey.client.ClientRequest;
|
|
||||||
import org.glassfish.jersey.client.OpenTelemetryResponseCallbackWrapper;
|
|
||||||
|
|
||||||
public class JerseyClientConnectionErrorInstrumentation implements TypeInstrumentation {
|
|
||||||
@Override
|
|
||||||
public ElementMatcher<TypeDescription> typeMatcher() {
|
|
||||||
return named("org.glassfish.jersey.client.ClientRuntime");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void transform(TypeTransformer transformer) {
|
|
||||||
transformer.applyAdviceToMethod(
|
|
||||||
isMethod()
|
|
||||||
.and(isPublic())
|
|
||||||
.and(named("invoke"))
|
|
||||||
.and(takesArgument(0, named("org.glassfish.jersey.client.ClientRequest"))),
|
|
||||||
this.getClass().getName() + "$InvokeAdvice");
|
|
||||||
transformer.applyAdviceToMethod(
|
|
||||||
isMethod()
|
|
||||||
.and(namedOneOf("submit", "createRunnableForAsyncProcessing"))
|
|
||||||
.and(takesArgument(0, named("org.glassfish.jersey.client.ClientRequest")))
|
|
||||||
.and(takesArgument(1, named("org.glassfish.jersey.client.ResponseCallback"))),
|
|
||||||
this.getClass().getName() + "$SubmitAdvice");
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
public static class InvokeAdvice {
|
|
||||||
|
|
||||||
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
|
||||||
public static void handleError(
|
|
||||||
@Advice.Argument(0) ClientRequest context, @Advice.Thrown Throwable throwable) {
|
|
||||||
if (throwable != null) {
|
|
||||||
JerseyClientUtil.handleException(context, throwable);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
public static class SubmitAdvice {
|
|
||||||
|
|
||||||
// using dynamic typing because parameter type is package private
|
|
||||||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
|
||||||
public static void handleError(
|
|
||||||
@Advice.Argument(0) ClientRequest context,
|
|
||||||
@Advice.Argument(value = 1, readOnly = false, typing = Assigner.Typing.DYNAMIC)
|
|
||||||
Object callback) {
|
|
||||||
callback = OpenTelemetryResponseCallbackWrapper.wrap(context, callback);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,35 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright The OpenTelemetry Authors
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package io.opentelemetry.javaagent.instrumentation.jaxrsclient.v2_0;
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* JAX-RS Client API doesn't define a good point where we can handle connection failures, so we must
|
|
||||||
* handle these errors at the implementation level.
|
|
||||||
*/
|
|
||||||
@AutoService(InstrumentationModule.class)
|
|
||||||
public class JerseyClientInstrumentationModule extends InstrumentationModule {
|
|
||||||
|
|
||||||
public JerseyClientInstrumentationModule() {
|
|
||||||
super("jaxrs-client", "jaxrs-client-2.0", "jersey-client", "jersey-client-2.0");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isHelperClass(String className) {
|
|
||||||
return className.equals("org.glassfish.jersey.client.OpenTelemetryResponseCallbackWrapper");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<TypeInstrumentation> typeInstrumentations() {
|
|
||||||
return singletonList(new JerseyClientConnectionErrorInstrumentation());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,23 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright The OpenTelemetry Authors
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package io.opentelemetry.javaagent.instrumentation.jaxrsclient.v2_0;
|
|
||||||
|
|
||||||
import static io.opentelemetry.javaagent.instrumentation.jaxrsclient.v2_0.JaxRsClientSingletons.instrumenter;
|
|
||||||
|
|
||||||
import io.opentelemetry.context.Context;
|
|
||||||
import org.glassfish.jersey.client.ClientRequest;
|
|
||||||
|
|
||||||
public final class JerseyClientUtil {
|
|
||||||
|
|
||||||
public static void handleException(ClientRequest context, Throwable exception) {
|
|
||||||
Object prop = context.getProperty(ClientTracingFilter.CONTEXT_PROPERTY_NAME);
|
|
||||||
if (prop instanceof Context) {
|
|
||||||
instrumenter().end((Context) prop, context, null, exception);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private JerseyClientUtil() {}
|
|
||||||
}
|
|
|
@ -1,40 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright The OpenTelemetry Authors
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.glassfish.jersey.client;
|
|
||||||
|
|
||||||
import static io.opentelemetry.javaagent.instrumentation.jaxrsclient.v2_0.JerseyClientUtil.handleException;
|
|
||||||
|
|
||||||
import javax.ws.rs.ProcessingException;
|
|
||||||
import org.glassfish.jersey.process.internal.RequestScope;
|
|
||||||
|
|
||||||
// implemented interface is package private so wrapper needs to be in the same package
|
|
||||||
public class OpenTelemetryResponseCallbackWrapper implements ResponseCallback {
|
|
||||||
private final ClientRequest request;
|
|
||||||
private final ResponseCallback delegate;
|
|
||||||
|
|
||||||
public OpenTelemetryResponseCallbackWrapper(ClientRequest request, ResponseCallback delegate) {
|
|
||||||
this.request = request;
|
|
||||||
this.delegate = delegate;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Object wrap(ClientRequest request, Object callback) {
|
|
||||||
if (callback instanceof ResponseCallback) {
|
|
||||||
return new OpenTelemetryResponseCallbackWrapper(request, (ResponseCallback) callback);
|
|
||||||
}
|
|
||||||
return callback;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void completed(ClientResponse clientResponse, RequestScope requestScope) {
|
|
||||||
delegate.completed(clientResponse, requestScope);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void failed(ProcessingException exception) {
|
|
||||||
handleException(request, exception.getCause());
|
|
||||||
delegate.failed(exception);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,17 +0,0 @@
|
||||||
plugins {
|
|
||||||
id("otel.javaagent-instrumentation")
|
|
||||||
}
|
|
||||||
|
|
||||||
muzzle {
|
|
||||||
pass {
|
|
||||||
group.set("org.jboss.resteasy")
|
|
||||||
module.set("resteasy-client")
|
|
||||||
versions.set("[3.0.0.Final,6)")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
library("org.jboss.resteasy:resteasy-client:3.0.0.Final")
|
|
||||||
|
|
||||||
implementation(project(":instrumentation:jaxrs-client:jaxrs-client-2.0:jaxrs-client-2.0-common:javaagent"))
|
|
||||||
}
|
|
|
@ -1,25 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright The OpenTelemetry Authors
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package io.opentelemetry.javaagent.instrumentation.jaxrsclient.v2_0;
|
|
||||||
|
|
||||||
import io.opentelemetry.context.propagation.TextMapSetter;
|
|
||||||
import javax.ws.rs.core.MultivaluedMap;
|
|
||||||
import org.jboss.resteasy.client.jaxrs.internal.ClientInvocation;
|
|
||||||
|
|
||||||
enum ClientInvocationHeaderSetter implements TextMapSetter<ClientInvocation> {
|
|
||||||
INSTANCE;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void set(ClientInvocation carrier, String key, String value) {
|
|
||||||
// Don't allow duplicates.
|
|
||||||
// Using MultivaluedMap instead of CaseInsensitiveMap returned by getHeaders because in versions
|
|
||||||
// prior to 3.0.10.Final CaseInsensitiveMap has putSingle(String, Object) which is not present
|
|
||||||
// in later versions. Going through MultivaluedMap ensures that we'll be calling
|
|
||||||
// putSingle(Object, Object) that is present in all versions.
|
|
||||||
MultivaluedMap<String, Object> map = carrier.getHeaders().getHeaders();
|
|
||||||
map.putSingle(key, value);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,87 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright The OpenTelemetry Authors
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package io.opentelemetry.javaagent.instrumentation.jaxrsclient.v2_0;
|
|
||||||
|
|
||||||
import static java.util.Collections.emptyList;
|
|
||||||
|
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientAttributesGetter;
|
|
||||||
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
import javax.ws.rs.core.Response;
|
|
||||||
import org.jboss.resteasy.client.jaxrs.internal.ClientInvocation;
|
|
||||||
|
|
||||||
final class ResteasyClientHttpAttributesGetter
|
|
||||||
implements HttpClientAttributesGetter<ClientInvocation, Response> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Nullable
|
|
||||||
public String method(ClientInvocation httpRequest) {
|
|
||||||
return httpRequest.getMethod();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String url(ClientInvocation httpRequest) {
|
|
||||||
return httpRequest.getUri().toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<String> requestHeader(ClientInvocation httpRequest, String name) {
|
|
||||||
List<Object> rawHeaders = httpRequest.getHeaders().getHeaders().getOrDefault(name, emptyList());
|
|
||||||
if (rawHeaders.isEmpty()) {
|
|
||||||
return emptyList();
|
|
||||||
}
|
|
||||||
List<String> stringHeaders = new ArrayList<>(rawHeaders.size());
|
|
||||||
for (Object headerValue : rawHeaders) {
|
|
||||||
stringHeaders.add(String.valueOf(headerValue));
|
|
||||||
}
|
|
||||||
return stringHeaders;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Nullable
|
|
||||||
public Long requestContentLength(ClientInvocation httpRequest, @Nullable Response httpResponse) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Nullable
|
|
||||||
public Long requestContentLengthUncompressed(
|
|
||||||
ClientInvocation httpRequest, @Nullable Response httpResponse) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String flavor(ClientInvocation httpRequest, @Nullable Response httpResponse) {
|
|
||||||
return SemanticAttributes.HttpFlavorValues.HTTP_1_1;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Integer statusCode(ClientInvocation httpRequest, Response httpResponse) {
|
|
||||||
return httpResponse.getStatus();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Nullable
|
|
||||||
public Long responseContentLength(ClientInvocation httpRequest, Response httpResponse) {
|
|
||||||
int length = httpResponse.getLength();
|
|
||||||
return length != -1 ? (long) length : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Nullable
|
|
||||||
public Long responseContentLengthUncompressed(
|
|
||||||
ClientInvocation httpRequest, Response httpResponse) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<String> responseHeader(
|
|
||||||
ClientInvocation clientInvocation, Response response, String name) {
|
|
||||||
return response.getStringHeaders().getOrDefault(name, emptyList());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,94 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright The OpenTelemetry Authors
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package io.opentelemetry.javaagent.instrumentation.jaxrsclient.v2_0;
|
|
||||||
|
|
||||||
import static io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge.currentContext;
|
|
||||||
import static io.opentelemetry.javaagent.instrumentation.jaxrsclient.v2_0.ResteasyClientSingletons.instrumenter;
|
|
||||||
import static java.util.Collections.singletonList;
|
|
||||||
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.takesArguments;
|
|
||||||
|
|
||||||
import com.google.auto.service.AutoService;
|
|
||||||
import io.opentelemetry.context.Context;
|
|
||||||
import io.opentelemetry.context.Scope;
|
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
|
||||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
|
||||||
import java.util.List;
|
|
||||||
import javax.ws.rs.core.Response;
|
|
||||||
import net.bytebuddy.asm.Advice;
|
|
||||||
import net.bytebuddy.description.type.TypeDescription;
|
|
||||||
import net.bytebuddy.matcher.ElementMatcher;
|
|
||||||
import org.jboss.resteasy.client.jaxrs.internal.ClientInvocation;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unlike other supported JAX-RS Client implementations, Resteasy's one is very simple and passes
|
|
||||||
* all requests through single point. Both sync ADN async! This allows for easy instrumentation and
|
|
||||||
* proper scope handling.
|
|
||||||
*
|
|
||||||
* <p>This specific instrumentation will not conflict with {@link JaxRsClientInstrumentationModule},
|
|
||||||
* because nested client spans are suppressed.
|
|
||||||
*/
|
|
||||||
@AutoService(InstrumentationModule.class)
|
|
||||||
public class ResteasyClientInstrumentationModule extends InstrumentationModule {
|
|
||||||
|
|
||||||
public ResteasyClientInstrumentationModule() {
|
|
||||||
super("jaxrs-client", "jaxrs-client-2.0", "resteasy-client", "resteasy-client-2.0");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<TypeInstrumentation> typeInstrumentations() {
|
|
||||||
return singletonList(new ResteasyClientConnectionErrorInstrumentation());
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final class ResteasyClientConnectionErrorInstrumentation
|
|
||||||
implements TypeInstrumentation {
|
|
||||||
@Override
|
|
||||||
public ElementMatcher<TypeDescription> typeMatcher() {
|
|
||||||
return named("org.jboss.resteasy.client.jaxrs.internal.ClientInvocation");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void transform(TypeTransformer transformer) {
|
|
||||||
transformer.applyAdviceToMethod(
|
|
||||||
isMethod().and(isPublic()).and(named("invoke")).and(takesArguments(0)),
|
|
||||||
ResteasyClientInstrumentationModule.class.getName() + "$InvokeAdvice");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
public static class InvokeAdvice {
|
|
||||||
|
|
||||||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
|
||||||
public static void methodEnter(
|
|
||||||
@Advice.This ClientInvocation invocation,
|
|
||||||
@Advice.Local("otelContext") Context context,
|
|
||||||
@Advice.Local("otelScope") Scope scope) {
|
|
||||||
Context parentContext = currentContext();
|
|
||||||
if (instrumenter().shouldStart(parentContext, invocation)) {
|
|
||||||
context = instrumenter().start(parentContext, invocation);
|
|
||||||
scope = context.makeCurrent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
|
||||||
public static void methodExit(
|
|
||||||
@Advice.This ClientInvocation invocation,
|
|
||||||
@Advice.Return Response response,
|
|
||||||
@Advice.Thrown Throwable throwable,
|
|
||||||
@Advice.Local("otelContext") Context context,
|
|
||||||
@Advice.Local("otelScope") Scope scope) {
|
|
||||||
if (scope == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
scope.close();
|
|
||||||
instrumenter().end(context, invocation, response, throwable);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,42 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright The OpenTelemetry Authors
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package io.opentelemetry.javaagent.instrumentation.jaxrsclient.v2_0;
|
|
||||||
|
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.net.NetClientAttributesGetter;
|
|
||||||
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
import javax.ws.rs.core.Response;
|
|
||||||
import org.jboss.resteasy.client.jaxrs.internal.ClientInvocation;
|
|
||||||
|
|
||||||
final class ResteasyClientNetAttributesGetter
|
|
||||||
implements NetClientAttributesGetter<ClientInvocation, Response> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String transport(ClientInvocation request, @Nullable Response response) {
|
|
||||||
return SemanticAttributes.NetTransportValues.IP_TCP;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Nullable
|
|
||||||
public String peerName(ClientInvocation request, @Nullable Response response) {
|
|
||||||
return request.getUri().getHost();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Integer peerPort(ClientInvocation request, @Nullable Response response) {
|
|
||||||
int port = request.getUri().getPort();
|
|
||||||
if (port != -1) {
|
|
||||||
return port;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Nullable
|
|
||||||
public String peerIp(ClientInvocation request, @Nullable Response response) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,57 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright The OpenTelemetry Authors
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package io.opentelemetry.javaagent.instrumentation.jaxrsclient.v2_0;
|
|
||||||
|
|
||||||
import io.opentelemetry.api.GlobalOpenTelemetry;
|
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.ErrorCauseExtractor;
|
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
|
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.PeerServiceAttributesExtractor;
|
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientAttributesExtractor;
|
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientMetrics;
|
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor;
|
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanStatusExtractor;
|
|
||||||
import io.opentelemetry.instrumentation.api.instrumenter.net.NetClientAttributesExtractor;
|
|
||||||
import javax.ws.rs.ProcessingException;
|
|
||||||
import javax.ws.rs.core.Response;
|
|
||||||
import org.jboss.resteasy.client.jaxrs.internal.ClientInvocation;
|
|
||||||
|
|
||||||
public class ResteasyClientSingletons {
|
|
||||||
private static final String INSTRUMENTATION_NAME =
|
|
||||||
"io.opentelemetry.jaxrs-client-2.0-resteasy-3.0";
|
|
||||||
|
|
||||||
private static final Instrumenter<ClientInvocation, Response> INSTRUMENTER;
|
|
||||||
|
|
||||||
static {
|
|
||||||
ResteasyClientHttpAttributesGetter httpAttributesGetter =
|
|
||||||
new ResteasyClientHttpAttributesGetter();
|
|
||||||
ResteasyClientNetAttributesGetter netAttributesGetter = new ResteasyClientNetAttributesGetter();
|
|
||||||
|
|
||||||
INSTRUMENTER =
|
|
||||||
Instrumenter.<ClientInvocation, Response>builder(
|
|
||||||
GlobalOpenTelemetry.get(),
|
|
||||||
INSTRUMENTATION_NAME,
|
|
||||||
HttpSpanNameExtractor.create(httpAttributesGetter))
|
|
||||||
.setSpanStatusExtractor(HttpSpanStatusExtractor.create(httpAttributesGetter))
|
|
||||||
.setErrorCauseExtractor(
|
|
||||||
(throwable) -> {
|
|
||||||
if (throwable instanceof ProcessingException) {
|
|
||||||
throwable = throwable.getCause();
|
|
||||||
}
|
|
||||||
return ErrorCauseExtractor.jdk().extractCause(throwable);
|
|
||||||
})
|
|
||||||
.addAttributesExtractor(HttpClientAttributesExtractor.create(httpAttributesGetter))
|
|
||||||
.addAttributesExtractor(NetClientAttributesExtractor.create(netAttributesGetter))
|
|
||||||
.addAttributesExtractor(PeerServiceAttributesExtractor.create(netAttributesGetter))
|
|
||||||
.addRequestMetrics(HttpClientMetrics.get())
|
|
||||||
.newClientInstrumenter(ClientInvocationHeaderSetter.INSTANCE);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Instrumenter<ClientInvocation, Response> instrumenter() {
|
|
||||||
return INSTRUMENTER;
|
|
||||||
}
|
|
||||||
|
|
||||||
private ResteasyClientSingletons() {}
|
|
||||||
}
|
|
|
@ -220,10 +220,7 @@ include(":instrumentation:jaxrs:jaxrs-2.0:jaxrs-2.0-common:testing")
|
||||||
include(":instrumentation:jaxrs:jaxrs-2.0:jaxrs-2.0-tomee-testing")
|
include(":instrumentation:jaxrs:jaxrs-2.0:jaxrs-2.0-tomee-testing")
|
||||||
include(":instrumentation:jaxrs:jaxrs-2.0:jaxrs-2.0-wildfly-testing")
|
include(":instrumentation:jaxrs:jaxrs-2.0:jaxrs-2.0-wildfly-testing")
|
||||||
include(":instrumentation:jaxrs-client:jaxrs-client-1.1:javaagent")
|
include(":instrumentation:jaxrs-client:jaxrs-client-1.1:javaagent")
|
||||||
include(":instrumentation:jaxrs-client:jaxrs-client-2.0:jaxrs-client-2.0-common:javaagent")
|
include(":instrumentation:jaxrs-client:jaxrs-client-2.0-testing")
|
||||||
include(":instrumentation:jaxrs-client:jaxrs-client-2.0:jaxrs-client-2.0-cxf-3.0:javaagent")
|
|
||||||
include(":instrumentation:jaxrs-client:jaxrs-client-2.0:jaxrs-client-2.0-jersey-2.0:javaagent")
|
|
||||||
include(":instrumentation:jaxrs-client:jaxrs-client-2.0:jaxrs-client-2.0-resteasy-3.0:javaagent")
|
|
||||||
include(":instrumentation:jaxws:jaxws-2.0:javaagent")
|
include(":instrumentation:jaxws:jaxws-2.0:javaagent")
|
||||||
include(":instrumentation:jaxws:jaxws-2.0-arquillian-testing")
|
include(":instrumentation:jaxws:jaxws-2.0-arquillian-testing")
|
||||||
include(":instrumentation:jaxws:jaxws-2.0-axis2-1.6:javaagent")
|
include(":instrumentation:jaxws:jaxws-2.0-axis2-1.6:javaagent")
|
||||||
|
|
Loading…
Reference in New Issue