diff --git a/agent-testweb/vertx-4-plugin-testweb/pom.xml b/agent-testweb/vertx-4-plugin-testweb/pom.xml
index a2ccca0d2b00..baf0e86b22cf 100644
--- a/agent-testweb/vertx-4-plugin-testweb/pom.xml
+++ b/agent-testweb/vertx-4-plugin-testweb/pom.xml
@@ -32,7 +32,7 @@
1.8
${env.JAVA_8_HOME}
- 4.2.2
+ 4.5.0
true
UTF-8
diff --git a/agent-testweb/vertx-4-plugin-testweb/src/main/java/com/pinpoint/test/plugin/Vertx4PluginTestStarter.java b/agent-testweb/vertx-4-plugin-testweb/src/main/java/com/pinpoint/test/plugin/Vertx4PluginTestStarter.java
index aaec9af58abe..9a92f1755130 100644
--- a/agent-testweb/vertx-4-plugin-testweb/src/main/java/com/pinpoint/test/plugin/Vertx4PluginTestStarter.java
+++ b/agent-testweb/vertx-4-plugin-testweb/src/main/java/com/pinpoint/test/plugin/Vertx4PluginTestStarter.java
@@ -57,7 +57,6 @@ public void start(Promise startPromise) throws Exception {
routingContext.response().end(buildMain("Welcome pinpoint vert.x HTTP server test", routes));
});
-
router.get("/request").handler(routingContext -> {
request(80, "naver.com", "/");
routingContext.response().end("Request http://naver.com:80/");
@@ -159,7 +158,7 @@ private void runOnContext(HttpServerRequest request, final int waitSeconds) {
private void runOnContextRequest(HttpServerRequest request) {
vertx.runOnContext(aVoid -> {
- request(80, "naver.com", "/");
+ request(80, "httpbin.org", "/");
request.response().end("Run on context request.");
});
}
diff --git a/plugins/vertx/README.md b/plugins/vertx/README.md
index 8536731e414f..eb49cdb5c48b 100644
--- a/plugins/vertx/README.md
+++ b/plugins/vertx/README.md
@@ -7,7 +7,7 @@
pinpoint.config
#### Compatibility setting
-Vert.x 3.6 ~ 3.7
+Vert.x 3.6 ~ 4.5
~~~
profiler.vertx.http.server.request-handler.method.name=io.vertx.ext.web.impl.RouterImpl.handle
~~~
diff --git a/plugins/vertx/src/main/java/com/navercorp/pinpoint/plugin/vertx/VertxPlugin.java b/plugins/vertx/src/main/java/com/navercorp/pinpoint/plugin/vertx/VertxPlugin.java
index 3954bb1c210a..a1797c69b170 100644
--- a/plugins/vertx/src/main/java/com/navercorp/pinpoint/plugin/vertx/VertxPlugin.java
+++ b/plugins/vertx/src/main/java/com/navercorp/pinpoint/plugin/vertx/VertxPlugin.java
@@ -39,6 +39,7 @@
import com.navercorp.pinpoint.plugin.vertx.interceptor.HandlerInterceptor;
import com.navercorp.pinpoint.plugin.vertx.interceptor.Http1xClientConnectionCreateRequest38Interceptor;
import com.navercorp.pinpoint.plugin.vertx.interceptor.Http1xClientConnectionCreateRequest4xInterceptor;
+import com.navercorp.pinpoint.plugin.vertx.interceptor.HttpClientImplCreateRequestInterceptor;
import com.navercorp.pinpoint.plugin.vertx.interceptor.HttpClientImplDoRequestInterceptor;
import com.navercorp.pinpoint.plugin.vertx.interceptor.HttpClientImplDoRequestInterceptorV4;
import com.navercorp.pinpoint.plugin.vertx.interceptor.HttpClientImplInterceptor;
@@ -77,7 +78,7 @@ public void setup(ProfilerPluginSetupContext context) {
}
// 3.3 <= x <= 3.5
- logger.info("Enable VertxPlugin. version range=[3.3, 4.2.2]");
+ logger.info("Enable VertxPlugin. version range=[3.3, 4.5.0]");
logger.info("{} config:{}", this.getClass().getSimpleName(), config);
// for vertx.io 3.3.x, 3.4.x
@@ -106,6 +107,8 @@ public void setup(ProfilerPluginSetupContext context) {
addContextImpl("io.vertx.core.impl.WorkerContext");
// 4.x
addContextImpl("io.vertx.core.impl.DuplicatedContext");
+ addContextImpl("io.vertx.core.impl.ContextBase");
+ transformTemplate.transform("io.vertx.core.impl.ContextInternal", ContextInternalTransform.class);
}
if (config.isEnableHttpServer()) {
@@ -226,12 +229,31 @@ public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader,
if (executeBlockingMethod4 != null) {
executeBlockingMethod4.addInterceptor(ContextImplExecuteBlockingInterceptor.class);
}
+ final InstrumentMethod executeBlockingMethod5 = target.getDeclaredMethod("executeBlocking", "io.vertx.core.impl.ContextInternal", "java.util.concurrent.Callable", "io.vertx.core.impl.WorkerPool", "io.vertx.core.impl.TaskQueue");
+ if (executeBlockingMethod5 != null) {
+ executeBlockingMethod5.addInterceptor(ContextImplExecuteBlockingInterceptor.class);
+ }
// skip executeFromIO()
return target.toBytecode();
}
}
+ public static class ContextInternalTransform implements TransformCallback {
+ @Override
+ public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, Class> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException {
+ final InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer);
+
+ final InstrumentMethod runOnContextMethod = target.getDeclaredMethod("runOnContext", "io.vertx.core.Handler");
+ if (runOnContextMethod != null) {
+ runOnContextMethod.addInterceptor(ContextImplRunOnContextInterceptor.class);
+ }
+
+ return target.toBytecode();
+ }
+ }
+
+
private void addRequestHandlerMethod(final String className, final String methodName) {
transformTemplate.transform(className, RequestHandlerMethodTransform.class, new Object[]{methodName}, new Class[]{String.class});
}
@@ -239,8 +261,7 @@ private void addRequestHandlerMethod(final String className, final String method
public static class RequestHandlerMethodTransform implements TransformCallback {
private final String methodName;
- public RequestHandlerMethodTransform(String methodName)
- {
+ public RequestHandlerMethodTransform(String methodName) {
this.methodName = methodName;
}
@@ -381,6 +402,26 @@ public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader,
if (doRequestMethod3 != null) {
doRequestMethod3.addScopedInterceptor(HttpClientImplDoRequestInterceptorV4.class, VertxConstants.HTTP_CLIENT_CREATE_REQUEST_SCOPE);
}
+ // 4.4.0
+ // void doRequest(HttpMethod method, SocketAddress peerAddress, SocketAddress server, String host, int port, Boolean useSSL, String requestURI, MultiMap headers, String traceOperation, long timeout, Boolean followRedirects, ProxyOptions proxyOptions, EndpointKey key, PromiseInternal requestPromise)
+ final InstrumentMethod doRequestMethod4 = target.getDeclaredMethod("doRequest", "io.vertx.core.http.HttpMethod", "io.vertx.core.net.SocketAddress", "io.vertx.core.net.SocketAddress", "java.lang.String", "int", "java.lang.Boolean", "java.lang.String", "io.vertx.core.MultiMap", "java.lang.String", "long", "java.lang.Boolean", "io.vertx.core.net.ProxyOptions", "io.vertx.core.http.impl.EndpointKey", "io.vertx.core.impl.future.PromiseInternal");
+ if (doRequestMethod4 != null) {
+ doRequestMethod4.addScopedInterceptor(HttpClientImplDoRequestInterceptorV4.class, VertxConstants.HTTP_CLIENT_CREATE_REQUEST_SCOPE);
+ }
+ // 4.5.0
+ // void doRequest(HttpMethod method, SocketAddress server, String host, int port, Boolean useSSL, String requestURI, MultiMap headers, String traceOperation, long connectTimeout, long idleTimeout, Boolean followRedirects, ProxyOptions proxyOptions, EndpointKey key, PromiseInternal requestPromise)
+ final InstrumentMethod doRequestMethod5 = target.getDeclaredMethod("doRequest", "io.vertx.core.http.HttpMethod", "io.vertx.core.net.SocketAddress", "java.lang.String", "int", "java.lang.Boolean", "java.lang.String", "io.vertx.core.MultiMap", "java.lang.String", "long", "long", "java.lang.Boolean", "io.vertx.core.net.ProxyOptions", "io.vertx.core.http.impl.EndpointKey", "io.vertx.core.impl.future.PromiseInternal");
+ if (doRequestMethod5 != null) {
+ doRequestMethod5.addScopedInterceptor(HttpClientImplDoRequestInterceptorV4.class, VertxConstants.HTTP_CLIENT_CREATE_REQUEST_SCOPE);
+ }
+
+ // 4.5.0
+ // Forward the asyncContext from HttpClientImpl to HttpClientRequestImpl.
+ final InstrumentMethod createRequestMethod = target.getDeclaredMethod("createRequest", "io.vertx.core.http.impl.HttpClientStream");
+ if (createRequestMethod != null) {
+ createRequestMethod.addInterceptor(HttpClientImplCreateRequestInterceptor.class);
+ }
+
return target.toBytecode();
}
}
@@ -405,6 +446,11 @@ public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader,
if (constructor2 != null) {
constructor2.addInterceptor(HttpClientRequestImplConstructorInterceptor.class);
}
+ // 4.5.0
+ InstrumentMethod constructor3 = target.getConstructor("io.vertx.core.http.impl.HttpClientStream", "io.vertx.core.impl.future.PromiseInternal", "io.vertx.core.http.HttpMethod", "io.vertx.core.net.SocketAddress", "java.lang.String", "int", "java.lang.String", "java.lang.String");
+ if (constructor3 != null) {
+ constructor3.addInterceptor(HttpClientRequestImplConstructorInterceptor.class);
+ }
// for HttpClientResponseImpl.
for (InstrumentMethod method : target.getDeclaredMethods(MethodFilters.name("doHandleResponse"))) {
@@ -470,6 +516,7 @@ public static class ClientConnectionTransform implements TransformCallback {
@Override
public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, String className, Class> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException {
final InstrumentClass target = instrumentor.getInstrumentClass(classLoader, className, classfileBuffer);
+ target.addField(AsyncContextAccessor.class);
target.addField(SamplingRateFlagAccessor.class);
// add pinpoint headers.
diff --git a/plugins/vertx/src/main/java/com/navercorp/pinpoint/plugin/vertx/interceptor/HttpClientImplCreateRequestInterceptor.java b/plugins/vertx/src/main/java/com/navercorp/pinpoint/plugin/vertx/interceptor/HttpClientImplCreateRequestInterceptor.java
new file mode 100644
index 000000000000..513b3e8624c6
--- /dev/null
+++ b/plugins/vertx/src/main/java/com/navercorp/pinpoint/plugin/vertx/interceptor/HttpClientImplCreateRequestInterceptor.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2023 NAVER Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.navercorp.pinpoint.plugin.vertx.interceptor;
+
+import com.navercorp.pinpoint.bootstrap.async.AsyncContextAccessorUtils;
+import com.navercorp.pinpoint.bootstrap.context.AsyncContext;
+import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor;
+import com.navercorp.pinpoint.bootstrap.logging.PLogger;
+import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory;
+
+public class HttpClientImplCreateRequestInterceptor implements AroundInterceptor {
+ private final PLogger logger = PLoggerFactory.getLogger(this.getClass());
+ private final boolean isDebug = logger.isDebugEnabled();
+
+ public HttpClientImplCreateRequestInterceptor() {
+ }
+
+ @Override
+ public void before(Object target, Object[] args) {
+ if (isDebug) {
+ logger.beforeInterceptor(target, args);
+ }
+
+ final AsyncContext asyncContext = AsyncContextAccessorUtils.getAsyncContext(target);
+ if (asyncContext != null) {
+ AsyncContextAccessorUtils.setAsyncContext(asyncContext, args, 0);
+ if (isDebug) {
+ logger.debug("Set asyncContext to args[0]. asyncContext={}", asyncContext);
+ }
+ }
+ }
+
+ @Override
+ public void after(Object target, Object[] args, Object result, Throwable throwable) {
+ }
+}
diff --git a/plugins/vertx/src/main/java/com/navercorp/pinpoint/plugin/vertx/interceptor/HttpClientImplDoRequestInterceptorV4.java b/plugins/vertx/src/main/java/com/navercorp/pinpoint/plugin/vertx/interceptor/HttpClientImplDoRequestInterceptorV4.java
index 14dd99e1f2bb..0132e85069ed 100644
--- a/plugins/vertx/src/main/java/com/navercorp/pinpoint/plugin/vertx/interceptor/HttpClientImplDoRequestInterceptorV4.java
+++ b/plugins/vertx/src/main/java/com/navercorp/pinpoint/plugin/vertx/interceptor/HttpClientImplDoRequestInterceptorV4.java
@@ -107,6 +107,12 @@ private String toHostAndPort(final Object[] args) {
final int port = (Integer) args[4];
return HostAndPort.toHostAndPortString(host, port);
}
+ } else if (length == 14) {
+ if (args[2] instanceof String && args[3] instanceof Integer) {
+ final String host = (String) args[2];
+ final int port = (Integer) args[3];
+ return HostAndPort.toHostAndPortString(host, port);
+ }
}
return null;