From 6208c7c8d47b17b5d5f6abe48eac8fdc125c3675 Mon Sep 17 00:00:00 2001 From: jaehong-kim Date: Thu, 16 Jun 2022 18:21:28 +0900 Subject: [PATCH] [#8930] Update lettuce reactive --- agent-testweb/bom/pom.xml | 2 +- agent-testweb/pom.xml | 1 + .../redis-lettuce-plugin-testweb/pom.xml | 48 ++++++++ .../test/plugin/HttpClientConfig.java | 31 +++++ .../plugin/RedisLettucePluginTestStarter.java | 28 +++++ .../test/plugin/RedisRateLimiterConfig.java | 29 +++++ .../com/pinpoint/test/plugin/SimpleRoute.java | 51 ++++++++ .../src/main/resources/application.yml | 22 ++++ .../async/AsyncContextAccessorUtils.java | 5 +- .../CoreSubscriberConstructorInterceptor.java | 5 +- .../FluxAndMonoConstructorInterceptor.java | 10 +- ...AndMonoOperatorConstructorInterceptor.java | 10 +- ...uxAndMonoOperatorSubscribeInterceptor.java | 10 +- .../FluxAndMonoSubscribeInterceptor.java | 10 +- .../reactor/ReactorContextAccessorUtils.java | 5 +- plugins/bom/pom.xml | 2 +- .../ParallelFluxSubscribeInterceptor.java | 5 +- .../RunnableCoreSubscriberInterceptor.java | 5 +- .../plugin/redis/lettuce/LettucePlugin.java | 112 +++++++++++++++++- .../RedisSubscriberInterceptor.java | 62 ++++++++++ .../RunnableNewInstanceInterceptor.java | 69 +++++++++++ .../interceptor/RunnableRunInterceptor.java | 42 +++++++ 22 files changed, 508 insertions(+), 56 deletions(-) create mode 100644 agent-testweb/redis-lettuce-plugin-testweb/pom.xml create mode 100644 agent-testweb/redis-lettuce-plugin-testweb/src/main/java/com/pinpoint/test/plugin/HttpClientConfig.java create mode 100644 agent-testweb/redis-lettuce-plugin-testweb/src/main/java/com/pinpoint/test/plugin/RedisLettucePluginTestStarter.java create mode 100644 agent-testweb/redis-lettuce-plugin-testweb/src/main/java/com/pinpoint/test/plugin/RedisRateLimiterConfig.java create mode 100644 agent-testweb/redis-lettuce-plugin-testweb/src/main/java/com/pinpoint/test/plugin/SimpleRoute.java create mode 100644 agent-testweb/redis-lettuce-plugin-testweb/src/main/resources/application.yml create mode 100644 plugins/redis-lettuce/src/main/java/com/navercorp/pinpoint/plugin/redis/lettuce/interceptor/RedisSubscriberInterceptor.java create mode 100644 plugins/redis-lettuce/src/main/java/com/navercorp/pinpoint/plugin/redis/lettuce/interceptor/RunnableNewInstanceInterceptor.java create mode 100644 plugins/redis-lettuce/src/main/java/com/navercorp/pinpoint/plugin/redis/lettuce/interceptor/RunnableRunInterceptor.java diff --git a/agent-testweb/bom/pom.xml b/agent-testweb/bom/pom.xml index 8a52b4536a82..55a1da9b6cdf 100644 --- a/agent-testweb/bom/pom.xml +++ b/agent-testweb/bom/pom.xml @@ -31,7 +31,7 @@ 2.4.2 - 5.1.2.RELEASE + 6.1.5.RELEASE 2.1.7.1 2.5.3 3.9.0 diff --git a/agent-testweb/pom.xml b/agent-testweb/pom.xml index 79211122d06e..dd12ed6b8d25 100644 --- a/agent-testweb/pom.xml +++ b/agent-testweb/pom.xml @@ -71,6 +71,7 @@ elasticsearch-8-plugin-testweb postgresql-plugin-testweb undertow-plugin-testweb + redis-lettuce-plugin-testweb diff --git a/agent-testweb/redis-lettuce-plugin-testweb/pom.xml b/agent-testweb/redis-lettuce-plugin-testweb/pom.xml new file mode 100644 index 000000000000..20fe697aea03 --- /dev/null +++ b/agent-testweb/redis-lettuce-plugin-testweb/pom.xml @@ -0,0 +1,48 @@ + + + + 4.0.0 + + com.navercorp.pinpoint + pinpoint-agent-testweb + 2.5.0-SNAPSHOT + + + pinpoint-redis-lettuce-plugin-testweb + + jar + + + + ${pinpoint.agent.default.jvmargument} + + + + + + org.springframework.boot + spring-boot-starter-webflux + ${spring.boot.version} + + + org.springframework.boot + spring-boot-autoconfigure + ${spring.boot.version} + + + + org.springframework.cloud + spring-cloud-starter-gateway + 3.0.7 + + + + org.springframework.boot + spring-boot-starter-data-redis-reactive + 2.6.2 + + + + \ No newline at end of file diff --git a/agent-testweb/redis-lettuce-plugin-testweb/src/main/java/com/pinpoint/test/plugin/HttpClientConfig.java b/agent-testweb/redis-lettuce-plugin-testweb/src/main/java/com/pinpoint/test/plugin/HttpClientConfig.java new file mode 100644 index 000000000000..66887ff39955 --- /dev/null +++ b/agent-testweb/redis-lettuce-plugin-testweb/src/main/java/com/pinpoint/test/plugin/HttpClientConfig.java @@ -0,0 +1,31 @@ +/* + * Copyright 2022 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.pinpoint.test.plugin; + +import io.netty.handler.logging.LogLevel; +import org.springframework.cloud.gateway.config.HttpClientCustomizer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import reactor.netty.transport.logging.AdvancedByteBufFormat; + +@Configuration +public class HttpClientConfig { + @Bean + public HttpClientCustomizer httpClientCustomizer() { + return httpClient -> httpClient.wiretap("reactor.netty.http.client.HttpClient", LogLevel.DEBUG, AdvancedByteBufFormat.TEXTUAL); + } +} diff --git a/agent-testweb/redis-lettuce-plugin-testweb/src/main/java/com/pinpoint/test/plugin/RedisLettucePluginTestStarter.java b/agent-testweb/redis-lettuce-plugin-testweb/src/main/java/com/pinpoint/test/plugin/RedisLettucePluginTestStarter.java new file mode 100644 index 000000000000..60bb5cbfcecb --- /dev/null +++ b/agent-testweb/redis-lettuce-plugin-testweb/src/main/java/com/pinpoint/test/plugin/RedisLettucePluginTestStarter.java @@ -0,0 +1,28 @@ +/* + * Copyright 2020 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.pinpoint.test.plugin; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class RedisLettucePluginTestStarter { + + public static void main(String[] args) { + SpringApplication.run(RedisLettucePluginTestStarter.class, args); + } +} \ No newline at end of file diff --git a/agent-testweb/redis-lettuce-plugin-testweb/src/main/java/com/pinpoint/test/plugin/RedisRateLimiterConfig.java b/agent-testweb/redis-lettuce-plugin-testweb/src/main/java/com/pinpoint/test/plugin/RedisRateLimiterConfig.java new file mode 100644 index 000000000000..54be4de451e9 --- /dev/null +++ b/agent-testweb/redis-lettuce-plugin-testweb/src/main/java/com/pinpoint/test/plugin/RedisRateLimiterConfig.java @@ -0,0 +1,29 @@ +/* + * Copyright 2022 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.pinpoint.test.plugin; + +import org.springframework.cloud.gateway.filter.ratelimit.RedisRateLimiter; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class RedisRateLimiterConfig { + @Bean + public RedisRateLimiter redisRateLimiter() { + return new RedisRateLimiter(10, 10); + } +} diff --git a/agent-testweb/redis-lettuce-plugin-testweb/src/main/java/com/pinpoint/test/plugin/SimpleRoute.java b/agent-testweb/redis-lettuce-plugin-testweb/src/main/java/com/pinpoint/test/plugin/SimpleRoute.java new file mode 100644 index 000000000000..6819753082ab --- /dev/null +++ b/agent-testweb/redis-lettuce-plugin-testweb/src/main/java/com/pinpoint/test/plugin/SimpleRoute.java @@ -0,0 +1,51 @@ +/* + * Copyright 2022 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.pinpoint.test.plugin; + +import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver; +import org.springframework.cloud.gateway.filter.ratelimit.RedisRateLimiter; +import org.springframework.cloud.gateway.route.RouteLocator; +import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpMethod; +import reactor.core.publisher.Mono; +import reactor.core.scheduler.Schedulers; + +@Configuration +public class SimpleRoute { + + @Bean + public RouteLocator route(RouteLocatorBuilder builder, RedisRateLimiter redisRateLimiter) { + KeyResolver keyResolver = exchange -> Mono.just("test-user"); + + return builder.routes() + .route("simple", r -> r.method(HttpMethod.GET).and().path("/simple") + .filters(f -> f + .addRequestHeader("foo", "bar") + .setPath("/headers") + // RequestRateLimiter 를 적용한 부분 + .requestRateLimiter().configure(config -> { + config.setKeyResolver(keyResolver); + config.setRateLimiter(redisRateLimiter); + }) + ) + .uri("https://httpbin.org") + ) + .build(); + } +} diff --git a/agent-testweb/redis-lettuce-plugin-testweb/src/main/resources/application.yml b/agent-testweb/redis-lettuce-plugin-testweb/src/main/resources/application.yml new file mode 100644 index 000000000000..4028597ae671 --- /dev/null +++ b/agent-testweb/redis-lettuce-plugin-testweb/src/main/resources/application.yml @@ -0,0 +1,22 @@ +# Defined in commandlineArgument of agent-test pom.xml + +server: + port: 18080 + +springdoc: + swagger-ui: + path: / + +logging: + level: + reactor.netty.http.client: debug + org.springframework.cloud.gateway.filter.ratelimit: debug + +spring: + redis: + cluster: + nodes: + - localhost:18001 + - localhost:18002 + - localhost:18003 + diff --git a/bootstraps/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/async/AsyncContextAccessorUtils.java b/bootstraps/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/async/AsyncContextAccessorUtils.java index 1e0ee1c096c8..2172b42e11e8 100644 --- a/bootstraps/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/async/AsyncContextAccessorUtils.java +++ b/bootstraps/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/async/AsyncContextAccessorUtils.java @@ -54,10 +54,7 @@ public static AsyncContext getAsyncContext(Object object) { public static void setAsyncContext(final AsyncContext asyncContext, final Object object) { if (object instanceof AsyncContextAccessor) { - final AsyncContext argAsyncContext = AsyncContextAccessorUtils.getAsyncContext(object); - if (argAsyncContext == null) { - ((AsyncContextAccessor) object)._$PINPOINT$_setAsyncContext(asyncContext); - } + ((AsyncContextAccessor) object)._$PINPOINT$_setAsyncContext(asyncContext); } } diff --git a/bootstraps/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/reactor/CoreSubscriberConstructorInterceptor.java b/bootstraps/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/reactor/CoreSubscriberConstructorInterceptor.java index 79be3ef53482..2fd7b6b735a2 100644 --- a/bootstraps/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/reactor/CoreSubscriberConstructorInterceptor.java +++ b/bootstraps/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/reactor/CoreSubscriberConstructorInterceptor.java @@ -53,9 +53,6 @@ public void after(Object target, Object[] args, Object result, Throwable throwab } protected void setReactorContextToTarget(final AsyncContext asyncContext, final Object target) { - final AsyncContext targetAsyncContext = ReactorContextAccessorUtils.getAsyncContext(target); - if (targetAsyncContext == null) { - ReactorContextAccessorUtils.setAsyncContext(asyncContext, target); - } + ReactorContextAccessorUtils.setAsyncContext(asyncContext, target); } } diff --git a/bootstraps/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/reactor/FluxAndMonoConstructorInterceptor.java b/bootstraps/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/reactor/FluxAndMonoConstructorInterceptor.java index 7e5385ff978d..89bac39137a4 100644 --- a/bootstraps/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/reactor/FluxAndMonoConstructorInterceptor.java +++ b/bootstraps/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/reactor/FluxAndMonoConstructorInterceptor.java @@ -56,17 +56,11 @@ public void after(Object target, Object[] args, Object result, Throwable throwab // Trace reactor protected void setReactorContextToTarget(final AsyncContext asyncContext, final Object target) { - final AsyncContext targetAsyncContext = ReactorContextAccessorUtils.getAsyncContext(target); - if (targetAsyncContext == null) { - ReactorContextAccessorUtils.setAsyncContext(asyncContext, target); - } + ReactorContextAccessorUtils.setAsyncContext(asyncContext, target); } // Trace subscribe() method protected void setAsyncContextToTarget(AsyncContext asyncContext, Object target) { - final AsyncContext targetAsyncContext = AsyncContextAccessorUtils.getAsyncContext(target); - if (targetAsyncContext == null) { - AsyncContextAccessorUtils.setAsyncContext(asyncContext, target); - } + AsyncContextAccessorUtils.setAsyncContext(asyncContext, target); } } diff --git a/bootstraps/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/reactor/FluxAndMonoOperatorConstructorInterceptor.java b/bootstraps/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/reactor/FluxAndMonoOperatorConstructorInterceptor.java index 1514331af564..8100ec0f61e8 100644 --- a/bootstraps/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/reactor/FluxAndMonoOperatorConstructorInterceptor.java +++ b/bootstraps/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/reactor/FluxAndMonoOperatorConstructorInterceptor.java @@ -101,17 +101,11 @@ protected AsyncContext getAsyncContextFromArgs(final Object target, final Object } protected void setAsyncContextToTarget(AsyncContext asyncContext, Object target) { - final AsyncContext targetAsyncContext = AsyncContextAccessorUtils.getAsyncContext(target); - if (targetAsyncContext == null) { - AsyncContextAccessorUtils.setAsyncContext(asyncContext, target); - } + AsyncContextAccessorUtils.setAsyncContext(asyncContext, target); } // Trace reactor protected void setReactorContextToTarget(AsyncContext asyncContext, Object target) { - final AsyncContext targetAsyncContext = ReactorContextAccessorUtils.getAsyncContext(target); - if (targetAsyncContext == null) { - ReactorContextAccessorUtils.setAsyncContext(asyncContext, target); - } + ReactorContextAccessorUtils.setAsyncContext(asyncContext, target); } } \ No newline at end of file diff --git a/bootstraps/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/reactor/FluxAndMonoOperatorSubscribeInterceptor.java b/bootstraps/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/reactor/FluxAndMonoOperatorSubscribeInterceptor.java index 3cdb649de708..03a540c35aac 100644 --- a/bootstraps/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/reactor/FluxAndMonoOperatorSubscribeInterceptor.java +++ b/bootstraps/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/reactor/FluxAndMonoOperatorSubscribeInterceptor.java @@ -75,17 +75,11 @@ boolean checkSubscriberReactorContextAccessor(final Object target, final Object[ } protected void setReactorContextToTarget(AsyncContext asyncContext, Object target) { - final AsyncContext targetAsyncContext = ReactorContextAccessorUtils.getAsyncContext(target); - if (targetAsyncContext == null) { - ReactorContextAccessorUtils.setAsyncContext(asyncContext, target); - } + ReactorContextAccessorUtils.setAsyncContext(asyncContext, target); } protected void setReactorContextToSubscriber(AsyncContext asyncContext, Object[] args) { - final AsyncContext subscriberAsyncContext = ReactorContextAccessorUtils.getAsyncContext(args, 0); - if (subscriberAsyncContext == null) { - ReactorContextAccessorUtils.setAsyncContext(asyncContext, args, 0); - } + ReactorContextAccessorUtils.setAsyncContext(asyncContext, args, 0); } @Override diff --git a/bootstraps/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/reactor/FluxAndMonoSubscribeInterceptor.java b/bootstraps/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/reactor/FluxAndMonoSubscribeInterceptor.java index 44f12ff7f0e0..1a0cf6fd9b40 100644 --- a/bootstraps/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/reactor/FluxAndMonoSubscribeInterceptor.java +++ b/bootstraps/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/reactor/FluxAndMonoSubscribeInterceptor.java @@ -75,17 +75,11 @@ private boolean checkSubscriberReactorContextAccessor(final Object target, final } protected void setReactorContextToTarget(AsyncContext asyncContext, Object target) { - final AsyncContext targetAsyncContext = ReactorContextAccessorUtils.getAsyncContext(target); - if (targetAsyncContext == null) { - ReactorContextAccessorUtils.setAsyncContext(asyncContext, target); - } + ReactorContextAccessorUtils.setAsyncContext(asyncContext, target); } protected void setReactorContextToSubscriber(AsyncContext asyncContext, Object[] args) { - final AsyncContext subscriberAsyncContext = ReactorContextAccessorUtils.getAsyncContext(args, 0); - if (subscriberAsyncContext == null) { - ReactorContextAccessorUtils.setAsyncContext(asyncContext, args, 0); - } + ReactorContextAccessorUtils.setAsyncContext(asyncContext, args, 0); } @Override diff --git a/bootstraps/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/reactor/ReactorContextAccessorUtils.java b/bootstraps/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/reactor/ReactorContextAccessorUtils.java index 7bf6d451f37c..c9ea85cce15d 100644 --- a/bootstraps/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/reactor/ReactorContextAccessorUtils.java +++ b/bootstraps/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/plugin/reactor/ReactorContextAccessorUtils.java @@ -52,10 +52,7 @@ public static AsyncContext getAsyncContext(Object object) { public static void setAsyncContext(final AsyncContext asyncContext, final Object object) { if (object instanceof ReactorContextAccessor) { - final AsyncContext argAsyncContext = ReactorContextAccessorUtils.getAsyncContext(object); - if (argAsyncContext == null) { - ((ReactorContextAccessor) object)._$PINPOINT$_setReactorContext(asyncContext); - } + ((ReactorContextAccessor) object)._$PINPOINT$_setReactorContext(asyncContext); } } diff --git a/plugins/bom/pom.xml b/plugins/bom/pom.xml index 08cf060fa14b..3c225fe6242a 100644 --- a/plugins/bom/pom.xml +++ b/plugins/bom/pom.xml @@ -31,7 +31,7 @@ 2.4.2 - 5.1.2.RELEASE + 6.1.5.RELEASE 2.1.7.1 2.5.3 3.9.0 diff --git a/plugins/reactor/src/main/java/com/navercorp/pinpoint/plugin/reactor/interceptor/ParallelFluxSubscribeInterceptor.java b/plugins/reactor/src/main/java/com/navercorp/pinpoint/plugin/reactor/interceptor/ParallelFluxSubscribeInterceptor.java index 2eeb65923102..a609bec37800 100644 --- a/plugins/reactor/src/main/java/com/navercorp/pinpoint/plugin/reactor/interceptor/ParallelFluxSubscribeInterceptor.java +++ b/plugins/reactor/src/main/java/com/navercorp/pinpoint/plugin/reactor/interceptor/ParallelFluxSubscribeInterceptor.java @@ -50,10 +50,7 @@ protected void setReactorContextToSubscriber(AsyncContext asyncContext, Object[] private void setAsyncContext(final AsyncContext asyncContext, final Object object) { if (object instanceof ReactorContextAccessor) { - final AsyncContext actualAsyncContext = ReactorContextAccessorUtils.getAsyncContext(object); - if (actualAsyncContext == null) { - ReactorContextAccessorUtils.setAsyncContext(asyncContext, object); - } + ReactorContextAccessorUtils.setAsyncContext(asyncContext, object); } } } diff --git a/plugins/reactor/src/main/java/com/navercorp/pinpoint/plugin/reactor/interceptor/RunnableCoreSubscriberInterceptor.java b/plugins/reactor/src/main/java/com/navercorp/pinpoint/plugin/reactor/interceptor/RunnableCoreSubscriberInterceptor.java index c28620790b32..78e610cff75a 100644 --- a/plugins/reactor/src/main/java/com/navercorp/pinpoint/plugin/reactor/interceptor/RunnableCoreSubscriberInterceptor.java +++ b/plugins/reactor/src/main/java/com/navercorp/pinpoint/plugin/reactor/interceptor/RunnableCoreSubscriberInterceptor.java @@ -34,10 +34,7 @@ public RunnableCoreSubscriberInterceptor(TraceContext traceContext, MethodDescri protected void doInBeforeTrace(SpanEventRecorder recorder, AsyncContext asyncContext, Object target, Object[] args) { final AsyncContext publisherAsyncContext = AsyncContextAccessorUtils.getAsyncContext(target); if (publisherAsyncContext != null) { - final AsyncContext subscriberAsyncContext = AsyncContextAccessorUtils.getAsyncContext(args, 0); - if (subscriberAsyncContext == null) { - AsyncContextAccessorUtils.setAsyncContext(publisherAsyncContext, args, 0); - } + AsyncContextAccessorUtils.setAsyncContext(publisherAsyncContext, args, 0); } } diff --git a/plugins/redis-lettuce/src/main/java/com/navercorp/pinpoint/plugin/redis/lettuce/LettucePlugin.java b/plugins/redis-lettuce/src/main/java/com/navercorp/pinpoint/plugin/redis/lettuce/LettucePlugin.java index 833888ef6642..3e84624e8d7f 100644 --- a/plugins/redis-lettuce/src/main/java/com/navercorp/pinpoint/plugin/redis/lettuce/LettucePlugin.java +++ b/plugins/redis-lettuce/src/main/java/com/navercorp/pinpoint/plugin/redis/lettuce/LettucePlugin.java @@ -16,6 +16,7 @@ package com.navercorp.pinpoint.plugin.redis.lettuce; +import com.navercorp.pinpoint.bootstrap.async.AsyncContextAccessor; import com.navercorp.pinpoint.bootstrap.instrument.InstrumentClass; import com.navercorp.pinpoint.bootstrap.instrument.InstrumentException; import com.navercorp.pinpoint.bootstrap.instrument.InstrumentMethod; @@ -28,13 +29,22 @@ import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin; import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPluginSetupContext; +import com.navercorp.pinpoint.bootstrap.plugin.reactor.CoreSubscriberConstructorInterceptor; +import com.navercorp.pinpoint.bootstrap.plugin.reactor.FluxAndMonoOperatorSubscribeInterceptor; +import com.navercorp.pinpoint.bootstrap.plugin.reactor.ReactorContextAccessor; +import com.navercorp.pinpoint.common.util.ArrayUtils; import com.navercorp.pinpoint.plugin.redis.lettuce.interceptor.AttachEndPointInterceptor; import com.navercorp.pinpoint.plugin.redis.lettuce.interceptor.LettuceMethodInterceptor; import com.navercorp.pinpoint.plugin.redis.lettuce.interceptor.RedisClientConstructorInterceptor; import com.navercorp.pinpoint.plugin.redis.lettuce.interceptor.RedisClusterClientConstructorInterceptor; +import com.navercorp.pinpoint.plugin.redis.lettuce.interceptor.RedisSubscriberInterceptor; +import com.navercorp.pinpoint.plugin.redis.lettuce.interceptor.RunnableNewInstanceInterceptor; +import com.navercorp.pinpoint.plugin.redis.lettuce.interceptor.RunnableRunInterceptor; import java.security.ProtectionDomain; +import static com.navercorp.pinpoint.common.util.VarArgs.va; + /** * @author jaehong.kim */ @@ -52,7 +62,7 @@ public void setup(ProfilerPluginSetupContext context) { return; } if (logger.isInfoEnabled()) { - logger.info("{} version range=[5.0.0.RELEASE, 5.2.1.RELEASE], config={}", this.getClass().getSimpleName(), config); + logger.info("{} version range=[5.0.0.RELEASE, 6.1.5.RELEASE], config={}", this.getClass().getSimpleName(), config); } // Set endpoint @@ -64,6 +74,8 @@ public void setup(ProfilerPluginSetupContext context) { // Commands addRedisCommands(config); + + addReactive(); } private void addRedisClient() { @@ -159,7 +171,7 @@ private void addRedisCommands(final LettucePluginConfig config) { } private void addAbstractRedisCommands(final String className, Class transformCallback, boolean getter) { - transformTemplate.transform(className, transformCallback, new Object[]{getter}, new Class[] {boolean.class}); + transformTemplate.transform(className, transformCallback, new Object[]{getter}, new Class[]{boolean.class}); } public static class AbstractRedisCommandsTransform implements TransformCallback { @@ -191,6 +203,102 @@ public byte[] doInTransform(Instrumentor instrumentor, ClassLoader classLoader, } } + private void addReactive() { + transformTemplate.transform("io.lettuce.core.RedisPublisher", RedisPublisherTransform.class); + transformTemplate.transform("io.lettuce.core.RedisPublisher$ImmediateSubscriber", RedisSubscriberTransform.class); + transformTemplate.transform("io.lettuce.core.RedisPublisher$PublishOnSubscriber", RedisSubscriberTransform.class); + transformTemplate.transform("io.lettuce.core.RedisPublisher$OnNext", RedisPublisherOnNextTransform.class); + transformTemplate.transform("io.lettuce.core.RedisPublisher$OnComplete", RedisPublisherOnCompleteTransform.class); + } + + public static class RedisPublisherTransform implements TransformCallback { + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + final InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer); + // Async Object + target.addField(AsyncContextAccessor.class); + target.addField(ReactorContextAccessor.class); + + final InstrumentMethod subscribeMethod = target.getDeclaredMethod("subscribe", "org.reactivestreams.Subscriber"); + if (subscribeMethod != null) { + subscribeMethod.addInterceptor(FluxAndMonoOperatorSubscribeInterceptor.class, va(LettuceConstants.REDIS_LETTUCE)); + } + + return target.toBytecode(); + } + } + + public static class RedisSubscriberTransform implements TransformCallback { + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + final InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer); + // Async Object + target.addField(AsyncContextAccessor.class); + target.addField(ReactorContextAccessor.class); + + for (InstrumentMethod constructorMethod : target.getDeclaredConstructors()) { + final String[] parameterTypes = constructorMethod.getParameterTypes(); + if (ArrayUtils.hasLength(parameterTypes)) { + constructorMethod.addInterceptor(CoreSubscriberConstructorInterceptor.class); + } + } + + for (InstrumentMethod method : target.getDeclaredMethods(MethodFilters.name("onNext", "onError", "onComplete"))) { + method.addInterceptor(RedisSubscriberInterceptor.class); + } + + return target.toBytecode(); + } + } + + public static class RedisPublisherOnNextTransform implements TransformCallback { + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + final InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer); + // Async Object + target.addField(AsyncContextAccessor.class); + + final InstrumentMethod newInstanceMethod = target.getDeclaredMethod("newInstance", "java.lang.Object", "org.reactivestreams.Subscriber"); + if (newInstanceMethod != null) { + newInstanceMethod.addInterceptor(RunnableNewInstanceInterceptor.class); + } + + final InstrumentMethod runMethod = target.getDeclaredMethod("run"); + if (runMethod != null) { + runMethod.addInterceptor(RunnableRunInterceptor.class); + } + + return target.toBytecode(); + } + } + + public static class RedisPublisherOnCompleteTransform implements TransformCallback { + @Override + public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { + final InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer); + // Async Object + target.addField(AsyncContextAccessor.class); + + // static OnComplete newInstance(Throwable signal, Subscriber subscriber) + final InstrumentMethod newInstanceMethod = target.getDeclaredMethod("newInstance", "java.lang.Throwable", "org.reactivestreams.Subscriber"); + if (newInstanceMethod != null) { + newInstanceMethod.addInterceptor(RunnableNewInstanceInterceptor.class); + } + // static OnComplete newInstance(Subscriber subscriber) + final InstrumentMethod newInstanceMethod2 = target.getDeclaredMethod("newInstance", "org.reactivestreams.Subscriber"); + if (newInstanceMethod2 != null) { + newInstanceMethod2.addInterceptor(RunnableNewInstanceInterceptor.class); + } + + final InstrumentMethod runMethod = target.getDeclaredMethod("run"); + if (runMethod != null) { + runMethod.addInterceptor(RunnableRunInterceptor.class); + } + + return target.toBytecode(); + } + } + @Override public void setTransformTemplate(TransformTemplate transformTemplate) { this.transformTemplate = transformTemplate; diff --git a/plugins/redis-lettuce/src/main/java/com/navercorp/pinpoint/plugin/redis/lettuce/interceptor/RedisSubscriberInterceptor.java b/plugins/redis-lettuce/src/main/java/com/navercorp/pinpoint/plugin/redis/lettuce/interceptor/RedisSubscriberInterceptor.java new file mode 100644 index 000000000000..2e58da2f217c --- /dev/null +++ b/plugins/redis-lettuce/src/main/java/com/navercorp/pinpoint/plugin/redis/lettuce/interceptor/RedisSubscriberInterceptor.java @@ -0,0 +1,62 @@ +/* + * Copyright 2022 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.redis.lettuce.interceptor; + +import com.navercorp.pinpoint.bootstrap.async.AsyncContextAccessorUtils; +import com.navercorp.pinpoint.bootstrap.context.AsyncContext; +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.interceptor.AsyncContextSpanEventSimpleAroundInterceptor; +import com.navercorp.pinpoint.bootstrap.plugin.reactor.ReactorContextAccessorUtils; +import com.navercorp.pinpoint.plugin.redis.lettuce.LettuceConstants; + +public class RedisSubscriberInterceptor extends AsyncContextSpanEventSimpleAroundInterceptor { + + public RedisSubscriberInterceptor(TraceContext traceContext, MethodDescriptor descriptor) { + super(traceContext, descriptor); + } + + @Override + public AsyncContext getAsyncContext(Object target, Object[] args) { + return getAsyncContextOrReactorContext(target); + } + + @Override + public void doInBeforeTrace(SpanEventRecorder recorder, AsyncContext asyncContext, Object target, Object[] args) { + } + + @Override + public AsyncContext getAsyncContext(Object target, Object[] args, Object result, Throwable throwable) { + return getAsyncContextOrReactorContext(target); + } + + @Override + public void doInAfterTrace(SpanEventRecorder recorder, Object target, Object[] args, Object result, Throwable throwable) { + recorder.recordApi(methodDescriptor); + recorder.recordServiceType(LettuceConstants.REDIS_LETTUCE); + recorder.recordException(throwable); + } + + AsyncContext getAsyncContextOrReactorContext(Object target) { + AsyncContext asyncContext = AsyncContextAccessorUtils.getAsyncContext(target); + if (asyncContext != null) { + return asyncContext; + } + return ReactorContextAccessorUtils.getAsyncContext(target); + } +} diff --git a/plugins/redis-lettuce/src/main/java/com/navercorp/pinpoint/plugin/redis/lettuce/interceptor/RunnableNewInstanceInterceptor.java b/plugins/redis-lettuce/src/main/java/com/navercorp/pinpoint/plugin/redis/lettuce/interceptor/RunnableNewInstanceInterceptor.java new file mode 100644 index 000000000000..ab67f1638b0b --- /dev/null +++ b/plugins/redis-lettuce/src/main/java/com/navercorp/pinpoint/plugin/redis/lettuce/interceptor/RunnableNewInstanceInterceptor.java @@ -0,0 +1,69 @@ +/* + * Copyright 2022 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.redis.lettuce.interceptor; + +import com.navercorp.pinpoint.bootstrap.async.AsyncContextAccessorUtils; +import com.navercorp.pinpoint.bootstrap.context.AsyncContext; +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.interceptor.AroundInterceptor; +import com.navercorp.pinpoint.bootstrap.logging.PLogger; +import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory; +import com.navercorp.pinpoint.bootstrap.plugin.reactor.ReactorContextAccessorUtils; +import com.navercorp.pinpoint.common.util.ArrayArgumentUtils; +import org.reactivestreams.Subscriber; + +public class RunnableNewInstanceInterceptor implements AroundInterceptor { + private final PLogger logger = PLoggerFactory.getLogger(getClass()); + private final boolean isDebug = logger.isDebugEnabled(); + + public RunnableNewInstanceInterceptor(TraceContext traceContext, MethodDescriptor methodDescriptor) { + } + + @Override + public void before(Object target, Object[] args) { + } + + @Override + public void after(Object target, Object[] args, Object result, Throwable throwable) { + if (isDebug) { + logger.afterInterceptor(target, args, result, throwable); + } + + Subscriber subscriber = ArrayArgumentUtils.getArgument(args, 1, Subscriber.class); + if (subscriber == null) { + subscriber = ArrayArgumentUtils.getArgument(args, 0, Subscriber.class); + } + + if (subscriber == null) { + return; + } + + AsyncContext asyncContext = AsyncContextAccessorUtils.getAsyncContext(subscriber); + if (asyncContext == null) { + asyncContext = ReactorContextAccessorUtils.getAsyncContext(subscriber); + } + if (asyncContext == null) { + return; + } + + // Set result to asyncContext + if (throwable != null) { + AsyncContextAccessorUtils.setAsyncContext(asyncContext, result); + } + } +} diff --git a/plugins/redis-lettuce/src/main/java/com/navercorp/pinpoint/plugin/redis/lettuce/interceptor/RunnableRunInterceptor.java b/plugins/redis-lettuce/src/main/java/com/navercorp/pinpoint/plugin/redis/lettuce/interceptor/RunnableRunInterceptor.java new file mode 100644 index 000000000000..544f5116e25c --- /dev/null +++ b/plugins/redis-lettuce/src/main/java/com/navercorp/pinpoint/plugin/redis/lettuce/interceptor/RunnableRunInterceptor.java @@ -0,0 +1,42 @@ +/* + * Copyright 2022 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.redis.lettuce.interceptor; + +import com.navercorp.pinpoint.bootstrap.context.AsyncContext; +import com.navercorp.pinpoint.bootstrap.context.MethodDescriptor; +import com.navercorp.pinpoint.bootstrap.context.SpanEventRecorder; +import com.navercorp.pinpoint.bootstrap.context.TraceContext; +import com.navercorp.pinpoint.bootstrap.interceptor.AsyncContextSpanEventSimpleAroundInterceptor; +import com.navercorp.pinpoint.plugin.redis.lettuce.LettuceConstants; + +public class RunnableRunInterceptor extends AsyncContextSpanEventSimpleAroundInterceptor { + + public RunnableRunInterceptor(TraceContext traceContext, MethodDescriptor descriptor) { + super(traceContext, descriptor); + } + + @Override + protected void doInBeforeTrace(SpanEventRecorder recorder, AsyncContext asyncContext, Object target, Object[] args) { + } + + @Override + public void doInAfterTrace(SpanEventRecorder recorder, Object target, Object[] args, Object result, Throwable throwable) { + recorder.recordApi(methodDescriptor); + recorder.recordServiceType(LettuceConstants.REDIS_LETTUCE); + recorder.recordException(throwable); + } +}