Skip to content

Commit

Permalink
[#10832] Backport: Support getStatusCode() for compatibility with S…
Browse files Browse the repository at this point in the history
…pring WebFlux 6.1 & Boot 3.x.

[#NotAssigned] Removed getRawStatusCode() method for removal in Spring Webflux 6.1

[#10736] Separate dummy java class not to disturb spring-web dependency

[#10736] Remove dummy classes after install the plugin

[#10736] Use maven-clean-plugin instead of exec

[#10736] Split spring-stub into separate modules
  • Loading branch information
intr3p1d committed Apr 2, 2024
1 parent d11d9e6 commit 1c0d070
Show file tree
Hide file tree
Showing 26 changed files with 653 additions and 18 deletions.
5 changes: 5 additions & 0 deletions plugins/assembly/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -417,5 +417,10 @@
<artifactId>pinpoint-spring-tx-plugin</artifactId>
<version>${project.version}</version>
</dependency>
<!-- <dependency>-->
<!-- <groupId>com.navercorp.pinpoint</groupId>-->
<!-- <artifactId>pinpoint-spring-stub</artifactId>-->
<!-- <version>${project.version}</version>-->
<!-- </dependency>-->
</dependencies>
</project>
1 change: 1 addition & 0 deletions plugins/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@
<module>agentsdk-async</module>
<module>spring-data-r2dbc</module>
<module>spring-tx</module>
<module>spring-stub</module>
</modules>


Expand Down
22 changes: 21 additions & 1 deletion plugins/resttemplate/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,32 @@
<artifactId>pinpoint-bootstrap-core</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.navercorp.pinpoint</groupId>
<artifactId>pinpoint-spring-stub</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>


<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<includes>
<include>com/navercorp/**/*</include>
<include>META-INF/**/*</include>
</includes>
</configuration>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -167,8 +169,9 @@ public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader,

final List<InstrumentMethod> 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);
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -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;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -35,10 +37,13 @@
public class ClientHttpResponseInterceptor extends SpanEventSimpleAroundInterceptorForPlugin {

private final ServerResponseHeaderRecorder<ClientHttpResponse> 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
Expand All @@ -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);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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
Expand All @@ -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));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -39,10 +41,13 @@
public class ListenableFutureInterceptor extends AsyncContextSpanEventSimpleAroundInterceptor {

private final ServerResponseHeaderRecorder<ClientHttpResponse> 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
Expand Down Expand Up @@ -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);
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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);
}
Original file line number Diff line number Diff line change
@@ -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();
}
}
}
Original file line number Diff line number Diff line change
@@ -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;
}
}
Original file line number Diff line number Diff line change
@@ -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;
}
}
Loading

0 comments on commit 1c0d070

Please sign in to comment.