Skip to content

Commit

Permalink
[pinpoint-apm#9702] Update reactor-netty plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
jaehong-kim committed Feb 15, 2023
1 parent 3702da1 commit 7f0b067
Show file tree
Hide file tree
Showing 11 changed files with 544 additions and 104 deletions.
4 changes: 4 additions & 0 deletions agent-testweb/spring-webflux-plugin-testweb/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@
<artifactId>spring-boot-autoconfigure</artifactId>
<version>${spring.boot.version}</version>
</dependency>
<dependency>
<groupId>com.navercorp.pinpoint</groupId>
<artifactId>pinpoint-agent-testweb-commons</artifactId>
</dependency>
</dependencies>

</project>
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@

package com.pinpoint.test.plugin;

import com.pinpoint.test.common.view.ApiLinkPage;
import com.pinpoint.test.common.view.HrefTag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpMethod;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.web.bind.annotation.GetMapping;
Expand All @@ -24,19 +27,60 @@
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.reactive.result.method.RequestMappingInfo;
import org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerMapping;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@RestController
public class SpringWebfluxPluginController {

private final RequestMappingHandlerMapping handlerMapping;

@Autowired
public SpringWebfluxPluginController(RequestMappingHandlerMapping handlerMapping) {
this.handlerMapping = handlerMapping;
}

@GetMapping("/")
String welcome() {
Map<RequestMappingInfo, HandlerMethod> handlerMethods = this.handlerMapping.getHandlerMethods();
List<HrefTag> list = new ArrayList<>();
for (RequestMappingInfo info : handlerMethods.keySet()) {
for (String path : info.getDirectPaths()) {
list.add(HrefTag.of(path));
}
}
list.sort(Comparator.comparing(HrefTag::getPath));
return new ApiLinkPage("spring-webflux-plugin-testweb")
.addHrefTag(list)
.build();
}

@GetMapping("/server/welcome/**")
public Mono<String> welcome(ServerWebExchange exchange) {
public Mono<String> serverWelcome(ServerWebExchange exchange) {
exchange.getAttributes().put("pinpoint.metric.uri-template", "/test");
return Mono.just("Welcome Home");
}

@GetMapping("/server/wait/3s")
public Mono<String> wait3(ServerWebExchange exchange) {
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
}
return Mono.just("Welcome Home");
}

@PostMapping("/server/post")
public Mono<String> welcome(@RequestBody String body) {
return Mono.just("Post=" + body);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*
* 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.reactor.netty;

public class HttpCallContext {
private long readBeginTime;
private long readEndTime;
private boolean readFail;

private long writeBeginTime;
private long writeEndTime;
private boolean writeFail;

public void setReadBeginTime(long readBeginTime) {
this.readBeginTime = readBeginTime;
}

public void setReadEndTime(long readEndTime) {
this.readEndTime = readEndTime;
}

public boolean isReadFail() {
return readFail;
}

public void setReadFail(boolean readFail) {
this.readFail = readFail;
}

public void setWriteBeginTime(long writeBeginTime) {
this.writeBeginTime = writeBeginTime;
}

public void setWriteEndTime(long writeEndTime) {
this.writeEndTime = writeEndTime;
}

public boolean isWriteFail() {
return writeFail;
}

public void setWriteFail(boolean writeFail) {
this.writeFail = writeFail;
}

public long getWriteElapsedTime() {
if (writeBeginTime == 0) {
return 0;
}
long result = writeEndTime - writeBeginTime;
return result > 0 ? result : 0;
}

public long getReadElapsedTime() {
if (readBeginTime == 0) {
return 0;
}
long result = readEndTime - readBeginTime;
return result > 0 ? result : 0;
}

@Override
public String toString() {
return "HttpCallContext{" +
"readBeginTime=" + readBeginTime +
", readEndTime=" + readEndTime +
", readFail=" + readFail +
", writeBeginTime=" + writeBeginTime +
", writeEndTime=" + writeEndTime +
", writeFail=" + writeFail +
'}';
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* 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.reactor.netty;

public interface HttpCallContextAccessor {
void _$PINPOINT$_setHttpCallContext(HttpCallContext httpCallContext);

HttpCallContext _$PINPOINT$_getHttpCallContext();
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@
import com.navercorp.pinpoint.plugin.reactor.netty.interceptor.HttpClientOperationsOnOutboundCompleteInterceptor;
import com.navercorp.pinpoint.plugin.reactor.netty.interceptor.HttpClientOperationsOnOutboundErrorInterceptor;
import com.navercorp.pinpoint.plugin.reactor.netty.interceptor.HttpClientOperationsSendInterceptor;
import com.navercorp.pinpoint.plugin.reactor.netty.interceptor.HttpIOHandlerObserverConstructorInterceptor;
import com.navercorp.pinpoint.plugin.reactor.netty.interceptor.HttpIOHandlerObserverOnStateChangeInterceptor;
import com.navercorp.pinpoint.plugin.reactor.netty.interceptor.HttpServerHandleHttpServerStateInterceptor;
import com.navercorp.pinpoint.plugin.reactor.netty.interceptor.HttpServerHandleStateInterceptor;
import com.navercorp.pinpoint.plugin.reactor.netty.interceptor.HttpTcpClientConnectInterceptor;
Expand Down Expand Up @@ -101,6 +103,8 @@ public void setup(ProfilerPluginSetupContext context) {
transformTemplate.transform("reactor.netty.http.client.HttpClientConnect$HttpTcpClient", HttpTcpClientTransform.class);
transformTemplate.transform("reactor.netty.http.client.HttpClientConnect$HttpClientHandler", HttpClientHandleTransform.class);
transformTemplate.transform("reactor.netty.http.client.HttpClientOperations", HttpClientOperationsTransform.class);
transformTemplate.transform("reactor.netty.http.client.HttpClientConnect$MonoHttpConnect", FluxAndMonoTransform.class);
transformTemplate.transform("reactor.netty.http.client.HttpClientConnect$HttpIOHandlerObserver", HttpIOHandlerObserverTransform.class);
}

transformTemplate.transform("reactor.netty.ByteBufFlux", FluxAndMonoOperatorTransform.class);
Expand Down Expand Up @@ -257,6 +261,26 @@ public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, Strin
}
}

public static class HttpIOHandlerObserverTransform implements TransformCallback {
@Override
public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException {
InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer);
target.addField(AsyncContextAccessor.class);
target.addField(HttpCallContextAccessor.class);

final InstrumentMethod constructorMethod = target.getConstructor("reactor.core.publisher.MonoSink", "reactor.netty.http.client.HttpClientConnect$HttpClientHandler");
if (constructorMethod != null) {
constructorMethod.addInterceptor(HttpIOHandlerObserverConstructorInterceptor.class);
}
final InstrumentMethod onStateChangeMethod = target.getDeclaredMethod("onStateChange", "reactor.netty.Connection", "reactor.netty.ConnectionObserver$State");
if (onStateChangeMethod != null) {
onStateChangeMethod.addInterceptor(HttpIOHandlerObserverOnStateChangeInterceptor.class);
}

return target.toBytecode();
}
}

public static class FluxAndMonoTransform implements TransformCallback {
@Override
public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException {
Expand Down
Loading

0 comments on commit 7f0b067

Please sign in to comment.