Migrate vertx HTTP client to Instrumenter API (#4510)
* Migrate vertx HTTP client to Instrumenter API * Fix vertx-reactive tests * Code review comments
This commit is contained in:
parent
3e3024d2b9
commit
bdb3511362
|
@ -7,7 +7,7 @@ package io.opentelemetry.javaagent.instrumentation.vertx.v3_0.client;
|
||||||
|
|
||||||
import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasClassesNamed;
|
import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasClassesNamed;
|
||||||
import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.implementsInterface;
|
import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.implementsInterface;
|
||||||
import static io.opentelemetry.javaagent.instrumentation.vertx.v3_0.client.VertxClientTracer.tracer;
|
import static io.opentelemetry.javaagent.instrumentation.vertx.v3_0.client.VertxClientSingletons.instrumenter;
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.isMethod;
|
import static net.bytebuddy.matcher.ElementMatchers.isMethod;
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.isPrivate;
|
import static net.bytebuddy.matcher.ElementMatchers.isPrivate;
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.nameStartsWith;
|
import static net.bytebuddy.matcher.ElementMatchers.nameStartsWith;
|
||||||
|
@ -88,13 +88,14 @@ public class HttpRequestInstrumentation implements TypeInstrumentation {
|
||||||
@Advice.This HttpClientRequest request,
|
@Advice.This HttpClientRequest request,
|
||||||
@Advice.Local("otelContext") Context context,
|
@Advice.Local("otelContext") Context context,
|
||||||
@Advice.Local("otelScope") Scope scope) {
|
@Advice.Local("otelScope") Scope scope) {
|
||||||
|
|
||||||
Context parentContext = Java8BytecodeBridge.currentContext();
|
Context parentContext = Java8BytecodeBridge.currentContext();
|
||||||
|
|
||||||
if (!tracer().shouldStartSpan(parentContext)) {
|
if (!instrumenter().shouldStart(parentContext, request)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
context = tracer().startSpan(parentContext, request, request);
|
context = instrumenter().start(parentContext, request);
|
||||||
Contexts contexts = new Contexts(parentContext, context);
|
Contexts contexts = new Contexts(parentContext, context);
|
||||||
VirtualField.find(HttpClientRequest.class, Contexts.class).set(request, contexts);
|
VirtualField.find(HttpClientRequest.class, Contexts.class).set(request, contexts);
|
||||||
|
|
||||||
|
@ -103,6 +104,7 @@ public class HttpRequestInstrumentation implements TypeInstrumentation {
|
||||||
|
|
||||||
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
||||||
public static void endScope(
|
public static void endScope(
|
||||||
|
@Advice.This HttpClientRequest request,
|
||||||
@Advice.Local("otelContext") Context context,
|
@Advice.Local("otelContext") Context context,
|
||||||
@Advice.Local("otelScope") Scope scope,
|
@Advice.Local("otelScope") Scope scope,
|
||||||
@Advice.Thrown Throwable throwable) {
|
@Advice.Thrown Throwable throwable) {
|
||||||
|
@ -110,7 +112,7 @@ public class HttpRequestInstrumentation implements TypeInstrumentation {
|
||||||
scope.close();
|
scope.close();
|
||||||
}
|
}
|
||||||
if (throwable != null) {
|
if (throwable != null) {
|
||||||
tracer().endExceptionally(context, throwable);
|
instrumenter().end(context, request, null, throwable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -129,7 +131,7 @@ public class HttpRequestInstrumentation implements TypeInstrumentation {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
tracer().endExceptionally(contexts.context, t);
|
instrumenter().end(contexts.context, request, null, t);
|
||||||
|
|
||||||
// Scoping all potential callbacks etc to the parent context
|
// Scoping all potential callbacks etc to the parent context
|
||||||
scope = contexts.parentContext.makeCurrent();
|
scope = contexts.parentContext.makeCurrent();
|
||||||
|
@ -157,7 +159,7 @@ public class HttpRequestInstrumentation implements TypeInstrumentation {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
tracer().end(contexts.context, response);
|
instrumenter().end(contexts.context, request, response, null);
|
||||||
|
|
||||||
// Scoping all potential callbacks etc to the parent context
|
// Scoping all potential callbacks etc to the parent context
|
||||||
scope = contexts.parentContext.makeCurrent();
|
scope = contexts.parentContext.makeCurrent();
|
||||||
|
@ -203,7 +205,7 @@ public class HttpRequestInstrumentation implements TypeInstrumentation {
|
||||||
if (handler != null) {
|
if (handler != null) {
|
||||||
VirtualField<HttpClientRequest, Contexts> virtualField =
|
VirtualField<HttpClientRequest, Contexts> virtualField =
|
||||||
VirtualField.find(HttpClientRequest.class, Contexts.class);
|
VirtualField.find(HttpClientRequest.class, Contexts.class);
|
||||||
handler = ExceptionHandlerWrapper.wrap(tracer(), request, virtualField, handler);
|
handler = ExceptionHandlerWrapper.wrap(instrumenter(), request, virtualField, handler);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.javaagent.instrumentation.vertx.v3_0.client;
|
||||||
|
|
||||||
|
import io.opentelemetry.javaagent.instrumentation.vertx.client.AbstractVertxHttpAttributesExtractor;
|
||||||
|
import io.vertx.core.http.HttpClientRequest;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
final class Vertx3HttpAttributesExtractor extends AbstractVertxHttpAttributesExtractor {
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
protected String url(HttpClientRequest request) {
|
||||||
|
return request.uri();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String method(HttpClientRequest request) {
|
||||||
|
return request.method().name();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.javaagent.instrumentation.vertx.v3_0.client;
|
||||||
|
|
||||||
|
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
|
||||||
|
import io.opentelemetry.javaagent.instrumentation.vertx.client.VertxClientInstrumenterFactory;
|
||||||
|
import io.vertx.core.http.HttpClientRequest;
|
||||||
|
import io.vertx.core.http.HttpClientResponse;
|
||||||
|
|
||||||
|
public final class VertxClientSingletons {
|
||||||
|
|
||||||
|
private static final Instrumenter<HttpClientRequest, HttpClientResponse> INSTRUMENTER =
|
||||||
|
VertxClientInstrumenterFactory.create(
|
||||||
|
"io.opentelemetry.vertx-http-client-3.0", new Vertx3HttpAttributesExtractor(), null);
|
||||||
|
|
||||||
|
public static Instrumenter<HttpClientRequest, HttpClientResponse> instrumenter() {
|
||||||
|
return INSTRUMENTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
private VertxClientSingletons() {}
|
||||||
|
}
|
|
@ -1,36 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright The OpenTelemetry Authors
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package io.opentelemetry.javaagent.instrumentation.vertx.v3_0.client;
|
|
||||||
|
|
||||||
import io.opentelemetry.javaagent.instrumentation.vertx.client.AbstractVertxClientTracer;
|
|
||||||
import io.vertx.core.http.HttpClientRequest;
|
|
||||||
import java.net.URI;
|
|
||||||
import java.net.URISyntaxException;
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
public class VertxClientTracer extends AbstractVertxClientTracer {
|
|
||||||
private static final VertxClientTracer TRACER = new VertxClientTracer();
|
|
||||||
|
|
||||||
public static VertxClientTracer tracer() {
|
|
||||||
return TRACER;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String getInstrumentationName() {
|
|
||||||
return "io.opentelemetry.vertx-http-client-3.0";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String method(HttpClientRequest request) {
|
|
||||||
return request.method().name();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Nullable
|
|
||||||
protected URI url(HttpClientRequest request) throws URISyntaxException {
|
|
||||||
return new URI(request.uri());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -5,10 +5,12 @@
|
||||||
|
|
||||||
package client
|
package client
|
||||||
|
|
||||||
|
import io.opentelemetry.api.common.AttributeKey
|
||||||
import io.opentelemetry.instrumentation.test.AgentTestTrait
|
import io.opentelemetry.instrumentation.test.AgentTestTrait
|
||||||
import io.opentelemetry.instrumentation.test.base.HttpClientTest
|
import io.opentelemetry.instrumentation.test.base.HttpClientTest
|
||||||
import io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpClientTest
|
import io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpClientTest
|
||||||
import io.opentelemetry.instrumentation.testing.junit.http.SingleConnection
|
import io.opentelemetry.instrumentation.testing.junit.http.SingleConnection
|
||||||
|
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes
|
||||||
import io.vertx.core.Vertx
|
import io.vertx.core.Vertx
|
||||||
import io.vertx.core.VertxOptions
|
import io.vertx.core.VertxOptions
|
||||||
import io.vertx.core.http.HttpClientOptions
|
import io.vertx.core.http.HttpClientOptions
|
||||||
|
@ -76,6 +78,15 @@ class VertxHttpClientTest extends HttpClientTest<HttpClientRequest> implements A
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
Set<AttributeKey<?>> httpAttributes(URI uri) {
|
||||||
|
def attributes = super.httpAttributes(uri)
|
||||||
|
attributes.remove(SemanticAttributes.HTTP_FLAVOR)
|
||||||
|
attributes.remove(SemanticAttributes.NET_PEER_NAME)
|
||||||
|
attributes.remove(SemanticAttributes.NET_PEER_PORT)
|
||||||
|
return attributes
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
SingleConnection createSingleConnection(String host, int port) {
|
SingleConnection createSingleConnection(String host, int port) {
|
||||||
//This test fails on Vert.x 3.0 and only works starting from 3.1
|
//This test fails on Vert.x 3.0 and only works starting from 3.1
|
||||||
|
|
|
@ -7,7 +7,7 @@ package io.opentelemetry.javaagent.instrumentation.vertx.v4_0.client;
|
||||||
|
|
||||||
import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasClassesNamed;
|
import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasClassesNamed;
|
||||||
import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.implementsInterface;
|
import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.implementsInterface;
|
||||||
import static io.opentelemetry.javaagent.instrumentation.vertx.v4_0.client.VertxClientTracer.tracer;
|
import static io.opentelemetry.javaagent.instrumentation.vertx.v4_0.client.VertxClientSingletons.instrumenter;
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.isMethod;
|
import static net.bytebuddy.matcher.ElementMatchers.isMethod;
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.isPrivate;
|
import static net.bytebuddy.matcher.ElementMatchers.isPrivate;
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.nameStartsWith;
|
import static net.bytebuddy.matcher.ElementMatchers.nameStartsWith;
|
||||||
|
@ -92,11 +92,11 @@ public class HttpRequestInstrumentation implements TypeInstrumentation {
|
||||||
@Advice.Local("otelScope") Scope scope) {
|
@Advice.Local("otelScope") Scope scope) {
|
||||||
Context parentContext = Java8BytecodeBridge.currentContext();
|
Context parentContext = Java8BytecodeBridge.currentContext();
|
||||||
|
|
||||||
if (!tracer().shouldStartSpan(parentContext)) {
|
if (!instrumenter().shouldStart(parentContext, request)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
context = tracer().startSpan(parentContext, request, request);
|
context = instrumenter().start(parentContext, request);
|
||||||
Contexts contexts = new Contexts(parentContext, context);
|
Contexts contexts = new Contexts(parentContext, context);
|
||||||
VirtualField.find(HttpClientRequest.class, Contexts.class).set(request, contexts);
|
VirtualField.find(HttpClientRequest.class, Contexts.class).set(request, contexts);
|
||||||
|
|
||||||
|
@ -105,6 +105,7 @@ public class HttpRequestInstrumentation implements TypeInstrumentation {
|
||||||
|
|
||||||
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
||||||
public static void endScope(
|
public static void endScope(
|
||||||
|
@Advice.This HttpClientRequest request,
|
||||||
@Advice.Local("otelContext") Context context,
|
@Advice.Local("otelContext") Context context,
|
||||||
@Advice.Local("otelScope") Scope scope,
|
@Advice.Local("otelScope") Scope scope,
|
||||||
@Advice.Thrown Throwable throwable) {
|
@Advice.Thrown Throwable throwable) {
|
||||||
|
@ -112,7 +113,7 @@ public class HttpRequestInstrumentation implements TypeInstrumentation {
|
||||||
scope.close();
|
scope.close();
|
||||||
}
|
}
|
||||||
if (throwable != null) {
|
if (throwable != null) {
|
||||||
tracer().endExceptionally(context, throwable);
|
instrumenter().end(context, request, null, throwable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -131,7 +132,7 @@ public class HttpRequestInstrumentation implements TypeInstrumentation {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
tracer().endExceptionally(contexts.context, t);
|
instrumenter().end(contexts.context, request, null, t);
|
||||||
|
|
||||||
// Scoping all potential callbacks etc to the parent context
|
// Scoping all potential callbacks etc to the parent context
|
||||||
scope = contexts.parentContext.makeCurrent();
|
scope = contexts.parentContext.makeCurrent();
|
||||||
|
@ -159,7 +160,7 @@ public class HttpRequestInstrumentation implements TypeInstrumentation {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
tracer().end(contexts.context, response);
|
instrumenter().end(contexts.context, request, response, null);
|
||||||
|
|
||||||
// Scoping all potential callbacks etc to the parent context
|
// Scoping all potential callbacks etc to the parent context
|
||||||
scope = contexts.parentContext.makeCurrent();
|
scope = contexts.parentContext.makeCurrent();
|
||||||
|
@ -205,7 +206,7 @@ public class HttpRequestInstrumentation implements TypeInstrumentation {
|
||||||
if (handler != null) {
|
if (handler != null) {
|
||||||
VirtualField<HttpClientRequest, Contexts> virtualField =
|
VirtualField<HttpClientRequest, Contexts> virtualField =
|
||||||
VirtualField.find(HttpClientRequest.class, Contexts.class);
|
VirtualField.find(HttpClientRequest.class, Contexts.class);
|
||||||
handler = ExceptionHandlerWrapper.wrap(tracer(), request, virtualField, handler);
|
handler = ExceptionHandlerWrapper.wrap(instrumenter(), request, virtualField, handler);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.javaagent.instrumentation.vertx.v4_0.client;
|
||||||
|
|
||||||
|
import io.opentelemetry.javaagent.instrumentation.vertx.client.AbstractVertxHttpAttributesExtractor;
|
||||||
|
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
|
||||||
|
import io.vertx.core.http.HttpClientRequest;
|
||||||
|
import io.vertx.core.http.HttpClientResponse;
|
||||||
|
import io.vertx.core.http.HttpVersion;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
final class Vertx4HttpAttributesExtractor extends AbstractVertxHttpAttributesExtractor {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String url(HttpClientRequest request) {
|
||||||
|
String uri = request.getURI();
|
||||||
|
if (!isAbsolute(uri)) {
|
||||||
|
uri = request.absoluteURI();
|
||||||
|
}
|
||||||
|
return uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isAbsolute(String uri) {
|
||||||
|
return uri.startsWith("http://") || uri.startsWith("https://");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String method(HttpClientRequest request) {
|
||||||
|
return request.getMethod().name();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
protected String flavor(HttpClientRequest request, @Nullable HttpClientResponse response) {
|
||||||
|
HttpVersion version = request.version();
|
||||||
|
if (version == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
switch (version) {
|
||||||
|
case HTTP_1_0:
|
||||||
|
return SemanticAttributes.HttpFlavorValues.HTTP_1_0;
|
||||||
|
case HTTP_1_1:
|
||||||
|
return SemanticAttributes.HttpFlavorValues.HTTP_1_1;
|
||||||
|
case HTTP_2:
|
||||||
|
return SemanticAttributes.HttpFlavorValues.HTTP_2_0;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.javaagent.instrumentation.vertx.v4_0.client;
|
||||||
|
|
||||||
|
import io.opentelemetry.instrumentation.api.instrumenter.net.NetClientAttributesExtractor;
|
||||||
|
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
|
||||||
|
import io.vertx.core.http.HttpClientRequest;
|
||||||
|
import io.vertx.core.http.HttpClientResponse;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
final class Vertx4NetAttributesExtractor
|
||||||
|
extends NetClientAttributesExtractor<HttpClientRequest, HttpClientResponse> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String transport(HttpClientRequest request, @Nullable HttpClientResponse response) {
|
||||||
|
return SemanticAttributes.NetTransportValues.IP_TCP;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public String peerName(HttpClientRequest request, @Nullable HttpClientResponse response) {
|
||||||
|
return request.getHost();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer peerPort(HttpClientRequest request, @Nullable HttpClientResponse response) {
|
||||||
|
return request.getPort();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public String peerIp(HttpClientRequest request, @Nullable HttpClientResponse response) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.javaagent.instrumentation.vertx.v4_0.client;
|
||||||
|
|
||||||
|
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
|
||||||
|
import io.opentelemetry.javaagent.instrumentation.vertx.client.VertxClientInstrumenterFactory;
|
||||||
|
import io.vertx.core.http.HttpClientRequest;
|
||||||
|
import io.vertx.core.http.HttpClientResponse;
|
||||||
|
|
||||||
|
public final class VertxClientSingletons {
|
||||||
|
|
||||||
|
private static final Instrumenter<HttpClientRequest, HttpClientResponse> INSTRUMENTER =
|
||||||
|
VertxClientInstrumenterFactory.create(
|
||||||
|
"io.opentelemetry.vertx-http-client-4.0",
|
||||||
|
new Vertx4HttpAttributesExtractor(),
|
||||||
|
new Vertx4NetAttributesExtractor());
|
||||||
|
|
||||||
|
public static Instrumenter<HttpClientRequest, HttpClientResponse> instrumenter() {
|
||||||
|
return INSTRUMENTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
private VertxClientSingletons() {}
|
||||||
|
}
|
|
@ -1,40 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright The OpenTelemetry Authors
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package io.opentelemetry.javaagent.instrumentation.vertx.v4_0.client;
|
|
||||||
|
|
||||||
import io.opentelemetry.javaagent.instrumentation.vertx.client.AbstractVertxClientTracer;
|
|
||||||
import io.vertx.core.http.HttpClientRequest;
|
|
||||||
import java.net.URI;
|
|
||||||
import java.net.URISyntaxException;
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
public class VertxClientTracer extends AbstractVertxClientTracer {
|
|
||||||
private static final VertxClientTracer TRACER = new VertxClientTracer();
|
|
||||||
|
|
||||||
public static VertxClientTracer tracer() {
|
|
||||||
return TRACER;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String getInstrumentationName() {
|
|
||||||
return "io.opentelemetry.vertx-http-client-4.0";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String method(HttpClientRequest request) {
|
|
||||||
return request.getMethod().name();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Nullable
|
|
||||||
protected URI url(HttpClientRequest request) throws URISyntaxException {
|
|
||||||
URI uri = new URI(request.getURI());
|
|
||||||
if (!uri.isAbsolute()) {
|
|
||||||
uri = new URI(request.absoluteURI());
|
|
||||||
}
|
|
||||||
return uri;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,55 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright The OpenTelemetry Authors
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package io.opentelemetry.javaagent.instrumentation.vertx.client;
|
|
||||||
|
|
||||||
import io.opentelemetry.context.propagation.TextMapSetter;
|
|
||||||
import io.opentelemetry.instrumentation.api.tracer.HttpClientTracer;
|
|
||||||
import io.opentelemetry.instrumentation.api.tracer.net.NetPeerAttributes;
|
|
||||||
import io.vertx.core.http.HttpClientRequest;
|
|
||||||
import io.vertx.core.http.HttpClientResponse;
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
public abstract class AbstractVertxClientTracer
|
|
||||||
extends HttpClientTracer<HttpClientRequest, HttpClientRequest, HttpClientResponse> {
|
|
||||||
|
|
||||||
protected AbstractVertxClientTracer() {
|
|
||||||
super(NetPeerAttributes.INSTANCE);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Nullable
|
|
||||||
protected Integer status(HttpClientResponse response) {
|
|
||||||
return response.statusCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Nullable
|
|
||||||
protected String requestHeader(HttpClientRequest request, String name) {
|
|
||||||
return request.headers().get(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Nullable
|
|
||||||
protected String responseHeader(HttpClientResponse response, String name) {
|
|
||||||
return response.getHeader(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected TextMapSetter<HttpClientRequest> getSetter() {
|
|
||||||
return Propagator.INSTANCE;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class Propagator implements TextMapSetter<HttpClientRequest> {
|
|
||||||
private static final Propagator INSTANCE = new Propagator();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void set(HttpClientRequest carrier, String key, String value) {
|
|
||||||
if (carrier != null) {
|
|
||||||
carrier.putHeader(key, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.javaagent.instrumentation.vertx.client;
|
||||||
|
|
||||||
|
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientAttributesExtractor;
|
||||||
|
import io.vertx.core.http.HttpClientRequest;
|
||||||
|
import io.vertx.core.http.HttpClientResponse;
|
||||||
|
import java.util.List;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
public abstract class AbstractVertxHttpAttributesExtractor
|
||||||
|
extends HttpClientAttributesExtractor<HttpClientRequest, HttpClientResponse> {
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
protected String flavor(HttpClientRequest request, @Nullable HttpClientResponse response) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<String> requestHeader(HttpClientRequest request, String name) {
|
||||||
|
return request.headers().getAll(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
protected Long requestContentLength(
|
||||||
|
HttpClientRequest request, @Nullable HttpClientResponse response) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
protected Long requestContentLengthUncompressed(
|
||||||
|
HttpClientRequest request, @Nullable HttpClientResponse response) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Integer statusCode(HttpClientRequest request, HttpClientResponse response) {
|
||||||
|
return response.statusCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
protected Long responseContentLength(HttpClientRequest request, HttpClientResponse response) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
protected Long responseContentLengthUncompressed(
|
||||||
|
HttpClientRequest request, HttpClientResponse response) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<String> responseHeader(
|
||||||
|
HttpClientRequest request, HttpClientResponse response, String name) {
|
||||||
|
return response.headers().getAll(name);
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,28 +7,30 @@ package io.opentelemetry.javaagent.instrumentation.vertx.client;
|
||||||
|
|
||||||
import io.opentelemetry.context.Scope;
|
import io.opentelemetry.context.Scope;
|
||||||
import io.opentelemetry.instrumentation.api.field.VirtualField;
|
import io.opentelemetry.instrumentation.api.field.VirtualField;
|
||||||
|
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
|
||||||
import io.vertx.core.Handler;
|
import io.vertx.core.Handler;
|
||||||
import io.vertx.core.http.HttpClientRequest;
|
import io.vertx.core.http.HttpClientRequest;
|
||||||
|
import io.vertx.core.http.HttpClientResponse;
|
||||||
|
|
||||||
public class ExceptionHandlerWrapper implements Handler<Throwable> {
|
public class ExceptionHandlerWrapper implements Handler<Throwable> {
|
||||||
private final AbstractVertxClientTracer tracer;
|
private final Instrumenter<HttpClientRequest, HttpClientResponse> instrumenter;
|
||||||
private final HttpClientRequest request;
|
private final HttpClientRequest request;
|
||||||
private final VirtualField<HttpClientRequest, Contexts> virtualField;
|
private final VirtualField<HttpClientRequest, Contexts> virtualField;
|
||||||
private final Handler<Throwable> handler;
|
private final Handler<Throwable> handler;
|
||||||
|
|
||||||
private ExceptionHandlerWrapper(
|
private ExceptionHandlerWrapper(
|
||||||
AbstractVertxClientTracer tracer,
|
Instrumenter<HttpClientRequest, HttpClientResponse> instrumenter,
|
||||||
HttpClientRequest request,
|
HttpClientRequest request,
|
||||||
VirtualField<HttpClientRequest, Contexts> virtualField,
|
VirtualField<HttpClientRequest, Contexts> virtualField,
|
||||||
Handler<Throwable> handler) {
|
Handler<Throwable> handler) {
|
||||||
this.tracer = tracer;
|
this.instrumenter = instrumenter;
|
||||||
this.request = request;
|
this.request = request;
|
||||||
this.virtualField = virtualField;
|
this.virtualField = virtualField;
|
||||||
this.handler = handler;
|
this.handler = handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Handler<Throwable> wrap(
|
public static Handler<Throwable> wrap(
|
||||||
AbstractVertxClientTracer tracer,
|
Instrumenter<HttpClientRequest, HttpClientResponse> instrumenter,
|
||||||
HttpClientRequest request,
|
HttpClientRequest request,
|
||||||
VirtualField<HttpClientRequest, Contexts> virtualField,
|
VirtualField<HttpClientRequest, Contexts> virtualField,
|
||||||
Handler<Throwable> handler) {
|
Handler<Throwable> handler) {
|
||||||
|
@ -36,7 +38,7 @@ public class ExceptionHandlerWrapper implements Handler<Throwable> {
|
||||||
return handler;
|
return handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ExceptionHandlerWrapper(tracer, request, virtualField, handler);
|
return new ExceptionHandlerWrapper(instrumenter, request, virtualField, handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -47,7 +49,7 @@ public class ExceptionHandlerWrapper implements Handler<Throwable> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
tracer.endExceptionally(contexts.context, throwable);
|
instrumenter.end(contexts.context, request, null, throwable);
|
||||||
|
|
||||||
try (Scope ignored = contexts.parentContext.makeCurrent()) {
|
try (Scope ignored = contexts.parentContext.makeCurrent()) {
|
||||||
callHandler(throwable);
|
callHandler(throwable);
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.javaagent.instrumentation.vertx.client;
|
||||||
|
|
||||||
|
import io.opentelemetry.context.propagation.TextMapSetter;
|
||||||
|
import io.vertx.core.http.HttpClientRequest;
|
||||||
|
|
||||||
|
public class HttpRequestHeaderSetter implements TextMapSetter<HttpClientRequest> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void set(HttpClientRequest carrier, String key, String value) {
|
||||||
|
if (carrier != null) {
|
||||||
|
carrier.putHeader(key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.javaagent.instrumentation.vertx.client;
|
||||||
|
|
||||||
|
import io.opentelemetry.api.GlobalOpenTelemetry;
|
||||||
|
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
|
||||||
|
import io.opentelemetry.instrumentation.api.instrumenter.InstrumenterBuilder;
|
||||||
|
import io.opentelemetry.instrumentation.api.instrumenter.PeerServiceAttributesExtractor;
|
||||||
|
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 io.vertx.core.http.HttpClientRequest;
|
||||||
|
import io.vertx.core.http.HttpClientResponse;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
public final class VertxClientInstrumenterFactory {
|
||||||
|
|
||||||
|
public static Instrumenter<HttpClientRequest, HttpClientResponse> create(
|
||||||
|
String instrumentationName,
|
||||||
|
AbstractVertxHttpAttributesExtractor httpAttributesExtractor,
|
||||||
|
@Nullable
|
||||||
|
NetClientAttributesExtractor<HttpClientRequest, HttpClientResponse>
|
||||||
|
netAttributesExtractor) {
|
||||||
|
|
||||||
|
InstrumenterBuilder<HttpClientRequest, HttpClientResponse> builder =
|
||||||
|
Instrumenter.<HttpClientRequest, HttpClientResponse>builder(
|
||||||
|
GlobalOpenTelemetry.get(),
|
||||||
|
instrumentationName,
|
||||||
|
HttpSpanNameExtractor.create(httpAttributesExtractor))
|
||||||
|
.setSpanStatusExtractor(HttpSpanStatusExtractor.create(httpAttributesExtractor))
|
||||||
|
.addAttributesExtractor(httpAttributesExtractor)
|
||||||
|
.addRequestMetrics(HttpClientMetrics.get());
|
||||||
|
|
||||||
|
if (netAttributesExtractor != null) {
|
||||||
|
builder
|
||||||
|
.addAttributesExtractor(netAttributesExtractor)
|
||||||
|
.addAttributesExtractor(PeerServiceAttributesExtractor.create(netAttributesExtractor));
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder.newClientInstrumenter(new HttpRequestHeaderSetter());
|
||||||
|
}
|
||||||
|
|
||||||
|
private VertxClientInstrumenterFactory() {}
|
||||||
|
}
|
|
@ -5,10 +5,12 @@
|
||||||
|
|
||||||
package client
|
package client
|
||||||
|
|
||||||
|
import io.opentelemetry.api.common.AttributeKey
|
||||||
import io.opentelemetry.instrumentation.test.AgentTestTrait
|
import io.opentelemetry.instrumentation.test.AgentTestTrait
|
||||||
import io.opentelemetry.instrumentation.test.base.HttpClientTest
|
import io.opentelemetry.instrumentation.test.base.HttpClientTest
|
||||||
import io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpClientTest
|
import io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpClientTest
|
||||||
import io.opentelemetry.instrumentation.testing.junit.http.SingleConnection
|
import io.opentelemetry.instrumentation.testing.junit.http.SingleConnection
|
||||||
|
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes
|
||||||
import io.vertx.circuitbreaker.CircuitBreakerOptions
|
import io.vertx.circuitbreaker.CircuitBreakerOptions
|
||||||
import io.vertx.core.AsyncResult
|
import io.vertx.core.AsyncResult
|
||||||
import io.vertx.core.VertxOptions
|
import io.vertx.core.VertxOptions
|
||||||
|
@ -97,6 +99,15 @@ class VertxRxCircuitBreakerWebClientTest extends HttpClientTest<HttpRequest<?>>
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
Set<AttributeKey<?>> httpAttributes(URI uri) {
|
||||||
|
def attributes = super.httpAttributes(uri)
|
||||||
|
attributes.remove(SemanticAttributes.HTTP_FLAVOR)
|
||||||
|
attributes.remove(SemanticAttributes.NET_PEER_NAME)
|
||||||
|
attributes.remove(SemanticAttributes.NET_PEER_PORT)
|
||||||
|
return attributes
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
SingleConnection createSingleConnection(String host, int port) {
|
SingleConnection createSingleConnection(String host, int port) {
|
||||||
return new VertxRxCircuitBreakerSingleConnection(host, port, breaker)
|
return new VertxRxCircuitBreakerSingleConnection(host, port, breaker)
|
||||||
|
|
|
@ -5,10 +5,12 @@
|
||||||
|
|
||||||
package client
|
package client
|
||||||
|
|
||||||
|
import io.opentelemetry.api.common.AttributeKey
|
||||||
import io.opentelemetry.instrumentation.test.AgentTestTrait
|
import io.opentelemetry.instrumentation.test.AgentTestTrait
|
||||||
import io.opentelemetry.instrumentation.test.base.HttpClientTest
|
import io.opentelemetry.instrumentation.test.base.HttpClientTest
|
||||||
import io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpClientTest
|
import io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpClientTest
|
||||||
import io.opentelemetry.instrumentation.testing.junit.http.SingleConnection
|
import io.opentelemetry.instrumentation.testing.junit.http.SingleConnection
|
||||||
|
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes
|
||||||
import io.vertx.core.VertxOptions
|
import io.vertx.core.VertxOptions
|
||||||
import io.vertx.core.http.HttpMethod
|
import io.vertx.core.http.HttpMethod
|
||||||
import io.vertx.ext.web.client.WebClientOptions
|
import io.vertx.ext.web.client.WebClientOptions
|
||||||
|
@ -83,6 +85,15 @@ class VertxRxWebClientTest extends HttpClientTest<HttpRequest<Buffer>> implement
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
Set<AttributeKey<?>> httpAttributes(URI uri) {
|
||||||
|
def attributes = super.httpAttributes(uri)
|
||||||
|
attributes.remove(SemanticAttributes.HTTP_FLAVOR)
|
||||||
|
attributes.remove(SemanticAttributes.NET_PEER_NAME)
|
||||||
|
attributes.remove(SemanticAttributes.NET_PEER_PORT)
|
||||||
|
return attributes
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
SingleConnection createSingleConnection(String host, int port) {
|
SingleConnection createSingleConnection(String host, int port) {
|
||||||
return new VertxRxSingleConnection(host, port)
|
return new VertxRxSingleConnection(host, port)
|
||||||
|
|
Loading…
Reference in New Issue