diff --git a/plugins/assembly/pom.xml b/plugins/assembly/pom.xml
index 545b664cea7e..281e547973b6 100644
--- a/plugins/assembly/pom.xml
+++ b/plugins/assembly/pom.xml
@@ -417,5 +417,10 @@
pinpoint-spring-tx-plugin
${project.version}
+
+
+
+
+
\ No newline at end of file
diff --git a/plugins/pom.xml b/plugins/pom.xml
index 252d9cbbaef9..8cf1f0d62e07 100644
--- a/plugins/pom.xml
+++ b/plugins/pom.xml
@@ -112,6 +112,7 @@
agentsdk-async
spring-data-r2dbc
spring-tx
+ spring-stub
diff --git a/plugins/resttemplate/pom.xml b/plugins/resttemplate/pom.xml
index 54b163413207..d87a7547b898 100644
--- a/plugins/resttemplate/pom.xml
+++ b/plugins/resttemplate/pom.xml
@@ -22,6 +22,12 @@
pinpoint-bootstrap-core
provided
+
+ com.navercorp.pinpoint
+ pinpoint-spring-stub
+ ${project.version}
+ provided
+
org.springframework
@@ -29,5 +35,19 @@
provided
-
+
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+
+
+ com/navercorp/**/*
+ META-INF/**/*
+
+
+
+
+
\ No newline at end of file
diff --git a/plugins/resttemplate/src/main/java/com/navercorp/pinpoint/plugin/resttemplate/RestTemplatePlugin.java b/plugins/resttemplate/src/main/java/com/navercorp/pinpoint/plugin/resttemplate/RestTemplatePlugin.java
index 988488f52e87..2995f4526996 100644
--- a/plugins/resttemplate/src/main/java/com/navercorp/pinpoint/plugin/resttemplate/RestTemplatePlugin.java
+++ b/plugins/resttemplate/src/main/java/com/navercorp/pinpoint/plugin/resttemplate/RestTemplatePlugin.java
@@ -117,8 +117,10 @@ public static class HttpRequestTransformer implements TransformCallback {
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);
InstrumentMethod executeMethod = InstrumentUtils.findMethod(target, "execute");
+
+ final int springVersion = SpringVersion.getVersion(classLoader);
if (executeMethod != null) {
- executeMethod.addScopedInterceptor(HttpRequestInterceptor.class, RestTemplateConstants.SCOPE, ExecutionPolicy.BOUNDARY);
+ executeMethod.addScopedInterceptor(HttpRequestInterceptor.class, va(springVersion), RestTemplateConstants.SCOPE, ExecutionPolicy.BOUNDARY);
}
return target.toBytecode();
@@ -167,8 +169,9 @@ public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader,
final List constructors = target.getDeclaredConstructors();
if (constructors != null && constructors.size() == 1) { //only intercept one-constructor response, no overloading
+ final int springVersion = SpringVersion.getVersion(classLoader);
for (InstrumentMethod constructor : constructors) {
- constructor.addScopedInterceptor(ClientHttpResponseInterceptor.class, "HttpResponse", ExecutionPolicy.BOUNDARY);
+ constructor.addScopedInterceptor(ClientHttpResponseInterceptor.class, va(springVersion), "HttpResponse", ExecutionPolicy.BOUNDARY);
}
}
diff --git a/plugins/resttemplate/src/main/java/com/navercorp/pinpoint/plugin/resttemplate/SpringVersion.java b/plugins/resttemplate/src/main/java/com/navercorp/pinpoint/plugin/resttemplate/SpringVersion.java
new file mode 100644
index 000000000000..aa53f4622528
--- /dev/null
+++ b/plugins/resttemplate/src/main/java/com/navercorp/pinpoint/plugin/resttemplate/SpringVersion.java
@@ -0,0 +1,56 @@
+package com.navercorp.pinpoint.plugin.resttemplate;/*
+ * Copyright 2024 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.
+ */
+
+import java.util.Objects;
+
+/**
+ * @author intr3p1d
+ */
+public class SpringVersion {
+
+ public static final int SPRING_VERSION_UNKNOWN = -1;
+ public static final int SPRING_VERSION_5 = 5_00_00;
+ public static final int SPRING_VERSION_6 = 6_00_00;
+
+ static final String SPRING5_HTTP_STATUS_INTERFACE_NAME = "org.springframework.http.HttpStatus";
+ static final String SPRING6_HTTP_STATUS_INTERFACE_NAME = "org.springframework.http.HttpStatusCode";
+
+
+ public static int getVersion(ClassLoader classLoader) {
+ // Spring 6.0 + (boot 3.0 + )
+ final Class> httpStatusCode = getClass(classLoader, SPRING6_HTTP_STATUS_INTERFACE_NAME);
+ if (httpStatusCode != null) {
+ return SpringVersion.SPRING_VERSION_6;
+ }
+
+ // ~ Spring 5.x (boot 2.0 -)
+ final Class> httpStatus = getClass(classLoader, SPRING5_HTTP_STATUS_INTERFACE_NAME);
+ if (httpStatus != null) {
+ return SpringVersion.SPRING_VERSION_5;
+ }
+ return SpringVersion.SPRING_VERSION_UNKNOWN;
+ }
+
+
+ static Class> getClass(ClassLoader classLoader, String className) {
+ Objects.requireNonNull(className, "className");
+ try {
+ return Class.forName(className, false, classLoader);
+ } catch (ClassNotFoundException ignored) {
+ return null;
+ }
+ }
+}
diff --git a/plugins/resttemplate/src/main/java/com/navercorp/pinpoint/plugin/resttemplate/interceptor/ClientHttpResponseInterceptor.java b/plugins/resttemplate/src/main/java/com/navercorp/pinpoint/plugin/resttemplate/interceptor/ClientHttpResponseInterceptor.java
index 6233a858ceb4..1eb707482444 100644
--- a/plugins/resttemplate/src/main/java/com/navercorp/pinpoint/plugin/resttemplate/interceptor/ClientHttpResponseInterceptor.java
+++ b/plugins/resttemplate/src/main/java/com/navercorp/pinpoint/plugin/resttemplate/interceptor/ClientHttpResponseInterceptor.java
@@ -25,6 +25,8 @@
import com.navercorp.pinpoint.common.trace.AnnotationKey;
import com.navercorp.pinpoint.plugin.resttemplate.RestTemplateConstants;
import com.navercorp.pinpoint.plugin.resttemplate.RestTemplateResponseHeaderAdaptor;
+import com.navercorp.pinpoint.plugin.resttemplate.interceptor.util.HttpStatusProvider;
+import com.navercorp.pinpoint.plugin.resttemplate.interceptor.util.HttpStatusProviderFactory;
import org.springframework.http.client.ClientHttpResponse;
import java.io.IOException;
@@ -35,10 +37,13 @@
public class ClientHttpResponseInterceptor extends SpanEventSimpleAroundInterceptorForPlugin {
private final ServerResponseHeaderRecorder responseHeaderRecorder;
+ private final HttpStatusProvider statusCodeProvider;
- public ClientHttpResponseInterceptor(TraceContext traceContext, MethodDescriptor descriptor) {
+ public ClientHttpResponseInterceptor(TraceContext traceContext, MethodDescriptor descriptor,
+ int springVersion) {
super(traceContext, descriptor);
this.responseHeaderRecorder = ResponseHeaderRecorderFactory.newResponseHeaderRecorder(traceContext.getProfilerConfig(), new RestTemplateResponseHeaderAdaptor());
+ this.statusCodeProvider = HttpStatusProviderFactory.getHttpStatusProvider(springVersion);
}
@Override
@@ -53,7 +58,7 @@ protected void doInAfterTrace(SpanEventRecorder recorder, Object target, Object[
if (target instanceof ClientHttpResponse) {
ClientHttpResponse clientHttpResponse = (ClientHttpResponse) target;
- recorder.recordAttribute(AnnotationKey.HTTP_STATUS_CODE, clientHttpResponse.getRawStatusCode());
+ recorder.recordAttribute(AnnotationKey.HTTP_STATUS_CODE, statusCodeProvider.getStatusCode(clientHttpResponse));
this.responseHeaderRecorder.recordHeader(recorder, clientHttpResponse);
}
}
diff --git a/plugins/resttemplate/src/main/java/com/navercorp/pinpoint/plugin/resttemplate/interceptor/HttpRequestInterceptor.java b/plugins/resttemplate/src/main/java/com/navercorp/pinpoint/plugin/resttemplate/interceptor/HttpRequestInterceptor.java
index 24e681695ec0..3c463e694426 100644
--- a/plugins/resttemplate/src/main/java/com/navercorp/pinpoint/plugin/resttemplate/interceptor/HttpRequestInterceptor.java
+++ b/plugins/resttemplate/src/main/java/com/navercorp/pinpoint/plugin/resttemplate/interceptor/HttpRequestInterceptor.java
@@ -23,6 +23,8 @@
import com.navercorp.pinpoint.common.trace.AnnotationKey;
import com.navercorp.pinpoint.plugin.resttemplate.RestTemplateConstants;
+import com.navercorp.pinpoint.plugin.resttemplate.interceptor.util.HttpStatusProvider;
+import com.navercorp.pinpoint.plugin.resttemplate.interceptor.util.HttpStatusProviderFactory;
import org.springframework.http.client.ClientHttpResponse;
import java.io.IOException;
@@ -32,8 +34,12 @@
*/
public class HttpRequestInterceptor extends SpanEventSimpleAroundInterceptorForPlugin {
- public HttpRequestInterceptor(TraceContext traceContext, MethodDescriptor descriptor) {
+ private final HttpStatusProvider statusCodeProvider;
+
+ public HttpRequestInterceptor(TraceContext traceContext, MethodDescriptor descriptor,
+ int springVersion) {
super(traceContext, descriptor);
+ this.statusCodeProvider = HttpStatusProviderFactory.getHttpStatusProvider(springVersion);
}
@Override
@@ -48,7 +54,7 @@ protected void doInAfterTrace(SpanEventRecorder recorder, Object target, Object[
if (result instanceof ClientHttpResponse) {
ClientHttpResponse clientHttpResponse = (ClientHttpResponse) result;
- recorder.recordAttribute(AnnotationKey.HTTP_STATUS_CODE, clientHttpResponse.getRawStatusCode());
+ recorder.recordAttribute(AnnotationKey.HTTP_STATUS_CODE, statusCodeProvider.getStatusCode(clientHttpResponse));
}
}
diff --git a/plugins/resttemplate/src/main/java/com/navercorp/pinpoint/plugin/resttemplate/interceptor/ListenableFutureInterceptor.java b/plugins/resttemplate/src/main/java/com/navercorp/pinpoint/plugin/resttemplate/interceptor/ListenableFutureInterceptor.java
index faaa9d840fb0..71b5be663f95 100644
--- a/plugins/resttemplate/src/main/java/com/navercorp/pinpoint/plugin/resttemplate/interceptor/ListenableFutureInterceptor.java
+++ b/plugins/resttemplate/src/main/java/com/navercorp/pinpoint/plugin/resttemplate/interceptor/ListenableFutureInterceptor.java
@@ -27,6 +27,8 @@
import com.navercorp.pinpoint.plugin.resttemplate.RestTemplateConstants;
import com.navercorp.pinpoint.plugin.resttemplate.RestTemplateResponseHeaderAdaptor;
import com.navercorp.pinpoint.plugin.resttemplate.field.accessor.TraceFutureFlagAccessor;
+import com.navercorp.pinpoint.plugin.resttemplate.interceptor.util.HttpStatusProvider;
+import com.navercorp.pinpoint.plugin.resttemplate.interceptor.util.HttpStatusProviderFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.client.AbstractClientHttpResponse;
import org.springframework.http.client.ClientHttpResponse;
@@ -39,10 +41,13 @@
public class ListenableFutureInterceptor extends AsyncContextSpanEventSimpleAroundInterceptor {
private final ServerResponseHeaderRecorder responseHeaderRecorder;
+ private final HttpStatusProvider statusCodeProvider;
- public ListenableFutureInterceptor(MethodDescriptor methodDescriptor, TraceContext traceContext) {
+ public ListenableFutureInterceptor(MethodDescriptor methodDescriptor, TraceContext traceContext,
+ int springVersion) {
super(traceContext, methodDescriptor);
this.responseHeaderRecorder = ResponseHeaderRecorderFactory.newResponseHeaderRecorder(traceContext.getProfilerConfig(), new RestTemplateResponseHeaderAdaptor());
+ this.statusCodeProvider = HttpStatusProviderFactory.getHttpStatusProvider(springVersion);
}
@Override
@@ -89,12 +94,9 @@ protected void doInAfterTrace(SpanEventRecorder recorder, Object target, Object[
if (args.length == 1 && args[0] instanceof AbstractClientHttpResponse) {
AbstractClientHttpResponse response = (AbstractClientHttpResponse) args[0];
try {
- HttpStatus statusCode = response.getStatusCode();
- if (statusCode != null) {
- recorder.recordAttribute(AnnotationKey.HTTP_STATUS_CODE, statusCode.value());
- }
+ recorder.recordAttribute(AnnotationKey.HTTP_STATUS_CODE, statusCodeProvider.getStatusCode(response));
this.responseHeaderRecorder.recordHeader(recorder, response);
- } catch (IOException ioException) {
+ } catch (Exception ioException) {
logger.warn("Failed to after process. {}", ioException.getMessage(), ioException);
}
}
diff --git a/plugins/resttemplate/src/main/java/com/navercorp/pinpoint/plugin/resttemplate/interceptor/util/HttpStatusProvider.java b/plugins/resttemplate/src/main/java/com/navercorp/pinpoint/plugin/resttemplate/interceptor/util/HttpStatusProvider.java
new file mode 100644
index 000000000000..17f8bc764e63
--- /dev/null
+++ b/plugins/resttemplate/src/main/java/com/navercorp/pinpoint/plugin/resttemplate/interceptor/util/HttpStatusProvider.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2024 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.resttemplate.interceptor.util;
+
+/**
+ * @author intr3p1d
+ */
+public interface HttpStatusProvider {
+ int getStatusCode(Object target);
+}
diff --git a/plugins/resttemplate/src/main/java/com/navercorp/pinpoint/plugin/resttemplate/interceptor/util/HttpStatusProviderFactory.java b/plugins/resttemplate/src/main/java/com/navercorp/pinpoint/plugin/resttemplate/interceptor/util/HttpStatusProviderFactory.java
new file mode 100644
index 000000000000..9e0565811cd3
--- /dev/null
+++ b/plugins/resttemplate/src/main/java/com/navercorp/pinpoint/plugin/resttemplate/interceptor/util/HttpStatusProviderFactory.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2024 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.resttemplate.interceptor.util;
+
+import com.navercorp.pinpoint.plugin.resttemplate.SpringVersion;
+
+/**
+ * @author intr3p1d
+ */
+public class HttpStatusProviderFactory {
+
+ public HttpStatusProviderFactory() {
+ }
+
+ public static HttpStatusProvider getHttpStatusProvider(int version) {
+ switch (version) {
+ case SpringVersion.SPRING_VERSION_5:
+ return new Spring5HttpStatusProvider();
+ case SpringVersion.SPRING_VERSION_6:
+ return new Spring6HttpStatusProvider();
+ default:
+ return new UnsupportedHttpStatusProvider();
+ }
+ }
+}
diff --git a/plugins/resttemplate/src/main/java/com/navercorp/pinpoint/plugin/resttemplate/interceptor/util/Spring5HttpStatusProvider.java b/plugins/resttemplate/src/main/java/com/navercorp/pinpoint/plugin/resttemplate/interceptor/util/Spring5HttpStatusProvider.java
new file mode 100644
index 000000000000..6d2985278ce0
--- /dev/null
+++ b/plugins/resttemplate/src/main/java/com/navercorp/pinpoint/plugin/resttemplate/interceptor/util/Spring5HttpStatusProvider.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2024 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.resttemplate.interceptor.util;
+
+import org.springframework.http.client.ClientHttpResponse;
+
+import java.io.IOException;
+
+/**
+ * @author intr3p1d
+ */
+public class Spring5HttpStatusProvider implements HttpStatusProvider {
+ @Override
+ public int getStatusCode(Object target) {
+ if (target instanceof ClientHttpResponse) {
+ final ClientHttpResponse response = (ClientHttpResponse) target;
+ try {
+ return response.getRawStatusCode();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ return -1;
+ }
+}
diff --git a/plugins/resttemplate/src/main/java/com/navercorp/pinpoint/plugin/resttemplate/interceptor/util/Spring6HttpStatusProvider.java b/plugins/resttemplate/src/main/java/com/navercorp/pinpoint/plugin/resttemplate/interceptor/util/Spring6HttpStatusProvider.java
new file mode 100644
index 000000000000..723bfaae5e20
--- /dev/null
+++ b/plugins/resttemplate/src/main/java/com/navercorp/pinpoint/plugin/resttemplate/interceptor/util/Spring6HttpStatusProvider.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2024 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.resttemplate.interceptor.util;
+
+import org.springframework.http.client.ClientHttpResponse;
+
+import java.io.IOException;
+
+/**
+ * @author intr3p1d
+ */
+public class Spring6HttpStatusProvider implements HttpStatusProvider {
+ @Override
+ public int getStatusCode(Object target) {
+ if (target instanceof ClientHttpResponse) {
+ final ClientHttpResponse response = (ClientHttpResponse) target;
+ try {
+ return response.getStatusCode().value();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ return -1;
+ }
+}
diff --git a/plugins/resttemplate/src/main/java/com/navercorp/pinpoint/plugin/resttemplate/interceptor/util/UnsupportedHttpStatusProvider.java b/plugins/resttemplate/src/main/java/com/navercorp/pinpoint/plugin/resttemplate/interceptor/util/UnsupportedHttpStatusProvider.java
new file mode 100644
index 000000000000..8ccb1a0e4890
--- /dev/null
+++ b/plugins/resttemplate/src/main/java/com/navercorp/pinpoint/plugin/resttemplate/interceptor/util/UnsupportedHttpStatusProvider.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2024 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.resttemplate.interceptor.util;
+
+/**
+ * @author intr3p1d
+ */
+public class UnsupportedHttpStatusProvider implements HttpStatusProvider {
+
+ @Override
+ public int getStatusCode(Object target) {
+ return -1;
+ }
+}
diff --git a/plugins/spring-stub/pom.xml b/plugins/spring-stub/pom.xml
new file mode 100644
index 000000000000..137ef995b6fc
--- /dev/null
+++ b/plugins/spring-stub/pom.xml
@@ -0,0 +1,46 @@
+
+
+ 4.0.0
+
+ com.navercorp.pinpoint
+ pinpoint-plugins
+ 2.5.4-SNAPSHOT
+
+
+ pinpoint-spring-stub
+ pinpoint-spring-stub
+ jar
+
+
+ 1.8
+ ${env.JAVA_8_HOME}
+ ${env.JAVA_8_HOME}
+ ${spring5.version}
+
+
+
+
+ com.navercorp.pinpoint
+ pinpoint-bootstrap-core
+ provided
+
+
+
+ org.springframework
+ spring-webflux
+ provided
+
+
+ org.springframework
+ spring-core
+ provided
+
+
+ org.springframework
+ spring-web
+ provided
+
+
+
+
\ No newline at end of file
diff --git a/plugins/spring-stub/src/main/java/org/springframework/http/HttpStatusCode.java b/plugins/spring-stub/src/main/java/org/springframework/http/HttpStatusCode.java
new file mode 100644
index 000000000000..7259f84e8e3c
--- /dev/null
+++ b/plugins/spring-stub/src/main/java/org/springframework/http/HttpStatusCode.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2024 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 org.springframework.http;
+
+/**
+ * @author intr3p1d
+ */
+public interface HttpStatusCode {
+ int value();
+}
diff --git a/plugins/spring-stub/src/main/java/org/springframework/http/client/ClientHttpResponse.java b/plugins/spring-stub/src/main/java/org/springframework/http/client/ClientHttpResponse.java
new file mode 100644
index 000000000000..cb3c095ae3ad
--- /dev/null
+++ b/plugins/spring-stub/src/main/java/org/springframework/http/client/ClientHttpResponse.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2024 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 org.springframework.http.client;
+
+import org.springframework.http.HttpInputMessage;
+import org.springframework.http.HttpStatusCode;
+
+import java.io.Closeable;
+import java.io.IOException;
+
+/**
+ * @author intr3p1d
+ */
+public interface ClientHttpResponse extends HttpInputMessage, Closeable {
+ HttpStatusCode getStatusCode() throws IOException;
+
+ int getRawStatusCode() throws IOException;
+}
\ No newline at end of file
diff --git a/plugins/spring-stub/src/main/java/org/springframework/http/client/reactive/ClientHttpResponse.java b/plugins/spring-stub/src/main/java/org/springframework/http/client/reactive/ClientHttpResponse.java
new file mode 100644
index 000000000000..983ff4fe05ad
--- /dev/null
+++ b/plugins/spring-stub/src/main/java/org/springframework/http/client/reactive/ClientHttpResponse.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2024 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 org.springframework.http.client.reactive;
+
+import org.springframework.http.HttpStatusCode;
+import org.springframework.http.HttpInputMessage;
+
+import java.io.Closeable;
+
+/**
+ * @author intr3p1d
+ */
+public interface ClientHttpResponse extends HttpInputMessage, Closeable {
+ HttpStatusCode getStatusCode();
+
+ int getRawStatusCode();
+}
diff --git a/plugins/spring-webflux/pom.xml b/plugins/spring-webflux/pom.xml
index e9fd1297b3ef..8e82e772ea0f 100644
--- a/plugins/spring-webflux/pom.xml
+++ b/plugins/spring-webflux/pom.xml
@@ -1,6 +1,6 @@
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
4.0.0
com.navercorp.pinpoint
@@ -24,6 +24,12 @@
pinpoint-bootstrap-core
provided
+
+ com.navercorp.pinpoint
+ pinpoint-spring-stub
+ ${project.version}
+ provided
+
org.springframework
@@ -38,4 +44,19 @@
+
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+
+
+ com/navercorp/**/*
+ META-INF/**/*
+
+
+
+
+
diff --git a/plugins/spring-webflux/src/main/java/com/navercorp/pinpoint/plugin/spring/webflux/SpringVersion.java b/plugins/spring-webflux/src/main/java/com/navercorp/pinpoint/plugin/spring/webflux/SpringVersion.java
new file mode 100644
index 000000000000..af243691416b
--- /dev/null
+++ b/plugins/spring-webflux/src/main/java/com/navercorp/pinpoint/plugin/spring/webflux/SpringVersion.java
@@ -0,0 +1,56 @@
+package com.navercorp.pinpoint.plugin.spring.webflux;/*
+ * Copyright 2024 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.
+ */
+
+import java.util.Objects;
+
+/**
+ * @author intr3p1d
+ */
+public class SpringVersion {
+
+ public static final int SPRING_VERSION_UNKNOWN = -1;
+ public static final int SPRING_VERSION_5 = 5_00_00;
+ public static final int SPRING_VERSION_6 = 6_00_00;
+
+ static final String SPRING5_HTTP_STATUS_INTERFACE_NAME = "org.springframework.http.HttpStatus";
+ static final String SPRING6_HTTP_STATUS_INTERFACE_NAME = "org.springframework.http.HttpStatusCode";
+
+
+ public static int getVersion(ClassLoader classLoader) {
+ // Spring 6.0 + (boot 3.0 + )
+ final Class> httpStatusCode = getClass(classLoader, SPRING6_HTTP_STATUS_INTERFACE_NAME);
+ if (httpStatusCode != null) {
+ return SpringVersion.SPRING_VERSION_6;
+ }
+
+ // ~ Spring 5.x (boot 2.0 -)
+ final Class> httpStatus = getClass(classLoader, SPRING5_HTTP_STATUS_INTERFACE_NAME);
+ if (httpStatus != null) {
+ return SpringVersion.SPRING_VERSION_5;
+ }
+ return SpringVersion.SPRING_VERSION_UNKNOWN;
+ }
+
+
+ static Class> getClass(ClassLoader classLoader, String className) {
+ Objects.requireNonNull(className, "className");
+ try {
+ return Class.forName(className, false, classLoader);
+ } catch (ClassNotFoundException ignored) {
+ return null;
+ }
+ }
+}
diff --git a/plugins/spring-webflux/src/main/java/com/navercorp/pinpoint/plugin/spring/webflux/SpringWebFluxPlugin.java b/plugins/spring-webflux/src/main/java/com/navercorp/pinpoint/plugin/spring/webflux/SpringWebFluxPlugin.java
index 13ee2610b32f..a23200761be8 100644
--- a/plugins/spring-webflux/src/main/java/com/navercorp/pinpoint/plugin/spring/webflux/SpringWebFluxPlugin.java
+++ b/plugins/spring-webflux/src/main/java/com/navercorp/pinpoint/plugin/spring/webflux/SpringWebFluxPlugin.java
@@ -190,7 +190,8 @@ public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, Strin
final InstrumentMethod logResponseMethod = target.getDeclaredMethod("logResponse", "org.springframework.http.client.reactive.ClientHttpResponse", "java.lang.String");
if (logResponseMethod != null) {
- logResponseMethod.addInterceptor(ClientResponseFunctionInterceptor.class);
+ final int springVersion = SpringVersion.getVersion(loader);
+ logResponseMethod.addInterceptor(ClientResponseFunctionInterceptor.class, va(springVersion));
}
return target.toBytecode();
diff --git a/plugins/spring-webflux/src/main/java/com/navercorp/pinpoint/plugin/spring/webflux/interceptor/ClientResponseFunctionInterceptor.java b/plugins/spring-webflux/src/main/java/com/navercorp/pinpoint/plugin/spring/webflux/interceptor/ClientResponseFunctionInterceptor.java
index d6c5381cf9ce..ae8382dad2c2 100644
--- a/plugins/spring-webflux/src/main/java/com/navercorp/pinpoint/plugin/spring/webflux/interceptor/ClientResponseFunctionInterceptor.java
+++ b/plugins/spring-webflux/src/main/java/com/navercorp/pinpoint/plugin/spring/webflux/interceptor/ClientResponseFunctionInterceptor.java
@@ -26,6 +26,8 @@
import com.navercorp.pinpoint.plugin.spring.webflux.SpringWebFluxConstants;
import com.navercorp.pinpoint.plugin.spring.webflux.SpringWebFluxResponseHeaderAdaptor;
+import com.navercorp.pinpoint.plugin.spring.webflux.interceptor.util.HttpStatusProvider;
+import com.navercorp.pinpoint.plugin.spring.webflux.interceptor.util.HttpStatusProviderFactory;
import org.springframework.http.client.reactive.ClientHttpResponse;
/**
@@ -34,10 +36,13 @@
public class ClientResponseFunctionInterceptor extends SpanEventSimpleAroundInterceptorForPlugin {
private final ServerResponseHeaderRecorder responseHeaderRecorder;
+ private final HttpStatusProvider statusCodeProvider;
- public ClientResponseFunctionInterceptor(TraceContext traceContext, MethodDescriptor descriptor) {
+ public ClientResponseFunctionInterceptor(TraceContext traceContext, MethodDescriptor descriptor,
+ int springVersion) {
super(traceContext, descriptor);
this.responseHeaderRecorder = ResponseHeaderRecorderFactory.newResponseHeaderRecorder(traceContext.getProfilerConfig(), new SpringWebFluxResponseHeaderAdaptor());
+ this.statusCodeProvider = HttpStatusProviderFactory.getHttpStatusProvider(springVersion);
}
@Override
@@ -52,8 +57,8 @@ protected void doInAfterTrace(SpanEventRecorder recorder, Object target, Object[
if (args[0] instanceof ClientHttpResponse) {
ClientHttpResponse response = (ClientHttpResponse) args[0];
- recorder.recordAttribute(AnnotationKey.HTTP_STATUS_CODE, response.getRawStatusCode());
+ recorder.recordAttribute(AnnotationKey.HTTP_STATUS_CODE, statusCodeProvider.getStatusCode(response));
this.responseHeaderRecorder.recordHeader(recorder, response);
}
}
-}
\ No newline at end of file
+}
diff --git a/plugins/spring-webflux/src/main/java/com/navercorp/pinpoint/plugin/spring/webflux/interceptor/util/HttpStatusProvider.java b/plugins/spring-webflux/src/main/java/com/navercorp/pinpoint/plugin/spring/webflux/interceptor/util/HttpStatusProvider.java
new file mode 100644
index 000000000000..f983f65435d4
--- /dev/null
+++ b/plugins/spring-webflux/src/main/java/com/navercorp/pinpoint/plugin/spring/webflux/interceptor/util/HttpStatusProvider.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2024 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.spring.webflux.interceptor.util;
+
+/**
+ * @author intr3p1d
+ */
+public interface HttpStatusProvider {
+ int getStatusCode(Object target);
+}
diff --git a/plugins/spring-webflux/src/main/java/com/navercorp/pinpoint/plugin/spring/webflux/interceptor/util/HttpStatusProviderFactory.java b/plugins/spring-webflux/src/main/java/com/navercorp/pinpoint/plugin/spring/webflux/interceptor/util/HttpStatusProviderFactory.java
new file mode 100644
index 000000000000..e256b58998b7
--- /dev/null
+++ b/plugins/spring-webflux/src/main/java/com/navercorp/pinpoint/plugin/spring/webflux/interceptor/util/HttpStatusProviderFactory.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2024 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.spring.webflux.interceptor.util;
+
+import com.navercorp.pinpoint.plugin.spring.webflux.SpringVersion;
+
+/**
+ * @author intr3p1d
+ */
+public class HttpStatusProviderFactory {
+
+ public HttpStatusProviderFactory() {
+ }
+
+ public static HttpStatusProvider getHttpStatusProvider(int version) {
+ switch (version) {
+ case SpringVersion.SPRING_VERSION_5:
+ return new Spring5HttpStatusProvider();
+ case SpringVersion.SPRING_VERSION_6:
+ return new Spring6HttpStatusProvider();
+ default:
+ return new UnsupportedHttpStatusProvider();
+ }
+ }
+}
diff --git a/plugins/spring-webflux/src/main/java/com/navercorp/pinpoint/plugin/spring/webflux/interceptor/util/Spring5HttpStatusProvider.java b/plugins/spring-webflux/src/main/java/com/navercorp/pinpoint/plugin/spring/webflux/interceptor/util/Spring5HttpStatusProvider.java
new file mode 100644
index 000000000000..e307c01a30c6
--- /dev/null
+++ b/plugins/spring-webflux/src/main/java/com/navercorp/pinpoint/plugin/spring/webflux/interceptor/util/Spring5HttpStatusProvider.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2024 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.spring.webflux.interceptor.util;
+
+import org.springframework.http.client.reactive.ClientHttpResponse;
+
+/**
+ * @author intr3p1d
+ */
+public class Spring5HttpStatusProvider implements HttpStatusProvider {
+ @Override
+ public int getStatusCode(Object target) {
+ if (target instanceof ClientHttpResponse) {
+ final ClientHttpResponse response = (ClientHttpResponse) target;
+ try {
+ return response.getRawStatusCode();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+ return -1;
+ }
+}
diff --git a/plugins/spring-webflux/src/main/java/com/navercorp/pinpoint/plugin/spring/webflux/interceptor/util/Spring6HttpStatusProvider.java b/plugins/spring-webflux/src/main/java/com/navercorp/pinpoint/plugin/spring/webflux/interceptor/util/Spring6HttpStatusProvider.java
new file mode 100644
index 000000000000..d8c52a4d3e12
--- /dev/null
+++ b/plugins/spring-webflux/src/main/java/com/navercorp/pinpoint/plugin/spring/webflux/interceptor/util/Spring6HttpStatusProvider.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2024 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.spring.webflux.interceptor.util;
+
+import org.springframework.http.client.reactive.ClientHttpResponse;
+
+/**
+ * @author intr3p1d
+ */
+public class Spring6HttpStatusProvider implements HttpStatusProvider {
+ @Override
+ public int getStatusCode(Object target) {
+ if (target instanceof ClientHttpResponse) {
+ final ClientHttpResponse response = (ClientHttpResponse) target;
+ try {
+ return response.getStatusCode().value();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+ return -1;
+ }
+}
diff --git a/plugins/spring-webflux/src/main/java/com/navercorp/pinpoint/plugin/spring/webflux/interceptor/util/UnsupportedHttpStatusProvider.java b/plugins/spring-webflux/src/main/java/com/navercorp/pinpoint/plugin/spring/webflux/interceptor/util/UnsupportedHttpStatusProvider.java
new file mode 100644
index 000000000000..35c5c0b5eb73
--- /dev/null
+++ b/plugins/spring-webflux/src/main/java/com/navercorp/pinpoint/plugin/spring/webflux/interceptor/util/UnsupportedHttpStatusProvider.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2024 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.spring.webflux.interceptor.util;
+
+/**
+ * @author intr3p1d
+ */
+public class UnsupportedHttpStatusProvider implements HttpStatusProvider {
+
+ @Override
+ public int getStatusCode(Object target) {
+ return -1;
+ }
+}